1)各类码图如二维码,验证码此类码图的生成,实际原理就是后台通过某种规则去生成图片流,将图片流返回给前端后,前端进行显示。后续内容将展开BufferedImage的实际应用。
2)此篇文章来自我的有道云笔记,耗时一周左右的摸索总结测试,以及看了相关的其他博主所写,根据自己的测试和探索,最终编写了自己的工具类。地址:我的有道云笔记链接
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组件处理即可。
三.验证码... data(){ return { src1:'/test/d01', } }, methods:{ update1(){ //1.需要设置一个随机参数来改变这个URL,否则H5不会重新渲染图片 this.src1 = this.src1+"?time="+Math.random(); }, ...hello world
![]()
在上述的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.所有类型二维码的通用配置 HashMap02.Codabarconfigs = 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()));
①Codabar是由Monarch Marking Systems在1972年研制的条码。它是在"2 of 5"后早期阶段引入的条码。注意他的编码集是有限的!!!
②代码示例
没有特殊点,需要注意是有限字符
//1.所有类型二维码的通用配置 HashMap03.CODE_39configs = 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()));
①CODE 39是 Intermec公司在1975年研制成功的。包括数字、字母和一些符号在内,条码共包括43个字符。
②场景:由于可以处理字母,CODE 39在工业领域必不可少,用于汽车、电子等工厂自动化行业。在美国,汽车工业行动组织已经对其进行了标准化。
③代码示例,无特殊配置
//1.所有类型二维码的通用配置 HashMap04.CODE_93configs = 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()));
①Code 93码与Code 39码的字符集相同,但93码的密度要比39码高,因而在面积不足的情况下,可以用93码代替39码。它没有自校验功能,为了确保数据安全性,采用了双校验字符,其可靠性比39条码还要高.
②场景:用于汽车、电子等工厂自动化行业,内部管理
③代码示例,无特殊配置
//1.所有类型二维码的通用配置 HashMap05.CODE_128configs = 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()));
①CODE128码是1981年引入的一种高密度条码,CODE128 码可表示从 ASCII 0 到ASCII 127 共128个字符,故称128码。其中包含了数字、字母和符号字符。
②场景: CODE128码是广泛应用在企业内部管理、生产流程、物流控制系统方面的条码码制,由于其优良的特性在管理信息系统的设计中被广泛使用,CODE128码是应用最广泛的条码码制之一
③代码示例,无特殊配置
//1.所有类型二维码的通用配置 HashMap06.DATA_MATRIXconfigs = 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()));
①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.所有类型二维码的通用配置 HashMap07.EAN_8 和 EAN_13configs = 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()));
①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.所有类型二维码的通用配置 HashMap08.ITFconfigs = 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()));
①ITF条码,又称交叉二五条码
②用途
主要用于运输包装,是印刷条件较差,不允许印刷EAN-13和UPC-A条码时应选用的一种条码
③代码实例,无特殊配置
//1.所有类型二维码的通用配置 HashMap09.MAXICODEconfigs = 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()));
①1980年代晚期,美国知名的UPS(United Parcel Service)快递公司认知到利用机器辨读资讯可有效改善作业效率、提高服务品质而研发的条码。
//1.所有类型二维码的通用配置 HashMap10.PDF417configs = 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()));
①PDF417二维条码是一种堆叠式二维条码,目前应用最为广泛。PDF417条码是由美国SYMBOL公司发明的,PDF(Portable Data File)意思是“便携数据文件”。组成条码的每一个条码字符由4个条和4个空共17个模块构成,故称为PDF417条码。 PDF417条码需要有417解码功能的条码阅读器才能识别。PDF417条码最大的优势在于其庞大的数据容量和极强的纠错能力
②用途
二维条码PDF417做为一种新的信息存储和传递技术,从诞生之始就受到了国际社会的广泛关注。经过几年的努力,现已广泛地应用在国防、公共安全、交通运输、医疗保健、工业、商业、金融、海关及政府管理等领域。
③代码实例,有特殊点
//1.所有类型二维码的通用配置 HashMap11.RSS_14 And RSS_EXPANDEDconfigs = 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()));
①RSS系列条码是一维码和二维码的组合码。
②场景:非常小的产品项目
③代码实例,测试失败。待定
①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.所有类型二维码的通用配置 HashMap13.QR_CODEconfigs = 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()));
①QR Code码,是由Denso公司于1994年9月研制的一种矩阵二维码符号,它具有一维条码及其它二维条码所具有的信息容量大、可靠性高、可表示汉字及图象多种文字信息、保密防伪性强等优点。最常见的二维码。
②用途
客户信息,个人信息,信息载体
③代码实例
//1.所有类型二维码的通用配置 HashMapconfigs = 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进行属性的连续配置调用。
所有的方法都写了注释
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;
}
}



