Java通过Zxing生成和解析二维码

Posted 第三眼的思绪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java通过Zxing生成和解析二维码相关的知识,希望对你有一定的参考价值。

java在对二维码进行操作的工具jar来源主要有两种,一种google开发提供的Zxing相关jar,一种是小日本开发提供的Qrcode.jar。以下将对二维码的生成和解析进行详解。
本例中采用google提供的二维码生成工具jar进行操作
 

生成二维码:

在贴出demo代码之前,我们先把其中会用到的部分工具类源码贴出来。

矩阵输出为图片流工具类MatrixToImageWriter:

package com.google.zxing.client.j2se;

import com.google.zxing.common.BitMatrix;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Path;
import javax.imageio.ImageIO;

public final class MatrixToImageWriter

  private static final MatrixToImageConfig DEFAULT_CONFIG = new MatrixToImageConfig();
  
  public static BufferedImage toBufferedImage(BitMatrix matrix)
  
    return toBufferedImage(matrix, DEFAULT_CONFIG);
  
  
  public static BufferedImage toBufferedImage(BitMatrix matrix, MatrixToImageConfig config)
  
    int width = matrix.getWidth();
    int height = matrix.getHeight();
    BufferedImage image = new BufferedImage(width, height, config.getBufferedImageColorModel());
    int onColor = config.getPixelOnColor();
    int offColor = config.getPixelOffColor();
    for (int x = 0; x < width; x++) 
      for (int y = 0; y < height; y++) 
        image.setRGB(x, y, matrix.get(x, y) ? onColor : offColor);
      
    
    return image;
  
  
  @Deprecated
  public static void writeToFile(BitMatrix matrix, String format, File file)
    throws IOException
  
    writeToPath(matrix, format, file.toPath());
  
  
  public static void writeToPath(BitMatrix matrix, String format, Path file)
    throws IOException
  
    writeToPath(matrix, format, file, DEFAULT_CONFIG);
  
  
  @Deprecated
  public static void writeToFile(BitMatrix matrix, String format, File file, MatrixToImageConfig config)
    throws IOException
  
    writeToPath(matrix, format, file.toPath(), config);
  
  
  public static void writeToPath(BitMatrix matrix, String format, Path file, MatrixToImageConfig config)
    throws IOException
  
    BufferedImage image = toBufferedImage(matrix, config);
    if (!ImageIO.write(image, format, file.toFile())) 
      throw new IOException("Could not write an image of format " + format + " to " + file);
    
  
  
  public static void writeToStream(BitMatrix matrix, String format, OutputStream stream)
    throws IOException
  
    writeToStream(matrix, format, stream, DEFAULT_CONFIG);
  
  
  public static void writeToStream(BitMatrix matrix, String format, OutputStream stream, MatrixToImageConfig config)
    throws IOException
  
    BufferedImage image = toBufferedImage(matrix, config);
    if (!ImageIO.write(image, format, stream)) 
      throw new IOException("Could not write an image of format " + format);
    
  

二维码矩阵图片配置类MatrixToImageConfig(这里主要配置背景及条码颜色):

package com.google.zxing.client.j2se;

public final class MatrixToImageConfig

  public static final int BLACK = -16777216;
  public static final int WHITE = -1;
  private final int onColor;
  private final int offColor;
  
  public MatrixToImageConfig()
  
    this(-16777216, -1);
  
  
  public MatrixToImageConfig(int onColor, int offColor)
  
    this.onColor = onColor;
    this.offColor = offColor;
  
  
  public int getPixelOnColor()
  
    return this.onColor;
  
  
  public int getPixelOffColor()
  
    return this.offColor;
  
  
  int getBufferedImageColorModel()
  
    if ((this.onColor == -16777216) && (this.offColor == -1)) 
      return 12;
    
    if ((hasTransparency(this.onColor)) || (hasTransparency(this.offColor))) 
      return 2;
    
    return 1;
  
  
  private static boolean hasTransparency(int argb)
  
    return (argb & 0xFF000000) != -16777216;
  


生成二维码代码如下:

@Test  
public void testEncode() throws WriterException, IOException   
	String content = "http://www.baidu.com";//这里content为二维码数据。为地址将直接访问,为text将直接解析
	int width = 200; // 图像宽度
	int height = 200; // 图像高度
	String format = "png";// 图像类型
	Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
	hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
	hints.put(EncodeHintType.MARGIN, 4);//设置二维码边的空度,非负数,默认值为4。
	BitMatrix bitMatrix = new MultiFormatWriter().encode(content,BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵
	//MatrixToImageWriter提供多种方式输出二维码,并同时提供二维码其他信息配置的重载方法
	MatrixToImageWriter.writeToFile(bitMatrix, format, new File("d:/qrcode_test.png"));// 输出图像

到此,二维码的生成就完成了。

但是,如果要在二维码上添加logo图片,则上述的方法是做不到的,需要自定义一些方法,例如:logo图片的缩放(是否等比例和不等比例情况是否补白)、边框处理、整合到二维码矩阵和颜色设置。如下所示:

logo图片处理代码如下。

/**
 * 把传入的原始图像按高度和宽度进行等比例缩放,生成符合要求的图标
 * 
 * @param srcImageFile 源文件地址
 * @param width 目标宽度
 * @param height 目标高度
 * @param hasFiller 比例不对时是否需要补白:true为补白; false为不补白;
 * @throws IOException
 */
private static BufferedImage scale(String srcImageFile, int width, int height, boolean hasFiller) throws IOException 
	double ratio = 1.0; // 缩放比例
	File file = new File(srcImageFile);
	BufferedImage srcImage = ImageIO.read(file);
	Image destImage = srcImage.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH);
	// 计算比例
	if ((srcImage.getHeight() != height) || (srcImage.getWidth() != width)) 
		if (srcImage.getHeight() > srcImage.getWidth()) 
			ratio = (new Integer(height)).doubleValue() / srcImage.getHeight();
		 else 
			ratio = (new Integer(width)).doubleValue() / srcImage.getWidth();
		
		//等比例缩放。若不等比例缩放,而是直接缩放,这需要两个缩放因子ratiox和ratioy分别传入即可
		AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null);
		destImage = op.filter(srcImage, null);
	
	if (hasFiller) // 补白
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics2D graphic = image.createGraphics();
		graphic.setColor(Color.white);
		graphic.fillRect(0, 0, width, height);
		if (width == destImage.getWidth(null))
			graphic.drawImage(destImage, 0, (height - destImage.getHeight(null)) / 2, destImage.getWidth(null), destImage.getHeight(null), Color.white, null);
		else
			graphic.drawImage(destImage, (width - destImage.getWidth(null)) / 2, 0, destImage.getWidth(null), destImage.getHeight(null), Color.white, null);
		graphic.dispose();
		destImage = image;
	
	return (BufferedImage) destImage;

整合二维码、logo图片、边框并加上颜色。

public void testEncode2() throws WriterException, IOException 
	//**个人见解:logo高宽为二维码高宽1/5为佳,logo边框宽度为二维码高宽1/10为佳。logo占比例太大会导致难识别
	int logoW = 20; //logo图像宽度
	int logoH = 20; //logo图像高度
	int width = 200; // 二维码图像宽度
	int height = 200; // 二维码图像高度
	int frameW = 2; //边框宽度
	String logoUrl = "D:/Koala.jpg"; //logo图片地址

	BufferedImage scaledImage = scale(logoUrl, logoW, logoH, false);
	//声明二维数组,用于存储logo像素RGB值
	int[][] scaledPixels = new int[scaledImage.getWidth()][scaledImage.getHeight()];
	//将缩放后的图片像素点RGB值存放到二维数组中
	for (int i = 0; i < scaledImage.getWidth(); i++) 
		for (int j = 0; j < scaledImage.getHeight(); j++) 
			scaledPixels[i][j] = scaledImage.getRGB(i, j);
		
	
	String content = "内容";//这里content为二维码数据。为地址将直接访问,为text将直接解析
	String format = "jpg";// 图像类型
	Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
	hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
	BitMatrix matrix = new MultiFormatWriter().encode(content,BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵
	//声明并计算赋值二维码矩阵和中心图的半宽和半高,用于判断计算各部分区域
	int matrixHalfWidth = matrix.getWidth() / 2;
	int matrixHalfHeight = matrix.getHeight() / 2;
	int logoHalfWidth = scaledImage.getWidth() / 2;
	int logoHalfHeight = scaledImage.getHeight() / 2;
	//声明一维数组
	int[] pixels = new int[matrix.getWidth() * matrix.getHeight()];
	for (int y = 0; y < matrix.getHeight(); y++) 
		for (int x = 0; x < matrix.getWidth(); x++) 
			//中心图片
			if(x > matrixHalfWidth - logoHalfWidth
					&& x < matrixHalfWidth + logoHalfWidth
					&& y > matrixHalfHeight - logoHalfHeight
					&& y <  matrixHalfHeight + logoHalfHeight)
				pixels[y * width + x] = scaledPixels[x - matrixHalfWidth + logoHalfWidth][y - matrixHalfHeight + logoHalfHeight];
			//边框
			else if((x > matrixHalfWidth - logoHalfWidth - frameW
					&& x < matrixHalfHeight + logoHalfHeight + frameW
					&& y > matrixHalfHeight - logoHalfHeight - frameW
					&& y < matrixHalfHeight + logoHalfHeight + frameW)
					&& !(x > matrixHalfWidth - logoHalfWidth
							&& x < matrixHalfWidth + logoHalfWidth
							&& y > matrixHalfHeight - logoHalfHeight
							&& y <  matrixHalfHeight + logoHalfHeight))
				pixels[y * width + x] = 0xfffffff;//白色
			else
				//这里是二维码颜色,可以设置二维码和背景颜色,方法get(x, y)获取此像素点上是否存在矩阵点
				pixels[y * width + x] = matrix.get(x, y) ? 0xff000000 : 0xfffffff;
			
		
	
	BufferedImage image = new BufferedImage(matrix.getWidth(), matrix.getHeight(), BufferedImage.TYPE_INT_RGB);
	image.getRaster().setDataElements(0, 0, matrix.getWidth(), matrix.getHeight(), pixels);
	ImageIO.write(image, format, new File("D:/qrcode.png"));

这样就完成了带logo的二维码设计。


二维码解码
下面对二维码进行解码,解码代码如下:

@Test
public void testDecode()
	try 
		String filePath = "D:/qrcode_test.png";
		// 读取二维码图片到缓冲区
		BufferedImage image = ImageIO.read(new File(filePath));
		LuminanceSource source = new BufferedImageLuminanceSource(image);
		Binarizer binarizer = new HybridBinarizer(source);
		BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
		Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
		hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
		Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 对图像进行解码
		System.out.println("======>>encode Type: " + result.getBarcodeFormat() + "      ======>>content:" + result.getText());
	 catch (Exception e) 
		e.printStackTrace();
	

支持带logo和未带logo解码。
 

以上是关于Java通过Zxing生成和解析二维码的主要内容,如果未能解决你的问题,请参考以下文章

java zxing实现二维码生成和解析zxing实现二维码生成和解析

java zxing实现二维码生成和解析zxing实现二维码生成和解析

java生成和解析二维码

Java使用ZXing生成/解析二维码图片

关于java的二维码的生成与解析

Java条形码/二维码生成和解析