Как избежать OutOfMemory ex во время поворота изображения?

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; } 

Я использую этот метод для поворота исходных фотографий, сделанных камерой устройства. В настоящее время камера может быть больше 8MPix (Samsung Galaxy S4 имеет 13 мегапиксельную камеру). И даже с меньшей камерой MPix (мой 5 МП , 2592 x 1944 пикселей, что в сочетании с ARGB_888 занимает 19 МБ ОЗУ в соответствии с официальными документами), я уже получил OutOfMemory. Итак, вопрос в том, как повернуть фотографию БЕЗ потери первоначального разрешения и, таким образом, качества?

    Поскольку ответа не было, я полагаю, что нет ответа или, может быть, я просто задал вопрос немного неправильно. Похоже, что единственный вариант – увеличить размер кучи приложения
    ОБНОВИТЬ:
    Существует еще один вариант – работать с растровыми изображениями через NDK / JNI, как здесь, или использовать Android Image-Magic lib . Image Magic lib довольно круто, чтобы повернуть изображение, в котором вы нуждаетесь:

     ImageInfo imageInfo = new ImageInfo(imageFile.getAbsolutePath()); MagickImage magickImage = new MagickImage(imageInfo); magickImage.setCompression(100); // to minimize loss magickImage.rotateImage(90.0f).writeImage(imageInfo); 

    В MagickImage есть много других возможностей манипулирования изображениями. Размытие, матовый, масштаб, древесный уголь и многие другие. Однако размер его библиотек примечателен. Авторы сделали отличную работу, и они охватили все возможные формы: arm64-v8a, armeabi, armeabi-v7a, mips, mips64, x86, x86_64 и конечный размер всех этих libs – более 36Mb. Поэтому вы должны подумать, прежде чем добавлять все библиотеки в один apk, возможно, упаковка 6 различных версий, использующих манифест для фильтрации по набору микросхем / платформы, является правильным способом.
    ОБНОВИТЬ
    Другим вариантом является преобразование Неизменяемого Bitmap в Mutable (свертывание битмапов в MappedByteBuffer)

    Создайте файл декодирования имени метода:

     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; } 

    Затем вызовите этот метод, как это (вы можете вызвать этот метод в нажатие кнопки clicker)

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

    Где путь – путь изображения, где вы сохраняете изображение. В моем случае это

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

    В случае каких-либо проблем – спросите 🙂 Надеюсь, это поможет.