在如今的生活中,二维码随处可见,二维码的出现既减少了宣传纸张的浪费,又方便了人们的生活。这一篇我来说说 Java 利用第三方 Jar 包 zxing 生成二维码。
1、下载zxing相关Jar包并引入工程中
若是maven工程,则在pom.xml中引入如下dependency即可,若不是maven工程,则可自行百度”zxing Jar“下载。
<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.0</version>
</dependency>
2、生成二维码主要有两种,一种是最普通的黑白二维码,另一种是中间带logo的彩色二维码,下面来一一介绍。
1)普通二维码
这种二维码的实现原理比较简单,就是根据二维码的高度和宽度,再根据zxing中的算法,拆分成一个一个的像素点,用黑白两色来填充即可。
/** * 生成二维码图片文件(不带LOGO) * * @param content 要生成二维码的内容 * @param width 二维码的高度 * @param height 二维码的宽度 * @return 二维码图片 * @throws WriterException 异常 */ private static BufferedImage genQrcode(String content, int width, int height) throws WriterException { Map<EncodeHintType, String> hints = new HashMap<>(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); //根据高度和宽度生成像素矩阵 BitMatrix bitMatrix = multiWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints); BufferedImage image = new BufferedImage(bitMatrix.getWidth(), bitMatrix.getHeight(), BufferedImage.TYPE_INT_RGB); for (int x = 0; x < bitMatrix.getWidth(); x++) { for (int y = 0; y < bitMatrix.getHeight(); y++) { //填充黑白两色 image.setRGB(x, y, bitMatrix.get(x, y) ? BLACK : WHITE); } } return image; }
2)中间带logo的彩色二维码
这种二维码的实现原理是根据二维码的高度和宽度,再根据zxing中的算法,拆分成一个一个的像素点,用各种颜色来填充,实现彩色二维码和渐变色二维码。
中间的logo则是相同原理,将logo图片拆解成像素点,在二维码中间区域用logo的像素点来填充。
下面列举几种二维码样式的核心生成代码
// 左上角颜色,根据自己需要调整颜色范围和颜色 if (x > 0 && x < 170 && y > 0 && y < 170) { Color color = new Color(231, 144, 56); int colorInt = color.getRGB(); pixels[y * width + x] = matrix.get(x, y) ? colorInt : 16777215; }
// 读取源图像并拆分成像素点 BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH, IMAGE_HEIGHT, true); int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT]; for (int i = 0; i < scaleImage.getWidth(); i++) { for (int j = 0; j < scaleImage.getHeight(); j++) { srcPixels[i][j] = scaleImage.getRGB(i, j);//图片的像素点 } } 。。。 // 将Logo图片的像素点填充到二维码中间区域 if (x > halfW - IMAGE_HALF_WIDTH && x < halfW + IMAGE_HALF_WIDTH && y > halfH - IMAGE_HALF_WIDTH && y < halfH + IMAGE_HALF_WIDTH) { pixels[y * width + x] = srcPixels[x - halfW + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH]; }
if (matrix.get(x, y)) { //生成渐变色 if (x < width / 2) { int num1 = (int) (255 - (255.0 - 120.0) / matrix.getHeight() * (matrix.getHeight() - y)); int num2 = (int) (0 - (0.0 - 0.0) / matrix.getHeight() * (matrix.getHeight() - y)); int num3 = (int) (0 - (0.0 - 0.0) / matrix.getHeight() * (matrix.getHeight() - y)); Color color = new Color(num1, num2, num3); int colorInt = color.getRGB(); // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色; pixels[y * width + x] = matrix.get(x, y) ? colorInt : 0xFF000000;// 0x000000:0xffffff } else { int num1 = (int) (0 - (0.0 - 0.0) / matrix.getHeight() * (matrix.getHeight() - y)); int num2 = (int) (0 - (0.0 - 0.0) / matrix.getHeight() * (matrix.getHeight() - y)); int num3 = (int) (255 - (255.0 - 120.0) / matrix.getHeight() * (matrix.getHeight() - y)); Color color = new Color(num1, num2, num3); int colorInt = color.getRGB(); // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色; pixels[y * width + x] = matrix.get(x, y) ? colorInt : 0xFF000000;// 0x000000:0xffffff } } else { pixels[y * width + x] = -1; //白色 }
if (matrix.get(x, y)) { //生成4色 if (x < width / 2 && y < height / 2) { pixels[y * width + x] = 0xFF0094FF;// 蓝色 Integer.toHexString(new Random().nextInt()); } else if (x < width / 2 && y > height / 2) { pixels[y * width + x] = 0xFFFED545;// 黄色 } else if (x > width / 2 && y > height / 2) { pixels[y * width + x] = 0xFF5ACF00;// 绿色 } else { pixels[y * width + x] = 0xFF000000;// 黑色 } } else { pixels[y * width + x] = -1; //白色 }
3、总结
以上说明了几种二维码的生成原理,并列举出了部份核心代码,其实根据拆分像素的原理,可以用任何形式的像素内容替换二维码中的像素,这样则可进行二维码的深度定制,生成其他更漂亮的二维码。
这里推荐CSDN的”一灰灰blog“,这篇文章讲解了如何深度定制二维码,希望大家可以看看。
https://blog.csdn.net/liuyueyi25/article/details/77131810
(CSDN”一灰灰blog“深度定制的二维码)
最后,贴上本篇文章中生成二维码的完整代码,供大家参考,希望能有所帮助。
package com.qrcode; 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; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import java.util.Random; public class CreateColourImageQRCode { // 图片宽度的一半 private static final int IMAGE_WIDTH = 50; private static final int IMAGE_HEIGHT = 50; private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2; private static final int FRAME_WIDTH = 2; private static final int BLACK = 0xFF000000; private static final int WHITE = 0xFFFFFFFF; // 二维码写码器 private static MultiFormatWriter multiWriter = new MultiFormatWriter(); public static void main(String[] args) throws UnsupportedEncodingException { // 依次为内容,宽,长,储存路径 CreateColourImageQRCode.encode("https://www.baidu.com/", 500, 500, null, "d:\\qrcode.jpg"); // 依次为内容,宽,长,logo图标路径,储存路径 CreateColourImageQRCode.encode("https://www.baidu.com/", 500, 500, "d:\\logo.jpg", "d:\\qrcode2.jpg"); } /** * 生成二维码 * * @param content 要生成二维码的内容 * @param width 二维码的宽度 * @param height 二维码的高度 * @param srcImagePath 二维码中间logo图片的路径 * @param destImagePath 生成二维码图片的路径 * @return 是否生成成功 */ public static void encode(String content, int width, int height, String srcImagePath, String destImagePath) { try { if (srcImagePath == null || "".equals(srcImagePath)) { //生成二维码图片文件(不带LOGO) ImageIO.write(genQrcode(content, width, height), "jpg", new File(destImagePath)); } else { //生成二维码图片文件(带LOGO) ImageIO.write(genQrcodeWithLogo(content, width, height, srcImagePath), "jpg", new File(destImagePath)); } } catch (Exception e) { e.printStackTrace(); } } /** * 生成二维码图片文件(不带LOGO) * * @param content 要生成二维码的内容 * @param width 二维码的高度 * @param height 二维码的宽度 * @return 二维码图片 * @throws WriterException 异常 */ private static BufferedImage genQrcode(String content, int width, int height) throws WriterException { Map<EncodeHintType, String> hints = new HashMap<>(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); //根据高度和宽度生成像素矩阵 BitMatrix bitMatrix = multiWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints); BufferedImage image = new BufferedImage(bitMatrix.getWidth(), bitMatrix.getHeight(), BufferedImage.TYPE_INT_RGB); for (int x = 0; x < bitMatrix.getWidth(); x++) { for (int y = 0; y < bitMatrix.getHeight(); y++) { //填充黑白两色 image.setRGB(x, y, bitMatrix.get(x, y) ? BLACK : WHITE); } } return image; } /** * 生成二维码图片文件(带LOGO) * * @param content 要生成二维码的内容 * @param width 二维码的宽度 * @param height 二维码的高度 * @param srcImagePath 二维码中间logo图片的路径 * @return 二维码图片 * @throws WriterException 异常 * @throws IOException 异常 */ private static BufferedImage genQrcodeWithLogo(String content, int width, int height, String srcImagePath) throws WriterException, IOException { // 读取源图像并拆分成像素点 BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH, IMAGE_HEIGHT, true); int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT]; for (int i = 0; i < scaleImage.getWidth(); i++) { for (int j = 0; j < scaleImage.getHeight(); j++) { srcPixels[i][j] = scaleImage.getRGB(i, j);//图片的像素点 } } //编码 Map hints = new Hashtable<EncodeHintType, String>(); hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //设置容错等级,在这里我们使用M级别 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); // 生成二维码 BitMatrix matrix = multiWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints); // 二维矩阵转为一维像素数组 int halfW = matrix.getWidth() / 2; int halfH = matrix.getHeight() / 2; int[] pixels = new int[width * height]; for (int y = 0; y < matrix.getHeight(); y++) { for (int x = 0; x < matrix.getWidth(); x++) { // 左上角颜色,根据自己需要调整颜色范围和颜色 if (x > 0 && x < 170 && y > 0 && y < 170) { Color color = new Color(231, 144, 56); int colorInt = color.getRGB(); pixels[y * width + x] = matrix.get(x, y) ? colorInt : 16777215; } else // 将Logo图片的像素点填充到二维码中间区域 if (x > halfW - IMAGE_HALF_WIDTH && x < halfW + IMAGE_HALF_WIDTH && y > halfH - IMAGE_HALF_WIDTH && y < halfH + IMAGE_HALF_WIDTH) { pixels[y * width + x] = srcPixels[x - halfW + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH]; } // 在图片四周形成边框 else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH) || (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH) || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH - IMAGE_HALF_WIDTH + FRAME_WIDTH) || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH && y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH)) { pixels[y * width + x] = 0xfffffff; } else { if (matrix.get(x, y)) { // //生成4色 // if (x < width / 2 && y < height / 2) { // pixels[y * width + x] = 0xFF0094FF;// 蓝色 // Integer.toHexString(new Random().nextInt()); // } else if (x < width / 2 && y > height / 2) { // pixels[y * width + x] = 0xFFFED545;// 黄色 // } else if (x > width / 2 && y > height / 2) { // pixels[y * width + x] = 0xFF5ACF00;// 绿色 // } else { // pixels[y * width + x] = 0xFF000000;// 黑色 // } //生成渐变色 if (x < width / 2) { int num1 = (int) (255 - (255.0 - 120.0) / matrix.getHeight() * (matrix.getHeight() - y)); int num2 = (int) (0 - (0.0 - 0.0) / matrix.getHeight() * (matrix.getHeight() - y)); int num3 = (int) (0 - (0.0 - 0.0) / matrix.getHeight() * (matrix.getHeight() - y)); Color color = new Color(num1, num2, num3); int colorInt = color.getRGB(); // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色; pixels[y * width + x] = matrix.get(x, y) ? colorInt : 0xFF000000;// 0x000000:0xffffff } else { int num1 = (int) (0 - (0.0 - 0.0) / matrix.getHeight() * (matrix.getHeight() - y)); int num2 = (int) (0 - (0.0 - 0.0) / matrix.getHeight() * (matrix.getHeight() - y)); int num3 = (int) (255 - (255.0 - 120.0) / matrix.getHeight() * (matrix.getHeight() - y)); Color color = new Color(num1, num2, num3); int colorInt = color.getRGB(); // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色; pixels[y * width + x] = matrix.get(x, y) ? colorInt : 0xFF000000;// 0x000000:0xffffff } } else { pixels[y * width + x] = -1; //白色 } } } } BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); image.getRaster().setDataElements(0, 0, width, height, pixels); return image; } /** * 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标 * * @param srcImageFile 源文件地址 * @param height 目标高度 * @param width 目标宽度 * @param hasFiller 比例不对时是否需要补白:true为补白; false为不补白; * @throws IOException */ private static BufferedImage scale(String srcImageFile, int height, int width, boolean hasFiller) throws IOException { double ratio = 0.0; // 缩放比例 File file = new File(srcImageFile); BufferedImage srcImage = ImageIO.read(new File(srcImageFile)); 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(); } 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; } }