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; 21b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.BitmapFactory; 22b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.Matrix; 23b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.RectF; 24b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.pdf.PdfDocument.Page; 25b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.net.Uri; 26975c49f182d754dfe1a38ba0457d6e603b125570John Hofordimport android.os.AsyncTask; 27b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.Bundle; 28b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.CancellationSignal; 29b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.ParcelFileDescriptor; 30b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PageRange; 31b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintAttributes; 32b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintDocumentAdapter; 33b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintDocumentInfo; 34b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintManager; 35b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.pdf.PrintedPdfDocument; 36b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.util.Log; 37b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 38b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.FileNotFoundException; 39b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.FileOutputStream; 40b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.IOException; 41b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.InputStream; 42b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 43b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav/** 44b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Kitkat specific PrintManager API implementation. 45b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 46975c49f182d754dfe1a38ba0457d6e603b125570John Hofordclass PrintHelperKitkat { 47b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav private static final String LOG_TAG = "PrintHelperKitkat"; 48b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // will be <= 300 dpi on A4 (8.3×11.7) paper (worst case of 150 dpi) 49b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav private final static int MAX_PRINT_SIZE = 3500; 50b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav final Context mContext; 51975c49f182d754dfe1a38ba0457d6e603b125570John Hoford BitmapFactory.Options mDecodeOptions = null; 52975c49f182d754dfe1a38ba0457d6e603b125570John Hoford private final Object mLock = new Object(); 53b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 54b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * image will be scaled but leave white space 55b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 56b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public static final int SCALE_MODE_FIT = 1; 57b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 58b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * image will fill the paper and be cropped (default) 59b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 60b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public static final int SCALE_MODE_FILL = 2; 61b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 6209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov /** 63975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * select landscape (default) 64975c49f182d754dfe1a38ba0457d6e603b125570John Hoford */ 65975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public static final int ORIENTATION_LANDSCAPE = 1; 66975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 67975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /** 68975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * select portrait 69975c49f182d754dfe1a38ba0457d6e603b125570John Hoford */ 70975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public static final int ORIENTATION_PORTRAIT = 2; 71975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 72975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /** 7309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * this is a black and white image 7409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov */ 7509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov public static final int COLOR_MODE_MONOCHROME = 1; 7609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov /** 7709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * this is a color image (default) 7809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov */ 7909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov public static final int COLOR_MODE_COLOR = 2; 8009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov 81b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav int mScaleMode = SCALE_MODE_FILL; 82b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 8309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov int mColorMode = COLOR_MODE_COLOR; 8409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov 85975c49f182d754dfe1a38ba0457d6e603b125570John Hoford int mOrientation = ORIENTATION_LANDSCAPE; 86975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 87b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav PrintHelperKitkat(Context context) { 88b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav mContext = context; 89b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 90b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 91b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 92b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Selects whether the image will fill the paper and be cropped 93975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * <p/> 94b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * {@link #SCALE_MODE_FIT} 95b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * or whether the image will be scaled but leave white space 96b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * {@link #SCALE_MODE_FILL}. 97b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 98b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param scaleMode {@link #SCALE_MODE_FIT} or 99b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * {@link #SCALE_MODE_FILL} 100b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 101b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public void setScaleMode(int scaleMode) { 102b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav mScaleMode = scaleMode; 103b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 104b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 105b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 106b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Returns the scale mode with which the image will fill the paper. 107b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 108b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @return The scale Mode: {@link #SCALE_MODE_FIT} or 109b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * {@link #SCALE_MODE_FILL} 110b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 111b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public int getScaleMode() { 112b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav return mScaleMode; 113b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 114b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 115b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 11609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * Sets whether the image will be printed in color (default) 11709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * {@link #COLOR_MODE_COLOR} or in back and white 11809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * {@link #COLOR_MODE_MONOCHROME}. 11909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * 12009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * @param colorMode The color mode which is one of 121975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * {@link #COLOR_MODE_COLOR} and {@link #COLOR_MODE_MONOCHROME}. 12209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov */ 12309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov public void setColorMode(int colorMode) { 12409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov mColorMode = colorMode; 12509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov } 12609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov 12709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov /** 128975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * Sets whether to select landscape (default), {@link #ORIENTATION_LANDSCAPE} 129975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * or portrait {@link #ORIENTATION_PORTRAIT} 130975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @param orientation The page orientation which is one of 131975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}. 132975c49f182d754dfe1a38ba0457d6e603b125570John Hoford */ 133975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void setOrientation(int orientation) { 134975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mOrientation = orientation; 135975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 136975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 137975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /** 138975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * Gets the page orientation with which the image will be printed. 139975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * 140975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @return The preferred orientation which is one of 141975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT} 142975c49f182d754dfe1a38ba0457d6e603b125570John Hoford */ 143975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public int getOrientation() { 144975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return mOrientation; 145975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 146975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 147975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /** 14809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * Gets the color mode with which the image will be printed. 14909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * 15009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * @return The color mode which is one of {@link #COLOR_MODE_COLOR} 15109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov * and {@link #COLOR_MODE_MONOCHROME}. 15209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov */ 15309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov public int getColorMode() { 15409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov return mColorMode; 15509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov } 15609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov 15709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov /** 158b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Prints a bitmap. 159b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 160b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param jobName The print job name. 161b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param bitmap The bitmap to print. 162b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 163b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public void printBitmap(final String jobName, final Bitmap bitmap) { 164b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (bitmap == null) { 165b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav return; 166b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 167b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav final int fittingMode = mScaleMode; // grab the fitting mode at time of call 168b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE); 169b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav PrintAttributes.MediaSize mediaSize = PrintAttributes.MediaSize.UNKNOWN_PORTRAIT; 170b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (bitmap.getWidth() > bitmap.getHeight()) { 171b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav mediaSize = PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE; 172b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 17309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov PrintAttributes attr = new PrintAttributes.Builder() 17409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov .setMediaSize(mediaSize) 17509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov .setColorMode(mColorMode) 17609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov .build(); 177b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 178b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav printManager.print(jobName, 179b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav new PrintDocumentAdapter() { 180b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav private PrintAttributes mAttributes; 181b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 182b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav @Override 183b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public void onLayout(PrintAttributes oldPrintAttributes, 184b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav PrintAttributes newPrintAttributes, 185b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav CancellationSignal cancellationSignal, 186b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav LayoutResultCallback layoutResultCallback, 187b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav Bundle bundle) { 188b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 189b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav mAttributes = newPrintAttributes; 190b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 191b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName) 192b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO) 193b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav .setPageCount(1) 194b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav .build(); 195b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav boolean changed = !newPrintAttributes.equals(oldPrintAttributes); 196b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav layoutResultCallback.onLayoutFinished(info, changed); 197b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 198b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 199b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav @Override 200b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor, 201b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav CancellationSignal cancellationSignal, 202b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav WriteResultCallback writeResultCallback) { 203b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext, 204b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav mAttributes); 205b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav try { 206b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav Page page = pdfDocument.startPage(1); 207b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 208b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav RectF content = new RectF(page.getInfo().getContentRect()); 209b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 210975c49f182d754dfe1a38ba0457d6e603b125570John Hoford Matrix matrix = getMatrix(bitmap.getWidth(), bitmap.getHeight(), 211975c49f182d754dfe1a38ba0457d6e603b125570John Hoford content, fittingMode); 212b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 213b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Draw the bitmap. 214b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav page.getCanvas().drawBitmap(bitmap, matrix, null); 215b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 216b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Finish the page. 217b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav pdfDocument.finishPage(page); 218b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 219b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav try { 220b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Write the document. 221b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav pdfDocument.writeTo(new FileOutputStream( 222b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav fileDescriptor.getFileDescriptor())); 223b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Done. 224b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav writeResultCallback.onWriteFinished( 225b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav new PageRange[]{PageRange.ALL_PAGES}); 226b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } catch (IOException ioe) { 227b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Failed. 228b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav Log.e(LOG_TAG, "Error writing printed content", ioe); 229b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav writeResultCallback.onWriteFailed(null); 230b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 231b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } finally { 232b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (pdfDocument != null) { 233b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav pdfDocument.close(); 234b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 235b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (fileDescriptor != null) { 236b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav try { 237b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav fileDescriptor.close(); 238b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } catch (IOException ioe) { 239b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /* ignore */ 240b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 241b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 242b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 243b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 244b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav }, attr); 245b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 246b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 247b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 248975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * Calculates the transform the print an Image to fill the page 249975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * 250975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @param imageWidth with of bitmap 251975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @param imageHeight height of bitmap 252975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @param content The output page dimensions 253975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @param fittingMode The mode of fitting {@link #SCALE_MODE_FILL} vs {@link #SCALE_MODE_FIT} 254975c49f182d754dfe1a38ba0457d6e603b125570John Hoford * @return Matrix to be used in canvas.drawBitmap(bitmap, matrix, null) call 255975c49f182d754dfe1a38ba0457d6e603b125570John Hoford */ 256975c49f182d754dfe1a38ba0457d6e603b125570John Hoford private Matrix getMatrix(int imageWidth, int imageHeight, RectF content, int fittingMode) { 257975c49f182d754dfe1a38ba0457d6e603b125570John Hoford Matrix matrix = new Matrix(); 258975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 259975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Compute and apply scale to fill the page. 260975c49f182d754dfe1a38ba0457d6e603b125570John Hoford float scale = content.width() / imageWidth; 261975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (fittingMode == SCALE_MODE_FILL) { 262975c49f182d754dfe1a38ba0457d6e603b125570John Hoford scale = Math.max(scale, content.height() / imageHeight); 263975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } else { 264975c49f182d754dfe1a38ba0457d6e603b125570John Hoford scale = Math.min(scale, content.height() / imageHeight); 265975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 266975c49f182d754dfe1a38ba0457d6e603b125570John Hoford matrix.postScale(scale, scale); 267975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 268975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Center the content. 269975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final float translateX = (content.width() 270975c49f182d754dfe1a38ba0457d6e603b125570John Hoford - imageWidth * scale) / 2; 271975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final float translateY = (content.height() 272975c49f182d754dfe1a38ba0457d6e603b125570John Hoford - imageHeight * scale) / 2; 273975c49f182d754dfe1a38ba0457d6e603b125570John Hoford matrix.postTranslate(translateX, translateY); 274975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return matrix; 275975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 276975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 277975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /** 278b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Prints an image located at the Uri. Image types supported are those of 279b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * <code>BitmapFactory.decodeStream</code> (JPEG, GIF, PNG, BMP, WEBP) 280b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 281b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param jobName The print job name. 282b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param imageFile The <code>Uri</code> pointing to an image to print. 283b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @throws FileNotFoundException if <code>Uri</code> is not pointing to a valid image. 284b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 285975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void printBitmap(final String jobName, final Uri imageFile) 286975c49f182d754dfe1a38ba0457d6e603b125570John Hoford throws FileNotFoundException { 287975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final int fittingMode = mScaleMode; 288975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 289975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintDocumentAdapter printDocumentAdapter = new PrintDocumentAdapter() { 290975c49f182d754dfe1a38ba0457d6e603b125570John Hoford private PrintAttributes mAttributes; 291975c49f182d754dfe1a38ba0457d6e603b125570John Hoford AsyncTask<Uri, Boolean, Bitmap> loadBitmap; 292975c49f182d754dfe1a38ba0457d6e603b125570John Hoford Bitmap mBitmap = null; 293975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 294975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 295975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void onLayout(final PrintAttributes oldPrintAttributes, 296975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final PrintAttributes newPrintAttributes, 297975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final CancellationSignal cancellationSignal, 298975c49f182d754dfe1a38ba0457d6e603b125570John Hoford final LayoutResultCallback layoutResultCallback, 299975c49f182d754dfe1a38ba0457d6e603b125570John Hoford Bundle bundle) { 300975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (cancellationSignal.isCanceled()) { 301975c49f182d754dfe1a38ba0457d6e603b125570John Hoford layoutResultCallback.onLayoutCancelled(); 302975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mAttributes = newPrintAttributes; 303975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return; 304975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 305975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // we finished the load 306975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (mBitmap != null) { 307975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName) 308975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO) 309975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .setPageCount(1) 310975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .build(); 311975c49f182d754dfe1a38ba0457d6e603b125570John Hoford boolean changed = !newPrintAttributes.equals(oldPrintAttributes); 312975c49f182d754dfe1a38ba0457d6e603b125570John Hoford layoutResultCallback.onLayoutFinished(info, changed); 313975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return; 314975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 315975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 316975c49f182d754dfe1a38ba0457d6e603b125570John Hoford loadBitmap = new AsyncTask<Uri, Boolean, Bitmap>() { 317975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 318975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 319975c49f182d754dfe1a38ba0457d6e603b125570John Hoford protected void onPreExecute() { 320975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // First register for cancellation requests. 321975c49f182d754dfe1a38ba0457d6e603b125570John Hoford cancellationSignal.setOnCancelListener( 322975c49f182d754dfe1a38ba0457d6e603b125570John Hoford new CancellationSignal.OnCancelListener() { 323975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 324975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void onCancel() { // on different thread 325975c49f182d754dfe1a38ba0457d6e603b125570John Hoford cancelLoad(); 326975c49f182d754dfe1a38ba0457d6e603b125570John Hoford cancel(false); 327975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 328975c49f182d754dfe1a38ba0457d6e603b125570John Hoford }); 329975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 330975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 331975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 332975c49f182d754dfe1a38ba0457d6e603b125570John Hoford protected Bitmap doInBackground(Uri... uris) { 333975c49f182d754dfe1a38ba0457d6e603b125570John Hoford try { 334975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return loadConstrainedBitmap(imageFile, MAX_PRINT_SIZE); 335975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } catch (FileNotFoundException e) { 336975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /* ignore */ 337975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 338975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return null; 339975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 340975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 341975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 342975c49f182d754dfe1a38ba0457d6e603b125570John Hoford protected void onPostExecute(Bitmap bitmap) { 343975c49f182d754dfe1a38ba0457d6e603b125570John Hoford super.onPostExecute(bitmap); 344975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mBitmap = bitmap; 345975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (bitmap != null) { 346975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName) 347975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO) 348975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .setPageCount(1) 349975c49f182d754dfe1a38ba0457d6e603b125570John Hoford .build(); 350975c49f182d754dfe1a38ba0457d6e603b125570John Hoford boolean changed = !newPrintAttributes.equals(oldPrintAttributes); 351975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 352975c49f182d754dfe1a38ba0457d6e603b125570John Hoford layoutResultCallback.onLayoutFinished(info, changed); 353975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 354975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } else { 355975c49f182d754dfe1a38ba0457d6e603b125570John Hoford layoutResultCallback.onLayoutFailed(null); 356975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 357975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 358975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 359975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 360975c49f182d754dfe1a38ba0457d6e603b125570John Hoford protected void onCancelled(Bitmap result) { 361975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Task was cancelled, report that. 362975c49f182d754dfe1a38ba0457d6e603b125570John Hoford layoutResultCallback.onLayoutCancelled(); 363975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 364975c49f182d754dfe1a38ba0457d6e603b125570John Hoford }; 365975c49f182d754dfe1a38ba0457d6e603b125570John Hoford loadBitmap.execute(); 366975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 367975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mAttributes = newPrintAttributes; 368975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 369975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 370975c49f182d754dfe1a38ba0457d6e603b125570John Hoford private void cancelLoad() { 371975c49f182d754dfe1a38ba0457d6e603b125570John Hoford synchronized (mLock) { // prevent race with set null below 372975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (mDecodeOptions != null) { 373975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions.requestCancelDecode(); 374975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions = null; 375975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 376975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 377975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 378975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 379975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 380975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void onFinish() { 381975c49f182d754dfe1a38ba0457d6e603b125570John Hoford super.onFinish(); 382975c49f182d754dfe1a38ba0457d6e603b125570John Hoford cancelLoad(); 383975c49f182d754dfe1a38ba0457d6e603b125570John Hoford loadBitmap.cancel(true); 384975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 385975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 386975c49f182d754dfe1a38ba0457d6e603b125570John Hoford @Override 387975c49f182d754dfe1a38ba0457d6e603b125570John Hoford public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor, 388975c49f182d754dfe1a38ba0457d6e603b125570John Hoford CancellationSignal cancellationSignal, 389975c49f182d754dfe1a38ba0457d6e603b125570John Hoford WriteResultCallback writeResultCallback) { 390975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext, 391975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mAttributes); 392975c49f182d754dfe1a38ba0457d6e603b125570John Hoford try { 393975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 394975c49f182d754dfe1a38ba0457d6e603b125570John Hoford Page page = pdfDocument.startPage(1); 395975c49f182d754dfe1a38ba0457d6e603b125570John Hoford RectF content = new RectF(page.getInfo().getContentRect()); 396975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 397975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Compute and apply scale to fill the page. 398975c49f182d754dfe1a38ba0457d6e603b125570John Hoford Matrix matrix = getMatrix(mBitmap.getWidth(), mBitmap.getHeight(), 399975c49f182d754dfe1a38ba0457d6e603b125570John Hoford content, fittingMode); 400975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 401975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Draw the bitmap. 402975c49f182d754dfe1a38ba0457d6e603b125570John Hoford page.getCanvas().drawBitmap(mBitmap, matrix, null); 403975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 404975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Finish the page. 405975c49f182d754dfe1a38ba0457d6e603b125570John Hoford pdfDocument.finishPage(page); 406975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 407975c49f182d754dfe1a38ba0457d6e603b125570John Hoford try { 408975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Write the document. 409975c49f182d754dfe1a38ba0457d6e603b125570John Hoford pdfDocument.writeTo(new FileOutputStream( 410975c49f182d754dfe1a38ba0457d6e603b125570John Hoford fileDescriptor.getFileDescriptor())); 411975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Done. 412975c49f182d754dfe1a38ba0457d6e603b125570John Hoford writeResultCallback.onWriteFinished( 413975c49f182d754dfe1a38ba0457d6e603b125570John Hoford new PageRange[]{PageRange.ALL_PAGES}); 414975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } catch (IOException ioe) { 415975c49f182d754dfe1a38ba0457d6e603b125570John Hoford // Failed. 416975c49f182d754dfe1a38ba0457d6e603b125570John Hoford Log.e(LOG_TAG, "Error writing printed content", ioe); 417975c49f182d754dfe1a38ba0457d6e603b125570John Hoford writeResultCallback.onWriteFailed(null); 418975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 419975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } finally { 420975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (pdfDocument != null) { 421975c49f182d754dfe1a38ba0457d6e603b125570John Hoford pdfDocument.close(); 422975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 423975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (fileDescriptor != null) { 424975c49f182d754dfe1a38ba0457d6e603b125570John Hoford try { 425975c49f182d754dfe1a38ba0457d6e603b125570John Hoford fileDescriptor.close(); 426975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } catch (IOException ioe) { 427975c49f182d754dfe1a38ba0457d6e603b125570John Hoford /* ignore */ 428975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 429975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 430975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 431975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 432975c49f182d754dfe1a38ba0457d6e603b125570John Hoford }; 433975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 434975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE); 435975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintAttributes.Builder builder = new PrintAttributes.Builder(); 436975c49f182d754dfe1a38ba0457d6e603b125570John Hoford builder.setColorMode(mColorMode); 437975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 438975c49f182d754dfe1a38ba0457d6e603b125570John Hoford if (mOrientation == ORIENTATION_LANDSCAPE) { 439975c49f182d754dfe1a38ba0457d6e603b125570John Hoford builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE); 440975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } else if (mOrientation == ORIENTATION_PORTRAIT) { 441975c49f182d754dfe1a38ba0457d6e603b125570John Hoford builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_PORTRAIT); 442975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 443975c49f182d754dfe1a38ba0457d6e603b125570John Hoford PrintAttributes attr = builder.build(); 444975c49f182d754dfe1a38ba0457d6e603b125570John Hoford 445975c49f182d754dfe1a38ba0457d6e603b125570John Hoford printManager.print(jobName, printDocumentAdapter, attr); 446b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 447b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 448b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 449b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Loads a bitmap while limiting its size 450b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * 451b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param uri location of a valid image 452b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @param maxSideLength the maximum length of a size 453b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @return the Bitmap 454b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * @throws FileNotFoundException if the Uri does not point to an image 455b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 456b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav private Bitmap loadConstrainedBitmap(Uri uri, int maxSideLength) throws FileNotFoundException { 457b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (maxSideLength <= 0 || uri == null || mContext == null) { 458b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav throw new IllegalArgumentException("bad argument to getScaledBitmap"); 459b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 460b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Get width and height of stored bitmap 461b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav BitmapFactory.Options opt = new BitmapFactory.Options(); 462b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav opt.inJustDecodeBounds = true; 463b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav loadBitmap(uri, opt); 464b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 465b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav int w = opt.outWidth; 466b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav int h = opt.outHeight; 467b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 468b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // If bitmap cannot be decoded, return null 469b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (w <= 0 || h <= 0) { 470b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav return null; 471b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 472b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 473b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Find best downsampling size 474b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav int imageSide = Math.max(w, h); 475b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 476b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav int sampleSize = 1; 477b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav while (imageSide > maxSideLength) { 478b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav imageSide >>>= 1; 479b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav sampleSize <<= 1; 480b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 481b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 482b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav // Make sure sample size is reasonable 483b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (sampleSize <= 0 || 0 >= (int) (Math.min(w, h) / sampleSize)) { 484b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav return null; 485b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 486975c49f182d754dfe1a38ba0457d6e603b125570John Hoford BitmapFactory.Options decodeOptions = null; 487975c49f182d754dfe1a38ba0457d6e603b125570John Hoford synchronized (mLock) { // prevent race with set null below 488975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions = new BitmapFactory.Options(); 489975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions.inMutable = true; 490975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions.inSampleSize = sampleSize; 491975c49f182d754dfe1a38ba0457d6e603b125570John Hoford decodeOptions = mDecodeOptions; 492975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 493975c49f182d754dfe1a38ba0457d6e603b125570John Hoford try { 494975c49f182d754dfe1a38ba0457d6e603b125570John Hoford return loadBitmap(uri, decodeOptions); 495975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } finally { 496975c49f182d754dfe1a38ba0457d6e603b125570John Hoford synchronized (mLock) { 497975c49f182d754dfe1a38ba0457d6e603b125570John Hoford mDecodeOptions = null; 498975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 499975c49f182d754dfe1a38ba0457d6e603b125570John Hoford } 500b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 501b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav 502b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav /** 503b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Returns the bitmap from the given uri loaded using the given options. 504b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Returns null on failure. 505b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */ 506b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav private Bitmap loadBitmap(Uri uri, BitmapFactory.Options o) throws FileNotFoundException { 507b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav if (uri == null || mContext == null) { 508b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav throw new IllegalArgumentException("bad argument to loadBitmap"); 509b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 510b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav InputStream is = null; 511b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav try { 512b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav is = mContext.getContentResolver().openInputStream(uri); 513b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav return BitmapFactory.decodeStream(is, null, o); 514b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } finally { 515545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov if (is != null) { 516545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov try { 517545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov is.close(); 518545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov } catch (IOException t) { 519545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov Log.w(LOG_TAG, "close fail ", t); 520545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov } 521b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 522b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 523b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav } 524b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav}