栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java实现二维码,验证码详细总结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java实现二维码,验证码详细总结

一.概述

1)各类码图如二维码,验证码此类码图的生成,实际原理就是后台通过某种规则去生成图片流,将图片流返回给前端后,前端进行显示。后续内容将展开BufferedImage的实际应用。
2)此篇文章来自我的有道云笔记,耗时一周左右的摸索总结测试,以及看了相关的其他博主所写,根据自己的测试和探索,最终编写了自己的工具类。地址:我的有道云笔记链接

二.BufferedImage

1)是码图相关的一种非常重要的类,在各类码最终会转成此对象,返回到前端。
2)BufferImagTool是一个处理图片资源操作图片的类。下述将展示相关操作。

背景操作

没有在案例中使用到的方法,都有备注,阅读即可明白。

①案例一
如何通过此工具类生成一张全红的图呢?

BufferImagTool tool = new BufferImagTool();
try {
    //1.设置背景色,画板的最终背景色要在画板初始化之前设置
    //2.初始化画板
    //3.获取最终的图流
    BufferedImage image = tool.setBackgroundColor(Color.red)
                        .initBufferImage(200, 200, BufferImagTool.TYPE_INT_BGR)
                        .getImage();
    ImageIO.write(image,"JPEG",response.getOutputStream());
} catch (Exception e) {
    e.printStackTrace();
}

②案例二

BufferImagTool tool = new BufferImagTool();
try {
    //1.设置背景色
    BufferedImage image = tool.setBackgroundColor(Color.red)
                        //2.初始化画板
                        .initBufferImage(200, 200, BufferImagTool.TYPE_INT_BGR)
                        //3.设置备用的背景色
                        .setBackgroundColor(Color.blue)
                        //4.左上角插入一块背景
                        .insertBackGround(0f,0f,0.3f,0.3f)
                        //5.左下角插入一块背景
                        .insertBackGround(0f,0.7f,0.3f,0.3f)
                        //6.右上角插入一块背景
                        .insertBackGround(0.7f,0f,0.3f,0.3f)
                        //7.右下角插入一块背景
                        .insertBackGround(0.7f,0.7f,0.3f,0.3f)
                        .getImage();
    ImageIO.write(image,"JPEG",response.getOutputStream());
} catch (Exception e) {
    e.printStackTrace();
}
线操作

①案例一

BufferImagTool tool = new BufferImagTool();
try {
    //1.设置背景色
    BufferedImage image = tool.setBackgroundColor(Color.red)
                        //2.初始化画板
                        .initBufferImage(200, 200, BufferImagTool.TYPE_INT_BGR)
                        //3.设置当前备用的线条颜色
                        .setLineColor(Color.BLACK)
                        //4.从左上角画到右下角,取消随机色
                        .insertOneLine(0f,0f,1f,1f,false)
                        //5.设置当前的备用颜色
                        .setLineColor(Color.white)
                        //6.从左下角到右上角,取消随机色
                        .insertOneLine(0f,1f,1f,0f,false)
                        .getImage();
    ImageIO.write(image,"JPEG",response.getOutputStream());
} catch (Exception e) {
    e.printStackTrace();
}

②案例二
干扰线

BufferImagTool tool = new BufferImagTool();
try {
    //1.设置背景色
    BufferedImage image = tool.setBackgroundColor(Color.white)
                        //2.初始化画板
                        .initBufferImage(200, 200, BufferImagTool.TYPE_INT_BGR)
                        //3.使用随机色插入线条,位置也是随机的
                        .insertLines(50)
                        .getImage();
    ImageIO.write(image,"JPEG",response.getOutputStream());
} catch (Exception e) {
    e.printStackTrace();
}
字符串操作

BufferImagTool tool = new BufferImagTool();
try {
    //1.设置背景色
    BufferedImage image = tool.setBackgroundColor(Color.white)
                        .initBufferImage(200,200,BufferImagTool.TYPE_INT_BGR)
                        .insertString(0.5f,0.5f,"hello world")
                        .getImage();
    ImageIO.write(image,"JPEG",response.getOutputStream());
} catch (Exception e) {
    e.printStackTrace();
}
前端内容

前端写法都相似,通过get请求将后台数据流直接交给dom组件处理即可。

hello world

我的画板
... data(){ return { src1:'/test/d01', } }, methods:{ update1(){ //1.需要设置一个随机参数来改变这个URL,否则H5不会重新渲染图片 this.src1 = this.src1+"?time="+Math.random(); }, ...
三.验证码

在上述的BufferImagTool的应用背景下,验证码的生成显得非常简单。
案例:

BufferImagTool tool = new BufferImagTool();
try {
    //1.设置背景色
    BufferedImage image = tool.initBufferImage(100,100,BufferImagTool.TYPE_INT_BGR)
                            //2.设置需要的编码字符数量
                            .setVeri_CodeNum(5)
                            //3.设置干扰线
                            .insertLines(50,true)
                            //4.设置字体大小
                            .setFontStyle(30)
                            //5.插入编码
                            .insertVeriCode()
                            .getImage();
    System.out.println("code = " + tool.getVeri_Code());


    ImageIO.write(image,"JPEG",response.getOutputStream());
} catch (Exception e) {
    e.printStackTrace();
}
四.二维码

二维码相对来说更复杂,需要使用到谷歌的依赖包,
此处使用了另一个自己封装的工具类QRCodeTool。
后续有二维码的大量详细说明

简要概述

1)二维码的种类非常多,此封装类把写到的二维码类型都测试过,没有通过的类型,请不要使用。
2)二维码的初始化需要一个type来制定是哪种类型二维码
3)二维码的示例比较简洁,具体的细节写在最后一章的工具类总结里



    com.google.zxing
    core
    3.3.0



    com.google.zxing
    javase
    3.3.0

①案例一

QRCodeTool tool = new QRCodeTool();
BufferedImage qrCode = tool.setQrType(QRCodeTool.QRTYPE_QR_CODE)
                            .setQrCodeVersion(1)
                            .getQRCode();
ImageIO.write(qrCode,"JPEG",response.getOutputStream());

②案例二
插入图片,插入自定义内容,此处注意点较多,都写在代码注释里

QRCodeTool tool = new QRCodeTool();
BufferedImage qrCode = tool.setQrType(QRCodeTool.QRTYPE_QR_CODE)
                            .setQrCodeVersion(1)
                            .getQRCode();
ImageIO.write(qrCode,"JPEG",response.getOutputStream());

BufferImagTool btool1 = new BufferImagTool();
BufferImagTool btool2 = new BufferImagTool();

BufferedImage imge1 = btool1.initBufferImage(new File(pathHelper.getResourcesPath()+"/img/1.jpg"))
                    .getImage();
                    
BufferedImage imge2 = btool2
                    .initBufferImage(qrCode)
                    .insertImage(imge1,0.33f,0.33f,0.33f,0.33f)
                    .getImage();
ImageIO.write(qrCode,"JPEG",response.getOutputStream());
什么是二维码

不要以为二维码就是你认知中的二维码,实际上他的类型和应用超出你的想象!!!

各类二维码及其实现

下面展示的是使用谷歌依赖后,各类二维码的生成关键语句。

01.AZTEC

①Aztec Code是1995年,由Hand HeldProducts公司的Dr. Andrew Longacre设计。它是一种高容量的二维条形码格式。它可以对ASCII和扩展ASCII码进行编码。当使用最高容量和25%的纠错级别的時候,Aztec可以对3000个字符或者3750个数字进行编码
Aztec的矩阵大小在15 X 15和151 X 151之间变化。每个最小单位非黑即白。它独特的位于正中的模式识别标志和安置算法使Aztec看起来像个旋涡一样。
Aztec打印解决方案允许用户选择大小和纠错级别。一共有36中不同的格式供选择,此外还有19种纠错级别可供选择,默认纠错级别是5级23%。高纠错级别意味着更少的数据容量和更小的误码机会。效果如下:

②通常用于:机票和其他旅行文档以及汽车登记文档。还可以用于医院的患者识别,或识别药物、样本以及与特定患者相关的其他物品。

③代码示例

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
//2.不要设置容错
configs.put(EncodeHintType.AZTEC_LAYERS,-1);
BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));
02.Codabar

①Codabar是由Monarch Marking Systems在1972年研制的条码。它是在"2 of 5"后早期阶段引入的条码。注意他的编码集是有限的!!!

②代码示例
没有特殊点,需要注意是有限字符

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj,
             new MatrixToImageConfig(Color.BLACK.getRGB(), 
             Color.WHITE.getRGB()));
03.CODE_39

①CODE 39是 Intermec公司在1975年研制成功的。包括数字、字母和一些符号在内,条码共包括43个字符。

②场景:由于可以处理字母,CODE 39在工业领域必不可少,用于汽车、电子等工厂自动化行业。在美国,汽车工业行动组织已经对其进行了标准化。

③代码示例,无特殊配置

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, 
		new MatrixToImageConfig(Color.BLACK.getRGB(),
		 Color.WHITE.getRGB()));
04.CODE_93

①Code 93码与Code 39码的字符集相同,但93码的密度要比39码高,因而在面积不足的情况下,可以用93码代替39码。它没有自校验功能,为了确保数据安全性,采用了双校验字符,其可靠性比39条码还要高.

②场景:用于汽车、电子等工厂自动化行业,内部管理
③代码示例,无特殊配置

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));
05.CODE_128

①CODE128码是1981年引入的一种高密度条码,CODE128 码可表示从 ASCII 0 到ASCII 127 共128个字符,故称128码。其中包含了数字、字母和符号字符。
②场景: CODE128码是广泛应用在企业内部管理、生产流程、物流控制系统方面的条码码制,由于其优良的特性在管理信息系统的设计中被广泛使用,CODE128码是应用最广泛的条码码制之一
③代码示例,无特殊配置

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));
06.DATA_MATRIX

①Data Matrix原名Data code,由美国国际资料公司(International Data Matrix, 简称ID Matrix)于1989年发明。Data Matrix又可分为ECC000-140与ECC200两种类型,ECC000-140具有多种不同等级的错误纠正功能,而ECC200则透过Reed-Solomon演算法产生多项式计算出错误纠正码,其尺寸可以依需求印成不同大小,但采用的错误纠正码应与尺寸配合,由于其演算法较为容易,且尺寸较有弹性,故一般以ECC200较为普遍。

②场景 : 用途详见 https://baike.baidu.com/item/Datamatrix/2016699?fr=aladdin#8
③代码实例,无特殊配置

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));
07.EAN_8 和 EAN_13

①EAN码是国际物品编码协会制定的一种商品用条码,通用于全世界。EAN码符号有标准版(EAN-13)和缩短版(EAN-8)两种。标准版表示13位数字,又称为EAN13码,缩短版表示8位数字,又称EAN8。两种条码的最后一位为校验位,由前面的12位或7位数字计算得出。
EAN码(英文全称:European Article Number)由前缀码、厂商识别码、商品项目代码和校验码组成。前缀码是国际EAN组织标识各会员组织的代码,我国为690-695;厂商代码是EAN编码组织在EAN分配的前缀码的基础上分配给厂商的代码;商品项目代码由厂商自行编码;校验码为了校验代码的正确性。在编制商品项目代码时,厂商必须遵守商品编码的基本原则:对同一商品项目的商品必须编制相同的商品项目代码;对不同的商品项目必须编制不同的商品项目代码。保证商品项目与其标识代码一一对应,即一个商品项目只有一个代码,一个代码只标识一个商品项目.我国的通用商品条码与其等效。我们日常购买的商品包装上所印的条码一般就是EAN码。另外,图书和期刊作为特殊的商品也采用了EAN13表示ISBN和ISSN。前缀977被用于期刊号ISSN,图书号ISBN用978为前缀,我国被分配使用7开头的ISBN号,因此我国出版社出版的图书上的条码全部为9787开头 .
EAN-13码:由13个数字组成,为EAN的标准编码型式。
EAN- 8码:由8个数字组成,属EAN的简易编码型式。

②用途
所有在市场流通的商品
③代码实例,无特殊配置

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));
08.ITF

①ITF条码,又称交叉二五条码

②用途
主要用于运输包装,是印刷条件较差,不允许印刷EAN-13和UPC-A条码时应选用的一种条码

③代码实例,无特殊配置

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));
09.MAXICODE

①1980年代晚期,美国知名的UPS(United Parcel Service)快递公司认知到利用机器辨读资讯可有效改善作业效率、提高服务品质而研发的条码。

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));
10.PDF417

①PDF417二维条码是一种堆叠式二维条码,目前应用最为广泛。PDF417条码是由美国SYMBOL公司发明的,PDF(Portable Data File)意思是“便携数据文件”。组成条码的每一个条码字符由4个条和4个空共17个模块构成,故称为PDF417条码。 PDF417条码需要有417解码功能的条码阅读器才能识别。PDF417条码最大的优势在于其庞大的数据容量和极强的纠错能力
②用途
二维条码PDF417做为一种新的信息存储和传递技术,从诞生之始就受到了国际社会的广泛关注。经过几年的努力,现已广泛地应用在国防、公共安全、交通运输、医疗保健、工业、商业、金融、海关及政府管理等领域。

③代码实例,有特殊点

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
//含特殊配置
//是否使用紧凑模式
configs.put(EncodeHintType.PDF417_COMPACT, true);
//使用什么压缩模式
configs.put(EncodeHintType.PDF417_COMPACTION, Compaction.AUTO);
//最小和最大行数和列数
configs.put(EncodeHintType.PDF417_DIMENSIONS,
            new Dimensions(1,10, 1, 10));

BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));
11.RSS_14 And RSS_EXPANDED

①RSS系列条码是一维码和二维码的组合码。
②场景:非常小的产品项目
③代码实例,测试失败。待定

12.UPC-A,UPC_E,UPC_EAN_EXTENSION

①UPC-A 条码是美国较常用也较被广泛认可的条码类型。它主要用于零售行业,例如杂货店。UPC-A 由统一杂货产品代码委员会与 IBM 联合开发,自 1974 年开始使用。首例被扫描的 UPC 条码是一包箭牌果味口香糖。这包口香糖后来被陈列在史密森尼博物馆。
UPC-A 条码由 12 位组成。开头是个单数字系统字符,指示条码的分类方式:普通产品、加权项目、药物、优惠等。后面是个五位的制造商代码,接下来是个五位的产品代码,最后是个校验位。每位由不同宽度的两个条纹和两个空格的独有标识样式表示。除了数字之外,不能使用任何字母或其他特殊字符。

UPC-E 条码是一款通用产品条码,在美国应用较广泛。UPC-E 是标准尺寸的 UPC-A 数字条码的压缩版,用于国内的杂货店和其他零售场所。压缩版主要用于包装上没有足够面积显示全尺寸 UPC-A 条码的小尺寸产品。
UPC-E 条码只有UPC-A 的一半大小,即6 位。除此之外,这两种条码的结构相似,开头一位指示被扫描产品的类型(普通产品、优惠、加权产品等),后面是制造商代码、产品代码以及保证准确性的校验位。UPC-E 的尺寸之所以减小是因为它删掉了全尺寸代码中的所有额外的零:即产品代码前和制造商代码后面的零。

②用途
零售行业

③代码实例
三胞胎

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
BitMatrix qrObj = null;
try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));
13.QR_CODE

①QR Code码,是由Denso公司于1994年9月研制的一种矩阵二维码符号,它具有一维条码及其它二维条码所具有的信息容量大、可靠性高、可表示汉字及图象多种文字信息、保密防伪性强等优点。最常见的二维码。
②用途
客户信息,个人信息,信息载体
③代码实例

//1.所有类型二维码的通用配置
HashMap configs = new HashMap<>();
//1.1 定义字符集
configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
//1.2 设置容错等级
//configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
configs.put(EncodeHintType.MARGIN,10);

//1.AZTEC编码相关的配置,固定值
//2.不要设置容错
BitMatrix qrObj = null;
//3.指定纠错版本,使用中等级
configs.put(EncodeHintType.ERROR_CORRECTION,ErrorCorrectionLevel.M);
//4.指定编码的二维码版本,版本越高,二维码容量越大,相反解析越小
configs.put(EncodeHintType.QR_VERSION, qrCodeVersion);

try {
    qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
} catch (WriterException e) {
    e.printStackTrace();
}
//3.2 采用黑白两色
BufferedImage img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));

④自定义部分
下面这张图是QRCODE的编码结构图。

1)黑白的区域在QR码规范中被指定为固定的位置,称为寻像图形(finder pattern) 和 定位图形(timing pattern)。寻像图形和定位图形用来帮助解码程序确定图形中具体符号的坐标。
2)黄色的区域用来保存被编码的数据内容以及纠错信息码。
3)蓝色的区域,用来标识纠错的级别(也就是Level L到Level H)和所谓的"Mask pattern",这个区域被称为“格式化信息”(format information)。
4)五是扩展能力。QR码的Structure Append特点,使一个QR码可以分解成多个QR码,反之,也可以将多个QR码的数据组合到一个QR码

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

五.工具类总结

整体风格实现set进行属性的连续配置调用。
所有的方法都写了注释

BufferImageTool
package codeserver.tool;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Random;


public class BufferImagTool {

    
    public static final int TYPE_CUSTOM = 0;

    
    public static final int TYPE_INT_RGB = 1;

    
    public static final int TYPE_INT_ARGB = 2;

    
    public static final int TYPE_INT_ARGB_PRE = 3;

    
    public static final int TYPE_INT_BGR = 4;

    
    public static final int TYPE_3BYTE_BGR = 5;

    
    public static final int TYPE_4BYTE_ABGR = 6;

    
    public static final int TYPE_4BYTE_ABGR_PRE = 7;

    
    public static final int TYPE_USHORT_565_RGB = 8;

    
    public static final int TYPE_USHORT_555_RGB = 9;

    
    public static final int TYPE_BYTE_GRAY = 10;

    
    public static final int TYPE_USHORT_GRAY = 11;

    
    public static final int TYPE_BYTE_BINARY = 12;

    
    public static final int TYPE_BYTE_INDEXED = 13;




    
    private BufferedImage image;
    private Random random=new Random();

    
    private Color fontColor=new Color(0,0,0);

    private Font fontStyle=new Font("Times New Roman", Font.ROMAN_baseLINE, 18);

    
    private Color lineColor=new Color(0,0,0);

    
    private Color backgroundColor=new Color(255,255,255);

    
    public static final float DEFAULT_POSITIONX=0.1f;
    
    public static final float DEFAULT_POSITIONY=0.8f;
    
    public static final boolean DEFAULT_MUTILCOLOR=true;
    
    public static final int DEFAULT_LINENUM=20;



    
    private String veri_ReferString="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

    
    private int veri_CodeNum = 4;

    
    private String veri_Code;



    
    public BufferedImage getImage() {
        return image;
    }

    
    public String getVeri_Code() {
        return veri_Code;
    }

    
    public BufferImagTool setFontColor(int r,int g,int b) {
        r=r<0?0:r>255?255:r;
        g=g<0?0:g>255?255:g;
        b=b<0?0:b>255?255:b;
        this.fontColor = new Color(r,g,b);
        return this;
    }

    
    public BufferImagTool setFontColor(Color color) {
        this.fontColor = color;
        return this;
    }

    
    public BufferImagTool setBackgroundColor(Color backgroundColor) {
        this.backgroundColor = backgroundColor;
        return this;
    }

    
    public BufferImagTool setBackgroundColor(int r,int g,int b) {
        r=r<0?0:r>255?255:r;
        g=g<0?0:g>255?255:g;
        b=b<0?0:b>255?255:b;
        this.backgroundColor = new Color(r,g,b);
        return this;
    }

    
    public BufferImagTool setLineColor(int r,int g,int b) {
        r=r<0?0:r>255?255:r;
        g=g<0?0:g>255?255:g;
        b=b<0?0:b>255?255:b;
        this.lineColor = new Color(r,g,b);
        return this;
    }

    
    public BufferImagTool setLineColor(Color color) {
        this.lineColor = color;
        return this;
    }

    
    public BufferImagTool setFontStyle(Font fontStyle) {
        this.fontStyle = fontStyle;
        return this;
    }

    
    public BufferImagTool setFontStyle(String name,int style,int size) {
        this.fontStyle = new Font(name,style,size);
        return this;
    }

    
    public BufferImagTool setFontStyle(String name,int size) {
        this.fontStyle = new Font(name,Font.ROMAN_baseLINE,size);
        return this;
    }

    
    public BufferImagTool setFontStyle(int size) {
        this.fontStyle = new Font("Times New Roman",Font.ROMAN_baseLINE,size);
        return this;
    }


    
    public BufferImagTool setVeri_ReferString(String veri_ReferString) {
        veri_ReferString=veri_ReferString.trim();
        if(!veri_ReferString.equals("") && veri_ReferString!=null){
            this.veri_ReferString = veri_ReferString;
        }
        return this;
    }

    
    public BufferImagTool setVeri_CodeNum(int veri_CodeNum) {
        if(veri_CodeNum>0){
            this.veri_CodeNum = veri_CodeNum;
        }
        if(veri_CodeNum>veri_ReferString.length()){
            this.veri_CodeNum=veri_ReferString.length();
        }
        return this;
    }

    
    public static BufferedImage getBufferedImage(File input) throws IOException {
        return ImageIO.read(input);
    }

    
    public static BufferedImage getBufferedImage(InputStream stream) throws IOException {
        return ImageIO.read(stream);
    }

    
    public static BufferedImage getBufferedImage(URL url) throws IOException {
        return ImageIO.read(url);
    }

    
    public static BufferedImage getBufferedImage(ImageInputStream stream) throws IOException {
        return ImageIO.read(stream);
    }


    
    public BufferImagTool initBufferImage(BufferedImage image) throws IOException{
        if(image==null) throw new IOException("创建BufferedImage时,入参File对象不能为空!!!");
        this.image=image;
        return this;
    }
    
    public BufferImagTool initBufferImage(File input) throws IOException{
        if(input==null) throw new IOException("创建BufferImage时,入参File对象不能为空!!!");
        BufferedImage image = ImageIO.read(input);
        this.image=image;
        return this;
    }

    
    public BufferImagTool initBufferImage(InputStream stream) throws IOException{
        if(stream==null) throw new IOException("创建BufferImage时,入参InputStream对象不能为空!!!");
        BufferedImage image = ImageIO.read(stream);
        this.image=image;
        return this;
    }

    
    public BufferImagTool initBufferImage(URL url) throws IOException{
        if(url==null) throw new IOException("创建BufferImage时,入参InputStream对象不能为空!!!");
        BufferedImage image = ImageIO.read(url);
        this.image=image;
        return this;
    }

    
    public BufferImagTool initBufferImage(ImageInputStream stream) throws IOException{
        if(stream==null) throw new IOException("创建BufferImage时,入参ImageInputStream对象不能为空!!!");
        BufferedImage image = ImageIO.read(stream);
        this.image=image;
        return this;
    }

    
    public BufferImagTool initBufferImage(int width,int height,int imageType) throws Exception{
        if(width<0) throw new Exception("初始化图像时宽度必须大于0");
        if(height<0) throw new Exception("初始化图像时高度必须大于0");
        if(imageType<0 || imageType>13) throw new Exception("初始化图像时类型请设置在0~13之间");
        this.image = new BufferedImage(width, height, imageType);
        //1.画出画布
        Graphics pen = image.getGraphics();
        pen.setColor(backgroundColor);
        pen.fillRect(0,0,image.getWidth(),image.getHeight());
        return this;
    }


    
    public BufferImagTool insertString(float positionX,float positionY,String content) throws Exception{
        if(positionX<0 || positionX>1) positionX=DEFAULT_POSITIONX;
        if(positionY<0 || positionY>1) positionY=DEFAULT_POSITIONY;
        if(image==null){
            throw new Exception("请先初始化图像在进行插入操作!!!");
        }
        if(content!=null && !content.trim().equals("")){
            Graphics pen = image.getGraphics();
            //1.设置字体样式
            pen.setFont(fontStyle);
            //2.设置字体颜色
            pen.setColor(fontColor);
            pen.drawString(content,(int)(image.getWidth()*positionX),(int)(image.getHeight()*positionY));
            pen.dispose();
        }
        return this;
    }

    
    public BufferImagTool insertString(String content) throws Exception{
        insertString(DEFAULT_POSITIONX,DEFAULT_POSITIONY,content);
        return this;
    }

    
    public BufferImagTool insertBackGround(float percentX,float percentY,float percentWidth,float percentHeight) throws Exception{
        if(image==null) throw new Exception("请先初始化图像在进行插入操作!!!");
        percentX=Math.abs(percentX);
        percentY=Math.abs(percentY);
        percentWidth=Math.abs(percentWidth);
        percentHeight=Math.abs(percentHeight);
        if(percentX>1) throw new Exception("起始坐标X不能超过1!!!");
        if(percentY>1) throw new Exception("起始坐标Y不能超过1!!!");
        if(percentWidth>1) throw new Exception("宽度百分比不能不能超过1!!!");
        if(percentHeight>1) throw new Exception("高度百分比不能不能超过1!!!");

        Graphics pen = image.getGraphics();
        int width = image.getWidth();
        int height = image.getHeight();

        pen.setColor(backgroundColor);
        //1.画笔填充背景色
        pen.fillRect((int)(width*percentX),(int)(height*percentY)
                    ,(int)(width*percentWidth),(int)(height*percentHeight));
        return  this;
    }

    
    public BufferImagTool insertBackGround() throws Exception{
        if(image==null) throw new Exception("请先初始化图像在进行插入操作!!!");
        insertBackGround(0,0,image.getWidth(),image.getHeight());
        return this;
    }




    
    public BufferImagTool insertOneLine(float percentX1,float percentY1,float percentX2,float percentY2,boolean usingMutilColor) throws Exception{
        percentX1=Math.abs(percentX1);
        percentY1=Math.abs(percentY1);
        percentX2=Math.abs(percentX2);
        percentY2=Math.abs(percentY2);
        if(percentX1>1) throw new Exception("画线的时候起始位置X1坐标百分比不能大于1!!!");
        if(percentY1>1) throw new Exception("画线的时候起始位置Y1坐标百分比不能大于1!!!");
        if(percentX2>1) throw new Exception("画线的时候终点位置X2坐标百分比不能大于1!!!");
        if(percentY1>1) throw new Exception("画线的时候终点位置Y2坐标百分比不能大于1!!!");
        if(image==null) throw new Exception("请先初始化图像在进行插入操作!!!");

        Graphics pen = image.getGraphics();
        int width = image.getWidth();
        int height = image.getHeight();
        if(usingMutilColor){
            pen.setColor(getRandomColor());
        }else{
            pen.setColor(lineColor);
        }
        pen.drawLine((int)(width*percentX1),(int)(height*percentY1),
                (int)(width*percentX2),(int)(height*percentY2));
        pen.dispose();
        return this;
    }

    
    public BufferImagTool insertOneLine(float percentX1,float percentY1,float percentX2,float percentY2) throws Exception{
        insertOneLine(percentX1,percentY1,percentX2,percentY2,DEFAULT_MUTILCOLOR);
        return this;
    }

    
    public BufferImagTool insertLines(int lineNum,boolean usingMutilColor) throws Exception{
        if(lineNum<=0) lineNum=DEFAULT_LINENUM;
        if(image==null){
            throw new Exception("请先初始化图像在进行插入操作!!!");
        }

        Graphics pen = image.getGraphics();
        int width = image.getWidth();
        int height = image.getHeight();

        for (int i = 0; i 1) throw new Exception("x轴的起始位置和长度的百分比之和不能大于1!!!");
        if((percentY+percentHeight)>1) throw new Exception("y轴的起始位置和长度的百分比之和不能大于1!!!");

        int x=(int)(this.image.getWidth()*percentX);
        int y=(int)(this.image.getHeight()*percentY);
        int width=(int)(this.image.getWidth()*percentWight);
        int height=(int)(this.image.getHeight()*percentHeight);

        //1.resultImage是最终需要的图片,大小和当前图片大小一致,类型使用TYPE_INT_BGR来保证颜色的正确渲染
        BufferedImage resultImage = new BufferedImage(this.image.getWidth(),
                                                    this.image.getHeight(),
                                                    BufferedImage.TYPE_INT_BGR);
        //2.将原image覆盖画入
        Graphics pen = resultImage.getGraphics();
        pen.drawImage(this.image,0,0,null);

        //3.1 将目标图像进行压缩
        Image smallImage = image.getScaledInstance(width, height, Image.SCALE_DEFAULT);
        //3.2 将目标图像画入
        pen.drawImage(smallImage,x,y,null);
        pen.dispose();

        this.image=resultImage;
        return this;
    }

    
    public BufferImagTool insertImage(Image image) throws Exception{
        if(this.image==null) throw new Exception("请先初始化图像在进行插入操作!!!");
        if(image==null) throw new Exception("目标图像不能为空!!!");
        insertImage(image,0.33f,0.33f,0.33f,0.33f);
        return this;
    }

    
    public Color getRandomColor(){
        return new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255));
    }

    
    public BufferImagTool insertVeriCode(float positionX,float positionY) throws Exception{
        int len=veri_ReferString.length();
        String codes="";
        for (int i = 0; i  
QRCODETool 

二维码使用到外部依赖



    com.google.zxing
    core
    3.3.0



    com.google.zxing
    javase
    3.3.0

代码正文

package codeserver.tool;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.datamatrix.encoder.SymbolShapeHint;
import com.google.zxing.oned.CodaBarWriter;
import com.google.zxing.pdf417.encoder.Compaction;
import com.google.zxing.pdf417.encoder.Dimensions;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Version;
import com.sun.org.apache.xpath.internal.operations.And;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.HashMap;


public class QRCodeTool {

    
    public final static BarcodeFormat QRTYPE_AZTEC=BarcodeFormat.AZTEC;

    
    public final static BarcodeFormat QRTYPE_CODABAR=BarcodeFormat.CODABAR;
    
    public final static String QRTYPE_CODABAR_REFER="0123456789-$:/.+ABCD";

    
    public final static BarcodeFormat QRTYPE_CODE_39=BarcodeFormat.CODE_39;

    
    public final static BarcodeFormat QRTYPE_CODE_93=BarcodeFormat.CODE_93;

    
    public final static BarcodeFormat QRTYPE_CODE_128=BarcodeFormat.CODE_128;

    
    public final static BarcodeFormat QRTYPE_DATA_MATRIX=BarcodeFormat.DATA_MATRIX;

    
    public final static BarcodeFormat QRTYPE_EAN_8=BarcodeFormat.EAN_8;

    
    public final static BarcodeFormat QRTYPE_EAN_13=BarcodeFormat.EAN_13;

    
    public final static BarcodeFormat QRTYPE_ITF=BarcodeFormat.ITF;

    
    public final static BarcodeFormat QRTYPE_MAXICODE=BarcodeFormat.MAXICODE;

    
    public final static BarcodeFormat QRTYPE_PDF_417=BarcodeFormat.PDF_417;

    
    public final static BarcodeFormat QRTYPE_RSS_14=BarcodeFormat.RSS_14;

    
    public final static BarcodeFormat QRTYPE_RSS_EXPANDED=BarcodeFormat.RSS_EXPANDED;

    
    public final static BarcodeFormat QRTYPE_UPC_A=BarcodeFormat.UPC_A;

    
    public final static BarcodeFormat QRTYPE_UPC_E=BarcodeFormat.UPC_E;

    
    public final static BarcodeFormat QRTYPE_UPC_EAN_EXTENSION=BarcodeFormat.UPC_EAN_EXTENSION;

    
    public final static BarcodeFormat QRTYPE_QR_CODE=BarcodeFormat.QR_CODE;






    
    public final static String CHARSET="UTF-8";

    
    public final static String JPG="JPG";

    
    public final static String PNG="PNG";


    
    private BarcodeFormat qrType=QRTYPE_QR_CODE;

    
    private String qrContent="hello world";

    
    private int width=200;

    
    private int height=200;

    
    private int margin=0;

    
    private int qrCodeVersion=1;



    
    public QRCodeTool setQrType(BarcodeFormat qrType) {
        this.qrType = qrType;
        return this;
    }

    
    public QRCodeTool setQrContent(String qrContent) {
        this.qrContent = qrContent;
        return this;
    }

    
    public QRCodeTool setWidth(int width) {
        width=Math.abs(width);
        this.width = width;
        return this;
    }

    
    public QRCodeTool setHeight(int height) {
        height=Math.abs(height);
        this.height = height;
        return this;
    }

    
    public QRCodeTool setMargin(int margin) {
        margin=Math.abs(margin);
        this.margin = margin;
        return this;
    }

    
    public QRCodeTool setQrCodeVersion(int qrCodeVersion) {
        this.qrCodeVersion = qrCodeVersion;
        return this;
    }

    public BufferedImage getQRCode(){
        //1.所有类型二维码的通用配置
        HashMap configs = new HashMap<>();
        //1.1 定义字符集
        configs.put(EncodeHintType.CHARACTER_SET,CHARSET);
        //1.2 设置容错等级
        //configs.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        //1.3 设置二维码的外边距宽度,外边距部分会用白色进行填充
        configs.put(EncodeHintType.MARGIN,margin);
        BufferedImage img=null;
        //2.特殊配置
        try{
            switch (qrType){
                case AZTEC:
                    //2.1.AZTEC编码相关的配置,固定值;不要设置容错
                    configs.put(EncodeHintType.AZTEC_LAYERS,-1);
                    break;
                case CODABAR:
                    //2.2.有限字符集!!!简单校验,字符集实际还有组合规则,此处不校验,当异常直接抛出
                    for (int i = 0; i < qrContent.length(); i++) {
                        char ch=qrContent.charAt(i);
                        if(!QRTYPE_CODABAR_REFER.contains(ch+"")){
                            throw new Exception("CODABAR类型的二维码,字符必须是在有限集【"+QRTYPE_CODABAR_REFER+"】中!!!");
                        }
                    }
                    break;
                case PDF_417://无特殊配置
                    //含特殊配置
                    //1.是否使用紧凑模式
                    configs.put(EncodeHintType.PDF417_COMPACT, true);
                    //2.使用什么压缩模式
                    configs.put(EncodeHintType.PDF417_COMPACTION, Compaction.AUTO);
                    //3.最小和最大行数和列数
                    configs.put(EncodeHintType.PDF417_DIMENSIONS,
                            new Dimensions(1,10, 1, 10));
                    break;
                case QR_CODE:
                    //1.指定纠错版本,使用中等级
                    configs.put(EncodeHintType.ERROR_CORRECTION,ErrorCorrectionLevel.M);
                    //2.指定编码的二维码版本,版本越高,二维码容量越大,相反解析越小
                    configs.put(EncodeHintType.QR_VERSION, qrCodeVersion);
                    break;
                case CODE_39://有限字符集,内容多,不进行校验,无特殊配置
                case CODE_93://有限字符集,内容多,不进行校验,无特殊配置
                case CODE_128://有限字符集,内容多,不进行校验,无特殊配置
                case DATA_MATRIX://无特殊配置
                case EAN_8://无特殊配置
                case EAN_13://无特殊配置
                case ITF:
                    
                case RSS_14://无特殊配置
                case RSS_EXPANDED://无特殊配置
                case UPC_A://无特殊配置
                case UPC_E://无特殊配置
                case UPC_EAN_EXTENSION://无特殊配置
                    break;
            }
            
            BitMatrix qrObj = null;
            try {
                //new MultiFormatWriter().encode会自动识别类型,不需要针对不同二维码调用不同构造器的encode方法
                qrObj = new MultiFormatWriter().encode(qrContent, qrType, width, height, configs);
            } catch (WriterException e) {
                e.printStackTrace();
            }
            //3.2 采用黑白两色
            img = MatrixToImageWriter.toBufferedImage(qrObj, new MatrixToImageConfig(Color.BLACK.getRGB(), Color.WHITE.getRGB()));
        }catch (Exception e){
            e.printStackTrace();
        }
        return img;
    }

}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/677293.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号