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.common;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap;
20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap.CompressFormat;
218cdfc6a0cd6b32f4c2baa64dbaddb8f496dced6dOwen Linimport android.graphics.BitmapFactory;
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Canvas;
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Matrix;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Paint;
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Build;
26fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Changimport android.util.FloatMath;
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.util.Log;
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.io.ByteArrayOutputStream;
30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.lang.reflect.InvocationTargetException;
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.lang.reflect.Method;
32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class BitmapUtils {
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "BitmapUtils";
354bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    private static final int DEFAULT_JPEG_QUALITY = 90;
3604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    public static final int UNCONSTRAINED = -1;
37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private BitmapUtils(){}
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    /*
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * Compute the sample size as a function of minSideLength
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * and maxNumOfPixels.
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * minSideLength is used to specify that minimal width or height of a
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * bitmap.
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * maxNumOfPixels is used to specify the maximal size in pixels that is
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * tolerable in terms of memory usage.
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     *
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * The function returns a sample size based on the constraints.
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * Both size and minSideLength can be passed in as UNCONSTRAINED,
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * which indicates no care of the corresponding constraint.
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * The functions prefers returning a sample size that
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * generates a smaller bitmap, unless minSideLength = UNCONSTRAINED.
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     *
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * Also, the function rounds up the sample size to a power of 2 or multiple
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * of 8 because BitmapFactory only honors sample size this way.
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * For example, BitmapFactory downsamples an image by 2 even though the
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * request is 3. So we round up the sample size to avoid OOM.
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     */
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static int computeSampleSize(int width, int height,
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int minSideLength, int maxNumOfPixels) {
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int initialSize = computeInitialSampleSize(
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                width, height, minSideLength, maxNumOfPixels);
63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return initialSize <= 8
65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ? Utils.nextPowerOf2(initialSize)
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                : (initialSize + 7) / 8 * 8;
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static int computeInitialSampleSize(int w, int h,
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int minSideLength, int maxNumOfPixels) {
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (maxNumOfPixels == UNCONSTRAINED
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                && minSideLength == UNCONSTRAINED) return 1;
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :
75fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Chang                (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels));
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (minSideLength == UNCONSTRAINED) {
78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return lowerBound;
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int sampleSize = Math.min(w / minSideLength, h / minSideLength);
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return Math.max(sampleSize, lowerBound);
82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // This computes a sample size which makes the longer side at least
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // minSideLength long. If that's not possible, return 1.
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static int computeSampleSizeLarger(int w, int h,
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int minSideLength) {
895da31f8fd85d7c1e33133473bd1fbc5e3a240f2dOwen Lin        int initialSize = Math.max(w / minSideLength, h / minSideLength);
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (initialSize <= 1) return 1;
91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return initialSize <= 8
93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ? Utils.prevPowerOf2(initialSize)
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                : initialSize / 8 * 8;
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
974bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    // Find the min x that 1 / x >= scale
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static int computeSampleSizeLarger(float scale) {
99fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Chang        int initialSize = (int) FloatMath.floor(1f / scale);
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (initialSize <= 1) return 1;
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return initialSize <= 8
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ? Utils.prevPowerOf2(initialSize)
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                : initialSize / 8 * 8;
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1074bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    // Find the max x that 1 / x <= scale.
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static int computeSampleSize(float scale) {
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Utils.assertTrue(scale > 0);
110fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Chang        int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale));
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return initialSize <= 8
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ? Utils.nextPowerOf2(initialSize)
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                : (initialSize + 7) / 8 * 8;
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static Bitmap resizeBitmapByScale(
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Bitmap bitmap, float scale, boolean recycle) {
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int width = Math.round(bitmap.getWidth() * scale);
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int height = Math.round(bitmap.getHeight() * scale);
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (width == bitmap.getWidth()
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                && height == bitmap.getHeight()) return bitmap;
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Canvas canvas = new Canvas(target);
124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        canvas.scale(scale, scale);
125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        canvas.drawBitmap(bitmap, 0, 0, paint);
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (recycle) bitmap.recycle();
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return target;
129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static Bitmap.Config getConfig(Bitmap bitmap) {
132ea0feffc18ed2d0086d5fc4c57353f9e81154099Owen Lin        Bitmap.Config config = bitmap.getConfig();
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (config == null) {
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            config = Bitmap.Config.ARGB_8888;
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return config;
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static Bitmap resizeDownBySideLength(
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Bitmap bitmap, int maxLength, boolean recycle) {
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int srcWidth = bitmap.getWidth();
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int srcHeight = bitmap.getHeight();
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        float scale = Math.min(
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                (float) maxLength / srcWidth, (float) maxLength / srcHeight);
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (scale >= 1.0f) return bitmap;
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return resizeBitmapByScale(bitmap, scale, recycle);
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1494bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int w = bitmap.getWidth();
151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int h = bitmap.getHeight();
1524bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        if (w == size && h == size) return bitmap;
1534bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
1544bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        // scale the image so that the shorter side equals to the target;
1554bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        // the longer side will be center-cropped.
1564bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        float scale = (float) size / Math.min(w,  h);
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int width = Math.round(scale * bitmap.getWidth());
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int height = Math.round(scale * bitmap.getHeight());
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Canvas canvas = new Canvas(target);
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        canvas.translate((size - width) / 2f, (size - height) / 2f);
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        canvas.scale(scale, scale);
164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        canvas.drawBitmap(bitmap, 0, 0, paint);
166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (recycle) bitmap.recycle();
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return target;
168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static void recycleSilently(Bitmap bitmap) {
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (bitmap == null) return;
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            bitmap.recycle();
174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Throwable t) {
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, "unable recycle bitmap", t);
176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static Bitmap rotateBitmap(Bitmap source, int rotation, boolean recycle) {
18022493b29c32142f2588c623f5c78e9167352dddcOwen Lin        if (rotation == 0) return source;
181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int w = source.getWidth();
182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int h = source.getHeight();
183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Matrix m = new Matrix();
184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        m.postRotate(rotation);
185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, w, h, m, true);
186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (recycle) source.recycle();
187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return bitmap;
188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static Bitmap createVideoThumbnail(String filePath) {
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // MediaMetadataRetriever is available on API Level 8
192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // but is hidden until API Level 10
193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Class<?> clazz = null;
194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Object instance = null;
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            clazz = Class.forName("android.media.MediaMetadataRetriever");
197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            instance = clazz.newInstance();
198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Method method = clazz.getMethod("setDataSource", String.class);
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            method.invoke(instance, filePath);
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // The method name changes between API Level 9 and 10.
203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (Build.VERSION.SDK_INT <= 9) {
204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                return (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
2068cdfc6a0cd6b32f4c2baa64dbaddb8f496dced6dOwen Lin                byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
2078cdfc6a0cd6b32f4c2baa64dbaddb8f496dced6dOwen Lin                if (data != null) {
2088cdfc6a0cd6b32f4c2baa64dbaddb8f496dced6dOwen Lin                    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
2098cdfc6a0cd6b32f4c2baa64dbaddb8f496dced6dOwen Lin                    if (bitmap != null) return bitmap;
2108cdfc6a0cd6b32f4c2baa64dbaddb8f496dced6dOwen Lin                }
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (IllegalArgumentException ex) {
214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Assume this is a corrupt video file
215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (RuntimeException ex) {
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Assume this is a corrupt video file.
217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (InstantiationException e) {
218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.e(TAG, "createVideoThumbnail", e);
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (InvocationTargetException e) {
220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.e(TAG, "createVideoThumbnail", e);
221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (ClassNotFoundException e) {
222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.e(TAG, "createVideoThumbnail", e);
223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (NoSuchMethodException e) {
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.e(TAG, "createVideoThumbnail", e);
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (IllegalAccessException e) {
226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.e(TAG, "createVideoThumbnail", e);
227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            try {
229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (instance != null) {
230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    clazz.getMethod("release").invoke(instance);
231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } catch (Exception ignored) {
233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return null;
236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2384bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static byte[] compressToBytes(Bitmap bitmap) {
2394bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY);
2404bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    }
2414bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
2424bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin    public static byte[] compressToBytes(Bitmap bitmap, int quality) {
2434bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        ByteArrayOutputStream baos = new ByteArrayOutputStream(65536);
2444bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        bitmap.compress(CompressFormat.JPEG, quality, baos);
2454bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        return baos.toByteArray();
246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static boolean isSupportedByRegionDecoder(String mimeType) {
249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mimeType == null) return false;
250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mimeType = mimeType.toLowerCase();
251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mimeType.startsWith("image/") &&
252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                (!mimeType.equals("image/gif") && !mimeType.endsWith("bmp"));
253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static boolean isRotationSupported(String mimeType) {
256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mimeType == null) return false;
257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mimeType = mimeType.toLowerCase();
258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mimeType.equals("image/jpeg");
259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
261