问题
public static boolean rotateBitmapByExifAndSave(File targetFile){
if (targetFile==null || !targetFile.exists() || !targetFile.canRead() || !targetFile.canWrite())
return false;
boolean isSucceed = false;
// detect if photo is need to be rotated
try {
final Matrix matrix = new Matrix();
ExifInterface exifReader = new ExifInterface(targetFile.getAbsolutePath());
int orientation = exifReader.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
boolean isRotationNeeded = true;
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.postRotate(90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.postRotate(180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.postRotate(270);
break;
default: // ExifInterface.ORIENTATION_NORMAL
// Do nothing. The original image is fine.
isRotationNeeded = false;
isSucceed = true;
break;
}
if (isRotationNeeded){
BitmapFactory.Options bmfOtions = new BitmapFactory.Options();
Bitmap bitmap = null;
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(targetFile);
bitmap = BitmapFactory.decodeStream(fileInputStream,null,bmfOtions);
} catch (FileNotFoundException e){
isSucceed = false;
}
finally {
if (fileInputStream != null)
try {
fileInputStream.close();
} catch (IOException e) {}
}
if (bitmap!=null){
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
isSucceed = ImageUtils.saveBitmapToFile(bitmap, targetFile, 100);
bitmap.recycle();
}
}
} catch (IOException e) {
Log.e("ImageUtils", e);
} catch (Exception e) {
// like there is no EXIF support?
Log.e("ImageUtils", e);
} catch (Throwable e) {
// stupid Out of VM's memory
Log.e("ImageUtils", e.toString());
}
return isSucceed;
}
I use this method to rotate original photos made by device's camera. Nowadays camera could be bigger than 8MPix (Samsung Galaxy S4 has 13 Mega pixel camera). And even with less MPix camera (mine is 5 MP, 2592 x 1944 pixels which in conjunction of ARGB_888 takes 19Mb of RAM according to official docs) I already got OutOfMemory. So the question is how to rotate the photo WITHOUT loss of it's initial resolution and thus quality?
回答1:
Since there was no answer I assume there is no answer or maybe I just had asked the question a bit incorrectly. It looks like the only option here is to increase the app's heap size
UPDATE:
There is also another option - to work with bitmaps via NDK/JNI like here or to use Android Image-Magic lib. The Image Magic lib is pretty cool, to rotate an image all you need is:
ImageInfo imageInfo = new ImageInfo(imageFile.getAbsolutePath());
MagickImage magickImage = new MagickImage(imageInfo);
magickImage.setCompression(100); // to minimize loss
magickImage.rotateImage(90.0f).writeImage(imageInfo);
MagickImage has many other image manipulating options as well. Blur, matte, scale, charcoal and many more. However its libraries size is noticable. Authors made a great job and they covered all possible plaforms: arm64-v8a, armeabi, armeabi-v7a, mips, mips64, x86, x86_64 and final size of all these libs is over 36Mb. So you should think before adding all the libs into one apk, maybe packaging 6 different versions using manifest to filter by chipset/platform is the right way.
UPDATE
Another option is to convert Immutable Bitmap into Mutable (wrap bitmaps into MappedByteBuffer)
回答2:
Make a method name decode file:
public static Bitmap decodeFile(File f,int WIDTH,int HIGHT){
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_WIDTH=WIDTH;
final int REQUIRED_HIGHT=HIGHT;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HIGHT)
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;
}
then call this method like this (You can call this method in button click listener)
Bitmap bi = decodeFile(new File(path),1280,800);
Where path is the path of image where you save your image.. in my case it is
String path = Environment.getExternalStorageDirectory().toString() + "/nature.jpg";
In case of any problem - ask :) Hope this helps.
来源:https://stackoverflow.com/questions/17641135/how-to-avoid-outofmemory-ex-while-rotating-the-image