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

我之前做了一个使用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的一个开源二维码项目。

生成二维码的代码:

               //构造二维码写码器
MultiFormatWriter mutiWriter = new com.google.zxing.MultiFormatWriter();
Hashtable hint=new Hashtable();
hint.Add(EncodeHintType.CHARACTER_SET,"UTF-8");
hint.Add(EncodeHintType.ERROR_CORRECTION,com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.H);
//生成二维码
ByteMatrix bm = mutiWriter.encode(txtMsg.Text, com.google.zxing.BarcodeFormat.QR_CODE, , ,hint);
Bitmap img = bm.ToBitmap(); //要插入到二维码中的图片
Image middlImg = QRMiddleImg.Image;
//获取二维码实际尺寸(去掉二维码两边空白后的实际尺寸)
System.Drawing.Size realSize = mutiWriter.GetEncodeSize(txtMsg.Text, com.google.zxing.BarcodeFormat.QR_CODE, , );
//计算插入图片的大小和位置
int middleImgW = Math.Min((int)(realSize.Width / 3.5), middlImg.Width);
int middleImgH = Math.Min((int)(realSize.Height / 3.5),middlImg.Height);
int middleImgL = (img.Width - middleImgW) / ;
int middleImgT = (img.Height - middleImgH) / ; //将img转换成bmp格式,否则后面无法创建 Graphics对象
Bitmap bmpimg = new Bitmap(img.Width, img.Height,System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(bmpimg))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.DrawImage(img, , );
} //在二维码中插入图片
System.Drawing.Graphics MyGraphic = System.Drawing.Graphics.FromImage(bmpimg);
//白底
MyGraphic.FillRectangle(Brushes.White,middleImgL, middleImgT, middleImgW, middleImgH);
MyGraphic.DrawImage(middlImg, middleImgL, middleImgT, middleImgW, middleImgH); pictureBox1.Image = bmpimg; //自动保存图片到当前目录
string filename = System.Environment.CurrentDirectory + "\\QR" + DateTime.Now.Ticks.ToString() + ".jpg";
bmpimg.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg);
lbshow.Text = "图片已保存到:" + filename;

解析二维码的代码:

           //构建解码器
MultiFormatReader mutiReader = new com.google.zxing.MultiFormatReader();
Bitmap img = (Bitmap)Bitmap.FromFile(opFilePath);
if (img == null)
return;
LuminanceSource ls = new RGBLuminanceSource(img, img.Width, img.Height);
BinaryBitmap bb = new BinaryBitmap(new com.google.zxing.common.HybridBinarizer(ls));
//注意 必须是Utf-8编码
Hashtable hints = new Hashtable();
hints.Add(EncodeHintType.CHARACTER_SET, "UTF-8");
Result r = mutiReader.decode(bb, hints);
txtmsg2.Text = r.Text;
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

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

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

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

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

    Map<DecodeHintType, Object> mHints;
mQrCodeReader = new QRCodeReader();
mHints = new Hashtable<>();
mHints.put(DecodeHintType.CHARACTER_SET, "utf-8");
mHints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
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. 2.C#中泛型在方法Method上的实现

    阅读目录   一:C#中泛型在方法Method上的实现 把Persion类型序列化为XML格式的字符串,把Book类型序列化为XML格式的字符串,但是只写一份代码,而不是public static s ...

  2. apache工作模式:prefork和worker

    apache作为现今web服务器用的最广泛也是最稳定的开源服务器软件,其工作模式有许多中,目前主要有两种模式:prefork模式和worker模式 一.两种模式 prefork模式: prefork是 ...

  3. c# -- 对象销毁和垃圾回收

    有些对象需要显示地销毁代码来释放资源,比如打开的文件资源,锁,操作系统句柄和非托管对象.在.NET中,这就是所谓的对象销毁,它通过IDisposal接口来实现.不再使用的对象所占用的内存管理,必须在某 ...

  4. SQL语句调优-基础知识准备

    当确定了应用性能问题可以归结到某一个,或者几个耗时资源的语句后,对这些语句进行调优,就是数据库管理员或者数据库应用程序开发者当仁不让的职责了.语句调优是和数据库打交道的必备基本功之一. 当你面对一个“ ...

  5. React Native 重新建项目遇到的一些问题

    1.基本上一句话,就是本地的node太旧了,跟不上React_Native的节奏,所以需要更新node,但是单纯的更新node丫丫竟然不让我跟,因为是用Homebrew来管理的,所以先update了下 ...

  6. C8051 SMBus 原理

    一.SMBus总线   SMBus串行I/O接口完全符合系统管理总线规范 1.1 版.它是一个双线的双向串行总线,与I2C串行总线兼容.系统控制器对总线的读写操作都是以字节为单位的,由SMBus接口自 ...

  7. 测试卡尔曼滤波器(Kalman Filter)

    真实的温度测试数据,通过加热棒加热一盆水测得的真实数据,X轴是时间秒,Y轴是温度: 1)滤波前 2)滤波后(p=10, q=0.0001, r=0.05, kGain=0;) 2)滤波后(p=10, ...

  8. RadioButton 的background属性表现特征

    对于radiaoButton,应该很多人都用过.下面看一个场景     上方时radiogroup,细致观察发现左1,文字开始位置和右1文字开始位置不同,这是为何呢? 查看布局: <RadioB ...

  9. ionic介绍

    ionic介绍 Ionic是一个前端的框架,帮助开发者使用HTML5, CSS3和JavaScript做出原生应用. The beautiful, open source front-end fram ...

  10. 【转】每个人应该知道的NVelocity用法

    NVelocity是一个基于.NET的模板引擎(template engine).它允许任何人仅仅简单的使用模板语言(template language)来引用由.NET代码定义的对象.从而使得界面设 ...