QR二维码

http://blog.csdn.net/longteng1116/article/details/12753541


QR二维码_第1张图片

一、什么是二维码:
二维码 (2-dimensional bar code),是用某种特定的几何图形按一定规律在平面(二维方向上)
分布的黑白相间的图形记录数据符号信息的。

在许多种类的二维条码中,常用的码制有:Data Matrix, Maxi Code, Aztec, QR Code, Vericode, PDF417, Ultracode, Code 49, Code 16K等。
  1.堆叠式/行排式二维条码,如,Code 16K、Code 49、PDF417(如下图)等


    2.矩阵式二维码,最流行莫过于QR CODE,如:

QR二维码_第2张图片

二维码的名称是相对与一维码来说的,比如以前的条形码就是一个“一维码”,
它的优点有:二维码存储的数据量更大;可以包含数字、字符,及中文文本等混合内容;有一定的容错性(在部分损坏以后可以正常读取);空间利用率高等。

二、QR CODE 介绍
QR(Quick-Response) code是被广泛使用的一种二维码,解码速度快。
它可以存储多用类型



QR二维码_第3张图片


如上图时一个qrcode的基本结构,其中:
位置探测图形、位置探测图形分隔符、定位图形:用于对二维码的定位,对每个QR码来说,位置都是固定存在的,只是大小规格会有所差异;
校正图形:规格确定,校正图形的数量和位置也就确定了;
格式信息:表示改二维码的纠错级别,分为L、M、Q、H;

版本信息:即二维码的规格,QR码符号共有40种规格的矩阵(一般为黑白色),从21x21(版本1),到177x177(版本40),每一版本符号比前一版本 每边增加4个模块。
数据和纠错码字:实际保存的二维码信息,和纠错码字(用于修正二维码损坏带来的错误)。

简要的编码过程:
    1. 数据分析:确定编码的字符类型,按相应的字符集转换成符号字符; 选择纠错等级,在规格一定的条件下,纠错等级越高其真实数据的容量越小。

    2. 数据编码:将数据字符转换为位流,每8位一个码字,整体构成一个数据的码字序列。其实知道这个数据码字序列就知道了二维码的数据内容。
          

QR二维码_第4张图片


QR二维码_第5张图片


 
            数据可以按照一种模式进行编码,以便进行更高效的解码,例如:对数据:01234567编码(版本1-H),
            1)分组:012 345 67
             2)转成二进制:012→0000001100
                                                   345→0101011001
                                                    67 →1000011
              3)转成序列:0000001100 0101011001 1000011
              4)字符数 转成二进制:8→0000001000
              5)加入模式指示符(上图数字)0001:0001 0000001000 0000001100 0101011001 1000011
           对于字母、中文、日文等只是分组的方式、模式等内容有所区别。基本方法是一致的

    3. 纠错编码:按需要将上面的码字序列分块,并根据纠错等级和分块的码字,产生纠错码字,并把纠错码字加入到数据码字序列后面,成为一个新的序列。
             

QR二维码_第6张图片


        在二维码规格和纠错等级确定的情况下,其实它所能容纳的码字总数和纠错码字数也就确定了,比如:版本10,纠错等级时H时,总共能容纳346个码字,其中224个纠错码字。
        就是说二维码区域中大约1/3的码字时冗余的。对于这224个纠错码字,它能够纠正112个替代错误(如黑白颠倒)或者224个据读错误(无法读到或者无法译码),
        这样纠错容量为:112/346=32.4%
       
    4. 构造最终数据信息:在规格确定的条件下,将上面产生的序列按次序放如分块中
        按规定把数据分块,然后对每一块进行计算,得出相应的纠错码字区块,把纠错码字区块 按顺序构成一个序列,添加到原先的数据码字序列后面。
        如:D1, D12, D23, D35, D2, D13, D24, D36, ... D11, D22, D33, D45, D34, D46, E1, E23,E45, E67, E2, E24, E46, E68,...

构造矩阵:将探测图形、分隔符、定位图形、校正图形和码字模块放入矩阵中。
         
QR二维码_第7张图片
 
        
         把上面的完整序列填充到相应规格的二维码矩阵的区域中


    6. 掩摸:将掩摸图形用于符号的编码区域,使得二维码图形中的深色和浅色(黑色和白色)区域能够比率最优的分布。
             一个算法,不研究了,有兴趣的同学可以继续。
    7. 格式和版本信息:生成格式和版本信息放入相应区域内。
        版本7-40都包含了版本信息,没有版本信息的全为0。二维码上两个位置包含了版本信息,它们是冗余的。
        版本信息共18位,6X3的矩阵,其中6位时数据为,如版本号8,数据位的信息时 001000,后面的12位是纠错位。


至此,二维码的编码流程基本完成了,下面就来实践一下吧。

代码采用c#编写,需要引用两个dll,如下:

c#实现代码,已经简化代码,具体函数可自行查阅:


源代码下载链接:http://download.csdn.net/detail/longteng1116/6443195



http://www.cnblogs.com/tuyile006/p/3416008.html


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

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

背景知识

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

QRcode

QR二维码_第8张图片

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

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

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

 

我做的二维码插入图片:

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

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

界面:

QR二维码_第9张图片QR二维码_第10张图片 

程序界面如下:

QR二维码_第11张图片

其中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, 300, 300,hint);
                Bitmap img = bm.ToBitmap();

                //要插入到二维码中的图片
                Image middlImg = QRMiddleImg.Image; 
                //获取二维码实际尺寸(去掉二维码两边空白后的实际尺寸)
                System.Drawing.Size realSize = mutiWriter.GetEncodeSize(txtMsg.Text, com.google.zxing.BarcodeFormat.QR_CODE, 300, 300);
                //计算插入图片的大小和位置
                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;

                //将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, 0, 0);
                }

                //在二维码中插入图片
                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、第二个要注意的地方是图片大小

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

QR二维码_第12张图片

为了插入图片的完整性,我们选择在最中间插入,而且长宽建议为整个二维码的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的比例。

 

下载地址:

DEMO    

源码下载地址:http://www.51aspx.com/code/QRWithPicture/19074


你可能感兴趣的:(.net,.net,core,vb.net,C#,编程基础)