1e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/*
2e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Copyright (C) 2010 The Android Open Source Project
3e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
4e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License");
5e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * you may not use this file except in compliance with the License.
6e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * You may obtain a copy of the License at
7e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
8e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *      http://www.apache.org/licenses/LICENSE-2.0
9e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
10e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Unless required by applicable law or agreed to in writing, software
11e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS,
12e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * See the License for the specific language governing permissions and
14e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * limitations under the License.
15e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */
16e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
17e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapackage com.android.gallery3d.common;
18e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
19e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Bitmap;
20e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Bitmap.CompressFormat;
21e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.BitmapFactory;
22e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Canvas;
23e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Matrix;
24e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Paint;
25e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.os.Build;
26e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.FloatMath;
27e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.Log;
28e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
29e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.ByteArrayOutputStream;
30e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.lang.reflect.InvocationTargetException;
31e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.lang.reflect.Method;
32e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
33e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapublic class BitmapUtils {
34e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final String TAG = "BitmapUtils";
35e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final int DEFAULT_JPEG_QUALITY = 90;
36e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static final int UNCONSTRAINED = -1;
37e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
38e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private BitmapUtils(){}
39e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
40e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    /*
41e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * Compute the sample size as a function of minSideLength
42e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * and maxNumOfPixels.
43e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * minSideLength is used to specify that minimal width or height of a
44e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * bitmap.
45e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * maxNumOfPixels is used to specify the maximal size in pixels that is
46e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * tolerable in terms of memory usage.
47e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     *
48e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * The function returns a sample size based on the constraints.
49e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * Both size and minSideLength can be passed in as UNCONSTRAINED,
50e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * which indicates no care of the corresponding constraint.
51e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * The functions prefers returning a sample size that
52e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * generates a smaller bitmap, unless minSideLength = UNCONSTRAINED.
53e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     *
54e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * Also, the function rounds up the sample size to a power of 2 or multiple
55e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * of 8 because BitmapFactory only honors sample size this way.
56e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * For example, BitmapFactory downsamples an image by 2 even though the
57e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * request is 3. So we round up the sample size to avoid OOM.
58e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     */
59e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static int computeSampleSize(int width, int height,
60e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int minSideLength, int maxNumOfPixels) {
61e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int initialSize = computeInitialSampleSize(
62e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                width, height, minSideLength, maxNumOfPixels);
63e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
64e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return initialSize <= 8
65e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                ? Utils.nextPowerOf2(initialSize)
66e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                : (initialSize + 7) / 8 * 8;
67e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
68e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
69e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static int computeInitialSampleSize(int w, int h,
70e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int minSideLength, int maxNumOfPixels) {
71e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (maxNumOfPixels == UNCONSTRAINED
72e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                && minSideLength == UNCONSTRAINED) return 1;
73e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
74e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :
75e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels));
76e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
77e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (minSideLength == UNCONSTRAINED) {
78e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return lowerBound;
79e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
80e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int sampleSize = Math.min(w / minSideLength, h / minSideLength);
81e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return Math.max(sampleSize, lowerBound);
82e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
83e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
84e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
85e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // This computes a sample size which makes the longer side at least
86e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // minSideLength long. If that's not possible, return 1.
87e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static int computeSampleSizeLarger(int w, int h,
88e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int minSideLength) {
89e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int initialSize = Math.max(w / minSideLength, h / minSideLength);
90e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (initialSize <= 1) return 1;
91e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
92e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return initialSize <= 8
93e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                ? Utils.prevPowerOf2(initialSize)
94e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                : initialSize / 8 * 8;
95e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
96e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
97e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // Find the min x that 1 / x >= scale
98e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static int computeSampleSizeLarger(float scale) {
99e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int initialSize = (int) FloatMath.floor(1f / scale);
100e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (initialSize <= 1) return 1;
101e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
102e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return initialSize <= 8
103e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                ? Utils.prevPowerOf2(initialSize)
104e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                : initialSize / 8 * 8;
105e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
106e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
107e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // Find the max x that 1 / x <= scale.
108e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static int computeSampleSize(float scale) {
109e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Utils.assertTrue(scale > 0);
110e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale));
111e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return initialSize <= 8
112e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                ? Utils.nextPowerOf2(initialSize)
113e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                : (initialSize + 7) / 8 * 8;
114e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
115e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
116e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static Bitmap resizeBitmapByScale(
117e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Bitmap bitmap, float scale, boolean recycle) {
118e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int width = Math.round(bitmap.getWidth() * scale);
119e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int height = Math.round(bitmap.getHeight() * scale);
120e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (width == bitmap.getWidth()
121e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                && height == bitmap.getHeight()) return bitmap;
122e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
123e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Canvas canvas = new Canvas(target);
124e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        canvas.scale(scale, scale);
125e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
126e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        canvas.drawBitmap(bitmap, 0, 0, paint);
127e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (recycle) bitmap.recycle();
128e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return target;
129e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
130e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
131e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static Bitmap.Config getConfig(Bitmap bitmap) {
132e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Bitmap.Config config = bitmap.getConfig();
133e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (config == null) {
134e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            config = Bitmap.Config.ARGB_8888;
135e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
136e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return config;
137e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
138e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
139e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static Bitmap resizeDownBySideLength(
140e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Bitmap bitmap, int maxLength, boolean recycle) {
141e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int srcWidth = bitmap.getWidth();
142e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int srcHeight = bitmap.getHeight();
143e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float scale = Math.min(
144e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                (float) maxLength / srcWidth, (float) maxLength / srcHeight);
145e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (scale >= 1.0f) return bitmap;
146e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return resizeBitmapByScale(bitmap, scale, recycle);
147e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
148e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
149e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
150e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int w = bitmap.getWidth();
151e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int h = bitmap.getHeight();
152e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (w == size && h == size) return bitmap;
153e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
154e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // scale the image so that the shorter side equals to the target;
155e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // the longer side will be center-cropped.
156e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float scale = (float) size / Math.min(w,  h);
157e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
158e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
159e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int width = Math.round(scale * bitmap.getWidth());
160e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int height = Math.round(scale * bitmap.getHeight());
161e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Canvas canvas = new Canvas(target);
162e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        canvas.translate((size - width) / 2f, (size - height) / 2f);
163e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        canvas.scale(scale, scale);
164e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
165e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        canvas.drawBitmap(bitmap, 0, 0, paint);
166e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (recycle) bitmap.recycle();
167e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return target;
168e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
169e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
170e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static void recycleSilently(Bitmap bitmap) {
171e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (bitmap == null) return;
172e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        try {
173e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            bitmap.recycle();
174e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } catch (Throwable t) {
175e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Log.w(TAG, "unable recycle bitmap", t);
176e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
177e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
178e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
179e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static Bitmap rotateBitmap(Bitmap source, int rotation, boolean recycle) {
180e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (rotation == 0) return source;
181e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int w = source.getWidth();
182e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int h = source.getHeight();
183e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Matrix m = new Matrix();
184e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        m.postRotate(rotation);
185e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, w, h, m, true);
186e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (recycle) source.recycle();
187e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return bitmap;
188e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
189e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
190e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static Bitmap createVideoThumbnail(String filePath) {
191e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // MediaMetadataRetriever is available on API Level 8
192e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // but is hidden until API Level 10
193e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Class<?> clazz = null;
194e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Object instance = null;
195e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        try {
196e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            clazz = Class.forName("android.media.MediaMetadataRetriever");
197e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            instance = clazz.newInstance();
198e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
199e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Method method = clazz.getMethod("setDataSource", String.class);
200e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            method.invoke(instance, filePath);
201e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
202e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // The method name changes between API Level 9 and 10.
203e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (Build.VERSION.SDK_INT <= 9) {
204e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                return (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
205e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } else {
206e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
207e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (data != null) {
208e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
209e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (bitmap != null) return bitmap;
210e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
211e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
212e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
213e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } catch (IllegalArgumentException ex) {
214e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Assume this is a corrupt video file
215e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } catch (RuntimeException ex) {
216e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Assume this is a corrupt video file.
217e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } catch (InstantiationException e) {
218e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Log.e(TAG, "createVideoThumbnail", e);
219e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } catch (InvocationTargetException e) {
220e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Log.e(TAG, "createVideoThumbnail", e);
221e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } catch (ClassNotFoundException e) {
222e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Log.e(TAG, "createVideoThumbnail", e);
223e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } catch (NoSuchMethodException e) {
224e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Log.e(TAG, "createVideoThumbnail", e);
225e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } catch (IllegalAccessException e) {
226e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Log.e(TAG, "createVideoThumbnail", e);
227e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } finally {
228e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            try {
229e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (instance != null) {
230e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    clazz.getMethod("release").invoke(instance);
231e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
232e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } catch (Exception ignored) {
233e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
234e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
235e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return null;
236e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
237e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
238e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static byte[] compressToBytes(Bitmap bitmap) {
239e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY);
240e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
241e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
242e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static byte[] compressToBytes(Bitmap bitmap, int quality) {
243e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        ByteArrayOutputStream baos = new ByteArrayOutputStream(65536);
244e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        bitmap.compress(CompressFormat.JPEG, quality, baos);
245e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return baos.toByteArray();
246e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
247e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
248e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static boolean isSupportedByRegionDecoder(String mimeType) {
249e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (mimeType == null) return false;
250e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mimeType = mimeType.toLowerCase();
251e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return mimeType.startsWith("image/") &&
252e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                (!mimeType.equals("image/gif") && !mimeType.endsWith("bmp"));
253e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
254e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
255e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static boolean isRotationSupported(String mimeType) {
256e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (mimeType == null) return false;
257e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mimeType = mimeType.toLowerCase();
258e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return mimeType.equals("image/jpeg");
259e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
260e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka}
261