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 Linimport android.util.FloatMath;
274bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
28a625b6562d3bfc86465778b336c96fb42064be21Owen Linimport com.android.gallery3d.common.ApiHelper;
294bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Linimport com.android.gallery3d.common.BitmapUtils;
304bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Linimport com.android.gallery3d.common.Utils;
31f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescuimport com.android.photos.data.GalleryBitmapPool;
32df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Linimport com.android.gallery3d.ui.Log;
334bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Linimport com.android.gallery3d.util.ThreadPool.CancelListener;
344bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Linimport com.android.gallery3d.util.ThreadPool.JobContext;
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.io.FileDescriptor;
37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.io.FileInputStream;
38b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Changimport java.io.InputStream;
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class DecodeUtils {
41df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    private static final String TAG = "DecodeUtils";
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static class DecodeCanceller implements CancelListener {
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Options mOptions;
454bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public DecodeCanceller(Options options) {
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mOptions = options;
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
494bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
504bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        @Override
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void onCancel() {
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mOptions.requestCancelDecode();
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
56a625b6562d3bfc86465778b336c96fb42064be21Owen Lin    @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
57a625b6562d3bfc86465778b336c96fb42064be21Owen Lin    public static void setOptionsMutable(Options options) {
58a625b6562d3bfc86465778b336c96fb42064be21Owen Lin        if (ApiHelper.HAS_OPTIONS_IN_MUTABLE) options.inMutable = true;
59a625b6562d3bfc86465778b336c96fb42064be21Owen Lin    }
60a625b6562d3bfc86465778b336c96fb42064be21Owen Lin
614bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decode(JobContext jc, FileDescriptor fd, Options options) {
62c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin        if (options == null) options = new Options();
63c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin        jc.setCancelListener(new DecodeCanceller(options));
64a625b6562d3bfc86465778b336c96fb42064be21Owen Lin        setOptionsMutable(options);
65c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin        return ensureGLCompatibleBitmap(
66c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin                BitmapFactory.decodeFileDescriptor(fd, null, options));
67c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin    }
68c060a99d0d0f6a0bbcf3cd6bbc6ee9d91e15814dOwen Lin
69b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang    public static void decodeBounds(JobContext jc, FileDescriptor fd,
70b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang            Options options) {
71b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        Utils.assertTrue(options != null);
72b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        options.inJustDecodeBounds = true;
73b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        jc.setCancelListener(new DecodeCanceller(options));
74b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        BitmapFactory.decodeFileDescriptor(fd, null, options);
75b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        options.inJustDecodeBounds = false;
76b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang    }
77b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang
784bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decode(JobContext jc, byte[] bytes, Options options) {
794bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        return decode(jc, bytes, 0, bytes.length, options);
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
824bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decode(JobContext jc, byte[] bytes, int offset,
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int length, Options options) {
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (options == null) options = new Options();
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        jc.setCancelListener(new DecodeCanceller(options));
86a625b6562d3bfc86465778b336c96fb42064be21Owen Lin        setOptionsMutable(options);
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return ensureGLCompatibleBitmap(
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                BitmapFactory.decodeByteArray(bytes, offset, length, options));
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
91b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang    public static void decodeBounds(JobContext jc, byte[] bytes, int offset,
92b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang            int length, Options options) {
93b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        Utils.assertTrue(options != null);
94b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        options.inJustDecodeBounds = true;
95b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        jc.setCancelListener(new DecodeCanceller(options));
96b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        BitmapFactory.decodeByteArray(bytes, offset, length, options);
97b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang        options.inJustDecodeBounds = false;
98b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang    }
99b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang
1004bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decodeThumbnail(
1014bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            JobContext jc, String filePath, Options options, int targetSize, int type) {
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        FileInputStream fis = null;
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            fis = new FileInputStream(filePath);
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            FileDescriptor fd = fis.getFD();
1064bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            return decodeThumbnail(jc, fd, options, targetSize, type);
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Exception ex) {
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, ex);
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Utils.closeSilently(fis);
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1154bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decodeThumbnail(
1164bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            JobContext jc, FileDescriptor fd, Options options, int targetSize, int type) {
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (options == null) options = new Options();
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        jc.setCancelListener(new DecodeCanceller(options));
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        options.inJustDecodeBounds = true;
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        BitmapFactory.decodeFileDescriptor(fd, null, options);
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (jc.isCancelled()) return null;
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1244bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        int w = options.outWidth;
1254bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        int h = options.outHeight;
1264bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
1274bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        if (type == MediaItem.TYPE_MICROTHUMBNAIL) {
1284bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            // We center-crop the original image as it's micro thumbnail. In this case,
1294bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            // we want to make sure the shorter side >= "targetSize".
1304bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            float scale = (float) targetSize / Math.min(w, h);
1314bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            options.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
1324bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
1334bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            // For an extremely wide image, e.g. 300x30000, we may got OOM when decoding
1344bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            // it for TYPE_MICROTHUMBNAIL. So we add a max number of pixels limit here.
1354bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            final int MAX_PIXEL_COUNT = 640000; // 400 x 1600
1364bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            if ((w / options.inSampleSize) * (h / options.inSampleSize) > MAX_PIXEL_COUNT) {
1374bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin                options.inSampleSize = BitmapUtils.computeSampleSize(
1384bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin                        FloatMath.sqrt((float) MAX_PIXEL_COUNT / (w * h)));
1394bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            }
1404bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        } else {
1414bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            // For screen nail, we only want to keep the longer side >= targetSize.
1424bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            float scale = (float) targetSize / Math.max(w, h);
1434bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin            options.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
1444bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        }
1454bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        options.inJustDecodeBounds = false;
147a625b6562d3bfc86465778b336c96fb42064be21Owen Lin        setOptionsMutable(options);
1486c8d0fd879242f78a0c1a7daf4c037043663a49fChih-Chung Chang
1496c8d0fd879242f78a0c1a7daf4c037043663a49fChih-Chung Chang        Bitmap result = BitmapFactory.decodeFileDescriptor(fd, null, options);
1504bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        if (result == null) return null;
1514bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
1524bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        // We need to resize down if the decoder does not support inSampleSize
1534bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        // (For example, GIF images)
1544bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        float scale = (float) targetSize / (type == MediaItem.TYPE_MICROTHUMBNAIL
1554bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin                ? Math.min(result.getWidth(), result.getHeight())
1564bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin                : Math.max(result.getWidth(), result.getHeight()));
1574bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
1584bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        if (scale <= 0.5) result = BitmapUtils.resizeBitmapByScale(result, scale, true);
1596c8d0fd879242f78a0c1a7daf4c037043663a49fChih-Chung Chang        return ensureGLCompatibleBitmap(result);
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
162113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin    /**
163113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin     * Decodes the bitmap from the given byte array if the image size is larger than the given
164113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin     * requirement.
165113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin     *
1665da31f8fd85d7c1e33133473bd1fbc5e3a240f2dOwen Lin     * Note: The returned image may be resized down. However, both width and height must be
167113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin     * larger than the <code>targetSize</code>.
168113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin     */
1694bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap decodeIfBigEnough(JobContext jc, byte[] data,
170113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin            Options options, int targetSize) {
171113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        if (options == null) options = new Options();
172113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        jc.setCancelListener(new DecodeCanceller(options));
173113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin
174113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        options.inJustDecodeBounds = true;
175113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        BitmapFactory.decodeByteArray(data, 0, data.length, options);
176113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        if (jc.isCancelled()) return null;
177113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        if (options.outWidth < targetSize || options.outHeight < targetSize) {
178113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin            return null;
179113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        }
180113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        options.inSampleSize = BitmapUtils.computeSampleSizeLarger(
181113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin                options.outWidth, options.outHeight, targetSize);
182113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        options.inJustDecodeBounds = false;
183a625b6562d3bfc86465778b336c96fb42064be21Owen Lin        setOptionsMutable(options);
184a625b6562d3bfc86465778b336c96fb42064be21Owen Lin
185113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        return ensureGLCompatibleBitmap(
186113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin                BitmapFactory.decodeByteArray(data, 0, data.length, options));
187113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin    }
188113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // TODO: This function should not be called directly from
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // DecodeUtils.requestDecode(...), since we don't have the knowledge
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // if the bitmap will be uploaded to GL.
192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) {
193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (bitmap == null || bitmap.getConfig() != null) return bitmap;
194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false);
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        bitmap.recycle();
196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return newBitmap;
197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1994bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static BitmapRegionDecoder createBitmapRegionDecoder(
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            JobContext jc, byte[] bytes, int offset, int length,
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            boolean shareable) {
202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (offset < 0 || length <= 0 || offset + length > bytes.length) {
203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            throw new IllegalArgumentException(String.format(
204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    "offset = %s, length = %s, bytes = %s",
205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    offset, length, bytes.length));
206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return BitmapRegionDecoder.newInstance(
210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    bytes, offset, length, shareable);
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Throwable t)  {
212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, t);
213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2174bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static BitmapRegionDecoder createBitmapRegionDecoder(
218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            JobContext jc, String filePath, boolean shareable) {
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return BitmapRegionDecoder.newInstance(filePath, shareable);
221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Throwable t)  {
222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, t);
223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2274bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static BitmapRegionDecoder createBitmapRegionDecoder(
228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            JobContext jc, FileDescriptor fd, boolean shareable) {
229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return BitmapRegionDecoder.newInstance(fd, shareable);
231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Throwable t)  {
232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, t);
233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2374bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static BitmapRegionDecoder createBitmapRegionDecoder(
238b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            JobContext jc, InputStream is, boolean shareable) {
239b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang        try {
240b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            return BitmapRegionDecoder.newInstance(is, shareable);
241b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang        } catch (Throwable t)  {
242b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            // We often cancel the creating of bitmap region decoder,
243b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            // so just log one line.
244b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            Log.w(TAG, "requestCreateBitmapRegionDecoder: " + t);
245b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang            return null;
246b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang        }
247b289d441eb5af97ac8716479831b1a2c5fe2e878Chih-Chung Chang    }
248df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
249df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
250f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu    public static Bitmap decodeUsingPool(JobContext jc, byte[] data, int offset,
251f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            int length, BitmapFactory.Options options) {
252df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        if (options == null) options = new BitmapFactory.Options();
253df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        if (options.inSampleSize < 1) options.inSampleSize = 1;
254df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
255df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        options.inBitmap = (options.inSampleSize == 1)
256f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu                ? findCachedBitmap(jc, data, offset, length, options) : null;
257df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        try {
258df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            Bitmap bitmap = decode(jc, data, offset, length, options);
259df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            if (options.inBitmap != null && options.inBitmap != bitmap) {
260f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu                GalleryBitmapPool.getInstance().put(options.inBitmap);
261df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin                options.inBitmap = null;
262df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            }
263df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            return bitmap;
264df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        } catch (IllegalArgumentException e) {
265df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            if (options.inBitmap == null) throw e;
266df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
267df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
268f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            GalleryBitmapPool.getInstance().put(options.inBitmap);
269df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            options.inBitmap = null;
270df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            return decode(jc, data, offset, length, options);
271df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        }
272df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    }
273df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
274df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    // This is the same as the method above except the source data comes
275df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    // from a file descriptor instead of a byte array.
276df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
277f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu    public static Bitmap decodeUsingPool(JobContext jc,
278f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            FileDescriptor fileDescriptor, Options options) {
279df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        if (options == null) options = new BitmapFactory.Options();
280df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        if (options.inSampleSize < 1) options.inSampleSize = 1;
281df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
282df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        options.inBitmap = (options.inSampleSize == 1)
283f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu                ? findCachedBitmap(jc, fileDescriptor, options) : null;
284df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        try {
285df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            Bitmap bitmap = DecodeUtils.decode(jc, fileDescriptor, options);
286df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            if (options.inBitmap != null && options.inBitmap != bitmap) {
287f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu                GalleryBitmapPool.getInstance().put(options.inBitmap);
288df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin                options.inBitmap = null;
289df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            }
290df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            return bitmap;
291df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        } catch (IllegalArgumentException e) {
292df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            if (options.inBitmap == null) throw e;
293df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
294df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
295f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            GalleryBitmapPool.getInstance().put(options.inBitmap);
296df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            options.inBitmap = null;
297df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin            return decode(jc, fileDescriptor, options);
298df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        }
299df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    }
300df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
301f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu    private static Bitmap findCachedBitmap(JobContext jc, byte[] data,
302f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            int offset, int length, Options options) {
303df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        decodeBounds(jc, data, offset, length, options);
304f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu        return GalleryBitmapPool.getInstance().get(options.outWidth, options.outHeight);
305df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    }
306df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin
307f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu    private static Bitmap findCachedBitmap(JobContext jc, FileDescriptor fileDescriptor,
308f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            Options options) {
309df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin        decodeBounds(jc, fileDescriptor, options);
310f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu        return GalleryBitmapPool.getInstance().get(options.outWidth, options.outHeight);
311df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    }
312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
313