YUV 400 格式图像转换成 ARGB 格式图像中犯的一个低级 Bug
一、背景
最近在做 Android 巴枪项目,借助巴枪上面的二维扫描头拍照,然后去做 OCR。这属于定制需求,只能去和各个巴枪厂家去对接。后来厂家陆续暴露给了我们这个能力,但是接口都不一样(领教了 Android 的碎片化)。这个 Bug 就出在我适配一款巴枪的过程中。
二、Bug
这个厂家的 SDK 设计是通过回调的方式把图片数据返回给我。只有一个 byte 数组,不知道宽、高,不知道格式(ARGB、YUV),没有文档,只能去问他们的开发,沟通成本很高。最后问得宽是 1280,高是 960,格式是 YUV 400(只有 Y 通道数据)。我需要把这个数据转成 jpeg 格式的数据,上传到云端,识别并留底。问题来了,我转成 jpeg 格式之后先存储到了本地,验证格式转换这一步是成功的。发现存储的图片是无法打开的,一直报错“文件格式不支持”。我的转换代码如下:
// data 是 yuvDataint[] pixels = new int[width * height];for (int y = 0; y < height; y++){ for (int x = 0; x < width; x++) { int index = y * width + x; // !!! Y 到 ARGB 的快速转换 int grey = data[index] & 0xff; pixels[index] = 0xFF000000 | (grey * 0x00010101); }}ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);bitmap.setPixels(pixels, 0, width, 0, 0, width, height);bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);byte[] jpegData = byteArrayOutputStream.toByteArray();try { byteArrayOutputStream.close();} catch (IOException e) { e.printStackTrace();}
grey * 0x00010101
等同于 grey << 16 | grey << 8 | grey
,效果是灰度值是 120 的话,转化成的 rgb 值是(120,120,120)。
三、调试
开始怀疑厂家给的 yuvData 有问题。yuvData 数组确实多了 20 个字节的数据,1280*960=1228800,而数组长度是 1228820,值得怀疑。不过和对方的开发沟通,说后 20 个字节是空的,不会影响。分析一下数组只要长度不短,长度更长或者内容不对应该都不会导致图片打不开,内容不对只会导致图片打开之后看起来不对。
单步调试,查看中间结果,没有发现问题。其中 bitmap 这个中间结果用 ImageView 展示出来看也是正常的。(把中间结果输出出来、展示出来,二分法定位问题所在,很有用。白盒调试。而不是黑盒的在那里猜猜猜。)
写文件这里门板代码,出问题的概率不大。
最后不知道怎么想起来的,怀疑是不是这个巴枪打不开而已,文件本身是没问题。
事实证明确实是这个问题。而是只是文件管理 App 打不开而已,下载个 Google Photo 是可以打开的。也是我先入为主,适配的上一款巴枪文件管理 App 是可以打开的。到了这款巴枪,打不开了,我马上怀疑是文件损坏了。
总结:越难解的 Bug 可能越低级。
更多相关文章
- SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
- 一句话锁定MySQL数据占用元凶
- 【原创】Android(安卓)判断默认数据网络是否为开,若关则跳转到网
- Android(安卓)RecyclerView网格布局示例解析
- Netty UDP Server&Client
- Android(安卓)连接网络时显示进度条
- Fragment.setArguments()方法向fragment对象传递数据的重要作用
- 使用自己的数据库SQLite database
- Navigation(2)