裁剪图像没有OutOfMemory - Android

时间:2015-12-27 11:58:31

标签: android image crop

我想裁剪图片而不会收到OutOfMemory例外 它意味着我有裁剪图像的x,y,宽度和高度,并希望裁剪原始图像而不将其带入记忆 是的,我知道BitmapRegionDecoder是个好主意,但裁剪的图像可能太大而无法将其记忆。

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


编辑:我想保存裁剪的图片,而不只是在ImageView中显示 我想将其保存在新文件中而不会丢失尺寸

这是一个例子
enter image description here

在这种情况下裁剪的图像分辨率是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部分图像保存在文件中?

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

您可以使用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的像素数。处理任何值< = 1   注意:解码器使用基于2的幂的最终值,   任何其他值将向下舍入到最接近的2的幂。

现在它不是一个完美的解决方案,但你可以做数学找出你可以在options.inSampleSize上使用的最接近2的因子来节省内存。

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

答案 2 :(得分:1)

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

正如您所看到的,该区域的许多答案都指向了位图压缩的一般概念,这些概念确实适用于大多数问题,但不是特别适用于您的问题。

答案中建议的BitmapRegionDecoder也不会很好用。它确实可以防止在RAM中加载整个位图但是裁剪后的图像呢?裁剪图像后,它会为您提供一个巨大的位图,无论如何,都会给您一个OOM。

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

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

然而,如果你不关心裁剪图像的质量,那么通过缩放来解决这个问题并不比用户在裁剪时所看到的质量要好。这就是Google相机所做的,它只是降低了裁剪图像的质量,非常简单!

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

您可以查看带有图像裁剪设施的开源实施的Telegram消息传递应用程序;你猜对了,它处理所有类似的讨厌的工作与旧C ...因此,我们可能得出结论,一个良好的全球解决方案(或更好的说,一个几个适用的解决方案)似乎是处理磁盘的低级编程并记住你自己。

我知道我的答案没有给你的问题任何复制粘贴解决方案,但至少我希望它能给你一些想法我的朋友。

答案 3 :(得分:0)

BitmapRegionDecoder是裁剪大图像或大图像的好方法,但它可以从API 10及更高版本获得。

有一个名为BitmapRegionDecoder的类可能对您有所帮助,但它可以从API 10及更高版本获得。

如果你不能使用它:

许多图像格式都是压缩的,因此需要加载到内存中。

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

更简单的任务就是在JNI中完成所有操作,这样即使你会使用大量内存,至少你的应用程序也不会很快进入OOM,因为它不会被限制在最大值普通应用程序强加的堆大小。

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

参考: Crop image without loading into memory

或者你可以在下面找到一些可能对你有帮助的方法:

Bitmap/Canvas use and the NDK