最近一款软件需要保存图像时,不能有一丝一毫的失真,而且只限于本APP中打开。因此Bitmap.compress这种API是肯定不能用了。而网上的Android开发资料在保存Bitmap的时候都是用这个API的,千篇一律,没啥好借鉴的。所以我直接凭我的认知,写了几句代码实现了这个功能。
首先已知,安卓的Bitmap类提供了copyPixelsFromBuffer和copyPixelsToBuffer两个方法,意义分别是“从Buffer中复制像素到Bitmap”和“从Bitmap中复制像素到Buffer”,那么问题就很好搞了:
一、保存图片
1、先分析对象Bitmap使用的是何种像素编码格式,我使用的是固定4个字节的ARGB8888,所以先建立字节数组:
byte pixels[] = new byte[bitmap.getWidth() * bitmap.getHeight() * 4];
2、使用ByteBuffer.wrap包装该数组为一个Buffer,并且调用copyPixelsToBuffer复制所有像素到数组中
bitmap.copyPixelsToBuffer(ByteBuffer.wrap(pixels));
3、使用FileOutputStream输出整个数组:
File bmpfile = new File(filePath);
if (bmpfile.exists()) {
bmpfile.delete();
bmpfile.createNewFile();
}
FileOutputStream fos = new FileOutputStream(bmpfile);
fos.write(pixels);
fos.close();
这样即把所有像素保存好了。
完整代码如下:
//获取所有像素并保存
byte pixels[] = new byte[bitmap.getWidth() * bitmap.getHeight() * 4];
bitmap.copyPixelsToBuffer(ByteBuffer.wrap(pixels));
String filePath = "/mnt/shell/emulated/0/whiteboard/cache/pixelsRaw.dat";
File bmpfile = new File(filePath);
if (bmpfile.exists()) {
bmpfile.delete();
bmpfile.createNewFile();
}
FileOutputStream fos = new FileOutputStream(bmpfile);
fos.write(pixels);
fos.close();
二、读取图片
读取图片的过程其实就是保存图片的反向过程,就是用File.available方法了解这个文件还有多少字节需要读取,然后直接创建字节数组读取完所有这些字节,再使用ByteBuffer包装,并调用Bitmap.copyPixelsFromBuffer复制像素到Bitmap即可,唯一要注意的就是创建位图的时候,宽高要和保存的Bitmap一致,所以直接上源代码:
Bitmap bitmap = Bitmap.createBitmap(1920, 1080, Bitmap.Config.ARGB_8888);
File pixelDataFile = new File();
FileInputStream fileInputStream = new FileInputStream(pixelDataFile);
byte data[] = new byte[fileInputStream.available()];
fileInputStream.read(data);
ByteBuffer byteBuffer = ByteBuffer.wrap(data);
bitmap.copyPixelsFromBuffer(byteBuffer);
三、可能的扩展:
可能可以使用libJpeg达成同样的功能,直接保存成真正的Bmp文件。但是,也可以直接在保存图片的时候,在文件头写入符合BMP协议的格式描述,也可以形成真正的BMP文件,具体可以参考这篇文章: