【问题标题】:Crop image without OutOfMemory - Android没有 OutOfMemory 的裁剪图像 - Android
【发布时间】:2016-04-01 12:21:35
【问题描述】:

我想裁剪图像而不收到OutOfMemory 异常。
这意味着我有裁剪图像的 x、y、宽度和高度,并且想要裁剪原始图像而不将其带入内存。
是的,我知道BitmapRegionDecoder 是个好主意,但裁剪后的图像可能太大而无法记忆。

事实上,我不想剪裁位图,只想将剪裁后的图像从源文件写入目标文件。


编辑:我想 保存 裁剪的图像,而不仅仅是在 ImageView 中显示它 我想将它保存在一个新文件中不丢失尺寸

这是一个例子

在这种情况下,裁剪后的图像分辨率为 20000x20000,下面的代码将无法正常工作,导致 OOM:

BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(width / 2 - 100, height / 2 - 100, width / 2 + 100, height / 2 + 100), options);
mImageView.setImageBitmap(bitmap);

使用 inSampleSize 减小原始图片大小很好,但我保存的结果不再是 20000x20000。

如何裁剪 25000x25000 并将图像的 20000x20000 部分保存在文件中?

【问题讨论】:

  • 为什么要投反对票?分享你的知识
  • Stack Overflow 用于编程问题。你的问题是什么?如果您的问题是“我该怎么做?”,请说明您尝试过的方法以及遇到的具体问题。
  • 是的!我的问题是我如何在android中做到这一点?我已经在 StackOverflow 中尝试了有关相关问题的所有答案,每个答案都取决于 Bitmap 对象,这是 OOM 的风险。我不知道我的问题的哪一部分含糊不清@CommonsWare
  • 你能过去一些代码吗?您是否使用 backtask 来执行此操作?你用的是什么设备?
  • 我认为根据需要调整大图像的大小真的很棘手。请注意,android 是用于内存有限的小型设备的系统。即使您将使用 RGB_565,25000x25000 图像的大小在 RAM 中也将超过 1.1GB。因此,我所能建议的只是尝试查看一些流 Java 库,这些库可能会调整图像的大小,而无需“即时”将其加载到内存中。或者尝试查看 NDK、RenderScript 或 OpenGL。

标签: android image crop


【解决方案1】:

您检查过 BitmapRegionDecoder 吗?它将从原始图像中提取一个矩形。

BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(width / 2 - 100, height / 2 - 100, width / 2 + 100, height / 2 + 100), options);
mImageView.setImageBitmap(bitmap);

http://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html

【讨论】:

  • 问题是矩形可能太大,这条线可能会抛出OOM Bitmap bitmap = bitmapRegionDecoder.decodeRegion(...
【解决方案2】:

您可以使用BitmapFactory 解决此问题。要确定原始位图大小而不将其放入内存,请执行以下操作:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(..., options);

int originalImageWith = options.outWidth;
int originalImageHeight = options.outHeight;

现在你可以使用options.inSampleSize

如果设置的值 > 1,则请求解码器 对原始图像进行二次采样,返回要保存的较小图像 记忆。样本大小是任一维度的像素数 对应于解码位图中的单个像素。例如, inSampleSize == 4 返回的图像是宽度/高度的 1/4 原始,和 1/16 的像素数。任何值

现在这不是一个完美的解决方案,但您可以通过数学计算找到最接近 2 的因子,您可以在 options.inSampleSize 上使用它来节省内存。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
Bitmap bitmap = BitmapFactory.decodeResource(..., options);

【讨论】:

  • 不,伙计,我的观点完全是另一回事。我会更新我的问题
  • @SepehrBehroozi 不更新问题,而是提出一个新问题。我已经按原样回答了当前的问题。
  • 尊敬的你没有:) 我想将裁剪后的图像保存在一个文件中,而不仅仅是显示它。使用inSampleSize 有利于查看图像,但保存它会导致尺寸丢失
【解决方案3】:

BitmapRegionDecoder 是裁剪大图像或大图像的好方法,但它适用于 API 10 及更高版本。

有一个名为 BitmapRegionDecoder 的类可能会对您有所帮助,但它在 API 10 及更高版本中可用。

如果你不能使用它:

许多图像格式都经过压缩,因此需要某种形式的加载到内存中。

您需要阅读适合您需要的最佳图像格式,然后自己阅读,仅使用您需要的内存。

一个更简单的任务是在 JNI 中完成这一切,这样即使您将使用大量内存,至少您的应用不会这么快进入 OOM,因为它不会被限制在最大值强加于普通应用的堆大小。

当然,由于android是开源的,你可以尝试使用BitmapRegionDecoder并将其用于任何设备。

参考: Crop image without loading into memory

或者您可以在下面找到其他可能对您有帮助的方法:

Bitmap/Canvas use and the NDK

【讨论】:

    【解决方案4】:

    简单地说,它需要大量的低级编程和优化。

    如您所见,该地区的许多答案都指向位图压缩等通用概念,这些概念确实适用于大多数问题,但不适用于您的问题。

    答案中建议的 BitmapRegionDecoder 也不能正常工作。它确实可以防止将整个位图加载到 RAM 中,但是裁剪后的图像呢?裁剪图像后,它会给你一个巨大的位图,无论如何,都会给你一个 OOM。

    因为您所描述的问题,需要位图来写入或从磁盘读取,就像它们从内存中写入或读取一样;一种称为 BufferedBitmap(或其他)的东西,它通过将位图的小块保存到磁盘并稍后使用它们来有效地处理所需的内存,从而避免 OOM。

    任何其他想要解决缩放问题的解决方案只能完成一半的工作。为什么?因为裁剪后的图像本身可能对内存来说太大了(如你所说)。

    但是,如果您不关心裁剪图像的质量与用户在裁剪图像时看到的质量相比,通过缩放来解决问题并没有那么糟糕。这就是谷歌照片所做的,它只是降低了裁剪图像的质量,非常简单!

    我还没有看到任何 BufferedBitmap 类(但如果有的话,那就太棒了)。它们对于解决类似的问题肯定会很方便。

    您可以查看 Telegram 消息应用程序,该应用程序带有图像裁剪工具的开源实现;你猜对了,它可以处理所有与旧 C 语言类似的令人讨厌的工作......因此,我们可能会得出结论,一个好的全局解决方案(或者更好地说,几个适用的解决方案之一)似乎是处理磁盘的低级编程和自己的记忆。

    我知道我的回答未能为您的问题提供任何复制粘贴式的解决方案,但至少我希望它给您一些想法,我的朋友。

    【讨论】:

    • 是的,你说得对。我测试了几个图片编辑工具,你猜怎么着?没有什么能给我想要的结果。
    猜你喜欢
    • 1970-01-01
    • 2016-08-28
    • 2015-02-02
    • 1970-01-01
    • 2018-09-20
    • 2011-11-15
    • 1970-01-01
    • 1970-01-01
    • 2016-05-04
    相关资源
    最近更新 更多