【问题标题】:Bitmap resizing causes out of memory位图调整大小导致内存不足
【发布时间】:2015-08-28 11:04:45
【问题描述】:

我有一个简单的类,用于根据我的要求调整位图图像的大小。有一个简单的方法负责它:

public static Bitmap ResizeRichImages(Bitmap bitmap, Context mContext){
        try {
        float originalBitmapWidth = bitmap.getWidth();
        float originalBitmapHeight = bitmap.getHeight();
        float originalAspectRatio = originalBitmapWidth/originalBitmapHeight;
        double width_percentage = (0.05*screenWidthPixels(mContext));
        float newWidth = (float)((int)screenWidthPixels(mContext)-width_percentage);
        float newBitmapWidth = newWidth;
        float newBitmapHeight = newBitmapWidth/originalAspectRatio;
        bitmap = Bitmap.createScaledBitmap(bitmap, (int) newWidth, (int)newBitmapHeight, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;

    }

我就是这样称呼这个方法的:

String URL = "https://maps.googleapis.com/maps/api/staticmap?center=-33.86527274921529,151.2050531328867&zoom=15&size=640x360&sensor=false&markers=color:blue%7Clabel:!%7C-33.86527274921529,151.2050531328867";

try {
bmp = Picasso.with(ViewStory.this).load(URL)
                                                            .get();
bmp = ImageController.ResizeRichImages(bmp, ViewStory.this);
                                                } catch (Exception e) {
                                                    e.printStackTrace();
                                                }

但是,几乎每次我在调用 ResizeRichImages 方法时都会遇到内存不足异常。我哪里错了?

【问题讨论】:

标签: java android bitmap out-of-memory


【解决方案1】:
  • 您可以尝试像下面的代码 sn-p 一样压缩,而不是在清单中使用 largeHeap 选项(应该始终是最后一个选项)。

*

byteArrImage = null;

ByteArrayOutputStream baos = new ByteArrayOutputStream();
if(data != null) thumbnail = (Bitmap) data.getExtras().get("data");
if(thumbnail != null) {
    //thumbnail.compress(Bitmap.CompressFormat.PNG, 85, baos);
    thumbnail.compress(Bitmap.CompressFormat.JPEG, 85, baos);
    byteArrImage = baos.toByteArray();
    uploadImageToServer();
}

【讨论】:

    【解决方案2】:

    我之前也遇到过同样的错误,但经过一番搜索后,我找到了另一种调整大位图图像大小的方法。当您使用带有大图像的位图时,您必须使用 BitmapFactory.Options.inSampleSize 缩放图像。样本大小是对应于解码位图中的单个像素的任一维度中的像素数。当您使用 inSampleSize = 4 时,它会返回一个为原始宽度/高度 1/4 的图像。您还可以在 android 开发者网站中查看更多详细信息。

    使用此方法调整大小

    private Bitmap decodeFileWithSmallSize(String sdcard_path) {
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    Bitmap myBitmap = BitmapFactory.decodeFile(sdcard_path, options);
    return myBitmap;
    }
    

    在活动中使用

    try {
        Bitmap bitmap = null;
        if (bitmap != null) {
            bitmap.recycle();
            bitmap = null;
        }
        bitmap = decodeFileWithSmallSize("path");
    } 
    catch (OutOfMemoryError e)
    {
        Log.e("TAG",
                "OutOfMemoryError Exception" + e.getMessage());
    }
    

    【讨论】:

    • 你知道他已经有了毕加索的位图吗?这个答案如何适用于他的问题?或者它是您对所有 OOME 问题的通用答案?
    【解决方案3】:

    通常在处理位图时,我们需要根据我们所需的宽度和高度,通过减少位图的样本大小来减少内存大小。

    如果您想传递位图并根据您的要求更改位图文件路径,此函数采用位图文件路径。但这是有效加载图像的正确方法。

     public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {
    
    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);
    
    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
    }
    

    此函数计算所需图像的样本大小以减少内存..

    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) {
    
        final int halfHeight = height / 2;
        final int halfWidth = width / 2;
    
        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }
    
    return inSampleSize;
    }
    

    欲了解更多信息,请参阅此链接:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

    在您的情况下,如果您的目标最低级别为 19,那么请使用 API 级别 19 上可用的 重新配置功能 visit developers site

    【讨论】:

    • 你知道他已经有了毕加索的位图吗?这个答案如何适用于他的问题?或者它是您对所有 OOME 问题的通用答案?
    • @Selvin 你能清楚地看到这个问题吗?他得到了一个位图(代码名为 bmp),在尝试调整它的大小时出错了。
    • @Selvin 在调用 ResizeRichImages 函数之前他没有任何问题
    • 您是否了解您的代码... 他已解码位图 ...您的代码将(最终)在尚未解码的情况下工作...它检查原始大小没有解码的图像,然后解码较小的位图 ...
    【解决方案4】:

    您还没有告诉我们您的位图有多大。也许它只是用尽了你所有的可用内存,尤其是当你有其他大的位图(或其他东西)占用了大部分内存时。

    我会尝试在一个小位图上运行该过程,并将 newBitmapWidth 和 newBitmapHeight 减少到现在的十分之一。如果这消除了异常,则很确定您需要优化内存使用,然后才能处理完整大小。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 2011-07-16
    • 1970-01-01
    • 2020-12-29
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    相关资源
    最近更新 更多