How to avoid OutOfMemory ex during image rotation?

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 memory Log.e("ImageUtils", e.toString()); } return isSucceed; } 

I use this method to rotate the original photos taken by the deviceโ€™s camera. Currently, the camera may be larger than 8MPix (Samsung Galaxy S4 has a 13 megapixel camera). And even with a smaller MPix camera (my 5 MP , 2592 x 1944 pixels, which in combination with ARGB_888 takes up 19 MB of RAM according to official documents), I already got OutOfMemory. So the question is how to rotate a photo without losing its original resolution and thus quality?

+6
source share
2 answers

Since there was no answer, I believe there is no answer, or maybe I just asked the question a little wrong. It seems like the only option here is to increase the application heap size
UPDATE:
There is another option - work with raster images via NDK / JNI, for example here or use the Android Image-Magic lib . The Magic Magic library is pretty cool to rotate the image 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 management features. Blur, matte, scale, charcoal and many others. However, the size of their libraries is noteworthy. The authors did a great job and they covered all possible formats: arm64-v8a, armeabi, armeabi-v7a, mips, mips64, x86, x86_64 and the final size of all these libs is more than 36 Mb. Therefore, you should think before adding all the libraries to one apk, maybe packing 6 different versions using the manifest to filter by chipset / platform is the right way.
UPDATE
Another option is to convert the immutable bitmap to Mutable (crop bitmaps in MappedByteBuffer)

+2
source

Create a decoding file for the method name:

 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 as follows (you can call this method in the button listener)

 Bitmap bi = decodeFile(new File(path),1280,800); 

Where is the path - the path to the image, where you save your image. in my case it is

 String path = Environment.getExternalStorageDirectory().toString() + "/nature.jpg"; 

In case of any problems - ask :) I hope this helps.

-1
source

Source: https://habr.com/ru/post/949416/


All Articles