首页 > 编程语言 >QR二维码生成器源码(中间可插入小图片)

QR二维码生成器源码(中间可插入小图片)

时间:2024-01-15 10:46:08浏览次数:43  
标签:QR img int 生成器 二维码 源码 new 图片

QR二维码生成器源码(中间可插入小图片)

 

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

我之前做了一个使用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, 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、第二个要注意的地方是图片大小

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

为了插入图片的完整性,我们选择在最中间插入,而且长宽建议为整个二维码的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,img,int,生成器,二维码,源码,new,图片
From: https://www.cnblogs.com/sexintercourse/p/17964918

相关文章

  • Django 源码分析(一):命令分析
    Django源码分析(一):命令分析说明:本部分主要介绍Django程序在开发中常用的命令是如何控制生成的进行解析;1.分析入口启动命令:pythonmanage.pyrunserver127.0.0.1:8000项目启动的时候执行的manage.py脚本,相关代码如下:"""Django'scommand-lineutilityforadministrat......
  • Django 源码分析(二):wsgi & asgi
    Django源码分析(二):wsgi&asgi说明:上一节主要讲述了django项目的启动,后期主要会根据django请求的生命周期进行分析;参考文章:https://zhuanlan.zhihu.com/p/95942024参考文章:https://zhuanlan.zhihu.com/p/269456318附:生命周期参考图;第一步:浏览器发起请求补充:第一步和第......
  • Django 源码(三)-应用 & 中间件 & 配置文件
    Django源码(三)-应用&中间件&配置文件本部分主要是在为程序启动时候加载应用以及中间件的信息;1.应用的加载在程序启动的部分,我们分析到程序执行的时候都会执行一个setup()函数,相关的内容可以看之前的章节的部分;defsetup(set_prefix=True):"""Configurethes......
  • 源生成器:根据需要自动生成机械重复代码
    title:源生成器:根据需要自动生成机械重复代码date:2022-02-02tags:-C#-.NET-Roslyn前言本文概述了利用.NETCompilerPlatform(“Roslyn”)SDK附带的源生成器(SourceGenerator)自动生成机械重复的代码。关于这部分的基础入门知识可以在MSDN[1]学到。本文默认已经有一......
  • Promise超详细源码解读
    说到promise,相信大家在日常开发中都经常使用到,它是我们异步操作中必不可少的一部分,可以让代码看起来变得更好理解;我曾在技术社区看过许多关于promise底层原理的文章,大概原理明白,这次,我准备系统的分析实现源码并记录下来,本文将一行行代码去分析最后附加流程图和总结,希望这能对你......
  • 【设计模式】策略模式——策略模式在JDK源码中的应用
    策略模式在JDK中具有广泛的应用,本文只讨论最常见的应用。RejectedExecutionHandler在线程池使用有界队列并且最大线程数不为Integer.MAX_VALUE的时候,一旦task数量达到临界点,新的task添加到线程池的时候就会出现问题,ThreadPoolExecutor的构造方法中参数最多的方法中最后一个参数就是......
  • PyTorch项目源码学习(3)——Module类初步学习
    torch.nn.ModuleModule类是用户使用torch来自定义网络模型的基础,Module的设计要求包括低耦合性,高模块化等等。一般来说,计算图上所有的子图都可以是Module的子类,包括卷积,激活函数,损失函数节点以及相邻节点组成的集合等等,注意这里的关键词是“节点”,Module族类在计算图中主要起到搭......
  • 基于SpringBoot+Vue的OA办公系统设计实现(源码+lw+部署文档+讲解等)
    (文章目录)前言:heartpulse:博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌:heartpulse:......
  • Feign源码解析5:loadbalancer
    背景经过前面几篇的理解,我们大致梳理清楚了FeignClient的创建、Feign调用的大体流程,本篇会深入Feign调用中涉及的另一个重要组件:loadbalancer,了解loadbalancer在feign调用中的职责,再追溯其是如何创建的。在讲之前,我先提个重点,本文章的前期是引用了nacos依赖且开启了如下选项,启用......
  • 性能篇:深入源码解析和性能测试arraylist和LinkedList差异!
    嗨,大家好,我是小米!今天我们要谈论的是Java中两个常用的集合类:ArrayList和LinkedList。大家都知道,这两者在新增和删除元素的操作上有一些差异,那么它们究竟在性能上有何表现呢?我们通过深入源码解析和性能测试来一探究竟!ArrayList新增元素到末尾这是最常见的新增元素操作,我们使用......