在 Android 中创建和保存单色 PNG 位图时减少内存使用
Reducing memory usage while creating and saving a single color PNG bitmap in Android
我需要创建并保存单色 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 的内存似乎太过分了。
有没有更好的方法?
您只用一种颜色填充位图。
为什么不直接将颜色存储在 SharedPreferences 中?
效率会高很多
不过,您可以只为视图设置颜色背景。
其他选项是创建具有必要颜色的 1x1 像素大小的位图,并将其设置为背景。它将成为视图的大小。
P.S.
ALPHA_8 不存储颜色,只存储 alpha。完全错误,查看文档
您可以使用 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();
}
It seems so overkill to allocate almost 6 MB of memory for a file that will only have 8 KB.
这里有两个不同的东西。首先,为了在内存中分配完整图像而浪费了 space - 我的解决方案通过分配一行来缓解这一点。但是,除此之外,您犯了一个概念错误:将内存中分配的 space 与编码图像大小进行比较是没有意义的,因为 PNG 是一种压缩格式(并且单个彩色图像将被高度压缩).任何原始可编辑位图(Android中的Bitmap
、ImageIO中的BufferedImage
、PNGJ中我自己的ImageLineByte
等)分配的内存实际上永远不会被压缩,并且因此它总是会浪费每个像素 4 个字节 - 至少。你可以检查:1200x1200x4=5760000。
我需要创建并保存单色 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 的内存似乎太过分了。
有没有更好的方法?
您只用一种颜色填充位图。 为什么不直接将颜色存储在 SharedPreferences 中?
效率会高很多
不过,您可以只为视图设置颜色背景。
其他选项是创建具有必要颜色的 1x1 像素大小的位图,并将其设置为背景。它将成为视图的大小。
P.S.
ALPHA_8 不存储颜色,只存储 alpha。完全错误,查看文档
您可以使用 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();
}
It seems so overkill to allocate almost 6 MB of memory for a file that will only have 8 KB.
这里有两个不同的东西。首先,为了在内存中分配完整图像而浪费了 space - 我的解决方案通过分配一行来缓解这一点。但是,除此之外,您犯了一个概念错误:将内存中分配的 space 与编码图像大小进行比较是没有意义的,因为 PNG 是一种压缩格式(并且单个彩色图像将被高度压缩).任何原始可编辑位图(Android中的Bitmap
、ImageIO中的BufferedImage
、PNGJ中我自己的ImageLineByte
等)分配的内存实际上永远不会被压缩,并且因此它总是会浪费每个像素 4 个字节 - 至少。你可以检查:1200x1200x4=5760000。