1b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav/* 2b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Copyright (C) 2013 The Android Open Source Project 3b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 4b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Licensed under the Apache License, Version 2.0 (the "License"); 5b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * you may not use this file except in compliance with the License. 6b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * You may obtain a copy of the License at 7b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 8b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * http://www.apache.org/licenses/LICENSE-2.0 9b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 10b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Unless required by applicable law or agreed to in writing, software 11b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * distributed under the License is distributed on an "AS IS" BASIS, 12b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * See the License for the specific language governing permissions and 14b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * limitations under the License. 15b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 16b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 17b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavpackage android.support.v4.print; 18b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 19b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.content.Context; 20b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.Bitmap; 2116ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onukiimport android.graphics.Bitmap.Config; 22b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.BitmapFactory; 2316ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onukiimport android.graphics.Canvas; 2416ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onukiimport android.graphics.ColorMatrix; 2516ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onukiimport android.graphics.ColorMatrixColorFilter; 26b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.Matrix; 2716ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onukiimport android.graphics.Paint; 28b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.RectF; 29b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.pdf.PdfDocument.Page; 30b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.net.Uri; 31975c49f182d754dfe1a38ba0457d6e603b125570John Hofordimport android.os.AsyncTask; 32b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.Bundle; 33b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.CancellationSignal; 34b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.ParcelFileDescriptor; 35b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PageRange; 36b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintAttributes; 37b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintDocumentAdapter; 38b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintDocumentInfo; 39b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintManager; 40215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmannimport android.print.PrintAttributes.MediaSize; 41b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.pdf.PrintedPdfDocument; 42b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.util.Log; 43b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 44b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.FileNotFoundException; 45b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.FileOutputStream; 46b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.IOException; 47b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.InputStream; 48b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 49b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav/** 50b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Kitkat specific PrintManager API implementation. 51b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 52975c49f182d754dfe1a38ba0457d6e603b125570John Hofordclass PrintHelperKitkat { 53b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav private static final String LOG_TAG = "PrintHelperKitkat"; 54b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // will be <= 300 dpi on A4 (8.3×11.7) paper (worst case of 150 dpi) 55b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav private final static int MAX_PRINT_SIZE = 3500; 56b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav final Context mContext; 57975c49f182d754dfe1a38ba0457d6e603b125570John Hoford BitmapFactory.Options mDecodeOptions = null; 58975c49f182d754dfe1a38ba0457d6e603b125570John Hoford private final Object mLock = new Object(); 59b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 60b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * image will be scaled but leave white space 61b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 62b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public static final int SCALE_MODE_FIT = 1; 63b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 64b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * image will fill the paper and be cropped (default) 65b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 66b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public static final int SCALE_MODE_FILL = 2; 67b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 6809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov /** 69975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * select landscape (default) 70975c49f182d754dfe1a38ba0457d6e603b125570John Hoford */ 71975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public static final int ORIENTATION_LANDSCAPE = 1; 72975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 73975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /** 74975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * select portrait 75975c49f182d754dfe1a38ba0457d6e603b125570John Hoford */ 76975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public static final int ORIENTATION_PORTRAIT = 2; 77975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 78975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /** 7909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * this is a black and white image 8009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov */ 8109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov public static final int COLOR_MODE_MONOCHROME = 1; 8209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov /** 8309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * this is a color image (default) 8409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov */ 8509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov public static final int COLOR_MODE_COLOR = 2; 8609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov 87b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov public interface OnPrintFinishCallback { 88b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov public void onFinish(); 89b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov } 90b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov 91215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann /** 92215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann * Whether the PrintActivity respects the suggested orientation 93215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann */ 94215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann protected boolean mPrintActivityRespectsOrientation; 95215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann 9673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann /** 9773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * Whether the print subsystem handles min margins correctly. If not the print helper needs to 9873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * fake this. 9973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann */ 10073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann protected boolean mIsMinMarginsHandlingCorrect; 10173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 102b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav int mScaleMode = SCALE_MODE_FILL; 103b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 10409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov int mColorMode = COLOR_MODE_COLOR; 10509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov 106215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann int mOrientation; 107975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 108b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav PrintHelperKitkat(Context context) { 109215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann mPrintActivityRespectsOrientation = true; 11073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann mIsMinMarginsHandlingCorrect = true; 111215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann 112b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav mContext = context; 113b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 114b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 115b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 116b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Selects whether the image will fill the paper and be cropped 117975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * <p/> 118b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * {@link #SCALE_MODE_FIT} 119b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * or whether the image will be scaled but leave white space 120b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * {@link #SCALE_MODE_FILL}. 121b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 122b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param scaleMode {@link #SCALE_MODE_FIT} or 123b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * {@link #SCALE_MODE_FILL} 124b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 125b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public void setScaleMode(int scaleMode) { 126b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav mScaleMode = scaleMode; 127b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 128b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 129b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 130b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Returns the scale mode with which the image will fill the paper. 131b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 132b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @return The scale Mode: {@link #SCALE_MODE_FIT} or 133b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * {@link #SCALE_MODE_FILL} 134b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 135b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public int getScaleMode() { 136b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav return mScaleMode; 137b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 138b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 139b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 14009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * Sets whether the image will be printed in color (default) 14109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * {@link #COLOR_MODE_COLOR} or in back and white 14209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * {@link #COLOR_MODE_MONOCHROME}. 14309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * 14409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * @param colorMode The color mode which is one of 145975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * {@link #COLOR_MODE_COLOR} and {@link #COLOR_MODE_MONOCHROME}. 14609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov */ 14709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov public void setColorMode(int colorMode) { 14809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov mColorMode = colorMode; 14909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov } 15009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov 15109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov /** 152975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * Sets whether to select landscape (default), {@link #ORIENTATION_LANDSCAPE} 153975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * or portrait {@link #ORIENTATION_PORTRAIT} 154975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @param orientation The page orientation which is one of 155975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}. 156975c49f182d754dfe1a38ba0457d6e603b125570John Hoford */ 157975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void setOrientation(int orientation) { 158975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mOrientation = orientation; 159975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 160975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 161975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /** 162975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * Gets the page orientation with which the image will be printed. 163975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * 164975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @return The preferred orientation which is one of 165975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT} 166975c49f182d754dfe1a38ba0457d6e603b125570John Hoford */ 167975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public int getOrientation() { 168215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann /// Unset defaults to landscape but might turn image 169215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann if (mOrientation == 0) { 170215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann return ORIENTATION_LANDSCAPE; 171215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann } 172975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return mOrientation; 173975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 174975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 175975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /** 17609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * Gets the color mode with which the image will be printed. 17709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * 17809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * @return The color mode which is one of {@link #COLOR_MODE_COLOR} 17909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * and {@link #COLOR_MODE_MONOCHROME}. 18009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov */ 18109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov public int getColorMode() { 18209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov return mColorMode; 18309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov } 18409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov 18509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov /** 186215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann * Check if the supplied bitmap should best be printed on a portrait orientation paper. 187215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann * 188215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann * @param bitmap The bitmap to be printed. 189215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann * @return true iff the picture should best be printed on a portrait orientation paper. 190215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann */ 191215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann private static boolean isPortrait(Bitmap bitmap) { 192215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann if (bitmap.getWidth() <= bitmap.getHeight()) { 193215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann return true; 194215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann } else { 195215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann return false; 196215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann } 197215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann } 198215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann 199215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann /** 20073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * Create a build with a copy from the other print attributes. 20173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * 20273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * @param other The other print attributes 20373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * 20473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * @return A builder that will build print attributes that match the other attributes 20573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann */ 20673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann protected PrintAttributes.Builder copyAttributes(PrintAttributes other) { 20745f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann PrintAttributes.Builder b = (new PrintAttributes.Builder()) 20873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann .setMediaSize(other.getMediaSize()) 20973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann .setResolution(other.getResolution()) 21073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann .setMinMargins(other.getMinMargins()); 21145f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann 21245f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann if (other.getColorMode() != 0) { 21345f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann b.setColorMode(other.getColorMode()); 21445f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann } 21545f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann 21645f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann return b; 21773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } 21873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 21973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann /** 220b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Prints a bitmap. 221b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 222b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param jobName The print job name. 223b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param bitmap The bitmap to print. 224b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov * @param callback Optional callback to observe when printing is finished. 225b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 226b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov public void printBitmap(final String jobName, final Bitmap bitmap, 227b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov final OnPrintFinishCallback callback) { 228b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (bitmap == null) { 229b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav return; 230b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 231b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav final int fittingMode = mScaleMode; // grab the fitting mode at time of call 232b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE); 233215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann PrintAttributes.MediaSize mediaSize; 234215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann if (isPortrait(bitmap)) { 235215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann mediaSize = PrintAttributes.MediaSize.UNKNOWN_PORTRAIT; 236215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann } else { 237b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav mediaSize = PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE; 238b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 23909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov PrintAttributes attr = new PrintAttributes.Builder() 24009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov .setMediaSize(mediaSize) 24109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov .setColorMode(mColorMode) 24209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov .build(); 243b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 244b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav printManager.print(jobName, 245b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav new PrintDocumentAdapter() { 246b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav private PrintAttributes mAttributes; 247b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 248b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav @Override 249b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public void onLayout(PrintAttributes oldPrintAttributes, 250b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav PrintAttributes newPrintAttributes, 251b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav CancellationSignal cancellationSignal, 252b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav LayoutResultCallback layoutResultCallback, 253b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav Bundle bundle) { 254b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 255b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav mAttributes = newPrintAttributes; 256b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 257b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName) 258b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO) 259b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav .setPageCount(1) 260b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav .build(); 261b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav boolean changed = !newPrintAttributes.equals(oldPrintAttributes); 262b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav layoutResultCallback.onLayoutFinished(info, changed); 263b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 264b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 265b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav @Override 266b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor, 267b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav CancellationSignal cancellationSignal, 268b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav WriteResultCallback writeResultCallback) { 26973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann writeBitmap(mAttributes, fittingMode, bitmap, fileDescriptor, 27073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann writeResultCallback); 271b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 272b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov 273b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov @Override 274b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov public void onFinish() { 275b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov if (callback != null) { 276b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov callback.onFinish(); 277b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov } 278b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov } 279b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav }, attr); 280b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 281b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 282b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 283975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * Calculates the transform the print an Image to fill the page 284975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * 285975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @param imageWidth with of bitmap 286975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @param imageHeight height of bitmap 287975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @param content The output page dimensions 288975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @param fittingMode The mode of fitting {@link #SCALE_MODE_FILL} vs {@link #SCALE_MODE_FIT} 289975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @return Matrix to be used in canvas.drawBitmap(bitmap, matrix, null) call 290975c49f182d754dfe1a38ba0457d6e603b125570John Hoford */ 291975c49f182d754dfe1a38ba0457d6e603b125570John Hoford private Matrix getMatrix(int imageWidth, int imageHeight, RectF content, int fittingMode) { 292975c49f182d754dfe1a38ba0457d6e603b125570John Hoford Matrix matrix = new Matrix(); 293975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 294975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Compute and apply scale to fill the page. 295975c49f182d754dfe1a38ba0457d6e603b125570John Hoford float scale = content.width() / imageWidth; 296975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (fittingMode == SCALE_MODE_FILL) { 297975c49f182d754dfe1a38ba0457d6e603b125570John Hoford scale = Math.max(scale, content.height() / imageHeight); 298975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } else { 299975c49f182d754dfe1a38ba0457d6e603b125570John Hoford scale = Math.min(scale, content.height() / imageHeight); 300975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 301975c49f182d754dfe1a38ba0457d6e603b125570John Hoford matrix.postScale(scale, scale); 302975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 303975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Center the content. 304975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final float translateX = (content.width() 305975c49f182d754dfe1a38ba0457d6e603b125570John Hoford - imageWidth * scale) / 2; 306975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final float translateY = (content.height() 307975c49f182d754dfe1a38ba0457d6e603b125570John Hoford - imageHeight * scale) / 2; 308975c49f182d754dfe1a38ba0457d6e603b125570John Hoford matrix.postTranslate(translateX, translateY); 309975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return matrix; 310975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 311975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 312975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /** 31373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * Write a bitmap for a PDF document. 31473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * 31573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * @param attributes The print attributes 31673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * @param fittingMode How to fit the bitmap 31773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * @param bitmap The bitmap to write 31873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * @param fileDescriptor The file to write to 31973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann * @param writeResultCallback Callback to call once written 32073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann */ 32173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann private void writeBitmap(PrintAttributes attributes, int fittingMode, Bitmap bitmap, 32273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann ParcelFileDescriptor fileDescriptor, 32373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann PrintDocumentAdapter.WriteResultCallback writeResultCallback) { 32473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann PrintAttributes pdfAttributes; 32573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann if (mIsMinMarginsHandlingCorrect) { 32673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann pdfAttributes = attributes; 32773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } else { 32873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // If the handling of any margin != 0 is broken, strip the margins and add them to the 32973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // bitmap later 33073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann pdfAttributes = copyAttributes(attributes) 33173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann .setMinMargins(new PrintAttributes.Margins(0,0,0,0)).build(); 33273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } 33373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 33473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext, 33573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann pdfAttributes); 33673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 33773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann Bitmap maybeGrayscale = convertBitmapForColorMode(bitmap, 33873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann pdfAttributes.getColorMode()); 33973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann try { 34073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann Page page = pdfDocument.startPage(1); 34173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 34273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann RectF contentRect; 34373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann if (mIsMinMarginsHandlingCorrect) { 34473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann contentRect = new RectF(page.getInfo().getContentRect()); 34573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } else { 34673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // Create dummy doc that has the margins to compute correctly sized content 34773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // rectangle 34873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann PrintedPdfDocument dummyDocument = new PrintedPdfDocument(mContext, 34973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann attributes); 35073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann Page dummyPage = dummyDocument.startPage(1); 35173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann contentRect = new RectF(dummyPage.getInfo().getContentRect()); 35273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann dummyDocument.finishPage(dummyPage); 35373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann dummyDocument.close(); 35473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } 35573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 35673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // Resize bitmap 35773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann Matrix matrix = getMatrix( 35873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann maybeGrayscale.getWidth(), maybeGrayscale.getHeight(), 35973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann contentRect, fittingMode); 36073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 36173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann if (mIsMinMarginsHandlingCorrect) { 36273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // The pdfDocument takes care of the positioning and margins 36373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } else { 36473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // Move it to the correct position. 36573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann matrix.postTranslate(contentRect.left, contentRect.top); 36673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 36773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // Cut off margins 36873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann page.getCanvas().clipRect(contentRect); 36973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } 37073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 37173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // Draw the bitmap. 37273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann page.getCanvas().drawBitmap(maybeGrayscale, matrix, null); 37373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 37473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // Finish the page. 37573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann pdfDocument.finishPage(page); 37673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 37773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann try { 37873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // Write the document. 37973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann pdfDocument.writeTo(new FileOutputStream(fileDescriptor.getFileDescriptor())); 38073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // Done. 38173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann writeResultCallback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES}); 38273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } catch (IOException ioe) { 38373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // Failed. 38473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann Log.e(LOG_TAG, "Error writing printed content", ioe); 38573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann writeResultCallback.onWriteFailed(null); 38673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } 38773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } finally { 38873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann pdfDocument.close(); 38973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 39073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann if (fileDescriptor != null) { 39173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann try { 39273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann fileDescriptor.close(); 39373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } catch (IOException ioe) { 39473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // ignore 39573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } 39673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } 39773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann // If we created a new instance for grayscaling, then recycle it here. 39873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann if (maybeGrayscale != bitmap) { 39973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann maybeGrayscale.recycle(); 40073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } 40173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } 40273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann } 40373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann 40473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann /** 405b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Prints an image located at the Uri. Image types supported are those of 406b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * <code>BitmapFactory.decodeStream</code> (JPEG, GIF, PNG, BMP, WEBP) 407b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 408b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param jobName The print job name. 409b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param imageFile The <code>Uri</code> pointing to an image to print. 410b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov * @param callback Optional callback to observe when printing is finished. 411b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @throws FileNotFoundException if <code>Uri</code> is not pointing to a valid image. 412b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 413b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov public void printBitmap(final String jobName, final Uri imageFile, 414b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov final OnPrintFinishCallback callback) throws FileNotFoundException { 415975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final int fittingMode = mScaleMode; 416975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 417975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintDocumentAdapter printDocumentAdapter = new PrintDocumentAdapter() { 418975c49f182d754dfe1a38ba0457d6e603b125570John Hoford private PrintAttributes mAttributes; 419854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav AsyncTask<Uri, Boolean, Bitmap> mLoadBitmap; 420975c49f182d754dfe1a38ba0457d6e603b125570John Hoford Bitmap mBitmap = null; 421975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 422975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 423975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void onLayout(final PrintAttributes oldPrintAttributes, 424975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final PrintAttributes newPrintAttributes, 425975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final CancellationSignal cancellationSignal, 426975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final LayoutResultCallback layoutResultCallback, 427975c49f182d754dfe1a38ba0457d6e603b125570John Hoford Bundle bundle) { 428854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav 429215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann synchronized (this) { 430215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann mAttributes = newPrintAttributes; 431215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann } 432854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav 433975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (cancellationSignal.isCanceled()) { 434975c49f182d754dfe1a38ba0457d6e603b125570John Hoford layoutResultCallback.onLayoutCancelled(); 435975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return; 436975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 437975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // we finished the load 438975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (mBitmap != null) { 439975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName) 440975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO) 441975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .setPageCount(1) 442975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .build(); 443975c49f182d754dfe1a38ba0457d6e603b125570John Hoford boolean changed = !newPrintAttributes.equals(oldPrintAttributes); 444975c49f182d754dfe1a38ba0457d6e603b125570John Hoford layoutResultCallback.onLayoutFinished(info, changed); 445975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return; 446975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 447975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 448854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav mLoadBitmap = new AsyncTask<Uri, Boolean, Bitmap>() { 449975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 450975c49f182d754dfe1a38ba0457d6e603b125570John Hoford protected void onPreExecute() { 451975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // First register for cancellation requests. 452975c49f182d754dfe1a38ba0457d6e603b125570John Hoford cancellationSignal.setOnCancelListener( 453975c49f182d754dfe1a38ba0457d6e603b125570John Hoford new CancellationSignal.OnCancelListener() { 454975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 455975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void onCancel() { // on different thread 456975c49f182d754dfe1a38ba0457d6e603b125570John Hoford cancelLoad(); 457975c49f182d754dfe1a38ba0457d6e603b125570John Hoford cancel(false); 458975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 459975c49f182d754dfe1a38ba0457d6e603b125570John Hoford }); 460975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 461975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 462975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 463975c49f182d754dfe1a38ba0457d6e603b125570John Hoford protected Bitmap doInBackground(Uri... uris) { 464975c49f182d754dfe1a38ba0457d6e603b125570John Hoford try { 465975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return loadConstrainedBitmap(imageFile, MAX_PRINT_SIZE); 466975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } catch (FileNotFoundException e) { 467975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /* ignore */ 468975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 469975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return null; 470975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 471975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 472975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 473975c49f182d754dfe1a38ba0457d6e603b125570John Hoford protected void onPostExecute(Bitmap bitmap) { 474975c49f182d754dfe1a38ba0457d6e603b125570John Hoford super.onPostExecute(bitmap); 475215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann 476215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann // If orientation was not set by the caller, try to fit the bitmap on 477215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann // the current paper by potentially rotating the bitmap by 90 degrees. 478215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann if (bitmap != null 479215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann && (!mPrintActivityRespectsOrientation || mOrientation == 0)) { 480215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann MediaSize mediaSize; 481215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann 482215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann synchronized (this) { 483215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann mediaSize = mAttributes.getMediaSize(); 484215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann } 485215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann 486215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann if (mediaSize != null) { 487215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann if (mediaSize.isPortrait() != isPortrait(bitmap)) { 488215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann Matrix rotation = new Matrix(); 489215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann 490215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann rotation.postRotate(90); 491215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), 492215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann bitmap.getHeight(), rotation, true); 493215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann } 494215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann } 495215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann } 496215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann 497975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mBitmap = bitmap; 498975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (bitmap != null) { 499975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName) 500975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO) 501975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .setPageCount(1) 502975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .build(); 503215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann 504975c49f182d754dfe1a38ba0457d6e603b125570John Hoford boolean changed = !newPrintAttributes.equals(oldPrintAttributes); 505975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 506975c49f182d754dfe1a38ba0457d6e603b125570John Hoford layoutResultCallback.onLayoutFinished(info, changed); 507975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 508975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } else { 509975c49f182d754dfe1a38ba0457d6e603b125570John Hoford layoutResultCallback.onLayoutFailed(null); 510975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 511854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav mLoadBitmap = null; 512975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 513975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 514975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 515975c49f182d754dfe1a38ba0457d6e603b125570John Hoford protected void onCancelled(Bitmap result) { 516975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Task was cancelled, report that. 517975c49f182d754dfe1a38ba0457d6e603b125570John Hoford layoutResultCallback.onLayoutCancelled(); 518854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav mLoadBitmap = null; 519975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 520854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav }.execute(); 521975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 522975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 523975c49f182d754dfe1a38ba0457d6e603b125570John Hoford private void cancelLoad() { 524975c49f182d754dfe1a38ba0457d6e603b125570John Hoford synchronized (mLock) { // prevent race with set null below 525975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (mDecodeOptions != null) { 526975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions.requestCancelDecode(); 527975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions = null; 528975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 529975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 530975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 531975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 532975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 533975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void onFinish() { 534975c49f182d754dfe1a38ba0457d6e603b125570John Hoford super.onFinish(); 535975c49f182d754dfe1a38ba0457d6e603b125570John Hoford cancelLoad(); 536854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav if (mLoadBitmap != null) { 537854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav mLoadBitmap.cancel(true); 538854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav } 539b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov if (callback != null) { 540b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov callback.onFinish(); 541b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov } 54216ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki if (mBitmap != null) { 54316ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki mBitmap.recycle(); 54416ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki mBitmap = null; 54516ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki } 546975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 547975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 548975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 549975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor, 550975c49f182d754dfe1a38ba0457d6e603b125570John Hoford CancellationSignal cancellationSignal, 551975c49f182d754dfe1a38ba0457d6e603b125570John Hoford WriteResultCallback writeResultCallback) { 55273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann writeBitmap(mAttributes, fittingMode, mBitmap, fileDescriptor, writeResultCallback); 553975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 554975c49f182d754dfe1a38ba0457d6e603b125570John Hoford }; 555975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 556975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE); 557975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintAttributes.Builder builder = new PrintAttributes.Builder(); 558975c49f182d754dfe1a38ba0457d6e603b125570John Hoford builder.setColorMode(mColorMode); 559975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 560215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann if (mOrientation == ORIENTATION_LANDSCAPE || mOrientation == 0) { 561975c49f182d754dfe1a38ba0457d6e603b125570John Hoford builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE); 562975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } else if (mOrientation == ORIENTATION_PORTRAIT) { 563975c49f182d754dfe1a38ba0457d6e603b125570John Hoford builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_PORTRAIT); 564975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 565975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintAttributes attr = builder.build(); 566975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 567975c49f182d754dfe1a38ba0457d6e603b125570John Hoford printManager.print(jobName, printDocumentAdapter, attr); 568b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 569b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 570b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 571b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Loads a bitmap while limiting its size 572b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 573b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param uri location of a valid image 574b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param maxSideLength the maximum length of a size 575b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @return the Bitmap 576b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @throws FileNotFoundException if the Uri does not point to an image 577b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 578b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav private Bitmap loadConstrainedBitmap(Uri uri, int maxSideLength) throws FileNotFoundException { 579b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (maxSideLength <= 0 || uri == null || mContext == null) { 580b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav throw new IllegalArgumentException("bad argument to getScaledBitmap"); 581b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 582b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Get width and height of stored bitmap 583b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav BitmapFactory.Options opt = new BitmapFactory.Options(); 584b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav opt.inJustDecodeBounds = true; 585b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav loadBitmap(uri, opt); 586b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 587b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav int w = opt.outWidth; 588b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav int h = opt.outHeight; 589b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 590b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // If bitmap cannot be decoded, return null 591b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (w <= 0 || h <= 0) { 592b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav return null; 593b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 594b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 595b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Find best downsampling size 596b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav int imageSide = Math.max(w, h); 597b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 598b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav int sampleSize = 1; 599b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav while (imageSide > maxSideLength) { 600b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav imageSide >>>= 1; 601b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav sampleSize <<= 1; 602b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 603b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 604b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Make sure sample size is reasonable 605b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (sampleSize <= 0 || 0 >= (int) (Math.min(w, h) / sampleSize)) { 606b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav return null; 607b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 608975c49f182d754dfe1a38ba0457d6e603b125570John Hoford BitmapFactory.Options decodeOptions = null; 609975c49f182d754dfe1a38ba0457d6e603b125570John Hoford synchronized (mLock) { // prevent race with set null below 610975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions = new BitmapFactory.Options(); 611975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions.inMutable = true; 612975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions.inSampleSize = sampleSize; 613975c49f182d754dfe1a38ba0457d6e603b125570John Hoford decodeOptions = mDecodeOptions; 614975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 615975c49f182d754dfe1a38ba0457d6e603b125570John Hoford try { 616975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return loadBitmap(uri, decodeOptions); 617975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } finally { 618975c49f182d754dfe1a38ba0457d6e603b125570John Hoford synchronized (mLock) { 619975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions = null; 620975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 621975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 622b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 623b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 624b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 625b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Returns the bitmap from the given uri loaded using the given options. 626b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Returns null on failure. 627b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 628b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav private Bitmap loadBitmap(Uri uri, BitmapFactory.Options o) throws FileNotFoundException { 629b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (uri == null || mContext == null) { 630b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav throw new IllegalArgumentException("bad argument to loadBitmap"); 631b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 632b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav InputStream is = null; 633b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav try { 634b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav is = mContext.getContentResolver().openInputStream(uri); 635b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav return BitmapFactory.decodeStream(is, null, o); 636b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } finally { 637545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov if (is != null) { 638545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov try { 639545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov is.close(); 640545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov } catch (IOException t) { 641545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov Log.w(LOG_TAG, "close fail ", t); 642545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov } 643b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 644b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 645b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 64616ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki 64716ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki private Bitmap convertBitmapForColorMode(Bitmap original, int colorMode) { 64816ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki if (colorMode != COLOR_MODE_MONOCHROME) { 64916ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki return original; 65016ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki } 65116ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki // Create a grayscale bitmap 65216ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki Bitmap grayscale = Bitmap.createBitmap(original.getWidth(), original.getHeight(), 65316ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki Config.ARGB_8888); 65416ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki Canvas c = new Canvas(grayscale); 65516ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki Paint p = new Paint(); 65616ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki ColorMatrix cm = new ColorMatrix(); 65716ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki cm.setSaturation(0); 65816ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm); 65916ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki p.setColorFilter(f); 66016ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki c.drawBitmap(original, 0, 0, p); 66116ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki c.setBitmap(null); 66216ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki 66316ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki return grayscale; 66416ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki } 66573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann} 666