Downsampler.java revision e81c2c3c8fe1533de8ba8137ea831a42378b35a9
1f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnpackage com.bumptech.glide.resize.load;
2f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn
3f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport static com.bumptech.glide.resize.load.ImageHeaderParser.ImageType;
4f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport static com.bumptech.glide.resize.load.ImageHeaderParser.ImageType.PNG_A;
5f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport static com.bumptech.glide.resize.load.ImageHeaderParser.ImageType.JPEG;
6f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport static com.bumptech.glide.resize.load.ImageHeaderParser.ImageType.PNG;
7f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn
8f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport android.annotation.TargetApi;
9f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport android.graphics.Bitmap;
10b3a1e4bffbdbbf38304f216af405009868f43628sewardjimport android.graphics.BitmapFactory;
11f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport android.os.Build;
12f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport android.util.Log;
13f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport com.bumptech.glide.resize.RecyclableBufferedInputStream;
14f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport com.bumptech.glide.resize.bitmap_recycle.BitmapPool;
15f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport java.io.IOException;
16f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport java.util.EnumSet;
17f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnimport java.util.Set;
18f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn
19f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn/**
20f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn * A base class with methods for loading and decoding images from InputStreams.
21f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn */
22f536bbbd4bf2024926574c5ed99b3e6251c6ff44njnpublic abstract class Downsampler {
23f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn    private static final String TAG = "Downsampler";
24f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn
25f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn    private static final Set<ImageType> TYPES_THAT_USE_POOL = EnumSet.of(JPEG, PNG_A, PNG);
26f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn    private final String id = getClass().toString();
27f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn
28f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn    /**
29f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn     * Load and scale the image uniformly (maintaining the image's aspect ratio) so that the dimensions of the image
30f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn     * will be greater than or equal to the given width and height.
31f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn     *
32f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn     */
33f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn    public static Downsampler AT_LEAST = new Downsampler() {
34f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn        @Override
35f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn        protected int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight) {
36f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn            return Math.min(inHeight / outHeight, inWidth / outWidth);
37f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn        }
38f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn    };
39f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn
40f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn    /**
41535fb1b49a80f2e880f755ee618381de3e222ddfflorian     * Load and scale the image uniformly (maintaining the image's aspect ratio) so that the dimensions of the image
42f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn     * will be less than or equal to the given width and height.
43265aae7509903e05e907ff0ea4eb2da9446b9763njn     *
448eb8bab992e3998c33770b0cdb16059a8b918a06sewardj     */
456e340c7a2c09971ac5ead854c40bbc0491b67636sewardj    public static Downsampler AT_MOST = new Downsampler() {
46af839f52d74df156d655201a889954133ab01be7njn        @Override
47af839f52d74df156d655201a889954133ab01be7njn        protected int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight) {
48f1c91e04aa395a74092e26da815dbde4d769ee0asewardj            return Math.max(inHeight / outHeight, inWidth / outWidth);
498eb8bab992e3998c33770b0cdb16059a8b918a06sewardj        }
506e340c7a2c09971ac5ead854c40bbc0491b67636sewardj    };
51af839f52d74df156d655201a889954133ab01be7njn
52af839f52d74df156d655201a889954133ab01be7njn    /**
53f1c91e04aa395a74092e26da815dbde4d769ee0asewardj     * Load the image at its original size
54f1c91e04aa395a74092e26da815dbde4d769ee0asewardj     *
556e340c7a2c09971ac5ead854c40bbc0491b67636sewardj     */
56af839f52d74df156d655201a889954133ab01be7njn    public static Downsampler NONE = new Downsampler() {
57af839f52d74df156d655201a889954133ab01be7njn        @Override
58f1c91e04aa395a74092e26da815dbde4d769ee0asewardj        protected int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight) {
59cae0cc22b83ffb260ee8379e92099c5a701944cbcarll            return 0;
602c48c7b0a453d32375a4df17e153011b797ef28csewardj        }
612c48c7b0a453d32375a4df17e153011b797ef28csewardj    };
622c48c7b0a453d32375a4df17e153011b797ef28csewardj
63f1c91e04aa395a74092e26da815dbde4d769ee0asewardj    private static final int MARK_POSITION = 5 * 1024 * 1024; //5mb, max possible, not preallocated
64582d58245637ab05272d89fb94b12fd0f18fa0f8carll
65582d58245637ab05272d89fb94b12fd0f18fa0f8carll    /**
66582d58245637ab05272d89fb94b12fd0f18fa0f8carll     * Load the image for the given InputStream. If a recycled Bitmap whose dimensions exactly match those of the image
67582d58245637ab05272d89fb94b12fd0f18fa0f8carll     * for the given InputStream is available, the operation is much less expensive in terms of memory.
68582d58245637ab05272d89fb94b12fd0f18fa0f8carll     *
6959570ffbe31930ab4d678754daaeec0715117a3dsewardj     * Note - this method will throw an exception of a Bitmap with dimensions not matching those of the image for the
7059570ffbe31930ab4d678754daaeec0715117a3dsewardj     * given InputStream is provided.
7159570ffbe31930ab4d678754daaeec0715117a3dsewardj     *
7259570ffbe31930ab4d678754daaeec0715117a3dsewardj     * @param bis An InputStream to the data for the image
7359570ffbe31930ab4d678754daaeec0715117a3dsewardj     * @param options The options to pass to {@link BitmapFactory#decodeStream(java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options)}
74f0c1250e324f6684757c6a15545366447ef1d64fsewardj     * @param pool A pool of recycled bitmaps
75f0c1250e324f6684757c6a15545366447ef1d64fsewardj     * @param outWidth The width the final image should be close to
76f0c1250e324f6684757c6a15545366447ef1d64fsewardj     * @param outHeight The height the final image should be close to
77f0c1250e324f6684757c6a15545366447ef1d64fsewardj     * @return A new bitmap containing the image from the given InputStream, or recycle if recycle is not null
78f0c1250e324f6684757c6a15545366447ef1d64fsewardj     */
79f76d27a697a7b0bf3b84490baf60623fc96a23afnjn    public Bitmap downsample(RecyclableBufferedInputStream bis, BitmapFactory.Options options, BitmapPool pool, int outWidth, int outHeight) {
80f76d27a697a7b0bf3b84490baf60623fc96a23afnjn        bis.mark(MARK_POSITION);
81f76d27a697a7b0bf3b84490baf60623fc96a23afnjn        int orientation = 0;
82f76d27a697a7b0bf3b84490baf60623fc96a23afnjn        try {
83f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            orientation = new ImageHeaderParser(bis).getOrientation();
84b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj        } catch (IOException e) {
85b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj            e.printStackTrace();
86b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj        }
87b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj        try {
88b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj            bis.reset();
895db15403e889d4db339b342bc2a824ef0bfaa654sewardj        } catch (IOException e) {
905db15403e889d4db339b342bc2a824ef0bfaa654sewardj            e.printStackTrace();
915db15403e889d4db339b342bc2a824ef0bfaa654sewardj        }
925db15403e889d4db339b342bc2a824ef0bfaa654sewardj
935db15403e889d4db339b342bc2a824ef0bfaa654sewardj        final int[] inDimens = getDimensions(bis, options);
945db15403e889d4db339b342bc2a824ef0bfaa654sewardj        final int inWidth = inDimens[0];
955db15403e889d4db339b342bc2a824ef0bfaa654sewardj        final int inHeight = inDimens[1];
965db15403e889d4db339b342bc2a824ef0bfaa654sewardj
975db15403e889d4db339b342bc2a824ef0bfaa654sewardj        final int degreesToRotate = ImageResizer.getExifOrientationDegrees(orientation);
985db15403e889d4db339b342bc2a824ef0bfaa654sewardj        final int sampleSize;
995db15403e889d4db339b342bc2a824ef0bfaa654sewardj        if (degreesToRotate == 90 || degreesToRotate == 270) {
1004df0bfc0614379192c780c944415dc420d9cfe8epetarj            //if we're rotating the image +-90 degrees, we need to downsample accordingly so the image width is
1014df0bfc0614379192c780c944415dc420d9cfe8epetarj            //decreased to near our target's height and the image height is decreased to near our target width
1024df0bfc0614379192c780c944415dc420d9cfe8epetarj            sampleSize = getSampleSize(inHeight, inWidth, outWidth, outHeight);
1034df0bfc0614379192c780c944415dc420d9cfe8epetarj        } else {
1044df0bfc0614379192c780c944415dc420d9cfe8epetarj            sampleSize = getSampleSize(inWidth, inHeight, outWidth, outHeight);
1054df0bfc0614379192c780c944415dc420d9cfe8epetarj        }
1064df0bfc0614379192c780c944415dc420d9cfe8epetarj
1074df0bfc0614379192c780c944415dc420d9cfe8epetarj        final Bitmap downsampled = downsampleWithSize(bis, options, pool, inWidth, inHeight, sampleSize);
1084df0bfc0614379192c780c944415dc420d9cfe8epetarj        final Bitmap rotated = ImageResizer.rotateImageExif(downsampled, pool, orientation);
1094df0bfc0614379192c780c944415dc420d9cfe8epetarj
1104df0bfc0614379192c780c944415dc420d9cfe8epetarj        if (downsampled != rotated && !pool.put(downsampled)) {
111112711afefcfcd43680c7c4aa8d38ef180e8811esewardj            downsampled.recycle();
112112711afefcfcd43680c7c4aa8d38ef180e8811esewardj        }
113112711afefcfcd43680c7c4aa8d38ef180e8811esewardj
114112711afefcfcd43680c7c4aa8d38ef180e8811esewardj        return rotated;
115112711afefcfcd43680c7c4aa8d38ef180e8811esewardj    }
116112711afefcfcd43680c7c4aa8d38ef180e8811esewardj
117112711afefcfcd43680c7c4aa8d38ef180e8811esewardj    protected Bitmap downsampleWithSize(RecyclableBufferedInputStream bis, BitmapFactory.Options options, BitmapPool pool, int inWidth, int inHeight, int sampleSize) {
118112711afefcfcd43680c7c4aa8d38ef180e8811esewardj        if (sampleSize > 1) {
119f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn            options.inSampleSize = sampleSize;
120f1c91e04aa395a74092e26da815dbde4d769ee0asewardj        } else {
121f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn            // cannot reuse bitmaps when decoding images that are not PNG or JPG.
122f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn            // look at : https://groups.google.com/forum/#!msg/android-developers/Mp0MFVFi1Fo/e8ZQ9FGdWdEJ
123f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn            if (shouldUsePool(bis)) {
124af839f52d74df156d655201a889954133ab01be7njn                setInBitmap(options, pool.get(inWidth, inHeight, getConfig(bis)));
125af839f52d74df156d655201a889954133ab01be7njn            }
126af839f52d74df156d655201a889954133ab01be7njn        }
127f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn        return decodeStream(bis, options);
128af839f52d74df156d655201a889954133ab01be7njn    }
129af839f52d74df156d655201a889954133ab01be7njn
130af839f52d74df156d655201a889954133ab01be7njn    private boolean shouldUsePool(RecyclableBufferedInputStream bis) {
13185665ca6fa29dd64754dabe50eb98f25896e752acerion        bis.mark(1024);
132af839f52d74df156d655201a889954133ab01be7njn        try {
133af839f52d74df156d655201a889954133ab01be7njn            final ImageType type = new ImageHeaderParser(bis).getType();
134af839f52d74df156d655201a889954133ab01be7njn            return TYPES_THAT_USE_POOL.contains(type);
135cae0cc22b83ffb260ee8379e92099c5a701944cbcarll        } catch (IOException e) {
1362c48c7b0a453d32375a4df17e153011b797ef28csewardj            e.printStackTrace();
1372c48c7b0a453d32375a4df17e153011b797ef28csewardj        } finally {
1382c48c7b0a453d32375a4df17e153011b797ef28csewardj            try {
13959570ffbe31930ab4d678754daaeec0715117a3dsewardj                bis.reset();
1401dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj            } catch (IOException e) {
14159570ffbe31930ab4d678754daaeec0715117a3dsewardj                e.printStackTrace();
14259570ffbe31930ab4d678754daaeec0715117a3dsewardj            }
143f0c1250e324f6684757c6a15545366447ef1d64fsewardj        }
144f0c1250e324f6684757c6a15545366447ef1d64fsewardj        return false;
1450345188cc1524a809b8d7fe8785e1da098d9cbe4sewardj    }
1460345188cc1524a809b8d7fe8785e1da098d9cbe4sewardj
147b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj    private Bitmap.Config getConfig(RecyclableBufferedInputStream bis) {
148b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj        Bitmap.Config result = Bitmap.Config.RGB_565;
149b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj        bis.mark(1024); //we probably only need 25, but this is safer (particularly since the buffer size is > 1024)
150b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj        try {
151ccb843b2ba2c176708bfa1764ca8e4db31722e90florian            result = new ImageHeaderParser(bis).hasAlpha() ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
1525db15403e889d4db339b342bc2a824ef0bfaa654sewardj        } catch (IOException e) {
1535db15403e889d4db339b342bc2a824ef0bfaa654sewardj            e.printStackTrace();
1545db15403e889d4db339b342bc2a824ef0bfaa654sewardj        } finally {
1555db15403e889d4db339b342bc2a824ef0bfaa654sewardj            try {
1564df0bfc0614379192c780c944415dc420d9cfe8epetarj                bis.reset();
1574df0bfc0614379192c780c944415dc420d9cfe8epetarj            } catch (IOException e) {
1584df0bfc0614379192c780c944415dc420d9cfe8epetarj                e.printStackTrace();
1594df0bfc0614379192c780c944415dc420d9cfe8epetarj            }
160112711afefcfcd43680c7c4aa8d38ef180e8811esewardj        }
161112711afefcfcd43680c7c4aa8d38ef180e8811esewardj        return result;
162112711afefcfcd43680c7c4aa8d38ef180e8811esewardj    }
163112711afefcfcd43680c7c4aa8d38ef180e8811esewardj
164f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn    /**
165f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn     * Get some id that uniquely identifies the downsample for use as part of a cache key
166f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn     * @return A unique String
167f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn     */
1687821e2ed55ac6c2303eb51a06bafd5baada2423dsewardj    public String getId() {
169f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn        return id;
170af839f52d74df156d655201a889954133ab01be7njn    }
171cda2f0fbda4c4b2644babc830244be8aed95de1dnjn
1728eb8bab992e3998c33770b0cdb16059a8b918a06sewardj    /**
173ccb843b2ba2c176708bfa1764ca8e4db31722e90florian     * Determine the amount of downsampling to use for a load given the dimensions of the image to be downsampled and
174f536bbbd4bf2024926574c5ed99b3e6251c6ff44njn     * the dimensions of the view/target the image will be displayed in.
1757821e2ed55ac6c2303eb51a06bafd5baada2423dsewardj     *
176e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj     * @see BitmapFactory.Options#inSampleSize
1771dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj     *
1781dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj     * @param inWidth The width of the image to be downsampled
1791dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj     * @param inHeight The height of the image to be downsampled
1801dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj     * @param outWidth The width of the view/target the image will be displayed in
1811dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj     * @param outHeight The height of the view/target the imag will be displayed in
1821dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj     * @return An integer to pass in to {@link BitmapFactory#decodeStream(java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options)}
1831dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj     */
1841dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj    protected abstract int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeight);
1851dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj
1861dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj    /**
1871dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj     * A method for getting the dimensions of an image from the given InputStream
1881dbd3376656236debf5d35a9b5d8a507a6c307f0sewardj     *
18959570ffbe31930ab4d678754daaeec0715117a3dsewardj     * @param bis The InputStream representing the image
19059570ffbe31930ab4d678754daaeec0715117a3dsewardj     * @param options The options to pass to {@link BitmapFactory#decodeStream(java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options)}
19159570ffbe31930ab4d678754daaeec0715117a3dsewardj     * @return an array containing the dimensions of the image in the form {width, height}
19259570ffbe31930ab4d678754daaeec0715117a3dsewardj     */
19359570ffbe31930ab4d678754daaeec0715117a3dsewardj    public int[] getDimensions(RecyclableBufferedInputStream bis, BitmapFactory.Options options) {
19459570ffbe31930ab4d678754daaeec0715117a3dsewardj        options.inJustDecodeBounds = true;
19559570ffbe31930ab4d678754daaeec0715117a3dsewardj        decodeStream(bis, options);
196e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj        options.inJustDecodeBounds = false;
197e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj        return new int[] { options.outWidth, options.outHeight };
1981f0d814045aba94e01e62e04e968ca8b970b3d44cerion    }
199e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj
200e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj
201e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj    private Bitmap decodeStream(RecyclableBufferedInputStream bis, BitmapFactory.Options options) {
202e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj         if (options.inJustDecodeBounds) {
203e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj             bis.mark(MARK_POSITION); //this is large, but jpeg headers are not size bounded so we need
204e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj                         //something large enough to minimize the possibility of not being able to fit
205e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj                         //enough of the header in the buffer to get the image size so that we don't fail
206e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj                         //to load images. The BufferedInputStream will create a new buffer of 2x the
207e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj                         //original size each time we use up the buffer space without passing the mark so
208e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj                         //this is a maximum bound on the buffer size, not a default. Most of the time we
209e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj                         //won't go past our pre-allocated 16kb
210e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj         }
211e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj
212e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj        final Bitmap result = BitmapFactory.decodeStream(bis, null, options);
213e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj
214e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj        try {
215e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj            if (options.inJustDecodeBounds) {
216e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj                bis.reset();
2172c36d4285afacafc10232e2f70978e0519216138sewardj                bis.clearMark();
218e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj            } else {
2192c48c7b0a453d32375a4df17e153011b797ef28csewardj                bis.close();
2202c48c7b0a453d32375a4df17e153011b797ef28csewardj            }
2212c48c7b0a453d32375a4df17e153011b797ef28csewardj        } catch (IOException e) {
2222c48c7b0a453d32375a4df17e153011b797ef28csewardj            if (Log.isLoggable(TAG, Log.ERROR)) {
2232c48c7b0a453d32375a4df17e153011b797ef28csewardj                Log.e(TAG, "Exception loading inDecodeBounds=" + options.inJustDecodeBounds
2242c48c7b0a453d32375a4df17e153011b797ef28csewardj                        + " sample=" + options.inSampleSize, e);
225a3551be497f6c4afc5dfbbbcd7c7a955a68fb22bsewardj            }
226a3551be497f6c4afc5dfbbbcd7c7a955a68fb22bsewardj        }
227a3551be497f6c4afc5dfbbbcd7c7a955a68fb22bsewardj
228a3551be497f6c4afc5dfbbbcd7c7a955a68fb22bsewardj        return result;
229a3551be497f6c4afc5dfbbbcd7c7a955a68fb22bsewardj    }
2300daa4e31a3407ce0b0db8a90be8dd14bd8eccb35florian
2310daa4e31a3407ce0b0db8a90be8dd14bd8eccb35florian    @TargetApi(11)
2320daa4e31a3407ce0b0db8a90be8dd14bd8eccb35florian    private static void setInBitmap(BitmapFactory.Options options, Bitmap recycled) {
2330daa4e31a3407ce0b0db8a90be8dd14bd8eccb35florian        if (Build.VERSION.SDK_INT >= 11) {
234e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj            options.inBitmap = recycled;
235e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj        }
236e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj    }
237e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj}
238e2d1e670d412ff85c824ba5c043161816b9e26bdsewardj