5

C# QRCode二维码的解析与生成

 1 year ago
source link: https://www.cnblogs.com/magicMaQaQ/p/17639708.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

C# QRCode二维码的解析与生成

  已知一张二维码图片,怎么生成一张一模一样的图片出来?

  最近有个项目,需要用到QRCode,之前只做过Datamatrix格式的,想着应该也是差不多的,于是就依葫芦画瓢,掏出我的陈年OnBarcode类库,一通修改,生成了个崭新的QRCode,与客户提供的二维码图片一比对,虽然扫出来内容一样,但明显图案并不相同,于是我就意识到,事情并不简单。原图如下:

2447777-20230818114705632-1060549869.png

  首先第一个怀疑的就是参数问题啦,看了一下OnBarcode.Barcode.QRCode的属性,可疑的参数有DataMode、ECL、Version等等,毕竟这几个应该是常见的参数。最大的可能就是ECL,这个是二维码的纠错级别,一般是L/M/Q/H四个等级,对应可遮挡7%/15%/25%/30%,一般如果想在二维码中插入logo的话,就要把纠错级别调高一些。

  于是我尝试了一下,修改了不同的ECL,对应输出的图案都是不同的,但还是没有生成我想要的图案。

  难道是我的陈年OnBarcode类库跟不上时代了?于是我换成了QRCoder,又是一通折腾,还是没对上。再是找了一些在线生成二维码网站(见下方链接),逐个比较,发现还真是五花八门,有些是不提供设置直接生成,有些是可修改版本及ECL的,最后结果都不太一样,幸好有些网站生成的图片是对上了的,总算有条退路。

  既然有了备用方案,那我就可以慢慢研究了。查了下QRCode的生成原理,参考《【来龙去脉系列】QRCode二维码的生成细节和原理》,这一篇讲得不错,不过他在讲Mask那里有点模糊,这也导致我一不留神就掉坑了,后面看了另外两篇才纠正回来。看完大概有了概念,至少明确了,我这个码应该是是version1,Alphanumeric mode 字符编码,同时也知道还有个掩码参数(即Mask),而且从图案中可以看到Format Information,那里面存放着ECL跟Mask。文中将Format Information标注0-14,在左上角从上往下从右往左,并且说15个bits中包括5个数据bits:其中,2个bits用于表示使用什么样的Error Correction Level, 3个bits表示使用什么样的Mask,那我自然就认为0-4就是所谓的数据bits了,看了下是11100,跟10101异或得出01001,ECL是01-L?但我在线生成的时候是选的H,那就肯定不对。

  这时候我发现有个在线生成网站写明了用的是ZXing,于是我又引用了ZXing尝试了一下,按照常规的参数配置了ECL-H,还是不行,一度陷入瓶颈。

  我还突发奇想试着把原图上传到在线网站去解析,说不定有哪个网站能给出点提示,但最终也只是能看到内容。不过这么一来我又打开了思路,我可以自己解析,说不定就能拿到配置参数了,感觉可行性还是有的。

  刚好ZXing就有解码的功能,尝试一下:

 1 static void ParseQRCode(string imagePath, out string data, out IDictionary<ResultMetadataType, object> hints)
 2         {
 3             hints = null;
 4             BarcodeReader reader = new BarcodeReader();
 5             reader.Options.PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.QR_CODE };//可加可不加
 6             Bitmap bitmap = new Bitmap(imagePath);
 7             Result result = reader.Decode(bitmap);
 8             if (result != null)
 9             {
10                 data = result.Text;
11                 hints = result.ResultMetadata;
12             }
13             else
14             {
15                 data = null;
16             }
17         }

  输入图片路径,找了一下result的属性,果然在ResultMetadata里面存放着我要的信息:

2447777-20230818151540361-1567634061.png

   ECL是H,那就没错了,剩下的参数里面,这个QR_MASK_PATTERN不就是掩码参数咯,剩下两个看了下参数介绍,应该不是很重要,于是重点关注QR_MASK_PATTERN。刚好手头的代码引用的是ZXing,这里要注意的是,ZXing的Hints是不能整个赋值的,只能用Add的方式逐个插入参数:

 1 public static Bitmap CreateQRCode(string data)
 2         {
 3             Bitmap bitmap = null;
 4             GC.Collect();
 5             BarcodeWriter barCodeWriter = new BarcodeWriter();
 6             barCodeWriter.Format = BarcodeFormat.QR_CODE; // 生成码的方式(这里设置的是二维码),有条形码\二维码\还有中间嵌入图片的二维码等
 7             //barCodeWriter.Options.Hints.Add(EncodeHintType.CHARACTER_SET, "UTF-8");// 支持中文字符串
 8             barCodeWriter.Options.Hints.Add(EncodeHintType.ERROR_CORRECTION, ZXing.QrCode.Internal.ErrorCorrectionLevel.H);
 9             barCodeWriter.Options.Hints.Add(EncodeHintType.QR_MASK_PATTERN, 2);
10             barCodeWriter.Options.Height = 200;
11             barCodeWriter.Options.Width = 200;
12             barCodeWriter.Options.Margin = 0; //设置的白边大小
13             ZXing.Common.BitMatrix bm = barCodeWriter.Encode(data);
14             bitmap = barCodeWriter.Write(bm);
15             return bitmap;
16         }

  果然,结果跟原图一样(外面的圈是我自己加的):

2447777-20230818152816007-740566143.png

  问题已经解决了,但我还是有个疑惑,为什么我根据图案的Format Information得出的参数是不对的,于是我继续翻资料,终于在《[译] 为程序员写的Reed-Solomon码解释》这一篇里面看到了,是逆时针读的bit,wxxxx,最开始看的那一篇是顺时针标注的啊,那不就是反过来,仔细一看,读出来是00111,跟10101异或得10010,ECL是10-H,Mask是010-2,对上了。只能说,还是得多方考证吧。

  完结撒花。

  • 参考资料:

《【来龙去脉系列】QRCode二维码的生成细节和原理》 https://www.cnblogs.com/tuyile006/p/10916075.html

《二维码生成原理》 https://zhuanlan.zhihu.com/p/543574464

《[译] 为程序员写的Reed-Solomon码解释》 https://www.felix021.com/blog/read.php?2116

《C# 生成二维码方法(QRCoder)》 https://www.cnblogs.com/yakniu/p/16917897.html

《.NET Core(C#)使用ZXing.Net生成条码(Barcode)和二维码(QR code)图片及示例代码》 https://www.cnblogs.com/fireicesion/p/16809637.html

《C# 利用ZXing.Net来生成条形码和二维码》 https://blog.csdn.net/lwf3115841/article/details/128429605

  • 在线工具:

OSCHINA https://tool.oschina.net/qr

互联二维码 https://www.hlcode.cn/decode

草料二维码 https://cli.im/text

二维码工坊 https://www.2weima.com/?text=A0010101


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK