安卓bitmap与字节数组关系深入研究应用
Posted 小源子2016
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓bitmap与字节数组关系深入研究应用相关的知识,希望对你有一定的参考价值。
在做一些安卓偏底层开发时候,不得不面对图像数据和字节数组转换工作,但是往往理解不深,产生比较多的疑惑,今天专门做了一些实验、越多一些资料汇总
研究一:理解-1是怎么转换为FF颜色值的
注意:负数在计算中以原码的补码形式表达,例如-1对应的二进制是11111111111111111111111111
①: byte color=-1,a的取值范围是-128~127
②: -1转换为二进制表示 String b = Integer.toBinaryString(color);输出111..111(32个)
③: 转换为16进制字符串表示(注意不应理解为16进制值,只是每个字节转换为16进制表达而已,FFFFFFFF 16进制值实际对应了一个非常大的正常,不要混淆) String b =Integer.toHexString(color);输FFFFFFFF,这是二进制的16进制表达形式,不要理解为16进值了
④:byte颜色值转换为16进制 Integer.toHexString(color & 0xff),与0xff,消除了前面的24位,这样
11111111就对应16进制的FF,10进制的255(-1对应了颜色值的FF,也就是255)
研究二:ARGB_8888、ARGB_4444、 RGB_565、 ALPHA_8概念理解
最后8888表示每个像素的单通道占用了8位,想必4444,占用的位数越多,表达的越清晰
研究三:ARGB_8888顺序(Google给安卓兄弟留的坑)
通过实践,我们可以得知,ARGB_8888 格式图片的各通道顺序其实不是 ARGB,而是 RGBA
public static Bitmap getBitmap()
String TAG = "TTTTTTTTTT";
Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
bitmap.eraseColor(0xff336699); // AARRGGBB
// byte[] bytes = new byte[bitmap.getWidth() * bitmap.getHeight() * 4];
// Buffer dst = ByteBuffer.wrap(bytes);
ByteBuffer buffer = ByteBuffer.allocate(bitmap.getWidth() * bitmap.getHeight() * 4); // 使用allocate()静态方法创建字节缓冲区
bitmap.copyPixelsToBuffer(buffer); // 将位图的像素复制到指定的缓冲区
byte[] bytes = buffer.array();
// ARGB_8888 真实的存储顺序是 R-G-B-A
Log.d(TAG, "R: " + Integer.toHexString(bytes[0] & 0xff));
Log.d(TAG, "G: " + Integer.toHexString(bytes[1] & 0xff));
Log.d(TAG, "B: " + Integer.toHexString(bytes[2] & 0xff));
Log.d(TAG, "A: " + Integer.toHexString(bytes[3] & 0xff));
return bitmap;
TTTTTTTTTT: R: 33
TTTTTTTTTT: G: 66
TTTTTTTTTT: B: 99
TTTTTTTTTT: A: ff
研究四:bitmap和字节的转换
A.主要看下ARGB_8888格式的bitmap转字节(平时这种格式差不多足够了)
// byte[] bytes = new byte[bitmap.getWidth() * bitmap.getHeight() * 4];
// Buffer dst = ByteBuffer.wrap(bytes);
ByteBuffer buffer = ByteBuffer.allocate(bitmap.getWidth() * bitmap.getHeight() * 4); // 使用allocate()静态方法创建字节缓冲区
bitmap.copyPixelsToBuffer(buffer); // 将位图的像素复制到指定的缓冲区
byte[] bytes = buffer.array();
a.对于ARGB_8888,应该申请的字节缓存区大小是ByteBuffer.allocate(w*h*4)
b.对于ARGB_4444,经过实验和阅读资料,可能默认被当作ARGB_8888处理了
c.RGB_565 w*h*2大小就足够了,但是怎么从字节数组中转换会16进色值未研究,因为R只占用5bit
经过实验,搞成w*h*3也是不行的,看样子可能需要解析5bit,6bit,5bit这样操作
B.字节转换为Bitmap
android bitmap与byte转换_wh8876的博客-CSDN博客_android bitmap转byte
注意:字节实际内容和ARGB_8888要一致
public static Bitmap createBitmapByByte()
String TAG = "TTTTTTTTTT";
Bitmap bitmap= Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
// 缓存区是R、G、B、A存储顺序
// 根据之前的研究 byte -1就是代表FF颜色,3代表03色值,
//这里存储的就是R=FF G=03 B=FF A=FF
bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(new byte[]-1, 3, -1, -1));
// 验证bitmap转换为字节,再转换为16进制颜色形式
ByteBuffer buffer = ByteBuffer.allocate(bitmap.getWidth() * bitmap.getHeight() * 4); // 使用allocate()静态方法创建字节缓冲区
bitmap.copyPixelsToBuffer(buffer); // 将位图的像素复制到指定的缓冲区
byte[] bytes = buffer.array();
ByteBuffer buffer2 = ByteBuffer.allocate(bitmap.getWidth() * bitmap.getHeight() * 4);
byte[] bytes2 = buffer2.array();
System.arraycopy(bytes, 0, bytes2, 0, buffer2.array().length);
// ARGB_8888 真实的存储顺序是 R-G-B-A
Log.d(TAG, "R: " + Integer.toHexString(bytes2[0] & 0xff));
Log.d(TAG, "G: " + Integer.toHexString(bytes2[1] & 0xff));
Log.d(TAG, "B: " + Integer.toHexString(bytes2[2] & 0xff));
Log.d(TAG, "A: " + Integer.toHexString(bytes2[3] & 0xff));
return bitmap;
// 打印结果,和预测的一样,说明理解正确
D/TTTTTTTTTT: R: ff
D/TTTTTTTTTT: G: 3
D/TTTTTTTTTT: B: ff
D/TTTTTTTTTT: A: ff
研究五:字节数组的拷贝
先申请一个字节数组,再通过arraycopy方法拷贝过去
ByteBuffer buffer2 = ByteBuffer.allocate(bitmap.getWidth() * bitmap.getHeight() * 4); byte[] bytes2 = buffer2.array(); System.arraycopy(bytes, 0, bytes2, 0, buffer2.array().length);
研究六:修改bitmap的大小
fun imageScale(bitmap: Bitmap, dst_w: Int, dst_h: Int): Bitmap?
val src_w = bitmap.width
val src_h = bitmap.height
val scale_w = dst_w.toFloat() / src_w
val scale_h = dst_h.toFloat() / src_h
val matrix = Matrix()
matrix.postScale(scale_w, scale_h)
return Bitmap.createBitmap(
bitmap, 0, 0, src_w, src_h, matrix,
true
)
研究七:相机回调字节数组的格式
public void onPreviewFrame(byte[] data, Camera camera)
理解: NV21==YCbCr_420_SP 属于YUV420sp范围
官方注释:
Camera.Parameters.setPreviewFormat(int) is never called, the default will be the YCbCr_420_SP (NV21) format.
默认是 YCbCr_420_SP 格式,也就是NV21,不过可以通过PreviewFormat修改格式
YUV420sp分为NV12和NV21
参考资料:
1.你真的知道 ARGB_8888 格式图片的 A、R、G、B 每个通道的排列顺序吗?
你真的知道 ARGB_8888 格式图片的 A、R、G、B 每个通道的排列顺序吗?_阿飞__的博客-CSDN博客_argb中的a
2.四种色彩模式ARGB_8888、ARGB_4444、 RGB_565、 ALPHA_8的区别
四种色彩模式ARGB_8888、ARGB_4444、 RGB_565、 ALPHA_8的区别_hust_twj的博客-CSDN博客_色8888
3.负数的二进制表示方法
负数的二进制表示方法_weixin_33695082的博客-CSDN博客
4.YUV 420、YCbCr 422、RGB 444以及色度二次采样_SkyNullCode的博客-CSDN博客_ycbcr422和444哪个好
5.Camera相机研发介绍_mobileai的博客-CSDN博客_相机开发
以上是关于安卓bitmap与字节数组关系深入研究应用的主要内容,如果未能解决你的问题,请参考以下文章
安卓编程 怎么把一个bitmap从一个activity传到另一个activity里?如果不能穿bi