android入门:zxing学习笔记(六)
个人网站:臭蛋 www.choudan.net
我希望你骑着摩托车离开这里,沿着这条河一直到大海边。
已经连续写了五篇zxing的学习笔记了,刚开始写的时候,只是想简简单单的记录下自己在学习android过程积累的点滴,却没想到写着写着变成了好像在向某人诉说自己一点浅薄的理解似的。回头来看这些稚嫩的笔记,发现思维逻辑有点混乱,讲述的杂乱无章,没达要点。不求全面,但求透彻。在写这些随笔的过程,又更多的理解了Barcode scanner的设计,弄懂了之前很多的一知半解,尤其是理所当然的潜在错误认知,所谓的眼高手低。View,Camera,thread,looper我都再次认真的查阅资料,谨慎的看了多遍,当心自己写错,新年我愿慢慢进步。
言归正传。
在使用Barcode Scanner扫描GB2312编码的qr码,扫描结果会出现乱码,无法正常显示。之所以会出现这个问题,我通过跟踪调试后找到在DecodedBitStreamParser类里面完成了对原始的bytes进行了解析,这个代码有很多没明白,通过打日志知道了代码运行的轨迹。通过对二十多张不同编码方式的qr图扫描分析的结果,发现大部分都通过调用decodeByteSegment进行解析,其中会调用函数StringUtils.guessEncoding(byte[] bytes, Hashtable hints)来对编码方式进行猜测,hits中可以指定使用的编码方式,如果没有指定则猜测。
1 // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS,
2 // which should be by far the most common encodings. ISO-8859-1
3 // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS
4 // uses this as a first byte of a two-byte character. If we see this
5 // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS.
6 // If we see something else in that second byte, we'll make the risky guess
7 // that it's UTF-8.
这部分是代码中对编码方式猜测的基本方法。缺少对GB2312的猜测。GB2312使用两个字节来进行编码。第一个字节的范围在(0xB0,0xF7),紧接着的第二个字节的范围在(0xA0,0xF7)。根据GB2312的这个编码规则,可以进行一个简单的判断,解决扫描GB2312编码的qr图乱码问题。
1 for (int i = 0; i < length; i++) {
2 int value = bytes[i] & 0xFF;
3 if (value > 0x7F)// 如果大于127,则可能是GB2312,就开始判断该字节,和下一个字节
4 {
5 if (value > 0xB0 && value <= 0xF7)// 第一个字节再此范围内,则开始判断第二个自己
6 {
7 int value2 = bytes[i + 1] & 0xFF;
8 if (value2 > 0xA0 && value2 <= 0xF7)
9 {
10 return true;
11 }
12 }
13 }
14 }
以上是一个简单的判断,通过加入到guesscoding中后可以正确的识别出GB2312编码的qr图。但感觉这样的方法还是比较低效率的,没有真正融合到zxing的源码中。需要再一步的思考。
前面有一篇关于camera旋转的问题,如果将拍照转为竖屏,除了在manifest中指定该activity的方向外,还需要camera.setDisplayOrientation(90),调整预览时的方向。但是camera取的数据还是原来的横屏的朝向,如果在对图片进行分析前没有对图片做一个旋转的操作,则图片最后保存下来,会发现它是横的,并且那些ResultPoint也无法正确的标记出qr图上的特征点。今天看到一个帖子,解决了这个问题,看这个帖子请点这里。
其中最关键的代码是再DecodeHandler.java中得decode函数调用buildLuminanceSource函数前进行如下的一个旋转。
1 byte[] rotatedData = new byte[data.length];
2 for (int y = 0; y < height; y++) {
3 for (int x = 0; x < width; x++)
4 rotatedData[x * height + height - y - 1] = data[x + y * width];
5 }
这样就解决了ResultPoint点标记的不正确的问题,当然除了设置方向,旋转数据,还需要调整下view的布局,使扫描框看上去更协调。
今天是年前最后一天上班了,关于zxing的学习笔记也暂告一个段落,来年再更新。
愿新年龙行天下。