Downsampler.java revision 53c16e03081b659c2c9009721b1a50728d4fae80
1bcf4a0dae04a4ad14287eeb34069a97c96fe9bb1Sam Juddpackage com.bumptech.glide.load.resource.bitmap; 2c27229a159bfc992874609270ab8b57981fef339Sam Judd 3c27229a159bfc992874609270ab8b57981fef339Sam Juddimport android.annotation.TargetApi; 4c27229a159bfc992874609270ab8b57981fef339Sam Juddimport android.graphics.Bitmap; 5c27229a159bfc992874609270ab8b57981fef339Sam Juddimport android.graphics.BitmapFactory; 6c27229a159bfc992874609270ab8b57981fef339Sam Juddimport android.os.Build; 7e81c2c3c8fe1533de8ba8137ea831a42378b35a9Sam Juddimport android.util.Log; 89fc12334a7d14347cd6951d0653264b2597bd3a0Sam Juddimport com.bumptech.glide.load.DecodeFormat; 9aed5a1923b6add5101689ca462107cc16877b05eSam Juddimport com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 100ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Juddimport com.bumptech.glide.util.ByteArrayPool; 110ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd 12c27229a159bfc992874609270ab8b57981fef339Sam Juddimport java.io.IOException; 130ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Juddimport java.io.InputStream; 14aed5a1923b6add5101689ca462107cc16877b05eSam Juddimport java.util.ArrayDeque; 15c24284108320cf3d613497ddd67ba4e1b232ce74Savvas Dalkitsisimport java.util.EnumSet; 16aed5a1923b6add5101689ca462107cc16877b05eSam Juddimport java.util.Queue; 17c24284108320cf3d613497ddd67ba4e1b232ce74Savvas Dalkitsisimport java.util.Set; 18c27229a159bfc992874609270ab8b57981fef339Sam Judd 19c27229a159bfc992874609270ab8b57981fef339Sam Judd/** 20c27229a159bfc992874609270ab8b57981fef339Sam Judd * A base class with methods for loading and decoding images from InputStreams. 21c27229a159bfc992874609270ab8b57981fef339Sam Judd */ 220ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Juddpublic abstract class Downsampler implements BitmapDecoder<InputStream> { 23e81c2c3c8fe1533de8ba8137ea831a42378b35a9Sam Judd private static final String TAG = "Downsampler"; 24c24284108320cf3d613497ddd67ba4e1b232ce74Savvas Dalkitsis 250ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd private static final boolean CAN_RECYCLE = Build.VERSION.SDK_INT >= 11; 269fc12334a7d14347cd6951d0653264b2597bd3a0Sam Judd private static final Set<ImageHeaderParser.ImageType> TYPES_THAT_USE_POOL = EnumSet.of( 279fc12334a7d14347cd6951d0653264b2597bd3a0Sam Judd ImageHeaderParser.ImageType.JPEG, ImageHeaderParser.ImageType.PNG_A, ImageHeaderParser.ImageType.PNG); 280ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd 29aed5a1923b6add5101689ca462107cc16877b05eSam Judd private static final Queue<BitmapFactory.Options> OPTIONS_QUEUE = new ArrayDeque<BitmapFactory.Options>(); 30aed5a1923b6add5101689ca462107cc16877b05eSam Judd 310ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd @TargetApi(11) 32aed5a1923b6add5101689ca462107cc16877b05eSam Judd private static synchronized BitmapFactory.Options getDefaultOptions() { 33aed5a1923b6add5101689ca462107cc16877b05eSam Judd BitmapFactory.Options decodeBitmapOptions = OPTIONS_QUEUE.poll(); 34aed5a1923b6add5101689ca462107cc16877b05eSam Judd if (decodeBitmapOptions == null) { 35aed5a1923b6add5101689ca462107cc16877b05eSam Judd decodeBitmapOptions = new BitmapFactory.Options(); 36aed5a1923b6add5101689ca462107cc16877b05eSam Judd resetOptions(decodeBitmapOptions); 37aed5a1923b6add5101689ca462107cc16877b05eSam Judd } 38aed5a1923b6add5101689ca462107cc16877b05eSam Judd 39aed5a1923b6add5101689ca462107cc16877b05eSam Judd return decodeBitmapOptions; 40aed5a1923b6add5101689ca462107cc16877b05eSam Judd } 41aed5a1923b6add5101689ca462107cc16877b05eSam Judd 42aed5a1923b6add5101689ca462107cc16877b05eSam Judd private static void releaseOptions(BitmapFactory.Options decodeBitmapOptions) { 43aed5a1923b6add5101689ca462107cc16877b05eSam Judd resetOptions(decodeBitmapOptions); 44aed5a1923b6add5101689ca462107cc16877b05eSam Judd OPTIONS_QUEUE.offer(decodeBitmapOptions); 45aed5a1923b6add5101689ca462107cc16877b05eSam Judd } 46aed5a1923b6add5101689ca462107cc16877b05eSam Judd 47aed5a1923b6add5101689ca462107cc16877b05eSam Judd @TargetApi(11) 48aed5a1923b6add5101689ca462107cc16877b05eSam Judd private static void resetOptions(BitmapFactory.Options decodeBitmapOptions) { 49aed5a1923b6add5101689ca462107cc16877b05eSam Judd decodeBitmapOptions.inTempStorage = null; 50aed5a1923b6add5101689ca462107cc16877b05eSam Judd decodeBitmapOptions.inDither = false; 51aed5a1923b6add5101689ca462107cc16877b05eSam Judd decodeBitmapOptions.inScaled = false; 52aed5a1923b6add5101689ca462107cc16877b05eSam Judd decodeBitmapOptions.inSampleSize = 1; 53aed5a1923b6add5101689ca462107cc16877b05eSam Judd decodeBitmapOptions.inPreferredConfig = null; 54aed5a1923b6add5101689ca462107cc16877b05eSam Judd decodeBitmapOptions.inJustDecodeBounds = false; 55aed5a1923b6add5101689ca462107cc16877b05eSam Judd 56aed5a1923b6add5101689ca462107cc16877b05eSam Judd if (CAN_RECYCLE) { 57aed5a1923b6add5101689ca462107cc16877b05eSam Judd decodeBitmapOptions.inBitmap = null; 58aed5a1923b6add5101689ca462107cc16877b05eSam Judd decodeBitmapOptions.inMutable = true; 59aed5a1923b6add5101689ca462107cc16877b05eSam Judd } 600ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd } 610ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd 62c27229a159bfc992874609270ab8b57981fef339Sam Judd /** 63c27229a159bfc992874609270ab8b57981fef339Sam Judd * Load and scale the image uniformly (maintaining the image's aspect ratio) so that the dimensions of the image 64c27229a159bfc992874609270ab8b57981fef339Sam Judd * will be greater than or equal to the given width and height. 65c27229a159bfc992874609270ab8b57981fef339Sam Judd * 66c27229a159bfc992874609270ab8b57981fef339Sam Judd */ 67c27229a159bfc992874609270ab8b57981fef339Sam Judd public static Downsampler AT_LEAST = new Downsampler() { 68c27229a159bfc992874609270ab8b57981fef339Sam Judd @Override 69c27229a159bfc992874609270ab8b57981fef339Sam Judd protected int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight) { 70c27229a159bfc992874609270ab8b57981fef339Sam Judd return Math.min(inHeight / outHeight, inWidth / outWidth); 71c27229a159bfc992874609270ab8b57981fef339Sam Judd } 72423bc54484b4be962955b2c194cf72edf705a935Sam Judd 73423bc54484b4be962955b2c194cf72edf705a935Sam Judd @Override 74423bc54484b4be962955b2c194cf72edf705a935Sam Judd public String getId() { 75423bc54484b4be962955b2c194cf72edf705a935Sam Judd return "AT_LEAST.com.bumptech.glide.load.data.bitmap"; 76423bc54484b4be962955b2c194cf72edf705a935Sam Judd } 77c27229a159bfc992874609270ab8b57981fef339Sam Judd }; 78c27229a159bfc992874609270ab8b57981fef339Sam Judd 79c27229a159bfc992874609270ab8b57981fef339Sam Judd /** 80c27229a159bfc992874609270ab8b57981fef339Sam Judd * Load and scale the image uniformly (maintaining the image's aspect ratio) so that the dimensions of the image 81c27229a159bfc992874609270ab8b57981fef339Sam Judd * will be less than or equal to the given width and height. 82c27229a159bfc992874609270ab8b57981fef339Sam Judd * 83c27229a159bfc992874609270ab8b57981fef339Sam Judd */ 84c27229a159bfc992874609270ab8b57981fef339Sam Judd public static Downsampler AT_MOST = new Downsampler() { 85c27229a159bfc992874609270ab8b57981fef339Sam Judd @Override 86c27229a159bfc992874609270ab8b57981fef339Sam Judd protected int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight) { 87c27229a159bfc992874609270ab8b57981fef339Sam Judd return Math.max(inHeight / outHeight, inWidth / outWidth); 88c27229a159bfc992874609270ab8b57981fef339Sam Judd } 89423bc54484b4be962955b2c194cf72edf705a935Sam Judd 90423bc54484b4be962955b2c194cf72edf705a935Sam Judd @Override 91423bc54484b4be962955b2c194cf72edf705a935Sam Judd public String getId() { 92423bc54484b4be962955b2c194cf72edf705a935Sam Judd return "AT_MOST.com.bumptech.glide.load.data.bitmap"; 93423bc54484b4be962955b2c194cf72edf705a935Sam Judd } 94c27229a159bfc992874609270ab8b57981fef339Sam Judd }; 95c27229a159bfc992874609270ab8b57981fef339Sam Judd 96c27229a159bfc992874609270ab8b57981fef339Sam Judd /** 97c27229a159bfc992874609270ab8b57981fef339Sam Judd * Load the image at its original size 98c27229a159bfc992874609270ab8b57981fef339Sam Judd * 99c27229a159bfc992874609270ab8b57981fef339Sam Judd */ 100c27229a159bfc992874609270ab8b57981fef339Sam Judd public static Downsampler NONE = new Downsampler() { 101c27229a159bfc992874609270ab8b57981fef339Sam Judd @Override 102c27229a159bfc992874609270ab8b57981fef339Sam Judd protected int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight) { 103c27229a159bfc992874609270ab8b57981fef339Sam Judd return 0; 104c27229a159bfc992874609270ab8b57981fef339Sam Judd } 105423bc54484b4be962955b2c194cf72edf705a935Sam Judd 106423bc54484b4be962955b2c194cf72edf705a935Sam Judd @Override 107423bc54484b4be962955b2c194cf72edf705a935Sam Judd public String getId() { 108423bc54484b4be962955b2c194cf72edf705a935Sam Judd return "NONE.com.bumptech.glide.load.data.bitmap"; 109423bc54484b4be962955b2c194cf72edf705a935Sam Judd } 110c27229a159bfc992874609270ab8b57981fef339Sam Judd }; 111c27229a159bfc992874609270ab8b57981fef339Sam Judd 1120ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd // 5MB. This is the max image header size we can handle, we preallocate a much smaller buffer but will resize up to 1130ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd // this amount if necessary. 1140ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd private static final int MARK_POSITION = 5 * 1024 * 1024; 1150ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd 116c27229a159bfc992874609270ab8b57981fef339Sam Judd 117c27229a159bfc992874609270ab8b57981fef339Sam Judd /** 118c27229a159bfc992874609270ab8b57981fef339Sam Judd * Load the image for the given InputStream. If a recycled Bitmap whose dimensions exactly match those of the image 119c27229a159bfc992874609270ab8b57981fef339Sam Judd * for the given InputStream is available, the operation is much less expensive in terms of memory. 120c27229a159bfc992874609270ab8b57981fef339Sam Judd * 121c27229a159bfc992874609270ab8b57981fef339Sam Judd * Note - this method will throw an exception of a Bitmap with dimensions not matching those of the image for the 122c27229a159bfc992874609270ab8b57981fef339Sam Judd * given InputStream is provided. 123c27229a159bfc992874609270ab8b57981fef339Sam Judd * 1240ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd * @param is An InputStream to the data for the image 125c27229a159bfc992874609270ab8b57981fef339Sam Judd * @param pool A pool of recycled bitmaps 126c27229a159bfc992874609270ab8b57981fef339Sam Judd * @param outWidth The width the final image should be close to 127c27229a159bfc992874609270ab8b57981fef339Sam Judd * @param outHeight The height the final image should be close to 128c27229a159bfc992874609270ab8b57981fef339Sam Judd * @return A new bitmap containing the image from the given InputStream, or recycle if recycle is not null 129c27229a159bfc992874609270ab8b57981fef339Sam Judd */ 1300ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd @Override 13176fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd public Bitmap decode(InputStream is, BitmapPool pool, int outWidth, int outHeight, DecodeFormat decodeFormat) { 1320ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd final ByteArrayPool byteArrayPool = ByteArrayPool.get(); 1330ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd byte[] bytesForOptions = byteArrayPool.getBytes(); 1340ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd byte[] bytesForStream = byteArrayPool.getBytes(); 1350ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd RecyclableBufferedInputStream bis = new RecyclableBufferedInputStream(is, bytesForStream); 136d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd bis.mark(MARK_POSITION); 137d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd int orientation = 0; 138d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd try { 139f243e2db2fc16ab84ec68995520544f6a469b90dSam Judd orientation = new ImageHeaderParser(bis).getOrientation(); 140d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd } catch (IOException e) { 141d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd e.printStackTrace(); 142d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd } 143d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd try { 144d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd bis.reset(); 145d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd } catch (IOException e) { 146293fdc0fc9203e2286beef092ac4a1fcec55cd0dSam Judd e.printStackTrace(); 147d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd } 148d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd 1490ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd final BitmapFactory.Options options = getDefaultOptions(); 1500ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd options.inTempStorage = bytesForOptions; 1510ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd 152c27229a159bfc992874609270ab8b57981fef339Sam Judd final int[] inDimens = getDimensions(bis, options); 153293fdc0fc9203e2286beef092ac4a1fcec55cd0dSam Judd final int inWidth = inDimens[0]; 154293fdc0fc9203e2286beef092ac4a1fcec55cd0dSam Judd final int inHeight = inDimens[1]; 155d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd 1560ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd final int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation); 157d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd final int sampleSize; 158d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd if (degreesToRotate == 90 || degreesToRotate == 270) { 1590ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd // If we're rotating the image +-90 degrees, we need to downsample accordingly so the image width is 1600ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd // decreased to near our target's height and the image height is decreased to near our target width. 161293fdc0fc9203e2286beef092ac4a1fcec55cd0dSam Judd sampleSize = getSampleSize(inHeight, inWidth, outWidth, outHeight); 162d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd } else { 163d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd sampleSize = getSampleSize(inWidth, inHeight, outWidth, outHeight); 164d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd } 165c27229a159bfc992874609270ab8b57981fef339Sam Judd 16676fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd final Bitmap downsampled = downsampleWithSize(bis, options, pool, inWidth, inHeight, sampleSize, decodeFormat); 167d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd 168dbb67f826b0e76645c809be6d589e9dcb8271324Sam Judd Bitmap rotated = null; 169dbb67f826b0e76645c809be6d589e9dcb8271324Sam Judd if (downsampled != null) { 170dbb67f826b0e76645c809be6d589e9dcb8271324Sam Judd rotated = TransformationUtils.rotateImageExif(downsampled, pool, orientation); 171dbb67f826b0e76645c809be6d589e9dcb8271324Sam Judd 172dbb67f826b0e76645c809be6d589e9dcb8271324Sam Judd if (downsampled != rotated && !pool.put(downsampled)) { 173dbb67f826b0e76645c809be6d589e9dcb8271324Sam Judd downsampled.recycle(); 174dbb67f826b0e76645c809be6d589e9dcb8271324Sam Judd } 175d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd } 176d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd 1770ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd byteArrayPool.releaseBytes(bytesForOptions); 1780ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd byteArrayPool.releaseBytes(bytesForStream); 179aed5a1923b6add5101689ca462107cc16877b05eSam Judd releaseOptions(options); 180d7efd9c46ebd8872640bb4b4efb564968905507dSam Judd return rotated; 181c27229a159bfc992874609270ab8b57981fef339Sam Judd } 182c27229a159bfc992874609270ab8b57981fef339Sam Judd 183da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd protected Bitmap downsampleWithSize(RecyclableBufferedInputStream bis, BitmapFactory.Options options, 18476fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd BitmapPool pool, int inWidth, int inHeight, int sampleSize, DecodeFormat decodeFormat) { 185da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd // Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding. 18676fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd Bitmap.Config config = getConfig(bis, decodeFormat); 187da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd options.inSampleSize = sampleSize; 18876fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd options.inPreferredConfig = config; 189da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd if (options.inSampleSize == 1 || Build.VERSION.SDK_INT >= 19) { 19082341a72e30da80de01c59303e72855d10b5f945Savvas Dalkitsis if (shouldUsePool(bis)) { 19176fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd setInBitmap(options, pool.get(inWidth, inHeight, config)); 1922310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis } 193293fdc0fc9203e2286beef092ac4a1fcec55cd0dSam Judd } 194293fdc0fc9203e2286beef092ac4a1fcec55cd0dSam Judd return decodeStream(bis, options); 195293fdc0fc9203e2286beef092ac4a1fcec55cd0dSam Judd } 196293fdc0fc9203e2286beef092ac4a1fcec55cd0dSam Judd 197c24284108320cf3d613497ddd67ba4e1b232ce74Savvas Dalkitsis private boolean shouldUsePool(RecyclableBufferedInputStream bis) { 198da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd // On KitKat+, any bitmap can be used to decode any other bitmap. 199da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd if (Build.VERSION.SDK_INT >= 19) { 200da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd return true; 201da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd } 202da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd 2032310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis bis.mark(1024); 2042310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis try { 2059fc12334a7d14347cd6951d0653264b2597bd3a0Sam Judd final ImageHeaderParser.ImageType type = new ImageHeaderParser(bis).getType(); 206da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd // cannot reuse bitmaps when decoding images that are not PNG or JPG. 207da25daffc2047b70f7cf3eb1f6e7ae53043d9337Sam Judd // look at : https://groups.google.com/forum/#!msg/android-developers/Mp0MFVFi1Fo/e8ZQ9FGdWdEJ 208c24284108320cf3d613497ddd67ba4e1b232ce74Savvas Dalkitsis return TYPES_THAT_USE_POOL.contains(type); 2092310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis } catch (IOException e) { 2102310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis e.printStackTrace(); 2112310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis } finally { 2122310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis try { 2132310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis bis.reset(); 2142310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis } catch (IOException e) { 2152310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis e.printStackTrace(); 2162310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis } 2172310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis } 2182310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis return false; 2192310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis } 2202310318f0ff9ad1919ec61878a43cb8dc3bd5086Savvas Dalkitsis 22176fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd private Bitmap.Config getConfig(RecyclableBufferedInputStream bis, DecodeFormat format) { 22276fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd if (format == DecodeFormat.ALWAYS_ARGB_8888) { 22376fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd return Bitmap.Config.ARGB_8888; 22476fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd } 22576fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd 22676fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd boolean hasAlpha = false; 227525d50359e27ca73eeeba96a994155c684d05292Sam Judd bis.mark(1024); //we probably only need 25, but this is safer (particularly since the buffer size is > 1024) 228525d50359e27ca73eeeba96a994155c684d05292Sam Judd try { 22976fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd hasAlpha = new ImageHeaderParser(bis).hasAlpha(); 230525d50359e27ca73eeeba96a994155c684d05292Sam Judd } catch (IOException e) { 231525d50359e27ca73eeeba96a994155c684d05292Sam Judd e.printStackTrace(); 232525d50359e27ca73eeeba96a994155c684d05292Sam Judd } finally { 233525d50359e27ca73eeeba96a994155c684d05292Sam Judd try { 234525d50359e27ca73eeeba96a994155c684d05292Sam Judd bis.reset(); 235525d50359e27ca73eeeba96a994155c684d05292Sam Judd } catch (IOException e) { 236525d50359e27ca73eeeba96a994155c684d05292Sam Judd e.printStackTrace(); 237525d50359e27ca73eeeba96a994155c684d05292Sam Judd } 238525d50359e27ca73eeeba96a994155c684d05292Sam Judd } 23976fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd 24076fbad3dbce72240e9f5b82c826e3229c1176fb6Sam Judd return hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 241525d50359e27ca73eeeba96a994155c684d05292Sam Judd } 242525d50359e27ca73eeeba96a994155c684d05292Sam Judd 243c27229a159bfc992874609270ab8b57981fef339Sam Judd /** 244c27229a159bfc992874609270ab8b57981fef339Sam Judd * Determine the amount of downsampling to use for a load given the dimensions of the image to be downsampled and 245c27229a159bfc992874609270ab8b57981fef339Sam Judd * the dimensions of the view/target the image will be displayed in. 246c27229a159bfc992874609270ab8b57981fef339Sam Judd * 24753c16e03081b659c2c9009721b1a50728d4fae80Sam Judd * @see android.graphics.BitmapFactory.Options#inSampleSize 248c27229a159bfc992874609270ab8b57981fef339Sam Judd * 249c27229a159bfc992874609270ab8b57981fef339Sam Judd * @param inWidth The width of the image to be downsampled 250c27229a159bfc992874609270ab8b57981fef339Sam Judd * @param inHeight The height of the image to be downsampled 251c27229a159bfc992874609270ab8b57981fef339Sam Judd * @param outWidth The width of the view/target the image will be displayed in 252c27229a159bfc992874609270ab8b57981fef339Sam Judd * @param outHeight The height of the view/target the imag will be displayed in 253c27229a159bfc992874609270ab8b57981fef339Sam Judd * @return An integer to pass in to {@link BitmapFactory#decodeStream(java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options)} 254c27229a159bfc992874609270ab8b57981fef339Sam Judd */ 255c27229a159bfc992874609270ab8b57981fef339Sam Judd protected abstract int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight); 256c27229a159bfc992874609270ab8b57981fef339Sam Judd 257c27229a159bfc992874609270ab8b57981fef339Sam Judd /** 258c27229a159bfc992874609270ab8b57981fef339Sam Judd * A method for getting the dimensions of an image from the given InputStream 259c27229a159bfc992874609270ab8b57981fef339Sam Judd * 260c27229a159bfc992874609270ab8b57981fef339Sam Judd * @param bis The InputStream representing the image 261c27229a159bfc992874609270ab8b57981fef339Sam Judd * @param options The options to pass to {@link BitmapFactory#decodeStream(java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options)} 262c27229a159bfc992874609270ab8b57981fef339Sam Judd * @return an array containing the dimensions of the image in the form {width, height} 263c27229a159bfc992874609270ab8b57981fef339Sam Judd */ 264c27229a159bfc992874609270ab8b57981fef339Sam Judd public int[] getDimensions(RecyclableBufferedInputStream bis, BitmapFactory.Options options) { 265c27229a159bfc992874609270ab8b57981fef339Sam Judd options.inJustDecodeBounds = true; 266c27229a159bfc992874609270ab8b57981fef339Sam Judd decodeStream(bis, options); 267c27229a159bfc992874609270ab8b57981fef339Sam Judd options.inJustDecodeBounds = false; 268c27229a159bfc992874609270ab8b57981fef339Sam Judd return new int[] { options.outWidth, options.outHeight }; 269c27229a159bfc992874609270ab8b57981fef339Sam Judd } 270c27229a159bfc992874609270ab8b57981fef339Sam Judd 271c27229a159bfc992874609270ab8b57981fef339Sam Judd 272c27229a159bfc992874609270ab8b57981fef339Sam Judd private Bitmap decodeStream(RecyclableBufferedInputStream bis, BitmapFactory.Options options) { 273c27229a159bfc992874609270ab8b57981fef339Sam Judd if (options.inJustDecodeBounds) { 274c27229a159bfc992874609270ab8b57981fef339Sam Judd bis.mark(MARK_POSITION); //this is large, but jpeg headers are not size bounded so we need 275c27229a159bfc992874609270ab8b57981fef339Sam Judd //something large enough to minimize the possibility of not being able to fit 276c27229a159bfc992874609270ab8b57981fef339Sam Judd //enough of the header in the buffer to get the image size so that we don't fail 277c27229a159bfc992874609270ab8b57981fef339Sam Judd //to load images. The BufferedInputStream will create a new buffer of 2x the 278c27229a159bfc992874609270ab8b57981fef339Sam Judd //original size each time we use up the buffer space without passing the mark so 279c27229a159bfc992874609270ab8b57981fef339Sam Judd //this is a maximum bound on the buffer size, not a default. Most of the time we 280c27229a159bfc992874609270ab8b57981fef339Sam Judd //won't go past our pre-allocated 16kb 281c27229a159bfc992874609270ab8b57981fef339Sam Judd } 282c27229a159bfc992874609270ab8b57981fef339Sam Judd 283c27229a159bfc992874609270ab8b57981fef339Sam Judd final Bitmap result = BitmapFactory.decodeStream(bis, null, options); 284c27229a159bfc992874609270ab8b57981fef339Sam Judd 285c27229a159bfc992874609270ab8b57981fef339Sam Judd try { 286c27229a159bfc992874609270ab8b57981fef339Sam Judd if (options.inJustDecodeBounds) { 287c27229a159bfc992874609270ab8b57981fef339Sam Judd bis.reset(); 288c27229a159bfc992874609270ab8b57981fef339Sam Judd bis.clearMark(); 289c27229a159bfc992874609270ab8b57981fef339Sam Judd } else { 290c27229a159bfc992874609270ab8b57981fef339Sam Judd bis.close(); 291c27229a159bfc992874609270ab8b57981fef339Sam Judd } 292c27229a159bfc992874609270ab8b57981fef339Sam Judd } catch (IOException e) { 293e81c2c3c8fe1533de8ba8137ea831a42378b35a9Sam Judd if (Log.isLoggable(TAG, Log.ERROR)) { 294e81c2c3c8fe1533de8ba8137ea831a42378b35a9Sam Judd Log.e(TAG, "Exception loading inDecodeBounds=" + options.inJustDecodeBounds 295e81c2c3c8fe1533de8ba8137ea831a42378b35a9Sam Judd + " sample=" + options.inSampleSize, e); 296e81c2c3c8fe1533de8ba8137ea831a42378b35a9Sam Judd } 297c27229a159bfc992874609270ab8b57981fef339Sam Judd } 298c27229a159bfc992874609270ab8b57981fef339Sam Judd 299c27229a159bfc992874609270ab8b57981fef339Sam Judd return result; 300c27229a159bfc992874609270ab8b57981fef339Sam Judd } 301c27229a159bfc992874609270ab8b57981fef339Sam Judd 302c27229a159bfc992874609270ab8b57981fef339Sam Judd @TargetApi(11) 303c27229a159bfc992874609270ab8b57981fef339Sam Judd private static void setInBitmap(BitmapFactory.Options options, Bitmap recycled) { 304c27229a159bfc992874609270ab8b57981fef339Sam Judd if (Build.VERSION.SDK_INT >= 11) { 305c27229a159bfc992874609270ab8b57981fef339Sam Judd options.inBitmap = recycled; 306c27229a159bfc992874609270ab8b57981fef339Sam Judd } 307c27229a159bfc992874609270ab8b57981fef339Sam Judd } 308c27229a159bfc992874609270ab8b57981fef339Sam Judd} 309