Java 生成 二维码 (可带logo)(QrCode) google zxing
- 主要Maven 依赖。
<!--谷歌二维码 --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.3.0</version> </dependency>
- 代码片段
- 绘制二维码。
- 生成二维码 BitMatrix 。
- 构建一个同尺寸的 BufferedImage 对象。
- 双重遍历,将 二维码对象,通过RGB色值保存到 步骤 2 的 BufferedImage的对象里。
- 这里 二维码已经生成好了,只需将其导出即可。
- 如果需要插入logo的话,设置 好参数会自动居中插入的。
/** * 生成二维码 * * @param linkUrl * 二维码真实uri * @param hasFrame * 是否删除白边 * @param logoStatus * 是否插入logo * @param logoPath * logoPath * @param logoNeedCompress * 是否压缩 logo * @throws Exception */ public static BufferedImage createQrCode(String linkUrl, boolean hasFrame, boolean logoStatus, String logoPath, boolean logoNeedCompress, int qrCodeSize) throws Exception { Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); hints.put(EncodeHintType.CHARACTER_SET, CHARSET); hints.put(EncodeHintType.MARGIN, 1); // 二维码的默认尺寸为 172像素 if (qrCodeSize == 0) { qrCodeSize = QRCODE_SIZE; } BitMatrix bitMatrix = new MultiFormatWriter().encode(linkUrl, BarcodeFormat.QR_CODE, qrCodeSize, qrCodeSize, hints); // 删除白边 if (hasFrame) { bitMatrix = QrCodeUtil.deleteWhite(bitMatrix); } 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); } } // 插入二维码 logo if (logoStatus) { // 将logo 图片转换为 BufferedImage。 BufferedImage logoBufferedImage = QrCodeUtil.imageToBufferedImage(logoPath); // 构建画笔工具,将logo 绘制到二维码上。 QrCodeUtil.insertImage(image, logoBufferedImage, logoNeedCompress, hasFrame, qrCodeSize); } return image; }
补充001: 这里提供一些将 图片地址转换为 BufferdImage的 函数。(PS:转为BufferedImage 直接使用 ImageIO 可能会使图片染红。)
/** * image File 转 BufferedImage 直接使用 ImageIO 可能会使图片染红。 * * @param imaPath * @return * @throws Exception */ public static BufferedImage imageToBufferedImage(String imaPath) throws Exception { if (StringUtils.isNotBlank(imaPath)) { Image src = null; BufferedImage img = null; if (imaPath.startsWith("http")) { src = Toolkit.getDefaultToolkit().getImage(new URL(imaPath)); } else { src = Toolkit.getDefaultToolkit().getImage(imaPath); } if (src != null) { img = toBufferedImage(src); } return img; } else { return null; } } /** * image File 转 BufferedImage 的依赖函数 * * @param image * @return */ public static BufferedImage toBufferedImage(Image image) { if (image instanceof BufferedImage) { return (BufferedImage)image; } // This code ensures that all the pixels in the image are loaded image = new ImageIcon(image).getImage(); BufferedImage bimage = null; GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); try { int transparency = Transparency.OPAQUE; GraphicsDevice gs = ge.getDefaultScreenDevice(); GraphicsConfiguration gc = gs.getDefaultConfiguration(); bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency); } catch (HeadlessException e) { // The system does not have a screen } if (bimage == null) { // Create a buffered image using the default color model int type = BufferedImage.TYPE_INT_RGB; bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type); } // Copy image to buffered image Graphics g = bimage.createGraphics(); // Paint the image onto the buffered image g.drawImage(image, 0, 0, null); g.dispose(); return bimage; }
补充002:删除白边的函数。
/** * 删除二维码白边 * * @param bitMatrix * @return */ public static BitMatrix deleteWhite(BitMatrix bitMatrix) { int[] rec = bitMatrix.getEnclosingRectangle(); int resWidth = rec[2] + 1; int resHeight = rec[3] + 1; BitMatrix resMatrix = new BitMatrix(resWidth, resHeight); resMatrix.clear(); for (int i = 0; i < resWidth; i++) { for (int j = 0; j < resHeight; j++) { if (bitMatrix.get(i + rec[0], j + rec[1])) { resMatrix.set(i, j); } } } return resMatrix; }
补充003:二维码插入logo。
/* * 插入LOGO * * @param source 二维码图片 * * @param imgPath LOGO图片地址 * * @param needCompress 是否缩放 * * @param frame 是否去白边 * * @param qrCodeSize 二维码尺寸 * * @throws Exception */ public static void insertImage(BufferedImage source, BufferedImage logoBufferedImage, boolean needCompress, boolean frame, int qrCodeSize) throws Exception { if (logoBufferedImage == null) { return; } int width = logoBufferedImage.getWidth(); int height = logoBufferedImage.getHeight(); // 缩放 if (needCompress) { // 缩放的默认尺寸。 if (width > WIDTH) { width = WIDTH; } // 缩放的默认尺寸。 if (height > HEIGHT) { height = HEIGHT; } // 缩放。 logoBufferedImage = Thumbnails.of(logoBufferedImage).size(width, height).asBufferedImage(); } // 插入LOGO Graphics2D graph = source.createGraphics(); int x = 0; int y = 0; if (frame) { x = (qrCodeSize - width - (height / 2)) / 2; y = (qrCodeSize - height - (height / 2)) / 2; } else { x = (qrCodeSize - width) / 2; y = (qrCodeSize - height) / 2; } graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // logoBufferedImage 是 logo对象 xy 是gs两个边的距离,width height 是 logo的大小 graph.drawImage(logoBufferedImage, x, y, width, height, null); // 二维码logo居中时的边框 圆角的弧度。美观使用。 Shape shape = new RoundRectangle2D.Float(x, y, width, height, 8, 8); // 默认情况下,Graphics绘图类使用的笔画属性是粗细为1个像素的正方形,而Java2D的Graphics2D类可以调用setStroke()方法设置笔画的属性,如改变线条的粗细、虚实和定义线段端点的形状、风格等 graph.setStroke(new BasicStroke(3f)); graph.draw(shape); graph.dispose(); }
补充004: Thumbnails 这里使用了 google 的 压缩工具类。给出pom依赖。
<!-- google 图片处理工具 --> <dependency> <groupId>net.coobird</groupId> <artifactId>thumbnailator</artifactId> <version>0.4.6</version> </dependency>
补充005:logo 如果为PNG 格式,可能会出现低背 发黑的问题。解决办法建议,还jpg格式。或者~~~、
补充006:这个给出一个测试的将BufferedImage 序列化到本地磁盘的函数。
/** * * @param bufferImage * 画布对象 * @param scale * 缩放 (0.0~1.0) * @param outFormat * 输出格式(JPG。PNG) * @param outPutQuality * 输出品质(0.0~1.0) * @param pngPath * 输出路径 * @throws Exception */ public static void savePic(BufferedImage bufferImage, double scale, String outFormat, double outPutQuality, String pngPath) throws Exception { File file = new File(pngPath); byte[] picByQuality = QrCodeUtil.compressPicByQuality(bufferImage, 1f); ByteArrayInputStream in = new ByteArrayInputStream(picByQuality); BufferedImage qualityBufferImage = ImageIO.read(in); Thumbnails.of(qualityBufferImage).scale(scale).outputFormat(outFormat).outputQuality(outPutQuality) .toFile(file); }
- 绘制二维码。