二维码终于火了,现在大街小巷大小商品广告上的二维码标签都随处可见,而且大都不是简单的纯二维码,而是中间有个性图标的二维码。

我之前做了一个使用google开源项目zxing实现二维码、一维码编码解码的程序并开放了源码(用C#实现的条形码和二维码编码解码器),今天继续在此程序基础上,实现二维码中间加小图片。

背景知识

QRcode使用里德-所罗门码来进行错误修正。对于我们来说,里德-所罗门编码有两个非常重要的特性。第一,它是一种显式系统码,也就是说,你可以在最终的编码中直接看到原有的信息。就好比我们对”hello world”进行编码,最终看到的是”hello world”以及其后面跟随的几个容错码。第二点,里德-所罗门编码是可以被”异或”的,将两个不同里德-所罗门编码得到的结果异或运算后会得到一个新的里德-所罗门码,并且这个新码的原码即是原来两个原码的异或。如果你想知道为什么这两个特性会成立,请看Finite Field Arithmetic and Reed-Solomon Coding.

QRcode

一副QRcode图像会定义一些独特的描述符来帮助人们或者电脑识别出自己是一张QRcode。这种描述符随着QRcode的大小不同而略有区别——越大的QRcode图像拥有越多的描述符。但是对于人的识别来说,特征最明显的还是图片的四个角的符号是固定的,看到这样的四个角人类就本能的反应:这是一个QRcode。

(实际上,我们可以通过读取图像最左上角的两个象素点来判断编码的冗余程度。定义黑色为0,白色为1,那么如果看到00则是L级别的冗余,01是M,10是Q,11则是最高的H级别冗余。

有了上面的这些工作,我们可以非常容易的知道原码信息在图像中的位置。然后通过改变自己的原码信息,就可以改变图像中的像素以至于可以在里面作图了。虽说如此,下面的一些情形可以让事情变得更有趣。

我做的二维码插入图片:

需要用到ZXing.Net库。

ZXing.Net 源代码地址http://zxingnet.codeplex.com/

也可以使用Nuget包管理,添加如图:

之前我给大家免费提供了使用zxing开源项目改造而成的一二维码编码解码器,但未能插入图片。这次经过一番努力,成功将图片插入二维码,并能编码和解码。

插入图片的关键在于二维码容错系数的调整。

界面:

程序界面如下:

其中WinForm项目是我的Demo程序,zxing是Google的一个开源二维码项目。

生成二维码的代码:

  1. //构造二维码写码器
  2. MultiFormatWriter mutiWriter = new com.google.zxing.MultiFormatWriter();
  3. Hashtable hint=new Hashtable();
  4. hint.Add(EncodeHintType.CHARACTER_SET,"UTF-8");
  5. hint.Add(EncodeHintType.ERROR_CORRECTION,com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.H);
  6. //生成二维码
  7. ByteMatrix bm = mutiWriter.encode(txtMsg.Text, com.google.zxing.BarcodeFormat.QR_CODE, , ,hint);
  8. Bitmap img = bm.ToBitmap();
  9.  
  10. //要插入到二维码中的图片
  11. Image middlImg = QRMiddleImg.Image;
  12. //获取二维码实际尺寸(去掉二维码两边空白后的实际尺寸)
  13. System.Drawing.Size realSize = mutiWriter.GetEncodeSize(txtMsg.Text, com.google.zxing.BarcodeFormat.QR_CODE, , );
  14. //计算插入图片的大小和位置
  15. int middleImgW = Math.Min((int)(realSize.Width / 3.5), middlImg.Width);
  16. int middleImgH = Math.Min((int)(realSize.Height / 3.5),middlImg.Height);
  17. int middleImgL = (img.Width - middleImgW) / ;
  18. int middleImgT = (img.Height - middleImgH) / ;
  19.  
  20. //将img转换成bmp格式,否则后面无法创建 Graphics对象
  21. Bitmap bmpimg = new Bitmap(img.Width, img.Height,System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  22. using (Graphics g = Graphics.FromImage(bmpimg))
  23. {
  24. g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
  25. g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
  26. g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
  27. g.DrawImage(img, , );
  28. }
  29.  
  30. //在二维码中插入图片
  31. System.Drawing.Graphics MyGraphic = System.Drawing.Graphics.FromImage(bmpimg);
  32. //白底
  33. MyGraphic.FillRectangle(Brushes.White,middleImgL, middleImgT, middleImgW, middleImgH);
  34. MyGraphic.DrawImage(middlImg, middleImgL, middleImgT, middleImgW, middleImgH);
  35.  
  36. pictureBox1.Image = bmpimg;
  37.  
  38. //自动保存图片到当前目录
  39. string filename = System.Environment.CurrentDirectory + "\\QR" + DateTime.Now.Ticks.ToString() + ".jpg";
  40. bmpimg.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg);
  41. lbshow.Text = "图片已保存到:" + filename;

解析二维码的代码:

  1. //构建解码器
  2. MultiFormatReader mutiReader = new com.google.zxing.MultiFormatReader();
  3. Bitmap img = (Bitmap)Bitmap.FromFile(opFilePath);
  4. if (img == null)
  5. return;
  6. LuminanceSource ls = new RGBLuminanceSource(img, img.Width, img.Height);
  7. BinaryBitmap bb = new BinaryBitmap(new com.google.zxing.common.HybridBinarizer(ls));
  8. //注意 必须是Utf-8编码
  9. Hashtable hints = new Hashtable();
  10. hints.Add(EncodeHintType.CHARACTER_SET, "UTF-8");
  11. Result r = mutiReader.decode(bb, hints);
  12. txtmsg2.Text = r.Text;
  13. lbshow.Text = "解码成功!";

要在二维码中插入图片且可以正常解码,关键是要注意以下几个地方:

1、必须调整二维码的容错参数ErrorCorrectionLevel

Hashtable hint=new Hashtable();
hint.Add(EncodeHintType.CHARACTER_SET,"UTF-8");
hint.Add(EncodeHintType.ERROR_CORRECTION,com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.H);

hint是生成二维码的方法中最后一个参数,这个参数是一个hashtable,这里可以设置二维码的编码、容错系数等。

容错系数越高,生成的二维码图片越复杂,可以容忍二维码被污垢弄赃,甚至中间可以加一个小图片,识别也不受影响。

2、第二个要注意的地方是图片大小

从二维码的识别原理可以知道,二维码中原始信息被加密在下图黑色部分,而红色部分都是冗余信息,红色部分都是可以被自己的图片替换的。

为了插入图片的完整性,我们选择在最中间插入,而且长宽建议为整个二维码的3/7至1/3

  1. //计算插入图片的大小和位置
  2. int middleImgW = Math.Min((int)(realSize.Width / 3.5), middlImg.Width);
  3. int middleImgH = Math.Min((int)(realSize.Height / 3.5),middlImg.Height);
  4. int middleImgL = (img.Width - middleImgW) / 2;
  5. int middleImgT = (img.Height - middleImgH) / 2;

我们的例子中用的就是2/7的比例。

3、扫描二维码时的卡顿问题

直接用MultiFormatReader 进行解码,既可以识别二维码,也可以识别条形码,但会出现卡顿现象。如果你的业务需求只需要识别二维码,请直接使用QRCodeReader类来解析,字符集采用utf-8,使用Harder模式,并且把可能的解析格式只定义为BarcodeFormat.QR_CODE,这对于直接二维码扫描解析无疑是帮助最大的。

  1. Map<DecodeHintType, Object> mHints;
  2. mQrCodeReader = new QRCodeReader();
  3. mHints = new Hashtable<>();
  4. mHints.put(DecodeHintType.CHARACTER_SET, "utf-8");
  5. mHints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
  6. mHints.put(DecodeHintType.POSSIBLE_FORMATS, BarcodeFormat.QR_CODE);

下载地址:

DEMO

源码下载地址:

CODE

QR二维码生成器源码(中间可插入小图片)的更多相关文章

  1. DataMatrix二维条码源码分析检测识别图像位置

    发布时间:2014-10-31 DataMatrix的代码结构和QR码基本相同: 其中Detector的功能还是从原始图像中找出符号码的部分,并且进行透视转换纠正扭曲. 其解码流程与QR码差不多,关键 ...

  2. Google API快速生成QR二维码

    Google API快速生成QR二维码 现在来说生成二维码最简单的方法是使用Google Chart API来实现,再次膜拜Google大神- Google Chart API是一套可以让你在线生成报 ...

  3. C# vb .NET生成QR二维码

    二维码比条形码具有更多优势,有些场合使用二维码比较多,比如支付.通过将某些数据生成二维码,就可以实现一码走天下.那么如何在C#,.Net平台代码里生成二维码呢?答案是使用SharpBarcode! S ...

  4. C# vb .NET识别读取QR二维码

    二维码比条形码具有更多优势,有些场合使用二维码比较多,比如支付.那么如何在C#,.Net平台代码里读取二维码呢?答案是使用SharpBarcode! SharpBarcode是C#快速高效.准确的条形 ...

  5. QR 二维码总结

    @(Java ThirdParty)[QR] QR 二维码总结 根据Wiki中的介绍,QR Code(Quick Response Code),二维条形码,由日志设计应用于汽车制造工业中.条形码中包含 ...

  6. 【转】Delphi+Halcon实战一:两行代码识别QR二维码

    Delphi+Halcon实战一:两行代码识别QR二维码 感谢网友:绝代双椒( QQ号应原作者要求隐藏了:xxxx6348)的支持 本文是绝代双椒的作品,因为最近在忙zw量化培训,和ziwang.co ...

  7. [AX2012 R3]在SSRS报表中使用QR二维码

    AX2012是自带生成QR二维码的类,可以很方便的用在SSRS报表中,下面演示如何在RDP的报表中使用二维码,首先从定义临时表开始: 字段URL是要用于二维码的字符串,QrCode是container ...

  8. pbfunc外部函数扩展应用-直接在Datawindow中生成QR二维码,非图片方式

    利用pbfunc外部函数在Datawindow中直接生成QR二维码,非图片方式.需要注意以下面几点: Datawindow的DataObject的单位必须为像素(Pixels). Datawindow ...

  9. 利用zxing制作彩色,高容错,支持中文等UTF编码的QR二维码图片

    利用zxing制作彩色,高容错,支持中文等UTF编码的QR二维码图片.代码如下 import java.awt.Color;import java.io.File;import java.util.H ...

随机推荐

  1. Photoshop CS6 for Mac简体中文正式 完美破解版 支持Retina屏

    Photoshop CS6 MAC 中文版破解版 支持Retina屏 目前世界上“最好的化妆品”是一款叫做PhotoShop的产品,它可以帮你去除所有你不满意的地方.上周末,这款最好的化妆品推出了第十 ...

  2. 1.C#中几个简单的内置Attribute

    阅读目录 一:Obsolete 二:Conditional 一:Obsolete      这个内置属性是说这个方法废弃了不可用,它有两个参数,第一个参数message是说废弃的原因,第二个参数err ...

  3. struts2:数据校验,通过Action中的validate()方法实现校验(续:多业务方法时的不同验证处理)

    前文:struts2:数据校验,通过Action中的validate()方法实现校验,图解 如果定义的Action中存在多个逻辑处理方法,且不同的处理逻辑可能需要不同的校验规则,在这种情况下,就需要通 ...

  4. 不同iOS版本做代码适配__IPHONE_OS_VERSION_MAX_ALLOWED 和 __IPHONE_8_0等专业术语

    目前开发只想最低版本支持iOS8了,iOS8以前的就不管了,然后现在iOS9和iOS10出来以后,有些新的API,也有些弃用的API,为了兼容,有时候代码里面需要编写判断不同iOS版本,或者只允许指定 ...

  5. Oracle存储过程执行update语句不报错不生效问题

    转载链接:http://lin49940.iteye.com/blog/466626 今天一个同事写oracle 的存储过程遇到了一个问题, 他在里面update 操作不能完成更新的操作, 但是又不会 ...

  6. Firefox火狐添加书签功能失灵解决办法

    一直使用firefox,书签管理用的是插件Tabmix.感觉很好,只是不知道从那天起添加书签就不灵了!不论是Ctrl+D快捷键,还是Add Bookmark Here2插件,甚至“将此页加为书签”的菜 ...

  7. WPF RichTextBox设置文本颜色

    //追加 txtResult.Document.Blocks.Add(new Paragraph(new Run("add by run") { Foreground = Brus ...

  8. Python Django 开发 4 ORM

    第三篇最后写了,光知道那些基础的查询在项目中是没有什么卵用的,重点是实体关系映射(ORM),今天学习了,来记录一下,关键词:ForeignKey(多对一).OneToOneField(一对一).Man ...

  9. SQL Server 中关于 @@error 的一个小误区

    在SQL Server中,我常常会看到有些前辈这样写: ) ROLLBACK TRANSACTION T else COMMIT TRANSACTION T 一开始,我看见别人这么写,我就想当然的以为 ...

  10. Sql触发器模板

    触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程. 触发器主要是通过事件进行触发被自动调用执行的.而存储过程可以通过存储过程的名称被调用. SQL Server 2005中触发器可以分 ...