zxing解析中文符号错误

二维码扫描器app(Android)小结:

进入正题之前,先对之前做的这个手机二维码扫描器app做个总结吧,看官可以忽略这部分。

该扫描器的工作流程如下:

1. 解析扫到的二维码 ;

2. 分析扫到的信息,并向服务器发送相应的数据请求或修改命令;

3. 接收服务器返回数据并显示。


问题背景:

解析二维码的部分是用的zxing这个开源库;

二维码编码格式为按字节编码;

二维码生成工具为phpqrcode;

源数据为GB2312格式的字符串。

遇到的问题如下:当源数据中含有中文字符时,手机端解码就会出现错误。如中文乘号“×”,在源数据中由0xai0xc1两个字节表示,但是解码之后却变成了别的数据,这就导致手机端解码完毕后,虽然解码成功,显示也正常(“×”虽然二进制数据不对,但是在手机端却能正常显示,这点很奇怪 PS:手机端的文本编码格式都是GB2312),但是发到数据库的信息却是错的。

比如,有一张二维码的信息是“T2×2”,扫描器到这个信息后,会向服务器询问该零件是否存在与数据库中。数据库中的“×”是以0xa10xc1表示的,但是手机端发过来的却是另外的值,因此查询的结果是数据库中不存在该零件。

问题原因:

zxing在解qr码时,即使qr码的编码格式是按字节编码,decode的返回结果里的字符串也不是原始的字节串,因为zxing在解析qr码时,解析出原始的字节串之后,会调用一个名为StringUtils.guessEncoding(readBytes, hints);的函数,来猜测原始字符串的编码格式。猜测的具体过程我没有看,但是猜测的结果就是——把原始字节串破坏了。

解决方法:

我想既然编码方式里有按字节编码,解码结果里应该也有按字节输出的功能吧,结果并没有。于是,只能自己再写一个函数,在解码的最后,不进行编码猜测,而是直接输出解析出来的原始字节串并输出。

注意:下面代码是直接写在自己的工程里的,而不是添加到zxing里。代码中调用的一些方法在从gid上直接下载到的zxing版本中是不可见的,需要修改zxing的源代码并重新生成一个jar才可以。当然,也可以直接在zxing里添加一个函数来实现这个功能,这样的效率会更高。(其实也有可能是zxing中本身就有实现这个功能函数,但是我没找到。。)

代码如下:

</pre><pre name="code" class="java">private byte[] QRDetectAndDecode(PlanarYUVLuminanceSource img)
			{
				BinaryBitmap img_bitmap = new BinaryBitmap(new HybridBinarizer(img));
				try {
					Detector qrDetector = new Detector(img_bitmap.getBlackMatrix());
					try {
						DetectorResult detectRs = qrDetector.detect();
						BitMatrix codeBits = detectRs.getBits();
						BitMatrixParser paser = getQRPaser(codeBits);
						try {
							Decoder qrDecoder = new Decoder();
							DecoderResult rs = qrDecoder.decode(codeBits);
							byte[] rawByte = rs.getRawBytes();
							BitSource bits = new BitSource(rawByte);// 获取原始字节(带标识码和校验码)
							Mode mode = Mode.forBits(bits.readBits(4));// 获取qr类型(8bit或者kanji等等)
							int count = bits.readBits(mode.getCharacterCountBits(paser.readVersion()));
							byte[] readBytes = new byte[count];
							for (int i = 0; i < count; i++) {
								readBytes[i] = (byte) bits.readBits(8);
							}
							int isee = 0;
							return readBytes;
						} catch (ChecksumException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
							Log.e(TAG, "decode ChecksumException");
						} catch (FormatException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
							Log.e(TAG, "decode FormatException");
						}
						
					} catch (FormatException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} catch (NotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return null;
			}
private BitMatrixParser getQRPaser(BitMatrix tBitMatrix) {
				BitMatrixParser rs = null;
				Detector qrDetector = new Detector(tBitMatrix);
				DetectorResult tDetectorResult = null;
				try {
					tDetectorResult = qrDetector.detect();
				} catch (NotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					// Log.e(TAG, "detect NotFoundException");
					return null;
				} catch (FormatException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					Log.e(TAG, "detect FormatException");
					return null;
				}
				try {
					rs = new BitMatrixParser(tDetectorResult.getBits());
				} catch (FormatException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					return null;
				}

				return rs;
			}


补充:

按照上述改法,又出现了另一个问题——不是以完全以字节形式编码的信息,会解析不完全。

例如,源信息为“123”,如果在编码时,把123当做了数字进行处理的话,按照上述方法解析,将会解析不到“123”。

原因分析:

上述方法的实质是,自己直接从返回结果中的RawBytes取出了数据,而没有让zxing去帮你猜测这串字节的编码格式并自动转换为String,因此避免了自动转换环节出现的错误。但是,在源码中,RawBytes中存放的只是用Byte形式编码的数据,并没有存储以字母或者数字形式编码的数据。

解决方法:

二维码的编码的实质是,将整段信息拆分成若干端,存于一连串的有序的单元(segment)中,之后再加入适当校验信息。于是,解码的实质其实就是解析出每个segment中的值,之后再讲其拼接起来,最终得到原始信息。需要注意的是,这些单元是有类型之分的。一个单元的“类型”,标明了该单元需要用什么策略去解析。在我的项目中,遇到单元的类型有——字母,数字,字节这三种。

zxing在解析QR码时,只在解析字节型segment时,将解析出来的原始字节保存在了RawBytes中。因此,我将解析字母和数字segment得到的数据都也存入了segmentList(RawBytes的来源就是它)中。在原版本的源码中,只有字节模式的segment解析后才将解析出来的字节保存到segmentList里,其它类型的都不保存。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!要在C++解析二维码,您可以使用ZXing库。ZXing是一个开源的条码和二维码处理库,提供了多种编程语言的接口,包括C++。 以下是使用ZXing C++库解析二维码的基本步骤: 1. 首先,您需要下载并编译ZXing C++库。您可以从 https://github.com/nu-book/zxing-cpp 获取源代码,并按照项目的说明进行编译。 2. 在您的C++项目,包含所需的头文件。例如: ```cpp #include <zxing/ZXing.h> #include <zxing/DecodeHints.h> #include <zxing/BinaryBitmap.h> #include <zxing/ReaderException.h> #include <zxing/common/GlobalHistogramBinarizer.h> #include <zxing/qrcode/QRCodeReader.h> ``` 3. 创建一个二维码图像的二进制位图对象。您可以从图像文件加载二维码图像,或者根据其他方式创建二维码图像的位图对象。 ```cpp zxing::Ref<zxing::LuminanceSource> source = zxing::ImageSource::create("<image_filename>"); zxing::Ref<zxing::BinaryBitmap> bitmap = zxing::Ref<zxing::BinaryBitmap>(new zxing::BinaryBitmap(zxing::Ref<zxing::Binarizer>(new zxing::GlobalHistogramBinarizer(source)))); ``` 4. 创建一个解码提示对象,并设置所需的解码参数。例如,您可以指定要处理的条码类型: ```cpp zxing::DecodeHints hints; hints.setTryHarder(false); // 是否尝试更多次数的解码 hints.setFormats(zxing::BarcodeFormat::QR_CODE); // 设置要解码的条码类型,这里设置为QR码 ``` 5. 创建一个QR码阅读器对象,并使用上述设置进行解码: ```cpp zxing::Ref<zxing::qrcode::QRCodeReader> reader = zxing::Ref<zxing::qrcode::QRCodeReader>(); std::string result; try { result = reader->decode(bitmap, hints).getText()->getText(); } catch(const zxing::Exception& e) { // 处理解码异常 } ``` 6. 解码完成后,您可以从`result`变量获取解码结果。 这是一个基本的示例,用于在C++使用ZXing解析二维码。您可以根据自己的需求进行调整和扩展。 希望对您有所帮助!如有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值