欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

二维码(带Logo)加密解密-ZXing方式

程序员文章站 2022-04-26 14:44:36
...

二维码(带Logo)加密解密-ZXing方式

ZXing生成和解析二维码的流程步骤在代码的注解里面。

二维码的加密解密工具类

/**  
 * Copyright © 2020wangylCompany. All rights reserved.
 *
 * @Title: ZXingUtil.java
 * @Prject: MyTestDemo
 * @Package: zxing
 * @Description: TODO
 * @version: V1.0  
 */

package zxing;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
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;
import com.google.zxing.oned.MultiFormatUPCEANReader;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import jp.sourceforge.qrcode.util.Color;

/**
 * @ClassName: ZXingUtil
 * @Description: TODO
 * 
 *
 */

public class ZXingUtil {
	
	
	//二维码加密:文字--->二维码(无logo)
	public static void encodeImg(String imgPath,String format,String content,int width, int height) throws WriterException, IOException{
		/**
		 * 需要二维码图片,就需要生成图片
		 * 生成图片就需要用到ImageIO.write(im, formatName, output)
		 * 实际编写代码的时候一般是是倒着分析,由于生成图片使用的是
		 * ImageIO.write(im, formatName, output)
		 * 那么剩下的就是将里面的参数补齐就可以了
		 * im			RenderedImage
		 * formatName	格式名字
		 * output		文件类型,所以需要与现有文件
		 * 
		 * 先对文件的格式进行分析,output是文件类型,整个我们可以通过将二维码文件路径作为参数传递过来获取生成文件
		 * public void encodeImt(String imgPath)
		 * String imgPath----->file
		 * File file = new File(imgPath);
		 * 
		 * ImageIO.write(, , file)
		 * 
		 * 图片的格式formatName,二维码的图片格式,整个可以通过传参的方式传递进来
		 * encodeImt(String imgPath,String format)
		 * ImageIO.write(, format, file)
		 * 
		 * 
		 * im			RenderedImage内存中的一张图片
		 * 由于RenderedImage是一个接口类型不能直接用不能直接生成RenderedImage对象
		 * 需要使用RenderedImage的子类辅助,选中RenderedImage 然后ctrl+t查看子类
		 * 可以找到RenderedImage的子类有BufferedImage
		 * 所以这里我们可以产生一个RenderedImage对象,所以这里剩下的就是如何产生BufferedImage对象
		 * 
		 * BufferedImage img = new BufferedImage(width, height, imageType);
		 * 
		 * BufferedImage(width, height, imageType);
		 * 
		 * 二维码生成进一步分析:
		 * 由于二维码生成目前需要的是一个内存中图片对象BufferedImage,然后将内存中的二维码输出到硬盘即可
		 * 但是内存中中的二维码又是如何生成的?
		 * 二维码生成是将出传递进来的加密字符串转换成一个boolean[][],然后通过对二位数组循环遍历判断,
		 * 并对true进行着色标记生成成图片。
		 * (字符串转换二维数组后,字符串中的某一个字符对应二位数组的某一个点后,就标记为true)
		 * 那么这里整个boolean值怎么拿,如何判断二维数组中的某一个点是true还是false
		 * 这里需要一个工具类BitMatrix,这个里面包含了一个boolean[][]
		 * 
		 * 二维码生成的核心就是产生一个二维数组,产生二维数组需要BitMatrix,因为里面包含了一个二维数组
		 * 
		 * 那么BitMatrix怎么产生呢?
		 * new MultiFormatWriter().encode(contents, format, width, height)
		 * 这个可以产生图片需要的BitMatrix对象
		 * 产生BitMatrix需要将new MultiFormatWriter().encode(, , , )里面的参数补齐
		 * new MultiFormatWriter().encode(, , , )目的是将文本变成二维数组
		 * contents		加密的字符串,可以作为参数传进来
		 * new MultiFormatWriter().encode(content, , , )
		 * format		解密的类型(条形码、二维码.....)     这个类型和二维码图片类型需要区别开来,不是同一个
		 * new MultiFormatWriter().encode(contents,BarcodeFormat.QR_CODE , , )
		 * BarcodeFormat.QR_CODE指的就是二维码
		 * 
		 * width/height	这个宽高不太重要可以通过调用时候传参写固定
		 * new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height);
		 * 这样这个BitMatrix对象就产生了
		 * 
		 * 但是这里还有一个五个参数的也可以产生BitMatrix对象
		 * new MultiFormatWriter().encode(contents, format, width, height, hints)
		 * hints	Map<EncodeHintType, ?> hints;
		 * 所以这里需要一个Map类型对象,但是这个Map是interface Map<K,V>,由于是一个接口,所以需要使用实现类创建对象
		 * 这里使用Hashtable<K, V>
		 * K:EncodeHintType
		 * V:?		这里?代表的是任意类型,所以使用Object
		 * Hashtable<EncodeHintType, Object>
		 * 
		 * 至于为什么需要这个map,暂时不用管,因为这个代码需要,先提供这个对象先
		 * Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
		 * 
		 * 那么这个具体作用做什么的?
		 * 这个可以用来粗放一些参数值:编码格式、排错率。。。(用来存放加关于加密的参数)
		 * hints:加密涉及的参数
		 * 编码格式:
		 * 排错率:
		 * 外边距:
		 * 
		 * BitMatrix bitMatrix =new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
		 * 这样就可以产生一个BitMatrix对象了,然后就可以开始生成内存中的二维码
		 * BufferedImage img = new BufferedImage(width, height,imgType);
		 * imgType	图片类型	BufferedImage.TYPE_INT_RGB	
		 * 画BufferedImage需要用到BitMatrix,现在BitMatrix已经有了,可以开始画图
		 * 由于BitMatrix里面包含了一个二维数组,所需需要将二位数组整出来
		 * 
		 * 
		 */
		
		
		//生成二维码文件对象
		//File file = new File(imgPath);
		/**
		 * 内存中的一张图片,
		 * 此时需要的图片是二维码---(产生的前提)--->boolean[][]--(产生的需要)------>BitMatrix
		 */

		
		//产生图片需要的BitMatrix对象是需要用到的
		/**
		 * hints:加密涉及的参数
		 */
		Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
		//排错率
		hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
		//编码格式
		hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
		//外边距 margin	外边距就是二维码的黑框和背景白色边框的间距
		//这个暂时给定1,后面可以检查,大小不合适再调整
		hints.put(EncodeHintType.MARGIN, 1);
		
		//产生图片需要的BitMatrix对象
		//content:	需要加密的文字
		//BarcodeFormat.QR_CODE:要解析的类型(二维码)
		//BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height);
		
		BitMatrix bitMatrix =new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
		BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		//下面的两层for循环就类似二维数组
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				/**
				 * img.setRGB(x, y, rgb);//在坐标点指定颜色
				 * x,y代表坐标点
				 * rgb代表坐标点颜色
				 * 那么rgb怎么给定颜色?
				 * 二维码生成就是将加密字符串解析成二位数组,每个字符在二维数组中都有对应的点
				 * 每个对应的点都会被标记着色,也就是说需要将每个坐标的位置进行判断
				 * 如果当前点由字符对应的标记点,那么就着色
				 * bitMatrix里面就包含了二维数组
				 * img.setRGB(x, y, (bitMatrix.get(x, y)?black:white));
				 */
				img.setRGB(x, y, ( bitMatrix.get(x,y)? Color.BLACK:Color.WHITE ));
				//img.setRGB(x, y, ( bitMatrix.get(x,y)? 0:16777215 ));//也可以不报错
				/**
				 * 补充说明
				 * img.setRGB(x, y, ( bitMatrix.get(x,y)? Color.BLACK:Color.WHITE ))
				 * 这里可能报错
				 * 原因img.setRGB(x, y, rgb)三个参数都为int类型
				 * 但是bitMatrix.get(x,y)? Color.BLACK:Color.WHITE 结果不是int
				 * 我们这里需要的Color其实来源于jp.sourceforge.qrcode.util.Color
				 * 而这个包属于QRCode.jar
				 * 所以根本原因是缺少QECode.jar
				 * 
				 * 或者不想额外操作也可以尝试书写对应值
				 * Color.BLACK=0
				 * Color.WHITE=16777215
				 * img.setRGB(x, y, ( bitMatrix.get(x,y)? 0:16777215 ));//也可以不报错
				 */
			}
		 }
		
		//生成二维码文件对象
		File file = new File(imgPath);
		
		ImageIO.write(img, format, file);//format是二维码的图片格式
	}
	
	
	//二维码加密:文字--->二维码(logo版)
	public static void encodeLogoImg(String imgPath,String format,String content,int width, int height ,String logoPath) throws WriterException, IOException{
		/**
		 * 需要二维码图片,就需要生成图片
		 * 生成图片就需要用到ImageIO.write(im, formatName, output)
		 * 实际编写代码的时候一般是是倒着分析,由于生成图片使用的是
		 * ImageIO.write(im, formatName, output)
		 * 那么剩下的就是将里面的参数补齐就可以了
		 * im			RenderedImage
		 * formatName	格式名字
		 * output		文件类型,所以需要与现有文件
		 * 
		 * 先对文件的格式进行分析,output是文件类型,整个我们可以通过将二维码文件路径作为参数传递过来获取生成文件
		 * public void encodeImt(String imgPath)
		 * String imgPath----->file
		 * File file = new File(imgPath);
		 * 
		 * ImageIO.write(, , file)
		 * 
		 * 图片的格式formatName,二维码的图片格式,整个可以通过传参的方式传递进来
		 * encodeImt(String imgPath,String format)
		 * ImageIO.write(, format, file)
		 * 
		 * 
		 * im			RenderedImage内存中的一张图片
		 * 由于RenderedImage是一个接口类型不能直接用不能直接生成RenderedImage对象
		 * 需要使用RenderedImage的子类辅助,选中RenderedImage 然后ctrl+t查看子类
		 * 可以找到RenderedImage的子类有BufferedImage
		 * 所以这里我们可以产生一个RenderedImage对象,所以这里剩下的就是如何产生BufferedImage对象
		 * 
		 * BufferedImage img = new BufferedImage(width, height, imageType);
		 * 
		 * BufferedImage(width, height, imageType);
		 * 
		 * 二维码生成进一步分析:
		 * 由于二维码生成目前需要的是一个内存中图片对象BufferedImage,然后将内存中的二维码输出到硬盘即可
		 * 但是内存中中的二维码又是如何生成的?
		 * 二维码生成是将出传递进来的加密字符串转换成一个boolean[][],然后通过对二位数组循环遍历判断,
		 * 并对true进行着色标记生成成图片。
		 * (字符串转换二维数组后,字符串中的某一个字符对应二位数组的某一个点后,就标记为true)
		 * 那么这里整个boolean值怎么拿,如何判断二维数组中的某一个点是true还是false
		 * 这里需要一个工具类BitMatrix,这个里面包含了一个boolean[][]
		 * 
		 * 二维码生成的核心就是产生一个二维数组,产生二维数组需要BitMatrix,因为里面包含了一个二维数组
		 * 
		 * 那么BitMatrix怎么产生呢?
		 * new MultiFormatWriter().encode(contents, format, width, height)
		 * 这个可以产生图片需要的BitMatrix对象
		 * 产生BitMatrix需要将new MultiFormatWriter().encode(, , , )里面的参数补齐
		 * new MultiFormatWriter().encode(, , , )目的是将文本变成二维数组
		 * contents		加密的字符串,可以作为参数传进来
		 * new MultiFormatWriter().encode(content, , , )
		 * format		解密的类型(条形码、二维码.....)     这个类型和二维码图片类型需要区别开来,不是同一个
		 * new MultiFormatWriter().encode(contents,BarcodeFormat.QR_CODE , , )
		 * BarcodeFormat.QR_CODE指的就是二维码
		 * 
		 * width/height	这个宽高不太重要可以通过调用时候传参写固定
		 * new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height);
		 * 这样这个BitMatrix对象就产生了
		 * 
		 * 但是这里还有一个五个参数的也可以产生BitMatrix对象
		 * new MultiFormatWriter().encode(contents, format, width, height, hints)
		 * hints	Map<EncodeHintType, ?> hints;
		 * 所以这里需要一个Map类型对象,但是这个Map是interface Map<K,V>,由于是一个接口,所以需要使用实现类创建对象
		 * 这里使用Hashtable<K, V>
		 * K:EncodeHintType
		 * V:?		这里?代表的是任意类型,所以使用Object
		 * Hashtable<EncodeHintType, Object>
		 * 
		 * 至于为什么需要这个map,暂时不用管,因为这个代码需要,先提供这个对象先
		 * Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
		 * 
		 * 那么这个具体作用做什么的?
		 * 这个可以用来粗放一些参数值:编码格式、排错率。。。(用来存放加关于加密的参数)
		 * hints:加密涉及的参数
		 * 编码格式:
		 * 排错率:
		 * 外边距:
		 * 
		 * BitMatrix bitMatrix =new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
		 * 这样就可以产生一个BitMatrix对象了,然后就可以开始生成内存中的二维码
		 * BufferedImage img = new BufferedImage(width, height,imgType);
		 * imgType	图片类型	BufferedImage.TYPE_INT_RGB	
		 * 画BufferedImage需要用到BitMatrix,现在BitMatrix已经有了,可以开始画图
		 * 由于BitMatrix里面包含了一个二维数组,所需需要将二位数组整出来
		 * 
		 * 
		 */
		
		
		//生成二维码文件对象
		//File file = new File(imgPath);
		/**
		 * 内存中的一张图片,
		 * 此时需要的图片是二维码---(产生的前提)--->boolean[][]--(产生的需要)------>BitMatrix
		 */

		
		//产生图片需要的BitMatrix对象是需要用到的
		/**
		 * hints:加密涉及的参数
		 */
		Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
		//排错率
		hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
		//编码格式
		hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
		//外边距 margin	外边距就是二维码的黑框和背景白色边框的间距
		//这个暂时给定1,后面可以检查,大小不合适再调整
		hints.put(EncodeHintType.MARGIN, 1);
		
		//产生图片需要的BitMatrix对象
		//content:	需要加密的文字
		//BarcodeFormat.QR_CODE:要解析的类型(二维码)
		//BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height);
		
		BitMatrix bitMatrix =new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
		BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		//下面的两层for循环就类似二维数组
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				/**
				 * img.setRGB(x, y, rgb);//在坐标点指定颜色
				 * x,y代表坐标点
				 * rgb代表坐标点颜色
				 * 那么rgb怎么给定颜色?
				 * 二维码生成就是将加密字符串解析成二位数组,每个字符在二维数组中都有对应的点
				 * 每个对应的点都会被标记着色,也就是说需要将每个坐标的位置进行判断
				 * 如果当前点由字符对应的标记点,那么就着色
				 * bitMatrix里面就包含了二维数组
				 * img.setRGB(x, y, (bitMatrix.get(x, y)?black:white));
				 */
				img.setRGB(x, y, ( bitMatrix.get(x,y)? Color.BLACK:Color.WHITE ));
				//img.setRGB(x, y, ( bitMatrix.get(x,y)? 0:16777215 ));//也可以不报错
				/**
				 * 补充说明
				 * img.setRGB(x, y, ( bitMatrix.get(x,y)? Color.BLACK:Color.WHITE ))
				 * 这里可能报错
				 * 原因img.setRGB(x, y, rgb)三个参数都为int类型
				 * 但是bitMatrix.get(x,y)? Color.BLACK:Color.WHITE 结果不是int
				 * 我们这里需要的Color其实来源于jp.sourceforge.qrcode.util.Color
				 * 而这个包属于QRCode.jar
				 * 所以根本原因是缺少QECode.jar
				 * 
				 * 或者不想额外操作也可以尝试书写对应值
				 * Color.BLACK=0
				 * Color.WHITE=16777215
				 * img.setRGB(x, y, ( bitMatrix.get(x,y)? 0:16777215 ));//也可以不报错
				 */
			}
		 }
		//-------二维码添加Logo----------------start-------------------
		/**
		 * 先画二维码,二维码画完了再画logo 
		 * 由于Logo复杂点,所以单独写一个类
		 */
		img = LogoUtil.logoMatrix(img, logoPath);
		//-------二维码添加Logo----------------end---------------------
		//生成二维码文件对象
		File file = new File(imgPath);
		
		ImageIO.write(img, format, file);//format是二维码的图片格式
	}
	
	
	
	//二维码解密:二维码--->文字
	/**
	 * 
	 * @Title: decodeImg
	 * @Description: TODO
	 * @author: wangyl 
	 * @param file			解密需要传入解密的二维码文件
	 * @return
	 * @return: String		将解密后的字符串返回
	 
	 * @throws IOException 
	 * @throws NotFoundException 
	 */
	public static void decodeImg(File file) throws IOException, NotFoundException{
		/**
		 * 先判断该文件是否存在,不存在直接返回不执行
		 */
		if (!file.exists()) {
			return ;
		}
		
		/**
		 * 图片存在---->开始解密
		 * 先将图片文件读取到内存中
		 * 最终需要的是new MultiFormatUPCEANReader()对象
		 * MultiFormatReader formatReader = new MultiFormatReader();
		 * 因为MultiFormatReader里面有decode方法
		 * formatReader.decode()
		 * 这样就可以将图片里面包含的文字解析出来
		 * formatReader.decode(image)的返回值是Result
		 * Result result= formatReader.decode(image)是核心的方法
		 * formatReader.decode(image)参数里面提供图片的话就可以解析出来
		 * 接下来就看formatReader.decode(image)方法里面的参数需要什么就提供什么
		 * image是BinaryBitmap类型 的,也就是说decode需要BinaryBitmap类型的对象
		 * 新建BinaryBitmap对象
		 * new BinaryBitmap(binarizer)
		 * 新建BinaryBitmap对象的时候BinaryBitmap有需要一个Binarizer对象
		 * 继续新建一个Binarizer对象
		 * 但是由于Binarizer是一个抽象类,不能直接新建对象,只能使用子类HybridBinarizer新建对象
		 * new HybridBinarizer(source)新建需要source参数
		 * source是LuminanceSource类型的,所以这里新建一个LuminanceSource类型对象
		 * LuminanceSource是一个抽象类,不能直接创建对象,需要使用子类创建对象
		 * 这里使用BufferedImageLuminanceSource子类创建对象
		 *  new BufferedImageLuminanceSource(image)
		 *  BufferedImageLuminanceSource创建需要BufferedImage类型的image对象
		 *  
		 *  
		 *  由于我们可以通过二维码文件获取BufferedImage对象
		 * BufferedImage img = ImageIO.read(file);
		 * 所以new BufferedImageLuminanceSource(img)直接使用即可
		 * 
		 * 
		 * Result result= formatReader.decode(binaryBitmap);
		 * formatReader.decode(image, hints)解密还有一个方法
		 * hints是map类型的
		 * 这里需要map就提供一个map类型(需要什么提供什么)
		 * 
		 */
		//先将图片文件读取到内存中
		BufferedImage img = ImageIO.read(file);
		MultiFormatReader formatReader = new MultiFormatReader();
		//新建LuminanceSource对象
		LuminanceSource source = new BufferedImageLuminanceSource(img);
		//新建Binarizer对象
		Binarizer binarizer = new HybridBinarizer(source);
		//新建BinaryBitmap对象
		BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
		
		Map map = new HashMap<>();
		map.put(EncodeHintType.CHARACTER_SET, "utf-8");
		Result result= formatReader.decode(binaryBitmap,map);
		
		System.out.println("解析结果:"+result.toString());
				
//		return null;
	}
	
}

二维码Logo添加

/**  
 * Copyright © 2020wangylCompany. All rights reserved.
 *
 * @Title: LogoUtil.java
 * @Prject: MyTestDemo
 * @Package: zxing
 * @Description: TODO
 * @version: V1.0  
 */

package zxing;
/**
 * @ClassName: LogoUtil
 * @Description: TODO
 * 
 *
 */

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class LogoUtil {

	/**
	 * 由于新建一个logo的生成类,所以必然需要考虑方法的参数和返回值
	 * 
	 * 传入logo图像+二维码图像-------->带logo的二维码图像
	 * 
	 */
	/**
	 * 
	 * @Title: logo
	 * @Description: TODO
	 * @author: wangyl 
	 * @param img			二维码图像用来和logo组合
	 * @param logoPath		logo路径用来生成对象
	 * @return
	 * @return: BufferedImage		带logo的二维码图像
	 
	 * @throws IOException 
	 */
	public static BufferedImage logoMatrix(BufferedImage matrixImage ,String logoPath) throws IOException{
		/**
		 * 在二维码上画logo
		 * 产生了一个画板,一个二维码画板。这个画板上初始化就有了一个二维码
		 * 现在要在二维码的画板上画logo
		 */
		Graphics2D graphics2d = matrixImage.createGraphics();
		/**
		 * 画logo是在内存里面画,传进来的是logo地址
		 * 内存里面的图片对象是BufferedImage,
		 * 所以这里等同于需要将String logoPath转换成BufferedImage对象
		 * 
		 */
		BufferedImage logoImg = ImageIO.read(new File(logoPath));//logo已经到内存了
		/**
		 * 开始在画板里面画logo
		 * graphics2d.drawImage(img, x, y, width, height, observer);
		 * 那么从哪里开始画?
		 * 左上角的点就是坐标起点
		 * 将二维码看成横竖切割成5/或者7等分的样子来定位logo左上角的坐标位置
		 * 也就是需要提前获取二维码的对应做左上角的位置
		 * img 				logo对象
		 * x/y				左上角坐标起点		
		 * width/height		logo的大小(确保logo在二维码在最中间)
		 * observer			null
		 * 
		 */
		int height = matrixImage.getHeight();
		int width = matrixImage.getWidth();
		graphics2d.drawImage(logoImg, width*2/5, height*2/5, width/5, height/5, null);
		//以上ogo及已经添加上去了
		
		/**
		 * 但是在logo外面还有灰色的边框
		 * 再外层还有白色的边框
		 * 产生一个画 白色圆角正方形的画笔
		 * BasicStroke bs = new BasicStroke(width, cap, join)
		 * 画笔的参数:
		 * width 		笔的粗细(白的比灰的粗,白的暂定5,灰的暂定1)
		 * cap 			笔的样式(圆的还是尖的)	
		 * join			连接处的样式
		 * new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);//画笔
		 */
		BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);//画笔
		/**
		 * 画笔创建好了,但是画笔和画板需要关联起来
		 * 用哪只笔就需要关联哪只笔,就把画笔放进画板
		 */
		graphics2d.setStroke(stroke);
		/**
		 * 准备开始画:
		 * 首先需要确定画的形状:正方形
		 * 但是这个里面没有正方形,只有长方形
		 * new RoundRectangle2D.Float(x, y, w, h, arcw, arch)
		 * x,y			坐标起始位置
		 * w 			长方形宽
		 * h			长方形高
		 * arcw 		笔的样式BasicStroke.CAP_ROUND
		 * arch			连接处样式BasicStroke.JOIN_ROUND
		 * 
		 * x,y,w,h和logo相同
		 */
		//创建一个正方形
		RoundRectangle2D.Float round =new RoundRectangle2D.Float(width*2/5, height*2/5, width/5, height/5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
//		graphics2d.setColor(Color.WHITE);//正方形是白色的
		graphics2d.setColor(Color.RED);//正方形是白色的
		//图形准备好了,颜色设置好了,开始画
		graphics2d.draw(round);
		
		
		
		//白色的边框已经画完了,现在开始画灰色边框--------------------------------------
		//同理白色的边框,只是粗细和颜色做下调整
		BasicStroke stroke2 = new BasicStroke(1,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);//画笔
		graphics2d.setStroke(stroke2);
		//由于白色是在带logo二维码上画的,且坐标和logo相同,等同于覆盖了一部分logo边缘
		//灰色同理,但是灰色的框相对于白色更小一点,所以尺寸略有改动
		RoundRectangle2D.Float round2 =new RoundRectangle2D.Float(width*2/5+2, height*2/5+2, width/5-4, height/5-4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
//		graphics2d.setColor(Color.GRAY);//正方形边框是灰色的
		graphics2d.setColor(Color.BLUE);//正方形是白色的
		/**
		 * 如果有的颜色没有,但是有需要可以
		 * Color color = new Color(128, 128, 128);//灰色,可查询更改调整为其他颜色
		 * graphics2d.setColor(color);//灰色        也是可以的
		 */
		graphics2d.draw(round2);
		
		//画完所有的以后释放空间
		graphics2d.dispose();
		//由于是在内存matrixImage里面画的,画完刷新一下
		matrixImage.flush();
		return matrixImage;
		
	}
}

测试类

/**  
 * Copyright © 2020wangylCompany. All rights reserved.
 *
 * @Title: Test.java
 * @Prject: MyTestDemo
 * @Package: zxing
 * @Description: TODO
 * @version: V1.0  
 */

package zxing;

import java.io.File;
import java.io.IOException;

import com.google.zxing.NotFoundException;
import com.google.zxing.WriterException;

/**
 * @ClassName: Test
 * @Description: TODO
 * 
 *
 */

public class Test {

	/**
	 * @Title: main
	 * @Description: TODO
	 * @author: wangyl 
	 * @param args
	 * @return: void
	 
	 * @throws IOException 
	 * @throws WriterException 
	 * @throws NotFoundException */

	public static void main(String[] args) throws WriterException, IOException, NotFoundException {
		/**
		 * 这里我们使用zxing的方式生成二维码和解码
		 * 首先我们需要生成二维码
		 * 生成二维码之前这里需要进行需要先指明二维码文件的生成路径
		 * 然后准备生成二维码的文本内容
		 * 并且提前准备好logo的图片路径
		 */
		//生成二维码的文件路径
		String imgPath ="src/zxing二维码.png";
		//二维码中间的logo路径
		String logoImg ="src/logo.jpg";
		//二维码里面显示的类容,如果是网页会自动跳转
		String content = "http//:www.baidu.com";
		
		
		//二维码解密测试
		String testPath ="src/test.png";
		
		/**
		 * 二维码加密:文字--->二维码
		 */
//		ZXingUtil.encodeImg(imgPath, "png", content, 430, 430);
		
		ZXingUtil.encodeLogoImg(imgPath, "png", content, 430, 430,logoImg);
		
		/**
		 * 二维码解密:二维码--->文字
		 */
		ZXingUtil.decodeImg(new File(testPath));
	}

}

以上代码使用Eclipse编写