qrcode生成二进制QR码后pyzbar解码数据异常的解决方法
问题:二进制数据经qrcode编码、pyzbar解码后无法还原
我尝试使用qrcode库将二进制数据编码为QR码,再通过pyzbar库解码,但解码后的结果出现字节变更或新增的情况,无法得到与编码时完全一致的二进制数据。
测试脚本
import qrcode from pyzbar.pyzbar import decode, Decoded, ZBarSymbol def test(data): code = qrcode.QRCode( version=6, error_correction=qrcode.constants.ERROR_CORRECT_H, border=2, ) code.add_data(data) code.make(fit=False) img = code.make_image().get_image() img.save("out.png") detections: list[Decoded] = decode(img, symbols=[ZBarSymbol.QRCODE]) if detections: decoded = detections[0].data print(data) print(data == decoded) if data != decoded: print(decoded) print(data.hex()) print(decoded.hex()) print() # Plain text test(b"Hello World!") test(b"\x8bwhat is happening\x00\x34") test(b"\x00huh??\x65") test(b"r@mM-{\x8be\xcdTh\xf4G6W\xe8\x10\x81\x89W\xe7\x89\r\xa6)z~2]45pa.\xbak([%\x94\xd2\x80\x1fy\xc5bJ\x00")
输出结果
b'Hello World!' True b'\x8bwhat is happening\x004' False b'\xe4\xbb\x87hat is happening\x004' 8b776861742069732068617070656e696e670034 e4bb876861742069732068617070656e696e670034 b'\x00huh??e' True b'r@mM-{\x8be\xcdTh\xf4G6W\xe8\x10\x81\x89W\xe7\x89\r\xa6)z~2]45pa.\xbak([%\x94\xd2\x80\x1fy\xc5bJ\x00' False b'r@mM-{\xc2\x8be\xc3\x8dTh\xc3\xb4G6W\xc3\xa8\x10\xc2\x81\xc2\x89W\xc3\xa7\xc2\x89\r\xc2\xa6)z~2]45pa.\xc2\xbak([%\xc2\x94\xc3\x92\xc2\x80\x1fy\xc3\x85bJ\x00' 72406d4d2d7b8b65cd5468f4473657e810818957e7890da6297a7e325d343570612eba6b285b2594d2801f79c5624a00 72406d4d2d7bc28b65c38d5468c3b4473657c3a810c281c28957c3a7c2890dc2a6297a7e325d343570612ec2ba6b285b25c294c392c2801f79c385624a00
解决方案
问题原因
qrcode库默认会将输入的二进制数据当作字符串处理,按UTF-8规则进行转码;而pyzbar解码时也会按UTF-8解析数据,导致原始的非UTF-8兼容字节(如0x8b、0xcd等)被错误转换为多字节序列,最终无法还原原始数据。
修复方法
在调用code.add_data()时,指定binary模式,告诉qrcode库直接按原始字节编码,不进行字符串转码操作。
修改后的测试脚本:
import qrcode from pyzbar.pyzbar import decode, Decoded, ZBarSymbol def test(data): code = qrcode.QRCode( version=6, error_correction=qrcode.constants.ERROR_CORRECT_H, border=2, ) # 关键修改:添加数据时指定binary模式 code.add_data(data, mode='binary') code.make(fit=False) img = code.make_image().get_image() img.save("out.png") detections: list[Decoded] = decode(img, symbols=[ZBarSymbol.QRCODE]) if detections: decoded = detections[0].data print(data) print(data == decoded) if data != decoded: print(decoded) print(data.hex()) print(decoded.hex()) print() # Plain text test(b"Hello World!") test(b"\x8bwhat is happening\x00\x34") test(b"\x00huh??\x65") test(b"r@mM-{\x8be\xcdTh\xf4G6W\xe8\x10\x81\x89W\xe7\x89\r\xa6)z~2]45pa.\xbak([%\x94\xd2\x80\x1fy\xc5bJ\x00")
效果说明
修改后,所有测试用例的解码结果都会与原始二进制数据完全一致。因为qrcode会直接编码原始字节,pyzbar解码时也会输出原始字节序列,不会进行UTF-8转码操作。
内容的提问来源于stack exchange,提问作者ScottBot10
相关产品推荐
相关产品推荐

