package net.hockeyapp.android.utils; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * <h3>Description</h3> * * Various functions related to image loading and bitmap scaling. */ public class ImageUtils { public static final int ORIENTATION_PORTRAIT = 0; public static final int ORIENTATION_LANDSCAPE = 1; /** * Determines the orientation of the image based on its ratio. * * @param file the file handle of the image * @return The image orientation, either ORIENTATION_PORTRAIT or ORIENTATION_LANDSCAPE. * @throws IOException if the file couldn't be processed */ public static int determineOrientation(File file) throws IOException { InputStream input = null; try { input = new FileInputStream(file); return determineOrientation(input); } finally { if (input != null) { input.close(); } } } /** * Determines the orientation of the image based on its ratio. * * @param context the context to use * @param uri the URI of the image * @return The image orientation, either ORIENTATION_PORTRAIT or ORIENTATION_LANDSCAPE. * @throws IOException if the URI couldn't be processed */ public static int determineOrientation(Context context, Uri uri) throws IOException { InputStream input = null; try { input = context.getContentResolver().openInputStream(uri); return determineOrientation(input); } finally { if (input != null) { input.close(); } } } /** * Determines the orientation of the image based on its ratio. * * @param input the input stream of the image * @return The image orientation, either ORIENTATION_PORTRAIT or ORIENTATION_LANDSCAPE. */ public static int determineOrientation(InputStream input) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(input, null, options); if (options.outWidth == -1 || options.outHeight == -1) { return ORIENTATION_PORTRAIT; } // Choose orientation based on image ratio. float ratio = ((float) options.outWidth) / ((float) options.outHeight); return ratio > 1 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT; } /** * Decodes the image as a bitmap with a size as small as possible but with a minimum size of given reqWidth * and reqHeight. * * Based on: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html * * @param file the file handle of the image * @param reqWidth required width * @param reqHeight required height * @return decoded the decoded bitmap * @throws IOException if the URI couldn't be processed */ public static Bitmap decodeSampledBitmap(File file, int reqWidth, int reqHeight) throws IOException { // First decode with inJustDecodeBounds=true to check dimensions BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(file.getAbsolutePath(), options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options); return bitmap; } /** * Decodes the image as a bitmap with a size as small as possible but with a minimum size of given reqWidth * and reqHeight. * * Based on: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html * * @param context the context to use * @param imageUri the URI of the image * @param reqWidth required width * @param reqHeight required height * @return decoded the decoded bitmap * @throws IOException if the URI couldn't be processed */ public static Bitmap decodeSampledBitmap(Context context, Uri imageUri, int reqWidth, int reqHeight) throws IOException { // First decode with inJustDecodeBounds=true to check dimensions BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; InputStream inputBounds = context.getContentResolver().openInputStream(imageUri); BitmapFactory.decodeStream(inputBounds, null, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; InputStream inputBitmap = context.getContentResolver().openInputStream(imageUri); Bitmap bitmap = BitmapFactory.decodeStream(inputBitmap, null, options); return bitmap; } /** * Calculates the scale factor to scale down the image as much as possible while preserving a minimum size * defined by the given reqWidth and reqHeight. * * See: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html * * @param options options that describe the image * @param reqWidth required height * @param reqHeight required width * @return the scale factor */ private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; } }