1104c45677660586026a7e74ef8c47d396403d50eMichael Jurka/* 2104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Copyright (C) 2010 The Android Open Source Project 3104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 4104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 5104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * you may not use this file except in compliance with the License. 6104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * You may obtain a copy of the License at 7104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 8104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0 9104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 10104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Unless required by applicable law or agreed to in writing, software 11104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 12104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * See the License for the specific language governing permissions and 14104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * limitations under the License. 15104c45677660586026a7e74ef8c47d396403d50eMichael Jurka */ 16104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 17104c45677660586026a7e74ef8c47d396403d50eMichael Jurkapackage com.android.gallery3d.common; 18104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 19104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.graphics.Bitmap; 20104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.graphics.Bitmap.CompressFormat; 21104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.graphics.BitmapFactory; 22104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.graphics.Canvas; 23104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.graphics.Matrix; 24104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.graphics.Paint; 25104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.os.Build; 26104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.util.FloatMath; 27104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.util.Log; 28104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 29104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport java.io.ByteArrayOutputStream; 30104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport java.lang.reflect.InvocationTargetException; 31104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport java.lang.reflect.Method; 32104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 33104c45677660586026a7e74ef8c47d396403d50eMichael Jurkapublic class BitmapUtils { 34104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static final String TAG = "BitmapUtils"; 35104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static final int DEFAULT_JPEG_QUALITY = 90; 36104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static final int UNCONSTRAINED = -1; 37104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 38104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private BitmapUtils(){} 39104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 40104c45677660586026a7e74ef8c47d396403d50eMichael Jurka /* 41104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Compute the sample size as a function of minSideLength 42104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * and maxNumOfPixels. 43104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * minSideLength is used to specify that minimal width or height of a 44104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * bitmap. 45104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * maxNumOfPixels is used to specify the maximal size in pixels that is 46104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * tolerable in terms of memory usage. 47104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 48104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * The function returns a sample size based on the constraints. 49104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Both size and minSideLength can be passed in as UNCONSTRAINED, 50104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * which indicates no care of the corresponding constraint. 51104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * The functions prefers returning a sample size that 52104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * generates a smaller bitmap, unless minSideLength = UNCONSTRAINED. 53104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 54104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Also, the function rounds up the sample size to a power of 2 or multiple 55104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * of 8 because BitmapFactory only honors sample size this way. 56104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * For example, BitmapFactory downsamples an image by 2 even though the 57104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * request is 3. So we round up the sample size to avoid OOM. 58104c45677660586026a7e74ef8c47d396403d50eMichael Jurka */ 59104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static int computeSampleSize(int width, int height, 60104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int minSideLength, int maxNumOfPixels) { 61104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int initialSize = computeInitialSampleSize( 62104c45677660586026a7e74ef8c47d396403d50eMichael Jurka width, height, minSideLength, maxNumOfPixels); 63104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 64104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return initialSize <= 8 65104c45677660586026a7e74ef8c47d396403d50eMichael Jurka ? Utils.nextPowerOf2(initialSize) 66104c45677660586026a7e74ef8c47d396403d50eMichael Jurka : (initialSize + 7) / 8 * 8; 67104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 68104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 69104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static int computeInitialSampleSize(int w, int h, 70104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int minSideLength, int maxNumOfPixels) { 71104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (maxNumOfPixels == UNCONSTRAINED 72104c45677660586026a7e74ef8c47d396403d50eMichael Jurka && minSideLength == UNCONSTRAINED) return 1; 73104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 74104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : 75104c45677660586026a7e74ef8c47d396403d50eMichael Jurka (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels)); 76104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 77104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (minSideLength == UNCONSTRAINED) { 78104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return lowerBound; 79104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } else { 80104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int sampleSize = Math.min(w / minSideLength, h / minSideLength); 81104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return Math.max(sampleSize, lowerBound); 82104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 83104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 84104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 85104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // This computes a sample size which makes the longer side at least 86104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // minSideLength long. If that's not possible, return 1. 87104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static int computeSampleSizeLarger(int w, int h, 88104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int minSideLength) { 89104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int initialSize = Math.max(w / minSideLength, h / minSideLength); 90104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (initialSize <= 1) return 1; 91104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 92104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return initialSize <= 8 93104c45677660586026a7e74ef8c47d396403d50eMichael Jurka ? Utils.prevPowerOf2(initialSize) 94104c45677660586026a7e74ef8c47d396403d50eMichael Jurka : initialSize / 8 * 8; 95104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 96104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 97104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Find the min x that 1 / x >= scale 98104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static int computeSampleSizeLarger(float scale) { 99104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int initialSize = (int) FloatMath.floor(1f / scale); 100104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (initialSize <= 1) return 1; 101104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 102104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return initialSize <= 8 103104c45677660586026a7e74ef8c47d396403d50eMichael Jurka ? Utils.prevPowerOf2(initialSize) 104104c45677660586026a7e74ef8c47d396403d50eMichael Jurka : initialSize / 8 * 8; 105104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 106104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 107104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Find the max x that 1 / x <= scale. 108104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static int computeSampleSize(float scale) { 109104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Utils.assertTrue(scale > 0); 110104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale)); 111104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return initialSize <= 8 112104c45677660586026a7e74ef8c47d396403d50eMichael Jurka ? Utils.nextPowerOf2(initialSize) 113104c45677660586026a7e74ef8c47d396403d50eMichael Jurka : (initialSize + 7) / 8 * 8; 114104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 115104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 116104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static Bitmap resizeBitmapByScale( 117104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap bitmap, float scale, boolean recycle) { 118104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int width = Math.round(bitmap.getWidth() * scale); 119104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int height = Math.round(bitmap.getHeight() * scale); 120104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (width == bitmap.getWidth() 121104c45677660586026a7e74ef8c47d396403d50eMichael Jurka && height == bitmap.getHeight()) return bitmap; 122104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap)); 123104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Canvas canvas = new Canvas(target); 124104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.scale(scale, scale); 125104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); 126104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.drawBitmap(bitmap, 0, 0, paint); 127104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (recycle) bitmap.recycle(); 128104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return target; 129104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 130104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 131104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static Bitmap.Config getConfig(Bitmap bitmap) { 132104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap.Config config = bitmap.getConfig(); 133104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (config == null) { 134104c45677660586026a7e74ef8c47d396403d50eMichael Jurka config = Bitmap.Config.ARGB_8888; 135104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 136104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return config; 137104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 138104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 139104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static Bitmap resizeDownBySideLength( 140104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap bitmap, int maxLength, boolean recycle) { 141104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int srcWidth = bitmap.getWidth(); 142104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int srcHeight = bitmap.getHeight(); 143104c45677660586026a7e74ef8c47d396403d50eMichael Jurka float scale = Math.min( 144104c45677660586026a7e74ef8c47d396403d50eMichael Jurka (float) maxLength / srcWidth, (float) maxLength / srcHeight); 145104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (scale >= 1.0f) return bitmap; 146104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return resizeBitmapByScale(bitmap, scale, recycle); 147104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 148104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 149104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) { 150104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int w = bitmap.getWidth(); 151104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int h = bitmap.getHeight(); 152104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (w == size && h == size) return bitmap; 153104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 154104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // scale the image so that the shorter side equals to the target; 155104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // the longer side will be center-cropped. 156104c45677660586026a7e74ef8c47d396403d50eMichael Jurka float scale = (float) size / Math.min(w, h); 157104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 158104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap)); 159104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int width = Math.round(scale * bitmap.getWidth()); 160104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int height = Math.round(scale * bitmap.getHeight()); 161104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Canvas canvas = new Canvas(target); 162104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.translate((size - width) / 2f, (size - height) / 2f); 163104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.scale(scale, scale); 164104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); 165104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.drawBitmap(bitmap, 0, 0, paint); 166104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (recycle) bitmap.recycle(); 167104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return target; 168104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 169104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 170104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static void recycleSilently(Bitmap bitmap) { 171104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (bitmap == null) return; 172104c45677660586026a7e74ef8c47d396403d50eMichael Jurka try { 173104c45677660586026a7e74ef8c47d396403d50eMichael Jurka bitmap.recycle(); 174104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } catch (Throwable t) { 175104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Log.w(TAG, "unable recycle bitmap", t); 176104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 177104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 178104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 179104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static Bitmap rotateBitmap(Bitmap source, int rotation, boolean recycle) { 180104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (rotation == 0) return source; 181104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int w = source.getWidth(); 182104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int h = source.getHeight(); 183104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Matrix m = new Matrix(); 184104c45677660586026a7e74ef8c47d396403d50eMichael Jurka m.postRotate(rotation); 185104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, w, h, m, true); 186104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (recycle) source.recycle(); 187104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return bitmap; 188104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 189104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 190104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static Bitmap createVideoThumbnail(String filePath) { 191104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // MediaMetadataRetriever is available on API Level 8 192104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // but is hidden until API Level 10 193104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Class<?> clazz = null; 194104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Object instance = null; 195104c45677660586026a7e74ef8c47d396403d50eMichael Jurka try { 196104c45677660586026a7e74ef8c47d396403d50eMichael Jurka clazz = Class.forName("android.media.MediaMetadataRetriever"); 197104c45677660586026a7e74ef8c47d396403d50eMichael Jurka instance = clazz.newInstance(); 198104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 199104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Method method = clazz.getMethod("setDataSource", String.class); 200104c45677660586026a7e74ef8c47d396403d50eMichael Jurka method.invoke(instance, filePath); 201104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 202104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // The method name changes between API Level 9 and 10. 203104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (Build.VERSION.SDK_INT <= 9) { 204104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return (Bitmap) clazz.getMethod("captureFrame").invoke(instance); 205104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } else { 206104c45677660586026a7e74ef8c47d396403d50eMichael Jurka byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance); 207104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (data != null) { 208104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 209104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (bitmap != null) return bitmap; 210104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 211104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance); 212104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 213104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } catch (IllegalArgumentException ex) { 214104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Assume this is a corrupt video file 215104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } catch (RuntimeException ex) { 216104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Assume this is a corrupt video file. 217104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } catch (InstantiationException e) { 218104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Log.e(TAG, "createVideoThumbnail", e); 219104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } catch (InvocationTargetException e) { 220104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Log.e(TAG, "createVideoThumbnail", e); 221104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } catch (ClassNotFoundException e) { 222104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Log.e(TAG, "createVideoThumbnail", e); 223104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } catch (NoSuchMethodException e) { 224104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Log.e(TAG, "createVideoThumbnail", e); 225104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } catch (IllegalAccessException e) { 226104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Log.e(TAG, "createVideoThumbnail", e); 227104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } finally { 228104c45677660586026a7e74ef8c47d396403d50eMichael Jurka try { 229104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (instance != null) { 230104c45677660586026a7e74ef8c47d396403d50eMichael Jurka clazz.getMethod("release").invoke(instance); 231104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 232104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } catch (Exception ignored) { 233104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 234104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 235104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return null; 236104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 237104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 238104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static byte[] compressToBytes(Bitmap bitmap) { 239104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY); 240104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 241104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 242104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static byte[] compressToBytes(Bitmap bitmap, int quality) { 243104c45677660586026a7e74ef8c47d396403d50eMichael Jurka ByteArrayOutputStream baos = new ByteArrayOutputStream(65536); 244104c45677660586026a7e74ef8c47d396403d50eMichael Jurka bitmap.compress(CompressFormat.JPEG, quality, baos); 245104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return baos.toByteArray(); 246104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 247104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 248104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static boolean isSupportedByRegionDecoder(String mimeType) { 249104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mimeType == null) return false; 250104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mimeType = mimeType.toLowerCase(); 251104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mimeType.startsWith("image/") && 252104c45677660586026a7e74ef8c47d396403d50eMichael Jurka (!mimeType.equals("image/gif") && !mimeType.endsWith("bmp")); 253104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 254104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 255104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static boolean isRotationSupported(String mimeType) { 256104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mimeType == null) return false; 257104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mimeType = mimeType.toLowerCase(); 258104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mimeType.equals("image/jpeg"); 259104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 260104c45677660586026a7e74ef8c47d396403d50eMichael Jurka} 261