【问题标题】:Reducing memory usage while creating and saving a single color PNG bitmap in Android在 Android 中创建和保存单色 PNG 位图时减少内存使用
【发布时间】:2016-08-25 08:12:01
【问题描述】:

我需要创建和保存单色 PNG 图像(用单色填充的位图)。

我正在创建位图:

public static Bitmap createColorSwatchBitmap(int width, int height, int color) {
    final Bitmap colorBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    colorBitmap.eraseColor(color);
    return colorBitmap;
}

并将其保存到设备存储上的文件中:

stream = new FileOutputStream(filePath);
success = bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);

如果我创建一个 1200x1200 位图,则内存消耗为 5,760,000 字节 (5.76 MB),由 bitmap.getAllocationByteCount() 报告。但是 PNG 文件大小只有 8,493 字节。

为一个只有 8 KB 的文件分配将近 6 MB 的内存似乎太过分了。

还有更好的方法吗?

【问题讨论】:

  • 为什么?几乎可以肯定,使用 ColorDrawable 会更好。
  • @GabeSechan 你可以直接将 ColorDrawable 写入 PNG 文件,而不在内存中分配位图吗?

标签: android memory bitmap png


【解决方案1】:

您可以使用PNGJ 库(免责声明:我是作者)。因为是逐步保存图片,所以只需要分配一行。

例如:

 public static void create(OutputStream os,int cols,int rows,int r,int  g,int  b,int  a)  {     
        ImageInfo imi = new ImageInfo(cols, rows, 8, true); // 8 bits per channel, alpha
        PngWriter png = new PngWriter(os, imi);
        // just a hint to the coder to optimize compression+speed:
        png.setFilterType(FilterType.FILTER_NONE); 
        ImageLineByte iline = new ImageLineByte (imi);
        byte[] scanline = iline.getScanlineByte();// RGBA
        for (int col = 0,pos=0; col < imi.cols; col++) { 
           scanline[pos++]=(byte) r;  
           scanline[pos++]=(byte) g;
           scanline[pos++]=(byte) b;
           scanline[pos++]=(byte) a;
        }
        for (int row = 0; row < png.imgInfo.rows; row++) {
           png.writeRow(iline);
        }
        png.end();   
 }

为一个只有 8 KB 的文件分配将近 6 MB 的内存似乎太过分了。

这里有两种不同的东西。首先,为了在内存中分配完整图像而浪费了空间——我的解决方案通过分配单行来缓解这种情况。但是,除此之外,您还犯了一个概念性错误:将内存中分配的空间与编码图像大小进行比较是没有意义的,因为 PNG 是一种压缩格式(单色图像将被高度压缩)。任何原始可编辑位图(Android 中的Bitmap、ImageIO 中的BufferedImage、PNGJ 中我自己的ImageLineByte 或其他)分配的内存在实践中永远不会被压缩,因此它总是会浪费每个像素 4 个字节 -至少。你可以检查一下:1200x1200x4=5760000。

【讨论】:

    【解决方案2】:

    您只需用一种颜色填充位图。 为什么不将颜色存储在SharedPreferences 中?

    这样会更有效率。

    不过,您可以只为视图设置颜色背景。

    其他选项是使用必要的颜色创建大小为 1x1 像素的位图,并将其设置为背景。它会变成 View 的大小。

    附言

    ALPHA_8 不存储颜色,只存储 alpha。完全错误,检查文档

    【讨论】:

    • 你读过这个问题吗?我需要在设备存储中将这些位图写入并保存为 PNG 文件。我不想将它们设置为视图的背景。 (虽然感谢您提供 ALPHA_8 提示,但我没有对文档给予足够的关注。)
    • 如果您的颜色不使用 alpha - 然后使用 RGB_565 配置。虽然,在存储位图之后 - 它需要 recycle()-d
    猜你喜欢
    • 2017-01-25
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多