1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.data;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
19df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Linimport android.annotation.TargetApi;
20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap;
21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap.Config;
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.BitmapFactory;
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.BitmapFactory.Options;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.BitmapRegionDecoder;
25df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Linimport android.os.Build;
264bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
27a625b6562d3bfc86465778b336c96fb42064be21Owen Linimport com.android.gallery3d.common.ApiHelper;
284bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Linimport com.android.gallery3d.common.BitmapUtils;
294bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Linimport com.android.gallery3d.common.Utils;
30f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescuimport com.android.photos.data.GalleryBitmapPool;
31df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Linimport com.android.gallery3d.ui.Log;
324bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Linimport com.android.gallery3d.util.ThreadPool.CancelListener;
334bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Linimport com.android.gallery3d.util.ThreadPool.JobContext;
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.io.FileDescriptor;
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.io.FileInputStream;
37b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Changimport java.io.InputStream;
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class DecodeUtils {
40df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    private static final String TAG = "DecodeUtils";
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static class DecodeCanceller implements CancelListener {
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Options mOptions;
444bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public DecodeCanceller(Options options) {
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mOptions = options;
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
484bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
494bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        @Override
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void onCancel() {
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mOptions.requestCancelDecode();
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
55a625b6562d3bfc86465778b336c96fb42064be21Owen Lin    @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
56a625b6562d3bfc86465778b336c96fb42064be21Owen Lin    public static void setOptionsMutable(Options options) {
57a625b6562d3bfc86465778b336c96fb42064be21Owen Lin        if (ApiHelper.HAS_OPTIONS_IN_MUTABLE) options.inMutable = true;
58a625b6562d3bfc86465778b336c96fb42064be21Owen Lin    }
59a625b6562d3bfc86465778b336c96fb42064be21Owen Lin
604bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decode(JobContext jc, FileDescriptor fd, Options options) {
61c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin        if (options == null) options = new Options();
62c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin        jc.setCancelListener(new DecodeCanceller(options));
63a625b6562d3bfc86465778b336c96fb42064be21Owen Lin        setOptionsMutable(options);
64c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin        return ensureGLCompatibleBitmap(
65c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin                BitmapFactory.decodeFileDescriptor(fd, null, options));
66c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin    }
67c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin
68b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang    public static void decodeBounds(JobContext jc, FileDescriptor fd,
69b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang            Options options) {
70b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        Utils.assertTrue(options != null);
71b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        options.inJustDecodeBounds = true;
72b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        jc.setCancelListener(new DecodeCanceller(options));
73b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        BitmapFactory.decodeFileDescriptor(fd, null, options);
74b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        options.inJustDecodeBounds = false;
75b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang    }
76b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang
774bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decode(JobContext jc, byte[] bytes, Options options) {
784bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        return decode(jc, bytes, 0, bytes.length, options);
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
814bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decode(JobContext jc, byte[] bytes, int offset,
82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int length, Options options) {
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (options == null) options = new Options();
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        jc.setCancelListener(new DecodeCanceller(options));
85a625b6562d3bfc86465778b336c96fb42064be21Owen Lin        setOptionsMutable(options);
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return ensureGLCompatibleBitmap(
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                BitmapFactory.decodeByteArray(bytes, offset, length, options));
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
90b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang    public static void decodeBounds(JobContext jc, byte[] bytes, int offset,
91b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang            int length, Options options) {
92b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        Utils.assertTrue(options != null);
93b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        options.inJustDecodeBounds = true;
94b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        jc.setCancelListener(new DecodeCanceller(options));
95b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        BitmapFactory.decodeByteArray(bytes, offset, length, options);
96b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        options.inJustDecodeBounds = false;
97b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang    }
98b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang
994bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decodeThumbnail(
1004bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            JobContext jc, String filePath, Options options, int targetSize, int type) {
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        FileInputStream fis = null;
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            fis = new FileInputStream(filePath);
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            FileDescriptor fd = fis.getFD();
1054bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            return decodeThumbnail(jc, fd, options, targetSize, type);
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Exception ex) {
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, ex);
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Utils.closeSilently(fis);
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1144bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decodeThumbnail(
1154bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            JobContext jc, FileDescriptor fd, Options options, int targetSize, int type) {
116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (options == null) options = new Options();
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        jc.setCancelListener(new DecodeCanceller(options));
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        options.inJustDecodeBounds = true;
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        BitmapFactory.decodeFileDescriptor(fd, null, options);
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (jc.isCancelled()) return null;
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1234bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        int w = options.outWidth;
1244bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        int h = options.outHeight;
1254bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
1264bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        if (type == MediaItem.TYPE_MICROTHUMBNAIL) {
1274bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            // We center-crop the original image as it's micro thumbnail. In this case,
1284bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            // we want to make sure the shorter side >= "targetSize".
1294bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            float scale = (float) targetSize / Math.min(w, h);
1304bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            options.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
1314bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
1324bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            // For an extremely wide image, e.g. 300x30000, we may got OOM when decoding
1334bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            // it for TYPE_MICROTHUMBNAIL. So we add a max number of pixels limit here.
1344bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            final int MAX_PIXEL_COUNT = 640000; // 400 x 1600
1354bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            if ((w / options.inSampleSize) * (h / options.inSampleSize) > MAX_PIXEL_COUNT) {
1364bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin                options.inSampleSize = BitmapUtils.computeSampleSize(
1378a55d3ae7486b798e4c26eeb91993916145f3cefNeil Fuller                        (float) Math.sqrt((double) MAX_PIXEL_COUNT / (w * h)));
1384bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            }
1394bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        } else {
1404bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            // For screen nail, we only want to keep the longer side >= targetSize.
1414bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            float scale = (float) targetSize / Math.max(w, h);
1424bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            options.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
1434bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        }
1444bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        options.inJustDecodeBounds = false;
146a625b6562d3bfc86465778b336c96fb42064be21Owen Lin        setOptionsMutable(options);
1476c8d0fd879242f78a0c1a7daf4c037043663a49fChih-Chung Chang
1486c8d0fd879242f78a0c1a7daf4c037043663a49fChih-Chung Chang        Bitmap result = BitmapFactory.decodeFileDescriptor(fd, null, options);
1494bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        if (result == null) return null;
1504bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
1514bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        // We need to resize down if the decoder does not support inSampleSize
1524bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        // (For example, GIF images)
1534bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        float scale = (float) targetSize / (type == MediaItem.TYPE_MICROTHUMBNAIL
1544bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin                ? Math.min(result.getWidth(), result.getHeight())
1554bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin                : Math.max(result.getWidth(), result.getHeight()));
1564bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
1574bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        if (scale <= 0.5) result = BitmapUtils.resizeBitmapByScale(result, scale, true);
1586c8d0fd879242f78a0c1a7daf4c037043663a49fChih-Chung Chang        return ensureGLCompatibleBitmap(result);
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
161113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin    /**
162113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin     * Decodes the bitmap from the given byte array if the image size is larger than the given
163113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin     * requirement.
164113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin     *
1655da31f8fd85d7c1e33133473bd1fbc5e3a240f2dOwen Lin     * Note: The returned image may be resized down. However, both width and height must be
166113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin     * larger than the <code>targetSize</code>.
167113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin     */
1684bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decodeIfBigEnough(JobContext jc, byte[] data,
169113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin            Options options, int targetSize) {
170113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        if (options == null) options = new Options();
171113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        jc.setCancelListener(new DecodeCanceller(options));
172113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin
173113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        options.inJustDecodeBounds = true;
174113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        BitmapFactory.decodeByteArray(data, 0, data.length, options);
175113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        if (jc.isCancelled()) return null;
176113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        if (options.outWidth < targetSize || options.outHeight < targetSize) {
177113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin            return null;
178113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        }
179113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        options.inSampleSize = BitmapUtils.computeSampleSizeLarger(
180113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin                options.outWidth, options.outHeight, targetSize);
181113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        options.inJustDecodeBounds = false;
182a625b6562d3bfc86465778b336c96fb42064be21Owen Lin        setOptionsMutable(options);
183a625b6562d3bfc86465778b336c96fb42064be21Owen Lin
184113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        return ensureGLCompatibleBitmap(
185113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin                BitmapFactory.decodeByteArray(data, 0, data.length, options));
186113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin    }
187113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin
188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // TODO: This function should not be called directly from
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // DecodeUtils.requestDecode(...), since we don't have the knowledge
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // if the bitmap will be uploaded to GL.
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) {
192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (bitmap == null || bitmap.getConfig() != null) return bitmap;
193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false);
194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        bitmap.recycle();
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return newBitmap;
196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1984bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static BitmapRegionDecoder createBitmapRegionDecoder(
199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            JobContext jc, byte[] bytes, int offset, int length,
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            boolean shareable) {
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (offset < 0 || length <= 0 || offset + length > bytes.length) {
202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            throw new IllegalArgumentException(String.format(
203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    "offset = %s, length = %s, bytes = %s",
204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    offset, length, bytes.length));
205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return BitmapRegionDecoder.newInstance(
209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    bytes, offset, length, shareable);
210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Throwable t)  {
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, t);
212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2164bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static BitmapRegionDecoder createBitmapRegionDecoder(
217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            JobContext jc, String filePath, boolean shareable) {
218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return BitmapRegionDecoder.newInstance(filePath, shareable);
220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Throwable t)  {
221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, t);
222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2264bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static BitmapRegionDecoder createBitmapRegionDecoder(
227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            JobContext jc, FileDescriptor fd, boolean shareable) {
228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return BitmapRegionDecoder.newInstance(fd, shareable);
230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Throwable t)  {
231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, t);
232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2364bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static BitmapRegionDecoder createBitmapRegionDecoder(
237b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            JobContext jc, InputStream is, boolean shareable) {
238b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang        try {
239b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            return BitmapRegionDecoder.newInstance(is, shareable);
240b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang        } catch (Throwable t)  {
241b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            // We often cancel the creating of bitmap region decoder,
242b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            // so just log one line.
243b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            Log.w(TAG, "requestCreateBitmapRegionDecoder: " + t);
244b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            return null;
245b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang        }
246b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang    }
247df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
248df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
249f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu    public static Bitmap decodeUsingPool(JobContext jc, byte[] data, int offset,
250f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            int length, BitmapFactory.Options options) {
251df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        if (options == null) options = new BitmapFactory.Options();
252df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        if (options.inSampleSize < 1) options.inSampleSize = 1;
253df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
254df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        options.inBitmap = (options.inSampleSize == 1)
255f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu                ? findCachedBitmap(jc, data, offset, length, options) : null;
256df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        try {
257df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            Bitmap bitmap = decode(jc, data, offset, length, options);
258df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            if (options.inBitmap != null && options.inBitmap != bitmap) {
259f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu                GalleryBitmapPool.getInstance().put(options.inBitmap);
260df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin                options.inBitmap = null;
261df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            }
262df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            return bitmap;
263df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        } catch (IllegalArgumentException e) {
264df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            if (options.inBitmap == null) throw e;
265df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
266df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
267f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            GalleryBitmapPool.getInstance().put(options.inBitmap);
268df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            options.inBitmap = null;
269df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            return decode(jc, data, offset, length, options);
270df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        }
271df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    }
272df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
273df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    // This is the same as the method above except the source data comes
274df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    // from a file descriptor instead of a byte array.
275df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
276f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu    public static Bitmap decodeUsingPool(JobContext jc,
277f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            FileDescriptor fileDescriptor, Options options) {
278df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        if (options == null) options = new BitmapFactory.Options();
279df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        if (options.inSampleSize < 1) options.inSampleSize = 1;
280df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
281df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        options.inBitmap = (options.inSampleSize == 1)
282f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu                ? findCachedBitmap(jc, fileDescriptor, options) : null;
283df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        try {
284df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            Bitmap bitmap = DecodeUtils.decode(jc, fileDescriptor, options);
285df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            if (options.inBitmap != null && options.inBitmap != bitmap) {
286f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu                GalleryBitmapPool.getInstance().put(options.inBitmap);
287df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin                options.inBitmap = null;
288df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            }
289df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            return bitmap;
290df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        } catch (IllegalArgumentException e) {
291df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            if (options.inBitmap == null) throw e;
292df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
293df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
294f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            GalleryBitmapPool.getInstance().put(options.inBitmap);
295df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            options.inBitmap = null;
296df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            return decode(jc, fileDescriptor, options);
297df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        }
298df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    }
299df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
300f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu    private static Bitmap findCachedBitmap(JobContext jc, byte[] data,
301f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            int offset, int length, Options options) {
302df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        decodeBounds(jc, data, offset, length, options);
303f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu        return GalleryBitmapPool.getInstance().get(options.outWidth, options.outHeight);
304df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    }
305df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
306f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu    private static Bitmap findCachedBitmap(JobContext jc, FileDescriptor fileDescriptor,
307f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            Options options) {
308df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        decodeBounds(jc, fileDescriptor, options);
309f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu        return GalleryBitmapPool.getInstance().get(options.outWidth, options.outHeight);
310df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    }
311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
312