BitmapFactory.decodeFile在处理2400x2400像素的图片时出现内存不足的问题

16

我需要将一个文件中的图像发送到服务器。服务器请求以2400x2400的分辨率获取图像。

我尝试的步骤如下:

1)使用正确的inSampleSize使用BitmapFactory.decodeFile获取位图。

2)使用JPEG以40%的质量压缩图像

3)将图像编码为base64

4)发送到服务器

我无法完成第一步,它会抛出内存不足异常。 我确定inSampleSize是正确的,但即使使用inSampleSize,位图仍然很大(在DDMS中约为30 MB)。

有任何想法可以解决这个问题吗? 我是否可以在未创建位图对象的情况下执行这些步骤?我的意思是在文件系统而不是RAM内存中执行它。

以下是当前代码:

// The following function calculate the correct inSampleSize
Bitmap image = Util.decodeSampledBitmapFromFile(imagePath, width,height);   
// compressing the image
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 40, baos);
// encode image
String encodedImage = Base64.encodeToString(baos.toByteArray(),Base64.DEFAULT));


public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}

public static Bitmap decodeSampledBitmapFromFile(String path,int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(path,options);
}

通过阅读这篇文章,您将会对如何管理内存有一些了解。http://developer.android.com/training/displaying-bitmaps/manage-memory.html - Shakeeb Ayaz
getBitmap().recycle(); - Shakeeb Ayaz
你有图像文件,对吧?只需将此文件发送到服务器并在那里进行必要的转换即可。 - Henry
我无法将12MB的数据发送到服务器,调整大小和压缩图像可以显著减小文件大小,少于1MB。 - alasarr
3个回答

52

您可以跳过使用ARGB_8888,而改用RGB_565,然后对图像进行抖动以保持良好的质量。

 BitmapFactory.Options options = new BitmapFactory.Options();
 options.inJustDecodeBounds = false;
 options.inPreferredConfig = Config.RGB_565;
 options.inDither = true;

它成功地减小了位图的大小13 MB。非常感谢! - alasarr

1
你需要使用 BitmapFactory.Options,并将 inJustDecodeBounds 设置为 true。这样可以加载有关位图的信息,并计算缩小它的值(例如 inSampleSize)。

我想看一下。你能否在帖子中更新一下代码片段? - Blackbelt

1
不要将图像作为位图加载,将其转换为数组,然后发送。
相反:
以JPG格式读取文件。使用文件的字节数组对其进行编码,并将文件发送过去。
将其加载到位图中会导致不必要的巨大内存问题。以位图格式表示的图像将占用约20倍或更多的内存。
在服务器端,您也需要将其视为文件,而不是位图。
这里有一个链接可以将文件加载到byte[]中:Elegant way to read file into byte[] array in Java

我需要一个位图,因为我需要调整它的大小并压缩它。原始图像大小为12MB,我希望将其发送到服务器的大小约为700KB,而不是原始图像的12MB。 - alasarr
@alasarr 啊,我的错误。你可能没有正确地对其进行采样。请参见http://developer.android.com/training/displaying-bitmaps/load-bitmap.html。 - IAmGroot
@alasarr 请注意。一张位图格式的2400x2400像素,每个像素使用2个字节,大小为11MB。即使是700KB的jpg格式也无济于事。或者以4个字节表示为22MB - IAmGroot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接