Java生成四种格式的二维码

  • Post author:
  • Post category:java


2022年2月23日 随着技术的不断发展与更新,现在的二维码的生成,完全可以交给前端来进行实现。

基于谷歌zxing实现的生成二维码工具类。可生成纯二维码;带Logo二维码;带文字二维码;带Logo带文字二维码

pom文件引用

                <!-- zxing -->
		<dependency>
		    <groupId>com.google.zxing</groupId>
		    <artifactId>core</artifactId>
		    <version>3.2.1</version>
		</dependency>
		<dependency>
		    <groupId>com.google.zxing</groupId>
		    <artifactId>javase</artifactId>
		    <version>3.2.1</version>
		</dependency>

Java代码:

package com.imis.util;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
 * <p>
 * 生成二维码
 * </p>
 * 
 * @author XinLau
 * @since 2019年2月12日 下午5:20:29
 * @version 1.0
 */
@SuppressWarnings({ "unchecked", "rawtypes", "restriction" })
public class CreatrQrCode {

	/**
	 * logo默认边框颜色 WHITE
	 */
	public static final Color DEFAULT_BORDERCOLOR = Color.WHITE;
	/**
	 * logo默认边框宽度
	 */
	public static final int DEFAULT_BORDER = 1;
	/**
	 * logo大小默认为照片的1/6
	 */
	public static final int DEFAULT_LOGOPART = 4;
	/**
	 * logo图片的地址
	 */
	public static String LogoPath = new File("").getAbsolutePath() + File.separator + "logo.png";
	/**
	 * 边缘
	 */
	private final int border = DEFAULT_BORDER;
	/**
	 * 自定义颜色
	 */
	private final Color borderColor;
	/**
	 * 自定义logo大小
	 */
	private final int logoPart;
	/**
	 * 容错率
	 */
	public static final double RATE = 0.30d;
	/**
	 * 容错率 电平 L(低) 7%的码字可以被恢复。 M级(中) 15%的码字可以被恢复。 Q级(四分之一)25%的码字可以被恢复。 H级(高)
	 * 30%的码字可以被恢复。
	 * 
	 * 越高误差校正水平,越少的存储容量
	 * 
	 */
	private static final ErrorCorrectionLevel E_RATE = ErrorCorrectionLevel.M;
	/**
	 * 二维码宽
	 */
	public static final int QRCODE_WIDTH = 300;
	/**
	 * 二维码高(默认宽高相同)
	 */
	public static final int QRCODE_HEIGHT = 200;
	/**
	 * 二维码页边距(指定生成条码时要使用的边距,以像素为单位)
	 */
	public static final int QRCODE_MARGIN = 1;
	/**
	 * 二维码内容所使用字符集编码
	 */
	public static final String CHARACTER = "UTF-8";

	/**
	 * 颜色上创建一个默认配置,生成正常的黑白条码。
	 */
	public CreatrQrCode() {
		this(DEFAULT_BORDERCOLOR, DEFAULT_LOGOPART);
	}

	public CreatrQrCode(Color borderColor, int logoPart) {
		this.borderColor = borderColor;
		this.logoPart = logoPart;
	}

	public Color getBorderColor() {
		return borderColor;
	}

	public int getBorder() {
		return border;
	}

	public int getLogoPart() {
		return logoPart;
	}

	/**
	 * <p>
	 * addLogo 给二维码图片添加Logo
	 * </p>
	 * 
	 * @param qrPic
	 *            二维码文件
	 * @param logoPic
	 *            logo文件
	 * @param creatrQrCode
	 *            生成的二维码
	 * @return boolean
	 * @author XinLau
	 * @since 2019年2月12日下午5:23:11
	 */
	public static boolean addLogo(File qrPic, File logoPic, CreatrQrCode creatrQrCode) {
		try {
			if (!qrPic.isFile() || !logoPic.isFile()) {
				return false;
			}
			// 读取二维码图片,并构建绘图对象
			BufferedImage image = ImageIO.read(qrPic);
			Graphics2D g = image.createGraphics();
			// 读取Logo图片
			BufferedImage logo = ImageIO.read(logoPic);
			// 保持二维码是正方形的
			int widthLogo = image.getWidth() / creatrQrCode.getLogoPart();
			int heightLogo = image.getWidth() / creatrQrCode.getLogoPart();
			// 计算图片放置位置
			int x = (image.getWidth() - widthLogo) / 2;
			int y = (image.getHeight() - heightLogo) / 2;
			// 开始绘制图片
			g.drawImage(logo, x, y, widthLogo, heightLogo, null);
			g.drawRoundRect(x, y, widthLogo, heightLogo, 10, 10);
			g.setStroke(new BasicStroke(creatrQrCode.getBorder()));
			g.setColor(creatrQrCode.getBorderColor());
			g.drawRect(x, y, widthLogo, heightLogo);
			g.dispose();
			ImageIO.write(image, "jpeg", qrPic);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * <p>
	 * pressText 二维码图片添加文字
	 * </p>
	 * 
	 * @param pressText
	 *            二维码需要显示的文字
	 * @param newImg
	 *            带文字的图片
	 * @param targetImg
	 *            需要添加文字的图片
	 * @param fontStyle
	 *            文字样式
	 * @param color
	 *            颜色
	 * @param fontSize
	 *            字体大小
	 * @param width
	 *            图片宽度
	 * @param height
	 *            图片高度
	 * @return boolean
	 * @author XinLau
	 * @since 2019年2月12日下午5:31:50
	 */
	public static boolean pressText(String pressText, String newImg, String targetImg, int fontStyle, Color color,
			int fontSize, int width, int height) {
		// 计算文字开始的位置
		// x开始的位置(控制左右居中):(图片宽度-字体大小*字的个数)/2
		// int x = (width - (fontSize * pressText.length())) / 300;
		int x = (width - (fontSize * pressText.length())) / 2;
		// y开始的位置(控制上下居中):图片高度-(图片高度-图片宽度)/2
		int y = height - (height - width) / 3;
		try {
			File file = new File(targetImg);
			Image src = ImageIO.read(file);
			int imageWidth = src.getWidth(null);
			int imageHeight = src.getHeight(null);
			BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
			Graphics g = image.createGraphics();
			g.drawImage(src, 0, 0, imageWidth, imageHeight, null);
			g.setColor(color);
			g.setFont(new Font(null, fontStyle, fontSize));
			g.drawString(pressText, x, y);
			g.dispose();
			FileOutputStream out = new FileOutputStream(newImg);
			ImageIO.write(image, "JPEG", out);
			JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
			encoder.encode(image);
			out.close();
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * <p>
	 * createQrCode 生成二维码(无logo,无文字)如果要在二维码下方附上文字,把图片设置为长方形(高大于宽)
	 * </p>
	 * 
	 * @param qrcPath
	 *            用来存放生成的二维码图片
	 * @param content
	 *            二维码表示的内容
	 * @param width
	 *            图片完整的宽
	 * @param height
	 *            图片完整的高
	 * @return boolean
	 * @author XinLau
	 * @since 2019年2月12日下午5:32:41
	 */
	public boolean createQrCode(String qrcPath, String content, int width, int height) {
		try {
			Path path = Paths.get(qrcPath);
			MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
			Map<EncodeHintType, Comparable> hints = new HashMap<EncodeHintType, Comparable>(3);
			// 设置UTF-8, 防止中文乱码
			hints.put(EncodeHintType.CHARACTER_SET, CHARACTER);
			// 设置二维码四周白色区域的大小
			hints.put(EncodeHintType.MARGIN, QRCODE_MARGIN);
			// 设置二维码的容错性
			hints.put(EncodeHintType.ERROR_CORRECTION, E_RATE);
			// 画二维码,记得调用multiFormatWriter.encode()时最后要带上hints参数,不然上面设置无效
			BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
			// 开始画二维码
			MatrixToImageWriter.writeToPath(bitMatrix, "jpg", path);
			// 二维码生成成功
			return true;
		} catch (Exception e) {
			// 二维码生成失败
			return false;
		}
	}

	/**
	 * <p>
	 * createLogoQrCode 生成二维码(有logo,无文字)
	 * </p>
	 * 
	 * @param qrcPath
	 *            用来存放生成的二维码图片
	 * @param content
	 *            二维码表示的内容
	 * @param width
	 *            图片完整的宽
	 * @param height
	 *            图片完整的高
	 * @param logoPath
	 *            附加在二维码中的图片(logo)
	 * @return boolean
	 * @author XinLau
	 * @since 2019年2月12日下午5:34:01
	 */
	public boolean createLogoQrCode(String qrcPath, String content, int width, int height, String logoPath) {
		// 判断二维码是否生成成功
		if (createQrCode(qrcPath, content, width, height)) {
			// 在二维码中加入图片
			CreatrQrCode creatrQrCode = new CreatrQrCode();
			File logoFile = new File(logoPath);
			File qrcFile = new File(qrcPath);
			// 判断logo是否添加成功
			if (!addLogo(qrcFile, logoFile, creatrQrCode)) {
				return false;
			}
			return true;
		} else {
			return false;
		}
	}

	/**
	 * <p>
	 * createWordQrcode 生成二维码(无logo,有文字)
	 * </p>
	 * 
	 * @param newImageWithText
	 *            用来存放的带有文字的二维码图片
	 * @param targetImage
	 *            原二维码图片
	 * @param text
	 *            附加在图片上的文字信息
	 * @param width
	 *            图片宽度(用来计算文字x开始位置)
	 * @param height
	 *            图片高度(用来计算文字y开始位置)
	 * @return boolean
	 * @author XinLau
	 * @since 2019年2月12日下午5:34:47
	 */
	public boolean createWordQrcode(String newImageWithText, String targetImage, String text, int width, int height) {
		// 判断二维码是否生成成功
		if (createQrCode(newImageWithText, text, width, height)) {
			// 字体大小
			int font = 20;
			// 字体风格
			int fontStyle = 4;
			// 在二维码下方添加文字(是否替换原图)
			if (org.apache.commons.lang3.StringUtils.isNotBlank(targetImage)) {
				// 二维码图片添加文字是否成功
				if (!pressText(text, newImageWithText, targetImage, fontStyle, Color.red, font, width, height)) {
					return false;
				}
			} else {
				// 二维码图片添加文字是否成功
				if (!pressText(text, newImageWithText, newImageWithText, fontStyle, Color.red, font, width, height)) {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * <p>
	 * createWordLogoQrcode 生成二维码(有logo,有文字)
	 * </p>
	 * 
	 * @param newImageWithText
	 *            用来存放带有文字的二维码图片的位置
	 * @param targetImage
	 *            原二维码图片
	 * @param text
	 *            附加在二维码上的文字信息
	 * @param width
	 *            图片宽度(用来计算文字x开始位置)
	 * @param height
	 *            图片高度(用来计算文字y开始位置)
	 * @param logoPath
	 *            附加在二维码上的图片
	 * @return boolean
	 * @author XinLau
	 * @since 2019年2月12日下午5:35:27
	 */
	public boolean createWordLogoQrcode(String newImageWithText, String targetImage, String text, int width, int height,
			String logoPath) {
		// 判断二维码是否生成成功
		if (!createLogoQrCode(newImageWithText, text, width, height, logoPath)) {
			return false;
		}
		// 字体大小
		int font = 20;
		// 字体风格
		int fontStyle = 4;
		// 在二维码下方添加文字(是否替换原图)
		if (org.apache.commons.lang3.StringUtils.isNotBlank(targetImage)) {
			if (!pressText(text, newImageWithText, targetImage, fontStyle, Color.red, font, width, height)) {
				return false;
			}
		} else {
			if (!pressText(text, newImageWithText, newImageWithText, fontStyle, Color.red, font, width, height)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * <p>
	 * readQrCode 解析二维码
	 * </p>
	 * 
	 * @param path
	 * @return Result
	 * @author XinLau
	 * @since 2019年2月12日下午5:36:03
	 */
	public Result readQrCode(String path) {
		Result result = null;
		try {
			MultiFormatReader multiFormatReader = new MultiFormatReader();
			File file = new File(path);
			BufferedImage image = ImageIO.read(file);
			// 定义二维码参数
			Map hints = new HashMap(1);
			hints.put(EncodeHintType.CHARACTER_SET, CHARACTER);
			// 获取读取二维码结果
			BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(image)));
			result = multiFormatReader.decode(binaryBitmap, hints);
		} catch (Exception e) {

		}
		return result;
	}

}

测试代码:

package com.imis.util.test;

import java.io.File;

import com.google.zxing.Result;
import com.imis.util.CreatrQrCode;
import com.imis.util.DESUtils;
import com.imis.util.DateUtil;

/**
 * <p>
 *	QrCodeTest.java
 * </p>
 * @since 2019年4月19日 下午2:06:38
 * @author XinLau
 * @version 1.0
 */
public class QrCodeTest {
	
	/**
	 * <p>
	 *	main
	 *	测试类
	 * </p>
	 * @param args
	 * @return void
	 * @author XinLau
	 * @since 2019年2月12日下午5:36:45
	 */
    public static void main(String args[]) {
        try {
            CreatrQrCode creatrQrCode = new CreatrQrCode();
            //	图片存放地址
            String projectPath = new File("").getAbsolutePath();
            System.out.println("工程路径:"+projectPath);
            String path = projectPath + "/QrCode";
            System.out.println("二维码存放路径:"+path);
            //	路径不存在就创建此路径
            File dir = new File(path);
			if (!dir.exists()) {
				dir.mkdirs();
			}
			path += "/" + DateUtil.getCurrentDate("yyyyMMddHHmmss")+".png";
            //	图片显示的内容
            String text = "你瞅啥";
            
            //	Logo图片地址加名称
            String LogoPath = projectPath + "/src/main/webapp/images/logo.png";
            
            //	二维码
            //creatrQrCode.createQrCode(path,text,300,300);
            
            //	Logo
            //creatrQrCode.createLogoQrCode(path,text,300,300,LogoPath);
            
            //	文字
            //creatrQrCode.createWordQrcode(path, "",text, 400, 470);
            
            //	Logo+文字
            creatrQrCode.createWordLogoQrcode(path, "",text, 400, 470,LogoPath);
            
            //System.out.println(File.separator);
            /**
             * 解析二维码
             */
            Result result = creatrQrCode.readQrCode(path);
            System.out.println("读取二维码: " + result.toString());
            System.out.println("二维码格式: " + result.getBarcodeFormat());
            System.out.println("二维码内容: " + result.getText());
            
            //	解密二维码内容
            String encryptStr = result.getText();
            String decryptStr = DESUtils.doDecrypt(encryptStr,num);
            
            System.out.println("解密后的二维码内容: " + decryptStr);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}


注意:小心观察要生成的字符串长度是有限制的!!!!!理论上内容经过压缩处理后可以存7089个数字,4296 个字母和数字混合字符,2953个8位字节数据,1817个汉字;

二维码格式:



版权声明:本文为qq_40238006原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。