android - 旋转图像时如何避免 OutOfMemory ex?

标签 android image memory memory-management out-of-memory

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(三星 Galaxy S4 有 13 兆像素摄像头)。即使使用更少的 MPix 摄像头(我的是 5 MP,2592 x 1944 像素,根据官方文档,它与 ARGB_888 一起占用 19Mb 的 RAM)我已经得到了 OutOfMemory。所以问题是如何在不损失初始分辨率和质量的情况下旋转照片?

最佳答案

由于没有答案,我假设没有答案,或者我只是问错了问题。看起来这里唯一的选择是to increase the app's heap size
更新:
还有另一种选择 - 通过 NDK/JNI 处理位图,如 here或使用 Android Image-Magic lib . Image Magic 库非常酷,旋转图像只需:

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,所有这些库的最终大小超过 36Mb。所以你应该在将所有的库添加到一个apk之前考虑一下,也许使用manifest打包6个不同的版本来按芯片组/平台过滤是正确的方法。
更新
另一种选择是 convert Immutable Bitmap into Mutable (wrap bitmaps into MappedByteBuffer)

关于android - 旋转图像时如何避免 OutOfMemory ex?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17641135/

相关文章:

javascript - 灯箱将图像移动到右下角

Java:这个进程分配了多少内存?

java - 当我尝试从数据库中删除数据并刷新 ListView 时,应用程序崩溃了

Android EditText 背景,里面有线

javascript - 关于如何使用 Phonegap 在 Android 应用程序中捕获屏幕的建议?

c# - 启动隐藏的 Windows 窗体应用程序 - 高内存使用率?

iphone - 我释放了所有的内存,但我的程序需要更多,我该怎么办?

android - 如何使用 MediaSession.setMediaButtonReceiver(PendingIntent) 恢复播放

java - 如何将图像添加到 JFrame?

android - NV21 格式和奇数图像尺寸