二维码生成_二维码生成代码 - CSDN
精华内容
参与话题
  • 最近项目中需要开发生成二维码的功能,方便使用手机支付,在网上查了一些资料,把用过的方法进行总结。 1.前端js生成二维码 demo下载:http://download.csdn.net/download/yin767833376/10165335 html页面代码: ...

    最近项目中需要开发生成二维码的功能,方便使用手机支付,在网上查了一些资料,把用过的方法进行总结。

    1.前端js生成二维码

    demo下载:http://download.csdn.net/download/yin767833376/10165335

    html页面代码:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8" />
    <title></title>
    </head>
    <body>
    <script type="text/javascript" src="js/jquery-1.8.3.min.js" ></script>
    <script type="text/javascript" src="js/jquery.qrcode.js" ></script>
            <script type="text/javascript" src="js/qrcode.js" ></script> 
            <script type="text/javascript" src="js/utf.js" ></script>
    <p>Render in table</p>
    <div id="qrcodeTable"></div>
    <p>Render in canvas</p>
    <div id="qrcodeCanvas"></div>
    <script> 
        jQuery('#qrcodeTable').qrcode({
             render    : "table",                <!--二维码生成方式 -->
             text    : "http://www.baidu.com" , <!-- 二维码内容  -->
             width : "200",               //二维码的宽度
                     height : "200",
         });    
         jQuery('#qrcodeCanvas').qrcode({
          render    : "canvas",
             text    : "http://www.baidu.com",
             width : "200",               //二维码的宽度
                     height : "200",              //二维码的高度
                     background : "#ffffff",       //二维码的后景色
                     foreground : "#000000",        //二维码的前景色
                     src: 'img/gray.jpg'             //二维码中间的图片
         });
        
    </script>
    </body>
    </html>

    页面效果


    方法二:java生成二维码

    demo下载地址:http://download.csdn.net/download/yin767833376/10165628


    需要导入的jar包

    <!-- https://mvnrepository.com/artifact/com.google.zxing/javase -->
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>javase</artifactId>
        <version>3.3.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.3.1</version>
    </dependency>

    生成二维码的工具类,代码如下:

    package com.payplatform.util;


    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;


    import javax.imageio.ImageIO;


    import com.google.zxing.BarcodeFormat;
    import com.google.zxing.Binarizer;
    import com.google.zxing.BinaryBitmap;
    import com.google.zxing.EncodeHintType;
    import com.google.zxing.LuminanceSource;
    import com.google.zxing.MultiFormatReader;
    import com.google.zxing.MultiFormatWriter;
    import com.google.zxing.NotFoundException;
    import com.google.zxing.Result;
    import com.google.zxing.WriterException;
    import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
    import com.google.zxing.common.BitMatrix;
    import com.google.zxing.common.HybridBinarizer;
    /**
     * Google zxing二维码工具类
     * 
     * @2017年12月20日
     * @author yinxf
     *
     */
    public class QRCodeUtil {
    //二维码颜色  
        private static final int BLACK = 0xFF000000;  
        //二维码颜色  
        private static final int WHITE = 0xFFFFFFFF;  
      
        public static void main(String[] args) throws Exception {
    zxingCodeCreate("http://www.baidu.com", 300, 300, "D:/qrcode.jpg", "jpg");
    //    zxingCodeAnalyze("D:/qrcode.jpg");
    }
        /** 
         * 生成二维码
         * @param text    二维码内容
         * @param width    二维码宽 
         * @param height    二维码高 
         * @param outPutPath    二维码生成保存路径 
         * @param imageType     二维码生成格式 
         */  
        public static void zxingCodeCreate(String text, int width, int height, String outPutPath, String imageType){  
            Map<EncodeHintType, String> his = new HashMap<EncodeHintType, String>();  
            //设置编码字符集  
            his.put(EncodeHintType.CHARACTER_SET, "utf-8");  
            try {  
                //1、生成二维码  
                BitMatrix encode = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, his);  
                  
                //2、获取二维码宽高  
                int codeWidth = encode.getWidth();  
                int codeHeight = encode.getHeight();  
                  
                //3、将二维码放入缓冲流  
                BufferedImage image = new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);  
                for (int i = 0; i < codeWidth; i++) {  
                    for (int j = 0; j < codeHeight; j++) {  
                        //4、循环将二维码内容定入图片  
                        image.setRGB(i, j, encode.get(i, j) ? BLACK : WHITE);  
                    }  
                }  
                File outPutImage = new File(outPutPath);  
                //如果图片不存在创建图片  
                if(!outPutImage.exists())  
                    outPutImage.createNewFile();  
                //5、将二维码写入图片  
                ImageIO.write(image, imageType, outPutImage);  
            } catch (WriterException e) {  
                e.printStackTrace();  
                System.out.println("二维码生成失败");  
            } catch (IOException e) {  
                e.printStackTrace();  
                System.out.println("生成二维码图片失败");  
            }  
        }  
          
        /** 
         * 二维码解析 
         * @param analyzePath    二维码路径 
         * @return 
         * @throws IOException 
         */  
        @SuppressWarnings({ "rawtypes", "unchecked" })  
        public static String zxingCodeAnalyze(String analyzePath) throws Exception{  
            MultiFormatReader formatReader = new MultiFormatReader();  
            String resultStr = null;  
            try {  
                File file = new File(analyzePath);  
                if (!file.exists())  
                {  
                    return "二维码不存在";  
                }  
                BufferedImage image = ImageIO.read(file);  
                LuminanceSource source = new BufferedImageLuminanceSource(image);  
                Binarizer binarizer = new HybridBinarizer(source);    
                BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);  
                Map hints = new HashMap();  
                hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");  
                Result result = formatReader.decode(binaryBitmap, hints); 
                resultStr = result.getText();
            } catch (NotFoundException e) {  
                e.printStackTrace();  
            }    
            return resultStr;  
        }  
          
    }

    以上两种方法均已测试通过,可以直接下载demo运行,查看运行效果。

    展开全文
  • 二维码生成

    2020-07-30 23:32:04
    Java二维码生成器,既可以有图片,也可以没有图片的二维码生成器。。。。
  • 二维码生成原理及解析代码

    千次阅读 2019-06-14 17:38:19
    这里秉着好奇心,研究一下二维码生成,并尝试性写一个二维码解析源码。 一. 二维码基本知识 二维码另一个名称是QR Code(Quick Response Code),近年来在移动设备上经常使用,与传统条形码相比,可以存储更多的...

    自从大街小巷的小商小贩都开始布满了腾讯爸爸和阿里爸爸的二维码之后,我才感觉到我大天朝共享支付的优越性。最近毕业论文写的差不多了,在入职之前多学一些东西也是好的。这里秉着好奇心,研究一下二维码的生成,并尝试性写一个二维码解析源码。

    一. 二维码基本知识

    二维码另一个名称是QR Code(Quick Response Code),近年来在移动设备上经常使用,与传统条形码相比,可以存储更多的信息。二维码本质上是个密码算法,基本知识总结如下。 
    首先,二维码存在 40 种尺寸,在官方文档中,尺寸又被命名为 Version。尺寸与 Version 存在线性关系:Version 1 是 21×21 的矩阵,Version 2 是 25×25 的矩阵,每增加一个 Version,尺寸都会增加 4,故尺寸 Size 与 Version 的线性关系为:

     

    Size=(Version−1)×4Size=(Version−1)×4

     

    Version 的最大值是 40,故尺寸最大值是(40-1)*4+21 = 177,即 177 x 177 的矩阵。

    二维码结构如下图 1.1 所示: 
     
    图1.1 二维码结构 

     

    二维码的各部分都有自己的作用,基本上可被分为定位、功能数据、数据内容三部分。

    • 定位图案: 
      • Position Detection Pattern, 定位图案:用于标记二维码矩形的大小;用三个定位图案即可标识并确定一个二维码矩形的位置和方向了;
      • Separators for Position Detection Patterns, 定位图案分割器:用白边框将定位图案与其他区域区分;
      • Timing Patterns, 时序图案:用于定位,二维码如果尺寸过大,扫描时容易畸变,时序图案的作用就是防止扫描时畸变的产生;
      • Alignment Patterns, 对齐图案:只有在 Version 2 及其以上才会需要;
    • 功能数据: 
      • Format Information, 格式信息:存在于所有尺寸中,存放格式化数据;
      • Version Information, 版本信息:用于 Version 7 以上,需要预留两块 3×6 的区域存放部分版本信息;
    • 数据内容:剩余部分存储数据内容 
      • Data Code, 数据码;
      • Error Correction Code, 纠错码;

    二. 数据编码

    2.1 数据编码信息

    二维码的数据编码信息如下图 2.1, 2.2 中的列表所示: 
     
    图2.1 模式编号指示器 

     

     


     
    图2.2 字符计数指示器中的位数 

     

    上图 2.1 中,展示的是二维码支持的数据编码模式。 
    :其中中文编码模式为 1101;

    上图 2.2 中展示了不同版本(即不同尺寸)的二维码,单个编码对应二进制的位数。 
    :二维码规格说明书中,存在各式各样的编码规范表;

    图2.1, 2.2 表格具体含义,在后面的例程中会具体讲解。

    2.2 数据编码形式

    2.2.1 数字编码(Numeric Mode)

    数字编码的范围为 0~9。 
    对于数字编码,统计需要编码数字的个数是否为 3 的倍数:如果不是 3 的倍数,则剩下的 1 位或 2 位会被转为 4bits 或 8bits(十进制转二进制),每三位数字都会被编成 10bits, 12bits, 14bits,具体编码长度仍然需要二维码尺寸决定。

    2.2.2 字符编码(Alphanumeric Mode)

    字符编码的范围有:

    • 数字 0~9;
    • 大写 A~Z(无小写);
    • 几个符号$ % * + - . / 和空格。

    上述字符映射为一个索引表,如下图 2.3 所示: 

    图2.3 字符映射索引表 

     

    图中 Char 表示字符,Value 表示字符对应的索引值。 
    索引表中共 45 种对应关系,字符编码的过程,就是将每两个字符分为一组,然后转成上图 2.3 的 45 进制,再转为 11bits 的二进制结果。对于落单的一个字符,则转为 6bits 的二进制结果。 
    此外,根据上图 2.2 的设定,对不同 Version 的二维码使用 9/11/13 个二进制表示。

    注: 
    上图 2.3 中的 SP 代表空格。

    2.2.3 字节编码(Byte Mode)

    可以是 0-255 的 ISO-8859-1 字符。有些二维码的扫描器可以自动检测是否是 UTF-8 的编码。

    2.2.4 日文编码(Kanji Mode)

    日文编码同时也是双字节编码,同样也可以用于中文编码。 
    日文与中文编码流程基本相似:

    1. 首先减去一个值;
    2. 挑出差值结果的前两个 16 进制,乘以 0xC0;
    3. 加上后两个 16 进制位;
    4. 转为 13bits 编码;

    按照日文编码集 SHIFT_JIS为参照,可查询日文字符的对应编码。以“雅”与“芒”为例,转换过程如下图 2.4 所示: 
     
    图2.4 日文编码流程展示 

     

    2.2.5 其他编码

    其他类型的编码本文中不详细说明。其中包括:

    • 特殊字符集(Extended Channel Interpretation Mode):主要用于特殊的字符集,并不是所有的扫描器都支持这种编码;
    • 混合编码(Structured Append Mode):说明该二维码中包含了多种编码格式;
    • 特殊行业编码(FNC1 Mode):主要是给一些特殊的工业或行业用的,如GS1条形码等;

    2.3 数据编码示例说明

    分别用一个数字编码与字符编码的示例,说明数据编码的过程:

    2.3.1 例程1:数字编码

    问题:对于 Version 1 尺寸的二维码,纠错级别为 H,编码为:01234567 
    解析步骤:

    1. 将上述数字分为三组:012, 345, 67;
    2. 查询图 2.2 表格内容,Version 1 二维码的数字编码应转换为 10bits 的二进制数字,故将上面三组数字转为二进制分别为:012→0000001100, 345→0101011001, 67→1000011;
    3. 将三个二进制串连接起来:0000001100 0101011001 1000011;
    4. 将数字的个数转成二进制:对于数字编码,数字长度依旧用图 2.2 表格中查到的 10bits 二进制数字来表示,数字共有 8 个,故数字个数的二进制形式为:8→0000001000;
    5. 查询图 2.1 表格内容,数字编码的标志为 0001,将编码标志与步骤 4 编码结果加到步骤 3 结果之前,故最终结果为:0001 0000001000 0000001100 0101011001 1000011

    2.3.2 例程2:字符编码

    问题:对于 Version 1 尺寸的二维码,纠错级别为 H,编码为:AE-86 
    解析步骤:

    1. 在图 2.3 的字符索引表中分别找到 AE-86 五个字符的索引分别为:(10, 14, 41, 8, 6);
    2. 将五个字符两两分组:(10, 14) (41, 8) (6);
    3. 字符编码应将字符组转换为 11bits 的二进制,故上述三组字符首先转为 45 进制后再转为二进制: 
      • (10, 14):转为 45 进制:10×45+14=464;再转为 11bits 的二进制:00111010000;
      • (41, 8):转为 45 进制:41×45+8=1853;再转为 11bits 的二进制:11100111101;
      • (6):转为 45 进制:6;再转为 6bits 的二进制:000110;
    4. 将步骤 3 中得到的三个二进制结果连接起来:00111010000 11100111101 000110;
    5. 查询图 2.2 表格内容,Version 1 二维码的字符个数应转换为 9bits 的二进制数字,对于 5 个字符,二维码字符个数转为 9bits 二进制为:000000101;
    6. 查询图 2.1 表格内容,字符编码的标志为 0010,将编码标志与步骤 5 编码结果加到步骤 4 结果之前,故最终编码结果为:0010 000000101 00111010000 11100111101 000110;

    三. 结束符与补齐符

    对于结束符和补齐符,我们直接举例进行说明。 
    问题:对于 Version 1 尺寸的二维码,纠错级别为 H,以笔者的英文名作为编码:CHANDLERGENG 
    按照 2.3.2 字符编码例程进行分析,得到编码如下:

    编码 字符数 CHANDLERGENG 的编码
    0010 000001101 01000101101 00111011001 01001011110 01010010001 01011011110 10000011011

    3.1 结束符

    在需要在对于上述字符的编码,需要在最后加上结束符。结束符为连续 4 个 0 值。加上结束符后,得到的编码如下:

    编码 字符数 CHANDLERGENG 的编码 结束
    0010 000001101 01000101101 00111011001 01001011110 01010010001 01011011110 10000011011 0000

    如果所有的编码加起来不是 8 的倍数,则还需要在后面加上足够的 0。如上面一共有 83bits,所以与 8 的倍数还相差两位,故在最后加上 5 个 0,上表最终的数据变为: 
    00100000 01101010 00101101 00111011 00101001 01111001 01001000 10101101 11101000 00110110 00000000

    3.2 补齐符

    如果最后还没有达到我们最大的 Bits 数限制,则需要在编码最后加上补齐符(Padding Bytes)。 
    补齐符内容是不停重复两个字节:11101100 和 00010001。这两个二进制转成十进制,分别为 236 与17,具体不知道为什么选这两个值……关于每一个Version的每一种纠错级别的最大Bits限制,可以参看 QR Code Spec 的第35页到44页的 Table-7 一表(笔者参考的是《ISO/IEC 18004》2000版),大致如下图 3.1 所示:

     
    图3.1 二维码纠错级别的最大Bits限制(部分) 

     

    上图 3.1 中提到的 codewords,可译为码字,一个码字是一个字节。对于 Version 1 的 H 纠错级别,共需要 26 个码字,即 104bits(应该是208bits?)。现在加上用 0 补全的结束符,已经有了 88bits,故还需要补上 16 bits。补齐后的编码为:

    00100000 01101010 00101101 00111011 00101001 01111001 01001000 10101101 11101000 00110110 00000000 11101100 00010001

    以上数据即为数据码(Data Codewords)

    四. 纠错码

    前文提到了不同的纠错级别(Error Correction Code Level)。有了纠错机制,才可以使得有些二维码有了残缺也可以扫码解析出来,才可以使得二维码中心位置可以供某些商家加上对解析不必要的图标。 
    二维码一共有四种纠错级别:

    纠错水平 可被修正容量
    L 7% 码字
    M 15% 码字
    Q 25% 码字
    H 30% 码字

    二维码对数据码加上纠错码的过程,首先要对数据码进行分组,即分成不同的块(Block)。参看如上图 3.1 所示 QR Code Spec 的第35页到44页的 Table-7 中的最下方说明了分组的定义表:

     


     
    图4.1 二维码纠错级别说明(部分) 


    对于表中的最后两列的内容:

     

    • 纠错块个数(Number of error correction blocks):需要划分纠错快的个数;
    • 纠错块码字数(Error Correction Code Per Blocks):每个块中的码字个数,即有多少个字节Bytes;

    表中最下面关于 (c,k,r) 的解释:

    • c:码字总个数;
    • k:数据码个数;
    • r:纠错码容量

    注:

    • c,k,r的关系公式:c=k+2×rc=k+2×r。
    • 纠错码容量小于纠错码个数的一半

    以上图 4.1 中的 Version 5 + H 纠错机为例:图中红色方框说明共需要 4 个块(上下行各一组,每组 2 个块)。

    第一组的属性:

    • 纠错块个数 = 2:该组中有两个块;
    • (c, k, r) = (33, 11, 11):该组中每个块共有 33 个码字,其中 11 个数据码, 11×2=22 个纠错码;

    第二组的属性:

    • 纠错块个数 = 2:该组中有两个块;
    • (c, k, r) = (34, 12, 11):该组中每个块共有 34 个码字,其中 12 个数据码, 11×2=22 个纠错码;

    具体示例如下表所示,且由于使用二进制会使得表格过大,故转为范围在 0~255 的十进制。其中组 1 的每个块,都有 11 个数据码, 22 个纠错码;组 2 的每个块,都有 12 个数据码,22 个纠错码。

    数据 每个块的纠错码
    1

    2
    67 85 70 134 87 38 85 194 119 50 6 

    66 7 118 134 242 7 38 86 22 198 199
    199 11 45 115 247 241 223 229 248 154 117 236 38 6 50 17 7 236 213 87 148 235 

    177 212 76 133 75 242 238 76 195 230 189 106 248 134 76 40 154 27 195 255 117 129
    2

    2
    247 119 50 7 118 134 87 38 82 6 134 151 

    194 6 151 50 16 236 17 236 17 236 17 236
    96 60 202 182 124 157 200 134 27 129 209 182 70 85 246 230 247 70 66 247 118 134

    173 24 147 59 33 106 40 255 172 82 2 157 242 33 229 200 238 106 248 134 76 40

    二维码的纠错码主要是通过里德-所罗门纠错算法(Reed-Solomon Error Correction)实现的。

    (关于 Reed-Solomon 算法,现在此处占坑,回头研究了再写上去)

    五. 最终编码

    此时得到了数据,但还不能开始画图,因为二维码还需要将数据码与纠错码的各个字节交替放置。

    5.1 穿插放置

    继续以第四章中给出的示例为例,给出其穿插放置的过程。

    5.1.1 数据码穿插放置

    第四章示例中的数据码如下表所示:

    块数                      
    块1 67 85 70 134 87 38 85 194 119 50 6
    块2 66 7 118 134 242 7 38 86 22 198 199
    块3 247 119 50 7 118 134 87 38 82 6 134
    块4 194 6 151 50 16 236 17 236 17 236 17

    提取每一列数据:

    • 第一列:67, 66, 247, 194;
    • 第二列:85, 7, 119, 6;
    • ……
    • 第十一列:6, 199, 134, 17;
    • 第十二列:151, 236;

    将上述十二列的数据拼在一起:67, 66, 247, 194, 85, 7, 119, 6,…, 6, 199, 134, 17, 151, 236。

    纠错码如下表所示:

    块数                      
    块1 199 11 45 115 247 241 223 229 248 154 117
    块2 177 212 76 133 75 242 238 76 195 230 189
    块3 96 60 202 182 124 157 200 134 27 129 209
    块4 173 24 147 59 33 106 40 255 172 82 2

    同样的方法,将 22 列数据放在一起:199, 177, 96, 173, 11, 212, 60, 24, …, 148, 117, 118, 76, 235, 129, 134, 40。

    上述部分即为二维码的数据区。

    5.2 剩余位 (Remainder Bits)

    对于某些 Version 的二维码,得到上面的数据区结果长度依旧不足,需要加上最后的剩余位。比如对于 Version 5 + H 纠错等级的二维码,剩余位需要加 7bits,即加 7 个 0。参看 QR Code Spec 的 Table-1 一表即可查询不同 Version 的剩余位信息,如下图 5.1 所示:
     
    图5.1 不同 Version 的剩余位 

     

    六. 二维码的绘制

    终于讲到二维码绘制过程了,绘制的过程按照顺序对图 1.1 中各个重要部分依次讲解。

    6.1 定位图案 (Position Detection Pattern)

    首先在二维码的三个角上绘制定位图案。定位图案与尺寸大小无关,一定是一个 7×7 的矩阵。如下图 6.1 所示:
     
    图6.1 定位图案 (Position Detection Pattern) 

     

    6.2 对齐图案 (Alignment Pattern)

    然后绘制对齐图案。对齐图案与尺寸大小无关,一定是一个 5×5 的矩阵。如下图 6.2 所示:
     
    图6.2 对齐图案 (Alignment Pattern) 

     

    对齐图案绘制的位置,可参看 QR Code Spec 的 Table-E.1 一表查询,部分内容如下图 6.3 所示:
     
    图6.3 对齐图案位置索引表(部分) 

     

    下图 6.4 是上述表格中 Version 8 的一个例子,对于 Version 8 的二维码,行列值在 6, 24, 42 的几个点都会有对齐图案。

     


     
    图6.4 对齐图案例程 1 

     

    下图 6.5 是最近我老妈怂恿我用支付宝抢红包时给我发来的二维码,该二维码中只有一个对齐图案, 故 Version 应在 V2——V6 之间。

     


     
    图6.5 对齐图案例程 2 

     

    6.3 时序图案 (Timing Pattern)

    时序图案是两条连接三个定位图案的线,如下图 6.6 所示: 
     
    图6.6 时序图案例程 1 

     

    依旧拿支付宝红包的二维码为例,其时序图案如图 6.7 所示:
     
    图6.7 时序图案例程 2 


    这里写图片描述

     

    6.4 格式信息

    格式信息如下图 6.8 所示: 
     
    图6.8 格式信息 

     

    格式信息在定位图案周围分布,由于定位图案个数固定为 3 个,且大小固定,故格式信息也是一个固定 15bits 的信息。每个 bit 的位置如下图 6.9 所示:(注:图中的 Dark Module 是固定永远出现的
     
    图6.9 格式信息位置 

     

    15bits 中数据,按照 5bits 的数据位 + 10bits 纠错位的顺序排列:

    • 数据位占 5bits:其中 2bits 用于表示使用的纠错等级 (Error Correction Level),3bits 用于表示使用的蒙版 (Mask) 类别;
    • 纠错位占 10bits:主要通过 BCH Code 计算;

    为了减少扫描后图像识别的困难,最后还需要将 15bits 与 101010000010010 做异或 XOR 操作。因为我们在原格式信息中可能存在太多的 0 值(如纠错级别为 00,蒙版 Mask 为 000),使得格式信息全部为白色,这将增加分析图像的困难。

    纠错等级的编码如下图 6.10 的表格所示:
     
    图6.10 纠错等级编码 

     

    关于蒙版图案的生成,在后文 6.7 中具体说明。格式信息的示例如下:

    假设存在纠错等级为 M(对应 00),蒙版图案对应 000,5bits 的数据位为 00101,10bits 的纠错位为 0011011100: 
    则生成了在异或操作之前的 bits 序列为:001010011011100 
     101010000010010 做异或 XOR 操作,即得到最终格式信息:100000011001110

    6.5 版本信息 (Version Information)

    对于 Version 7 及其以上的二维码,需要加入版本信息。如下图 6.11 蓝色部分所示:
     
    图6.11 版本信息 

     

    版本信息依附在定位图案周围,故大小固定为 18bits。水平竖直方向的填充方式如下图 6.12 所示:
     
    图6.12 版本信息填充方式 

     

    18bits 的版本信息中,前 6bits 为版本号 (Version Number),后 12bits 为纠错码 (BCH Bits)。示例如下:

    假设存在一个 Version 为 7 的二维码(对应 6bits 版本号为 000111),其纠错码为 110010010100; 
    则版本信息图案中的应填充的数据为:000111110010010100

    6.6 数据码与纠错码

    此后即可填充第五章得到的数据内容了。填充的思想如下图 6.13 的 Version 3 二维码所示,从二维码的右下角开始,沿着红线进行填充,遇到非数据区域,则绕开或跳过。

     


     
    图6.13 二维码数据填充(原始版) 

     

    然而这样难以理解,我们可以将其分为许多小模块,然后将许多小模块串连在一起,如下图 6.14 所示(截取自 QR Code Spec 的图 15):

    图6.14 二维码数据填充 

     

    小模块可以分为常规模块和非常规模块,每个模块的容量都为 8。常规情况下,小模块都为宽度为 2 的竖直小矩阵,按照方向将 8bits 的码字填充在内。非常规情况下,模块会产生变形。 
    填充方式上图 6.14,图中深色区域(如 D1 区域)填充数据码,白色区域(如 E15 区域)填充纠错码。遍历顺序依旧从最右下角的 D1 区域开始,按照蛇形方向(D1→D2→…→D28→E1→E2→…→E16→剩余码)进行小模块的填充,并从右向左交替着上下移动。下面给出若干填充原则:

    原则 1:无论数据的填充方向是向上还是向下,常规模块(即 8bits 数据全在两列内)的排列顺序应是从右向左,如下图 6.15所示;
     
    图6.15 常规模块内的填充方向 

     

    原则 2:每个码字的最高有效位(即第7个bit)应置于第一个可用位。对于向上填充的方向,最高有效位应该占据模块的右下角;向下填充的方向,最高有效位占据模块的右上方。 
    注:对于某些模块(以下图 6.17 为例),如果前一个模块在右边模块的列内部结束,则该模块成为不规则模块,且与常规模块相比,原本填充方向向上时,最高位应该在右上角,此时则变为左下角; 
    原则 3:当一个模块的两列同时遇到对齐图案或时序图案的水平边界时,它将继续在图案的上方或下方延续; 
    原则 4:当模块到达区域的上下边界(包括二维码的上下边界、格式信息、版本信息或分隔符)时,码字中任何剩余 bits 将填充在左边的下一列中,且填充方向反转;如下图 6.16 中的两个模块遇到了二维码的上边界,则方向发生变化;

     
    图6.16 非常规模块填充方向的改变(举例于 QR Code Spec 图 13) 

     

    原则 5:当模块的右一列遇到对齐图案,或遇到被版本信息占据的区域时,数据位会沿着对齐图案或版本信息旁边的一列继续填充,并形成一个不规则模块。如果当前模块填充结束之前,下一个的两列都可用,则下一个码字的最高有效位应该放在单列中,如下图 6.17 所示:
     
    图6.17 模块单列填充 

     

    6.7 蒙版图案

    按照上述思路即可将二维码填充完毕。但是那些点并不均衡,如果出现了大面积的空白或黑块,扫描识别会十分困难,所以按照在前文 6.4 中格式信息的处理思路,对整个图像与蒙版进行蒙版操作(Masking),蒙版操作即为异或 XOR 操作。 
    二维码又 8 种蒙版可以使用,如下图 6.18 所示,公式也在图中说明。蒙版只会和数据区进行异或操作,不会影响与格式信息相关的功能区。 
    注:选择一个合适的蒙版也是有一定算法的。

    蒙版图案如下图 6.18 所示,对应的产生公式与蒙版 ID 如下图 6.19 的表格所示:
     
    图6.18 蒙版图案 


     
    图6.19 蒙版图案产生公式

     

    蒙版操作的过程与对比图如下图 6.20 所示,图中最上层是没有经过蒙版操作的原始二维码,其中存在大量黑色区域,难以后续的分析识别。经过两种不同蒙版的处理,可以看到最后生成的二维码变的更加混乱,容易识别。 
     
    图6.20 蒙版操作示例 

     

    蒙版操作之后,得到的二维码即为最终我们平常看到的结果。

    七. 源码

    笔者原本准备用 C++ 与 OpenCV 写一个二维码解析程序,现在学了二维码的原理后,发现好难。另外网上关于二维码解析与生成的程序基本都是用 Python 写的,笔者又想找个合适机会学习一下 Python,所以这段时间就准备从二维码入手,学习一下 Python 的基础~

    源码及解析笔者会随学习的进度持续更新~

    八. 后记

    笔者学习完毕二维码内容后不禁感叹,二维码规则的制定当真是凝聚了多少研究者的心血。学无止境,在知识的海洋中,当真是需要抱着敬畏之心和谦卑的态度,才能体会到这片海洋的浩瀚。 
    研究二维码的过程十分有趣,学到了不少东西,后续过程中笔者会持续更新对二维码的学习心得体会~

     

    展开全文
  • 二维码生成原理

    万次阅读 2018-03-20 12:07:04
    QR码生成原理(一) 一、什么是QR码 QR码属于矩阵式二维码中的一个种类,由DENSO(日本电装)公司开发,由JIS和ISO将其标准化。QR码的样子其实在很多场合已经能够被看到了,我这还是贴个图展示一下: 这个图如果被正确...

    QR码生成原理(一)

    一、什么是QR码

    QR码属于矩阵式二维码中的一个种类,由DENSO(日本电装)公司开发,由JIS和ISO将其标准化。QR码的样子其实在很多场合已经能够被看到了,我这还是贴个图展示一下:

    这个图如果被正确解码,应该看到我的名字和邮箱。

    二、QR码的特点

    说到QR码的特点,一是高速读取(QR就是取自“Quick Response”的首字母),对读取速度的体验源自于我手机上的一个软件,象上面贴出的码图,通过摄像头从拍摄到解码到显示内容也就三秒左右,对摄像的角度也没有什么要求;

    二是高容量、高密度;理论上内容经过压缩处理后可以存7089个数字,4296 个字母和数字混合字符,2953个8位字节数据,1817个汉字;

    三是支持纠错处理;纠错处理相对复杂,目前我还没有深入了解,按照QR码的标准文档说明,QR码的纠错分为4个级别,分别是:

    • level L : 最大 7% 的错误能够被纠正;
    • level M : 最大 15% 的错误能够被纠正;
    • level Q : 最大 25% 的错误能够被纠正;
    • level H : 最大 30% 的错误能够被纠正;

    四是结构化;看似无规则的图形,其实对区域有严格的定义,下图就是一个模式2、版本1的QR图结构(关于QR码的”模式”、”版本”将在后面进行介绍):

    在上图21*21的矩阵中,黑白的区域在QR码规范中被指定为固定的位置,称为寻像图形(finder pattern) 和 定位图形(timing pattern)。寻像图形和定位图形用来帮助解码程序确定图形中具体符号的坐标。

    黄色的区域用来保存被编码的数据内容以及纠错信息码。

    蓝色的区域,用来标识纠错的级别(也就是Level L到Level H)和所谓的”Mask pattern”,这个区域被称为“格式化信息”(format information)。

    五是扩展能力。QR码的Structure Append特点,使一个QR码可以分解成多个QR码,反之,也可以将多个QR码的数据组合到一个QR码中来

     

    三、QR码的模式和版本

    前面提到过QR码的模式(Model)和版本(Version)。QR码分为Model1和Model2两种模式,Model1是对QR的初始定义,Model2是对Model1的扩展,目前使用较为普遍的是Model2,本文的所有说明也仅用于Model2。

    QR图的大小(size)被定义为版本(Version),版本号从1到40。版本1就是一个21*21的矩阵,每增加一个版本号,矩阵的大小就增加4个模块(Module),因此,版本40就是一个177*177的矩阵。(版本越高,意味着存储的内容越多,纠错能力也越强)。

    三、QR码支持的编码内容

    QR码支持编码的内容包括纯数字、数字和字符混合编码、8位字节码和包含汉字在内的多字节字符。其中:

    数字:每三个为一组压缩成10bit。

    字母数字混合:每两个为一组,压缩成11bit。                                  

    8bit字节数据:无压缩直接保存。

    多字节字符:每一个字符被压缩成13bit。

    QR码编码原理(二)

    编码就是把常见的数字、字符等转换成QR码的方法。说具体的编码之前,先说一下QR码的最大容量问题。

    一、最大容量

    QR码的最大容量取决于选择的版本、纠错级别和编码模式(Mode:数字、字符、多字节字符等)。以版本1、纠错级别为Level Q的QR码为例,可以存储27个纯数字,或17个字母数字混合字符或11个8bit字节数据。如果要存储同样多的内容同时提高纠错级别,则需要采用更高的版本。版本1~9 数据容量、纠错码容量对照如下表:

    (version) (error correcting level) (count of data code words) count of EC code words (numeric) (alphanumeric) 8bit
    1 L 19 7 41 25 17
    M 16 10 34 20 14
    Q 13 13 27 16 11
    H 9 17 17 10 7
    2 L 34 10 77 47 32
    M 28 16 63 38 26
    Q 22 22 48 29 20
    H 16 28 34 20 14
    3 L 55 15 127 77 53
    M 44 26 101 61 42
    Q 34 36 77 47 32
    H 26 44 58 35 24
    4 L 80 20 187 114 78
    M 64 36 149 90 62
    Q 48 52 111 67 46
    H 36 64 82 50 34
    5 L 108 26 255 154 106
    M 86 48 202 122 84
    Q 62 72 144 87 60
    H 46 88 106 64 44
    6 L 136 36 322 195 134
    M 108 64 255 154 106
    Q 76 96 175 108 74
    H 60 112 139 84 58
    7 L 156 40 370 224 154
    M 124 72 293 178 122
    Q 88 108 207 125 86
    H 66 130 154 93 64
    8 L 194 48 461 279 192
    M 154 88 365 221 152
    Q 110 132 259 157 108
    H 86 156 202 122 84
    9 L 232 60 552 335 230
    M 182 110 432 262 180
    Q 132 160 312 189 130
    H 100 192 235 143 98

    如果要了解更详细的QR码容量信息,可以到电装的网站去看看http://www.denso-wave.com/qrcode/vertable1-e.html

     

    下面,就举例说明将“ABCDE123”转换成为版本1、Level H的QR码转换方法。

    二、模式标识符(Mode Indicator)

    QR码的模式(Mode)就是前文提到的数字、字符、8bit 字节码、多字节码等。对于不同的模式,都有对应的模式标识符(Mode Indicator)来帮助解码程序进行匹配,模式标识符是4bit的二进制数:

    1、数字模式(numeric mode ): 0001
    2、混合字符模式(alphanumeric mode) : 0010
    3、8bit byte mode: 0100
    4、日本汉字(KANJI mode) : 1000

    5、中国汉字(GB2312):1101

    由于示例文本串是混合字符,因此将选择alphanumeric mode,其标识码为:0010

    三、文本串计数标识符(Character count indicator)

    文本串计数标识符用来存储源内容字符串的长度,在版本1-9的QR码中,文本串长度标识符自身的长度被定义为:
    数字 : 10bit 
    混合字符 : 9bit
    8bit 字节码 : 8bit
    多字节码 : 8bit

    在本例中,源文本串的长度为8个字符,混合字符的长度为9bit,因此将字符个数8编码为9位二进制表示:000001000

    加上混合字符模式标识码,总的编码为0010 000001000

    四、数据内容编码

     1、数字模式下的编码

    在数字模式下,数据被限制为3个数字一段,分成若干段。如:”123456” 将分成”123” 和 “456”,分别被编码成10bit的二进制数。“123”的10bit二进制表示法为:0001111011,实际上就是二进制的123。

    当数据的长度不足3个数字时,如果只有1个数字则用4bit,如果有2个数字就用7个bit来表示。
    如:”9876”被分成”987”和”6”两段,因此被表示为”1111011011 0110”。

    2、混合字符模式下的编码

    混合字符模式编码,其字符对照表如下:

     0 
     A   10 
     K   20 
     U   30 
     +   40 
    1 1
    B 11
    L 21
    V 31
    - 41
    2 2
    C 12
    M 22
    W 32
    . 42
    3 3
    D 13
    N 23
    X 33
    / 43
    4 4
    E 14
    O 24
    Y 34
    : 44
    5 5
    F 15
    P 25
    Z 35
    6 6
    G 16
    Q 26
    [sp] 36
    7 7
    H 17
    R 27
    $ 37
    8 8
    I 18
    S 28
    % 38
    9 9
    J 19
    T 29
    * 3

     

    编码方式为:

    源码被分成两个字符一段,如下所示,每段的第一个字符乘上45,再用第二个数字相加。因此每段变成了11bit的2进制码,如果字符个数只有1个,则用6bit表示。

     

    示例: 



    “AB” “CD” “E1” “23”


    45*10+11 45*12+13 45*14+1 45*2+3


    461 553 631 93
    0010 000001000 00111001101 01000101001 01001110111 00001011101

    3、8bit字节数据不经编码转换直接保存。

    五、编码终止符(Terminator)

    如果编码后的字符长度不足当前版本和纠错级别所存储的容量,则在后续补”0000”,如果容量已满则无需添加终止符。此时得到的编码串为:

    0010 000001000 00111001101 01000101001 01001110111 000010111010000
    六、编成8bit码字(Code words)

    将以上的编码再按8bit一组,形成码字(code words):

     00100000 01000001 11001101 01000101 00101001 11011100 00101110 10000
    如果尾部数据不足8bit,则在尾部充0:

    00100000 01000001 11001101 01000101 00101001 11011100 00101110 10000000
    如果编码后的数据不足版本及纠错级别的最大容量,则在尾部补充 “11101100” 和 “00010001”,直到全部填满。最后,版本1、Level H下的”ABCDE123” 的QR码是:

    00100000 01000001 11001101 01000101 00101001 11011100 00101110 1000000011101100

    十进制表示法为:

    32 65 205 69 41 220 46 128 236

    QR码编码原理三(日本汉字和中文编码)

    一、日本汉字(KANJI)是两个字节表示的字符码,编码的方式是将其转换为13字节的二进制码制。

    转换步骤为:

    1、对于JIS值为8140(hex) 到9FFC(hex)之间字符:

    a)将待转换的JIS值减去8140(hex);

    b)将高位字节乘以C0(hex);

    c)将b)步骤生成的数据加上低位字节;

    d)将结果转换为13位二进制串。

    2、对于JIS值为E040(hex)到EBBF(hex)之间的字符:

    a)将待转换的JIS值减去C140(hex);

    b)将高位字节乘以C0(hex);

    c)将b)步骤生成的数据加上低位字节;

    d)将结果转换为13位二进制串。

     

    二、中文汉字的与日文汉字转换步骤相似:

    1、对于第一字节为0xA1~0xAA之间,第二字节在0xA1~0xFE之间字符:

    a)第一字节减去0xA1;

    b)上一步结果乘以0x60;

    c)第二字节减去0xA1;

    d)将b)步骤的结果加上c步骤的结果;

    e)将结果转换为13位二进制串。

    1、对于第一字节为0xB0~0xFA之间,第二字节在0xA1~0xFE之间字符:

    a)第一字节减去0xA6;

    b)上一步结果乘以0x60;

    c)第二字节减去0xA1;

    d)将b)步骤的结果加上c步骤的结果;

    e)将结果转换为13位二进制串。

    一、使用jquery-qrcode生成二维码

    先简单说一下jquery-qrcode,这个开源的三方库(可以从https://github.com/jeromeetienne/jquery-qrcode 获取),

    qrcode.js 是实现二维码数据计算的核心类,

    jquery.qrcode.js 是把它用jquery方式封装起来的,用它来实现图形渲染,其实就是画图(支持canvas和table两种方式)


    支持的功能主要有:

     

    Js代码  收藏代码

    1. text     : https://github.com/jeromeetienne/jquery-qrcode  //设置二维码内容  

     

    Js代码  收藏代码

    1. render   : “canvas”,//设置渲染方式  
    2. width       : 256,     //设置宽度  
    3. height      : 256,     //设置高度  
    4. typeNumber  : -1,      //计算模式  
    5. correctLevel    : QRErrorCorrectLevel.H,//纠错等级  
    6. background      : ”#ffffff”,//背景颜色  
    7. foreground      : ”#000000” //前景颜色  


     

    使用方式非常简单

     

    Js代码  收藏代码

    1. jQuery(‘#output’).qrcode({width:200,height:200,correctLevel:0,text:content});  


     

     经过简单实践,

    使用canvas方式渲染性能还是非常不错的,但是如果用table方式,性能不太理想,特别是IE9以下的浏览器,所以需要自行优化一下渲染table的方式,这里就不细述了。

     

    二、JS生成中文二维码

    其实上面的js有一个小小的缺点,就是默认不支持中文。

    这跟js的机制有关系,jquery-qrcode这个库是采用 charCodeAt() 这个方式进行编码转换的,

    而这个方法默认会获取它的 Unicode 编码,一般的解码器都是采用UTF-8, ISO-8859-1等方式,

    英文是没有问题,如果是中文,一般情况下Unicode是UTF-16实现,长度2位,而UTF-8编码是3位,这样二维码的编解码就不匹配了。

    解决方式当然是,在二维码编码前把字符串转换成UTF-8,具体代码如下:

     

    Js代码  收藏代码

    1. function utf16to8(str) {  
    2.     var out, i, len, c;  
    3.     out = ”“;  
    4.     len = str.length;  
    5.     for(i = 0; i < len; i++) {  
    6.     c = str.charCodeAt(i);  
    7.     if ((c >= 0x0001) && (c <= 0x007F)) {  
    8.         out += str.charAt(i);  
    9.     } else if (c > 0x07FF) {  
    10.         out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));  
    11.         out += String.fromCharCode(0x80 | ((c >>  6) & 0x3F));  
    12.         out += String.fromCharCode(0x80 | ((c >>  0) & 0x3F));  
    13.     } else {  
    14.         out += String.fromCharCode(0xC0 | ((c >>  6) & 0x1F));  
    15.         out += String.fromCharCode(0x80 | ((c >>  0) & 0x3F));  
    16.     }  
    17.     }  
    18.     return out;  

    三、参考

    https://github.com/jeromeetienne/jquery-qrcode

    http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt

    二维码生成原理


                </div>
    

    转自骆定华的博客:http://blog.csdn.net/jason_ldh/article/details/11801355

    展开全文
  • Android生成自定义二维码

    万次阅读 多人点赞 2019-11-13 10:20:38
    前面说过两种二维码扫描方式,现在说二维码生成,使用Google开源库Zxing,项目地址:https://github.com/ZBar/ZBar,我们只需要里面的jar包:core:x.x.x.jar,建议用core:3.3.0。 1.引入jar包 app build....

    本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 ChaoYoung 即可关注。

        前面说过两种二维码扫描方式,现在说二维码生成,使用Google开源库Zxing,Zxing的项目地址:https://github.com/ZBar/ZBar,我们只需要里面的jar包:core:x.x.x.jar,建议用core:3.3.0。

    划重点:

    • 一般二维码
    • 彩色二维码
    • 带logo二维码或带logo的彩色二维码
    • 黑色色块用图片代替的二维码

    1.引入jar包
    • app build.gradle中加入依赖
    dependencies {
        ...
        implementation 'com.google.zxing:core:3.3.0'
    }
    
    • 如果依赖同步失败,下载jar包导入libs下,并在app build.gradle中加入如下代码并Sync Now
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    

    2.How ?

      先看简单的二维码生成

    /**
     * 生成简单二维码
     *
     * @param content                字符串内容
     * @param width                  二维码宽度
     * @param height                 二维码高度
     * @param character_set          编码方式(一般使用UTF-8)
     * @param error_correction_level 容错率 L:7% M:15% Q:25% H:35%
     * @param margin                 空白边距(二维码与边框的空白区域)
     * @param color_black            黑色色块
     * @param color_white            白色色块
     * @return BitMap
     */
    public static Bitmap createQRCodeBitmap(String content, int width,int height,
                                            String character_set,String error_correction_level,
                                            String margin,int color_black, int color_white) {
        // 字符串内容判空
        if (TextUtils.isEmpty(content)) {
            return null;
        }
        // 宽和高>=0
        if (width < 0 || height < 0) {
            return null;
        }
        try {
            /** 1.设置二维码相关配置 */
            Hashtable<EncodeHintType, String> hints = new Hashtable<>();
            // 字符转码格式设置
            if (!TextUtils.isEmpty(character_set)) {
                hints.put(EncodeHintType.CHARACTER_SET, character_set);
            }
            // 容错率设置
            if (!TextUtils.isEmpty(error_correction_level)) {
                    hints.put(EncodeHintType.ERROR_CORRECTION, error_correction_level);
                }
            // 空白边距设置
            if (!TextUtils.isEmpty(margin)) {
                hints.put(EncodeHintType.MARGIN, margin);
            }
            /** 2.将配置参数传入到QRCodeWriter的encode方法生成BitMatrix(位矩阵)对象 */
            BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
    
            /** 3.创建像素数组,并根据BitMatrix(位矩阵)对象为数组元素赋颜色值 */
            int[] pixels = new int[width * height];
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    //bitMatrix.get(x,y)方法返回true是黑色色块,false是白色色块
                    if (bitMatrix.get(x, y)) {
                        pixels[y * width + x] = color_black;//黑色色块像素设置
                    } else {
                        pixels[y * width + x] = color_white;// 白色色块像素设置
                    }
                }
            }
            /** 4.创建Bitmap对象,根据像素数组设置Bitmap每个像素点的颜色值,并返回Bitmap对象 */
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
            return bitmap;
        } catch (WriterException e) {
            e.printStackTrace();
            return null;
        }
     }
    

    主要步骤:

    • 设置二维码相关配置,包括传入的二维码长宽、容错率和空白边距大小。
    • 将配置参数传入到QRCodeWriter的encode方法并生成BitMatrix(位矩阵)对象。
    • 位矩阵对象中bitMatrix.get(x, y)方法可判断是黑色色块还是白色色块,根据不同色块给数组元素赋我们传入的颜色值
    • 根据像素数组每个像素点的颜色值创建Bitmap对象并返回,即二维码

    主要参数介绍:

    • character_set
      字符集/字符转码格式,通常使用UTF-8,格式不对可能导致乱码。传null时,默认使用 “ISO-8859-1”

    • error_correction_level
      容错率,也就是纠错水平,二维码破损一部分也能扫码就归功于容错率,容错率可分为L、 M、 Q、 H四个等级,其分别占比为:L:7% M:15% Q:25% H:35%。传null时,默认使用 “L”
      当然容错率越高,二维码能存储的内容也随之变小。

    • margin
      二维码和边框的空白区域宽度

    • color_black、color_white
      黑色色块和白素色块,我们常见的二维码一般是黑白两色的,也就是这两个色块,可以自己传入两个颜色,so,彩色二维码不就实现了。

    调用生成:

    createQRCodeBitmap(content, 800, 800,"UTF-8","H", "1", Color.BLACK, Color.WHITE);
    

              

     黑色色块用绿色(Color.GREEN)、蓝色(Color.BLUE)、黄色(Color.YELLOW)…:

    createQRCodeBitmap(content, 800, 800,"UTF-8","H", "1", Color.GREEN, Color.WHITE);
    ...
    

      


    3.添加logo

        二维码生成当然少不了添加logo了,添加logo就是图片合成,将logo图片以一定比例合成在原二维码图片上。
        直接看代码

    /**
     * 向二维码中间添加logo图片(图片合成)
     *
     * @param srcBitmap 原图片(生成的简单二维码图片)
     * @param logoBitmap logo图片
     * @param logoPercent 百分比 (用于调整logo图片在原图片中的显示大小, 取值范围[0,1] )                    
     * @return
     */
     private static Bitmap addLogo(Bitmap srcBitmap,  Bitmap logoBitmap, float logoPercent){
        if(srcBitmap == null){
            return null;
        }
        if(logoBitmap == null){
            return srcBitmap;
        }
        //传值不合法时使用0.2F
        if(logoPercent < 0F || logoPercent > 1F){
            logoPercent = 0.2F;
        }
    
        /** 1. 获取原图片和Logo图片各自的宽、高值 */
        int srcWidth = srcBitmap.getWidth();
        int srcHeight = srcBitmap.getHeight();
        int logoWidth = logoBitmap.getWidth();
        int logoHeight = logoBitmap.getHeight();
    
        /** 2. 计算画布缩放的宽高比 */
        float scaleWidth = srcWidth * logoPercent / logoWidth;
        float scaleHeight = srcHeight * logoPercent / logoHeight;
    
        /** 3. 使用Canvas绘制,合成图片 */
        Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawBitmap(srcBitmap, 0, 0, null);
        canvas.scale(scaleWidth, scaleHeight, srcWidth/2, srcHeight/2);
        canvas.drawBitmap(logoBitmap, srcWidth/2 - logoWidth/2, srcHeight/2 - logoHeight/2, null);
    
        return bitmap;
    }
    

    参数说明:

    • srcBitmap:之前生成的简单二维码图片
    • logoBitmap:logo图片
    • logoPercent :logo图片所占的百分比,建议使用0.2F,百分比过大可能导致二维码扫描失败。

        这里就是一个简单的图片合成,首先获取原图片和logo图片各自的宽高,通过我们传入的百分比计算画布缩放的宽高比,然后使用Canvas绘制,合成最终带logo的二维码。

        为了方便,我们在最开始生成简单二维码的方法中传入logo图片和百分比,在生成Bitmap时添加logo,如下:

    /**
     *
     * @param content                字符串内容
     * @param width                  二维码宽度
     * @param height                 二维码高度
     * @param character_set          编码方式(一般使用UTF-8)
     * @param error_correction_level 容错率 L:7% M:15% Q:25% H:35%
     * @param margin                 空白边距(二维码与边框的空白区域)
     * @param color_black            黑色色块
     * @param color_white            白色色块
     * @param logoBitmap             logo图片
     * @param logoPercent            logo所占百分比
     * @return
     */
     public static Bitmap createQRCodeBitmap(String content, int width, int height, String character_set, 
                                             String error_correction_level,String margin, int color_black, 
                                             int color_white,Bitmap logoBitmap, float logoPercent) {
        // 字符串内容判空
        if (TextUtils.isEmpty(content)) {
            return null;
        }
        // 宽和高>=0
        if (width < 0 || height < 0) {
            return null;
        }
        try {
            /** 1.设置二维码相关配置,生成BitMatrix(位矩阵)对象 */
            Hashtable<EncodeHintType, String> hints = new Hashtable<>();
            // 字符转码格式设置
            if (!TextUtils.isEmpty(character_set)) {
                hints.put(EncodeHintType.CHARACTER_SET, character_set);
            }
            // 容错率设置
            if (!TextUtils.isEmpty(error_correction_level)) {
                hints.put(EncodeHintType.ERROR_CORRECTION, error_correction_level);
            }
            // 空白边距设置
            if (!TextUtils.isEmpty(margin)) {
                hints.put(EncodeHintType.MARGIN, margin);
            }
            /** 2.将配置参数传入到QRCodeWriter的encode方法生成BitMatrix(位矩阵)对象 */
            BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
    
            /** 3.创建像素数组,并根据BitMatrix(位矩阵)对象为数组元素赋颜色值 */
            int[] pixels = new int[width * height];
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    //bitMatrix.get(x,y)方法返回true是黑色色块,false是白色色块
                    if (bitMatrix.get(x, y)) {
                        pixels[y * width + x] = color_black;//黑色色块像素设置
                    } else {
                        pixels[y * width + x] = color_white;// 白色色块像素设置
                    }
                }
            }
    
            /** 4.创建Bitmap对象,根据像素数组设置Bitmap每个像素点的颜色值,并返回Bitmap对象 */
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
    
            /** 5.为二维码添加logo图标 */
            if(logoBitmap != null){
                return addLogo(bitmap, logoBitmap, logoPercent);
            }
            return bitmap;
        } catch (WriterException e) {
            e.printStackTrace();
            return null;
        }
    }
    

    调用:

    createQRCodeBitmap(content, 800, 800,"UTF-8","H", "1", Color.BLACK, Color.WHITE,logoBitmap,0.2F);
    

    logo图片需要转为Bitmap格式传入,将项目资源下的图片转为Bitmap可使用如下方法

    Resources res = getResources();
    Bitmap logoBitmap= BitmapFactory.decodeResource(res,R.mipmap.logo);
    

    效果图:
     

    4.使用图片代替黑色色块

    什么意思呢,看图
     

        就是将二维码的黑色色块使用图片代替,视觉效果就是你的图片在黑色色块部分被显示。
    实现方法:
        首先通过Bitmap的createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)方法从当前位图,按一定的比例创建一个新的位图,该方法需要传入四个参数,第一个参数就是当前图片,第二个和第三个参数是新位图长宽(这里传入二维码的长宽,保证图的大小一样),最后一个参数直接传false。

    Bitmap bitmap_black = Bitmap.createScaledBitmap(bitmap_black, width, height, false);
    

        创建好新位图后,在根据BitMatrix(位矩阵)对象为数组元素赋颜色值时,将黑色色块换为新位图的像素。

    if (bitMatrix.get(x, y)) {// 黑色色块像素设置
        if(bitmap_black != null) {//图片不为null,则将黑色色块换为新位图的像素。
           pixels[y * width + x] = bitmap_black.getPixel(x, y);
        } else {
           pixels[y * width + x] = color_black;
        }
    } else {
         pixels[y * width + x] = color_white;// 白色色块像素设置
    }
    

    注:尽量选用深色图片,否则影响扫描精度。

    代码如下:

    /**
     *  生成自定义二维码
     *
     * @param content                字符串内容
     * @param width                  二维码宽度
     * @param height                 二维码高度
     * @param character_set          编码方式(一般使用UTF-8)
     * @param error_correction_level 容错率 L:7% M:15% Q:25% H:35%
     * @param margin                 空白边距(二维码与边框的空白区域)
     * @param color_black            黑色色块
     * @param color_white            白色色块
     * @param logoBitmap             logo图片(传null时不添加logo)
     * @param logoPercent            logo所占百分比
     * @param bitmap_black           用来代替黑色色块的图片(传null时不代替)
     * @return
     */
    public static Bitmap createQRCodeBitmap(String content, int width, int height, String character_set, String error_correction_level,
                                                String margin, int color_black, int color_white, Bitmap logoBitmap, float logoPercent, Bitmap bitmap_black) {
        // 字符串内容判空
        if (TextUtils.isEmpty(content)) {
            return null;
        }
        // 宽和高>=0
        if (width < 0 || height < 0) {
            return null;
        }
        try {
            /** 1.设置二维码相关配置,生成BitMatrix(位矩阵)对象 */
            Hashtable<EncodeHintType, String> hints = new Hashtable<>();
            // 字符转码格式设置
            if (!TextUtils.isEmpty(character_set)) {
                hints.put(EncodeHintType.CHARACTER_SET, character_set);
            }
            // 容错率设置
            if (!TextUtils.isEmpty(error_correction_level)) {
                    hints.put(EncodeHintType.ERROR_CORRECTION, error_correction_level);
            }
            // 空白边距设置
            if (!TextUtils.isEmpty(margin)) {
                hints.put(EncodeHintType.MARGIN, margin);
            }
            /** 2.将配置参数传入到QRCodeWriter的encode方法生成BitMatrix(位矩阵)对象 */
            BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
    
            /** 3.创建像素数组,并根据BitMatrix(位矩阵)对象为数组元素赋颜色值 */
            if (bitmap_black != null) {
                //从当前位图按一定的比例创建一个新的位图
                bitmap_black = Bitmap.createScaledBitmap(bitmap_black, width, height, false);
            }
            int[] pixels = new int[width * height];
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    //bitMatrix.get(x,y)方法返回true是黑色色块,false是白色色块
                    if (bitMatrix.get(x, y)) {// 黑色色块像素设置
                        if (bitmap_black != null) {//图片不为null,则将黑色色块换为新位图的像素。
                            pixels[y * width + x] = bitmap_black.getPixel(x, y);
                        } else {
                            pixels[y * width + x] = color_black;
                        }
                    } else {
                        pixels[y * width + x] = color_white;// 白色色块像素设置
                    }
                }
            }
    
            /** 4.创建Bitmap对象,根据像素数组设置Bitmap每个像素点的颜色值,并返回Bitmap对象 */
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
    
            /** 5.为二维码添加logo图标 */
            if (logoBitmap != null) {
                return addLogo(bitmap, logoBitmap, logoPercent);
            }
            return bitmap;
        } catch (WriterException e) {
            e.printStackTrace();
            return null;
        }
    }
    

        源码已上传至GitHub:https://github.com/yangxch/GenerateQRCode
        生成二维码方法我放到了一个工具类,调用时如果不需要logo或不需要用图片代替黑色色块,传nulll 即可。
        当然图片不能直接写死,可以拍照或相册选择,生成二维码还可保存至手机或分享给他人,实现方式后续更新,敬请关注。
                 

    更新如下:
    Android生成二维码–拍照或从相册选取图片
    Android生成二维码–保存和分享二维码图片



    微信扫一扫下方二维码即可关注我的公众号

    展开全文
  • 二维码生成

    2017-01-20 14:06:47
    1.配置maven,jar包 com.google.zxing core 3.3.0 com.google.zxing javase 3.3.0 2.代码 package other; import java.awt.image.BufferedImage; import java.io.File;...import j
  • 在线二维码生成技术

    千次阅读 2018-12-21 17:09:44
    注:本文用以解决实际生产需求,而非深入学习研究所用,如需深入请接入:QR Code API 一、引入pom依赖 &lt;dependency&gt; &lt;groupId&gt;com.google.zxing&...${go...
  • 二维码生成器和二维码扫描器

    千次阅读 2016-07-13 00:14:41
    二维码生成器二维码扫描 一)二维码生成器 下载demo: 1.导入库文件( libqrencode)  配置:开启这个HAVE_CONFIG_H宏定义 如下图  build settings--> Preprocessor Macros ->添加 “HAVE_CONFIG...
  • Java实现二维码生成 Google-Zxing

    万次阅读 多人点赞 2020-06-23 17:24:49
    本篇文章将介绍java中如何生成二维码二维码的展示主要包括两各方面:1.直接生成图片(直接生成图片不需要web程序,maven工程即可) 2.将二维码转为字节数组,然后在web页面显示。web项目的目录结构以前面的一篇...
  • QRCode二维码生成组件(珍藏版)

    千次下载 热门讨论 2020-07-30 23:33:23
    现在网上很多应用都是用二维码来分享网址或者其它的信息。尤其在移动领域,二维码更是有很大的应用场景。因为项目的需要,需要在网站中增加一个生成二维码分析网址的功能,在谷歌大幅度抽筋的情况下无奈使用百度。...
  • 二维码生成 C++

    千次下载 热门讨论 2020-07-24 23:31:35
    二维码生成 C++ 用MFC Dialog 写的程序,源码非本人,本人做了些修改, 可以根据输入的文本生成任意大小的二维码, 代码体积小,好用
  • 上面一篇文章说到了用 js 实现二维码生成,下面来说说在后台生成,前端展示的方式。 引入 jar 包 &amp;amp;lt;!-- 条形码、二维码生成 --&amp;amp;gt; &amp;amp;lt;dependency&amp;amp;gt; &...
  • c#二维码生成

    千次下载 热门讨论 2020-07-30 23:30:34
    ASP.NET 二维码生成源码,Web界面,输入需要转换的文字或字符串,生成对应的二维码。代码精简,函数封装,便于复用。
  • .NET 二维码生成(ThoughtWorks.QRCode)源代码

    千次下载 热门讨论 2020-07-27 23:33:10
    .NET 二维码生成(ThoughtWorks.QRCode)源代码,源码介绍博客:http://www.cnblogs.com/jys509/p/4592539.html
  • 现在的互联网时代,二维码处处可见,这次我们研究下二维码生成插件qrious 二维码百科: 二维码又称二维条码,常见的二维码为QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比...
  • WIFI无线网络二维码生成

    热门讨论 2020-07-30 23:30:36
    WIFI 无线网络二维码生成器 输入无线网络的WIFI SSID,密码,选择类型, 即可以生成二维码, 这个二维码,用手机一扫,即可以生成登陆,方便各餐馆,方便客人,免得个个进来都问WIFI密码
  • 1. 使用github上C++二维码生成程序源码在Qt5.5.1(QWidget)上实现的二维码生成程序源码。 (github源码网址https://github.com/Hackaroth/QRCODE) 2. 二维码生成源码部分修改了一些使用Qt运行出现的问题及一些代码错误...
  • Android之二维码生成与扫描

    万次阅读 2018-10-17 18:02:20
    前言月底离开公司,准备月底休息一段时间,之前每天忙于工作,甚至连一些感兴趣的东西都没有研究过,趁着这段时间可以好好享受一下,今天这篇文章主要描述二维码生成与扫描,使用目前流行的Zxing,底部会给出整个...
  • VB制作二维码生成程序源码
  • 玩转Android之二维码生成与识别

    万次阅读 多人点赞 2016-05-26 15:29:27
    二维码,我们也称作QRCode,QR表示quick response即快速响应,在很多App中我们都能见到二维码的身影,最常见的莫过于微信了。那么今天我们就来看看怎么样在我们自己的App中集成二维码的扫描与生成功能。OK,废话不多...
1 2 3 4 5 ... 20
收藏数 82,840
精华内容 33,136
关键字:

二维码生成