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实现二维码生成和解析