My Problem
I take a picture with my android device. I then decode that picture from file.
Bitmap photo = BitmapFactory.deco
Here is a more complete example of how to resize/rotate, taken in part from the Android Developers guide (change REQ_WIDTH and REQ_HEIGHT):
private static final int REQ_WIDTH = 450;
private static final int REQ_HEIGHT = 450;
/**
* Resize, crop, rotate and Inserts the picture on the layout.
*
* @param mImageView to insert the bitmap.
* @param imageURI from wich to obtain the bitmap.
*
*/
private void setPic(ImageView mImageView, String imageURI) {
// Get the original bitmap dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageURI, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, REQ_HEIGHT, REQ_WIDTH);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(imageURI, options);
//need rotation?
float rotation = rotationForImage(getActivity(), Uri.fromFile(new File(imageURI)));
if (rotation != 0) {
//rotate
Matrix matrix = new Matrix();
matrix.preRotate(rotation);
mImageView.setImageBitmap(Bitmap.createBitmap(bitmap, 0, 0, REQ_HEIGHT, REQ_WIDTH, matrix, true));
} else {
//use the original
mImageView.setImageBitmap(BitmapFactory.decodeFile(imageURI, options));
}
}
public 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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
public static float rotationForImage(Context context, Uri uri) {
try {
if (uri.getScheme().equals("content")) {
String[] projection = { Images.ImageColumns.ORIENTATION };
Cursor c = context.getContentResolver().query(uri, projection, null, null, null);
if (c.moveToFirst()) {
return c.getInt(0);
}
} else if (uri.getScheme().equals("file")) {
ExifInterface exif = new ExifInterface(uri.getPath());
int rotation = (int) exifOrientationToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL));
return rotation;
}
return 0;
} catch (IOException e) {
Log.e(TAG, "Error checking exif", e);
return 0;
}
}
private static float exifOrientationToDegrees(int exifOrientation) {
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
return 90;
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
return 180;
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
return 270;
}
return 0;
}
For out of memory issue
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=70;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
scale*=2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
I had the exact same issue, doing the exact same thing on the exact same device! Unfortunately in my case the image needed to be submitted to a webservice, using the full size, original. What worked for me was turning on largeHeap in the application element of the manifest.
This will not solve the issue permanently - its possible that a device will come along with an even larger camera and the images will not fit in memory even with largeHeap enabled. To catch this extreme edge case I also put a try catch around the code that rotates the image, and just displayed a nice error to the user.
A fuller solution would be to write your own jpeg manipulation code that can rotate a jpeg using a stream based approach so that the image never needs to be loaded into memory.