Java后台利用Zxing实现生成二维码图片和二维码Base64

本篇文章将介绍Java使用Zxing和commons-codec实现生成二维码图片和二维码Base64。

说明:针对Maven工程和普通的java工程,jar包的引入方式不同,此处只介绍Maven工程jar引入方式。

一、在pom.xml文件中添加依赖



    com.google.zxing
    core
    3.4.0



    com.google.zxing
    javase
    3.4.0




     commons-codec
     commons-codec
     1.15

建议:jar有时候不一定非要引入最新的,在maven仓库中可以在最近的年份中选择使用人数最多的。

二、 生成 base64二维码

package utils;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import org.apache.commons.codec.binary.Base64;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;

/**
 * @name QrCodeUtils
 * @Description URL转Base64二维码
 * @author wanglong
 * @date   2021年1月20日下午1:08:53
 * @version 1.0
 */
public class QrCodeUtils {
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static String creatRrCode(String contents, int width, int height) {
		String base64 = "";
        
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
            
            // 1、读取文件转换为字节数组
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            BufferedImage image = toBufferedImage(bitMatrix);
            
            //转换成png格式的IO流
            ImageIO.write(image, "png", out);
            byte[] bytes = out.toByteArray();

            // 2、将字节数组转为二进制
            base64 = Base64.encodeBase64String(bytes).trim();
            
        } catch (WriterException e) {
            e.printStackTrace();
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return base64;
    }

    /**
     * image流数据处理
     */
    private static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        return image;
    }

    public static void main(String[] args) {
    	// 测试代码
        String base64Pic = QrCodeUtils.creatRrCode("http://zf.thxyy.cn/weixinmpPlus/byCodePay/list?dd=JC2101080005&ts=1610080940", 200,200);
        System.out.println(base64Pic);
    }
}

说明:此处生成Base64,使用的是org.apache.commons.codec.binary.Base64,而不是sun.misc.BASE64Encoder,因为后者在有的ide中提示是内部方法,有可能在未来版本会删除。建议还是使用第三方开源的。

使用场景:

<1>返回给前台,直接展示:

// 记得从后台返回的base64字符串要加上前缀:data:image/jpeg;base64,

<2>在jasper中使用,打印pdf预览(下面只提供简单样例,里面用到的工具类不在这书写):

// 4、打印 记录
@Override
public Map selectCourseGeneralData(String id, String token) {
    Map map = new HashMap<>();
		
	List> listMap = new ArrayList<>();
	Map params = new HashMap<>();
	try {
		EmrCourse record = emrCourseMapper.selectByPrimaryKey(id);
		if (record != null) {
			map.put("patientName", record.getPatientName());
			map.put("fkHosRegisterHosNo", record.getFkHosRegisterHosNo());

			String base64Pic = QrCodeUtils.creatRrCode("二维码内容", 200,200);
            map.put("base64Pic", base64Pic);

			String generalRecords = record.getGeneralRecords() == null ? "" : record.getGeneralRecords();
				
			params.put("courseRecordTime", DateUtil.dateToString(record.getCourseRecordTime(), "yyyy-MM-dd HH:mm"));
			params.put("generalRecords", generalRecords);
			params.put("signatureDate", DateUtil.dateToString(record.getSignatureDate(), "yyyy-MM-dd"));
				
			listMap.add(params);
			map.put("courseList", listMap);
		}
	} catch (Exception e) {
			e.printStackTrace();
	}
		
	return map;
}
	
// 4.1
@Override
public void printCourseGeneral(Map map, HttpServletResponse response) {
	try {
        /** jasper中用到List组件时,要用此构造函数 */
		JRDataSource jrDataSource = new JREmptyDataSource();
		File reportFile = new File(jasperPath + "emrCourseGeneral.jasper");
	    String exportFileName = Instant.now().toEpochMilli() + "记录.pdf";
	        
	    JasperHelper.exportToFile("pdf", jasperPath + exportFileName, reportFile, map, jrDataSource, "");
	    PdfUtil.downloadFile(response, jasperPath + exportFileName, exportFileName);
		        
	} catch (Exception e) {
		e.printStackTrace();
	}
}

下面来说下在jasper中的配置(此图与上面样例有些出入,重点是看图中的base64Pic所在位置

Java后台利用Zxing实现生成二维码图片和二维码Base64_第1张图片

 base64Pic字段所在的Image控件配置如下图所示:

Java后台利用Zxing实现生成二维码图片和二维码Base64_第2张图片

在Image Expression属性中,对base64Pic要做处理: new ByteArrayInputStream(org.apache.commons.codec.binary.Base64.decodeBase64($P{base64Pic}.getBytes()))

至此,对于URL转换为Base64二维码及展示大体如上所示。

三、生成二维码图片(可以内嵌 logo),保存到本地磁盘

package utils;

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Random;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
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.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

public class QrCodeUtils2 {
	private static final String CHARSET = "utf-8";
	
    private static final String FORMAT = "JPG";
    // 二维码尺寸  
    private static final int QRCODE_SIZE = 300;
    // LOGO宽度  
    private static final int LOGO_WIDTH = 60;
    // LOGO高度  
    private static final int LOGO_HEIGHT = 60;

    
    /**
     * 公用方法:1、生成图片
     */
    private static BufferedImage createImage(String content, String logoPath, boolean needCompress) throws Exception {
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        if (logoPath == null || "".equals(logoPath)) {
            return image;
        }
        
        // 插入图片  
        QrCodeUtils2.insertImage(image, logoPath, needCompress);
        return image;
    }

    /**
     * 公用方法:2、插入LOGO 
     * @param source 二维码图片 
     * @param logoPath LOGO图片地址 
     * @param needCompress 是否压缩 
     */
    private static void insertImage(BufferedImage source, String logoPath, boolean needCompress) throws Exception {
		File file = new File(logoPath);
		if (!file.exists()) {
			throw new Exception("logo file not found.");
		}

		Image src = ImageIO.read(new File(logoPath));
		int width = src.getWidth(null);
		int height = src.getHeight(null);
		if (needCompress) { // 压缩LOGO
			if (width > LOGO_WIDTH) {
				width = LOGO_WIDTH;
			}
			if (height > LOGO_HEIGHT) {
				height = LOGO_HEIGHT;
            }
			
            Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            g.drawImage(image, 0, 0, null); // 绘制缩小后的图  
            g.dispose();
            src = image;
        }
		
		// 插入LOGO
		Graphics2D graph = source.createGraphics();
		int x = (QRCODE_SIZE - width) / 2;
		int y = (QRCODE_SIZE - height) / 2;
		graph.drawImage(src, x, y, width, height, null);

		Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
		graph.setStroke(new BasicStroke(3f));
		graph.draw(shape);
		graph.dispose();
	}
    
    
    /**
     * 1、生成二维码(内嵌LOGO): 二维码文件名随机,文件名可能会有重复 
     * @param content 内容 
     * @param logoPath LOGO地址 
     * @param destPath 存放目录 
     * @param needCompress 是否压缩LOGO 
     */
    public static String encode(String content, String logoPath, String destPath, boolean needCompress) throws Exception {
        BufferedImage image = QrCodeUtils2.createImage(content, logoPath, needCompress);
        mkdirs(destPath);
        
        String fileName = new Random().nextInt(99999999) + "." + FORMAT.toLowerCase();
        ImageIO.write(image, FORMAT, new File(destPath + "/" + fileName));
        
        return fileName;
    }

    /**
     * 1.5 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir。 (mkdir如果父目录不存在则会抛出异常) 
     * @param destPath  存放目录 
     */
    public static void mkdirs(String destPath) {
    	File file = new File(destPath);
    	if (!file.exists() && !file.isDirectory()) {
    		file.mkdirs();
    	}
    }
    
    /**
     * 2、生成二维码(内嵌LOGO):调用指定二维码文件名 
     * @param content  内容 
     * @param logoPath LOGO地址 
     * @param destPath 存放目录 
     * @param fileName 二维码文件名 
     * @param needCompress 是否压缩LOGO 
     */
    public static String encode(String content, String logoPath, String destPath, String fileName, boolean needCompress) throws Exception {
		BufferedImage image = QrCodeUtils2.createImage(content, logoPath, needCompress);
		mkdirs(destPath);
		
		fileName = fileName.substring(0, fileName.indexOf(".") > 0 ? fileName.indexOf(".") : fileName.length()) + "." + FORMAT.toLowerCase();
		ImageIO.write(image, FORMAT, new File(destPath + "/" + fileName));
		
		return fileName;
	}
    


    /**
     * 3、生成二维码(内嵌LOGO) 
     * @param content  内容 
     * @param logoPath LOGO地址 
     * @param destPath 存储地址 
     */
    public static String encode(String content, String logoPath, String destPath) throws Exception {
        return QrCodeUtils2.encode(content, logoPath, destPath, false);
    }

    
    /**
     * 4、生成二维码 
     * @param content 内容 
     * @param destPath 存储地址 
     * @param needCompress 是否压缩LOGO 
     */
    public static String encode(String content, String destPath, boolean needCompress) throws Exception {
        return QrCodeUtils2.encode(content, null, destPath, needCompress);
    }

    
    /**
     * 5、生成二维码 
     * @param content 内容 
     * @param destPath 存储地址 
     */
    public static String encode(String content, String destPath) throws Exception {
        return QrCodeUtils2.encode(content, null, destPath, false);
    }

    
    /**
     * 6、生成二维码(内嵌LOGO) 
     * @param content 内容 
     * @param logoPath LOGO地址 
     * @param output 输出流 
     * @param needCompress 是否压缩LOGO 
     */
    public static void encode(String content, String logoPath, OutputStream output, boolean needCompress) throws Exception {
        BufferedImage image = QrCodeUtils2.createImage(content, logoPath, needCompress);
        ImageIO.write(image, FORMAT, output);
    }

    /**
     * 7、生成二维码 
     * @param content 内容 
     * @param output 输出流 
     */
    public static void encode(String content, OutputStream output) throws Exception {
        QrCodeUtils2.encode(content, null, output, false);
    }

    /**
     * 8、解析二维码 
     * @param file 二维码图片 
     */
    public static String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        
        Result result;
        Hashtable hints = new Hashtable();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        
        return resultStr;
    }

    
    /**
     * 9、解析二维码 
     * @param path 二维码图片地址 
     */
    public static String decode(String path) throws Exception {
        return QrCodeUtils2.decode(new File(path));
    }

    
    
    public static void main(String[] args) throws Exception {
        String text = "http://zf.thxyy.cn/weixinmpPlus/byCodePay/list?dd=JC2101080005&ts=1610080940";
        //不含Logo  
        QrCodeUtils2.encode(text, null, "C:\\jasper", true);
        
        //含Logo,不指定二维码图片名  
        QrCodeUtils2.encode(text, "E:\\WallPaper\\o_hd2.jpg", "C:\\jasper", true);
        
        //含Logo,指定二维码图片名  
        QrCodeUtils2.encode(text, "E:\\WallPaper\\o_hd2.jpg", "C:\\jasper", "qrcode", true);
    }
}

 

你可能感兴趣的:(工具类,java)