高质量、易识别、小尺寸二维码生成
1.增大二维码的原始尺寸(例如 1000 x 1000 或更大),再缩放为 PDF 所需的大小。这样可以保留更多像素细节,提高识别率。
2.降低容错级别到 L 或 M,如果你的内容不是特别长或复杂的话,这样能减少密集度。
3.优化缩放方式:
• 使用 BufferedImage 放大或缩小时,避免图片模糊。
• 尽量在原始生成阶段保持高分辨率。
需要引入zxing
<!-- zxing -->
<dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.0</version>
</dependency>
<dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.5.0</version>
</dependency>
/*** 生成二维码* @param content 字符串(二维码内容)* @param cb PDF模版文件* @throws Exception*/
private void generateQRcode(String content, PdfContentByte cb) throws Exception {Map<EncodeHintType, Object> hints = new HashMap<>();hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); // 容错级别调为 Lhints.put(EncodeHintType.MARGIN, 0); // 去掉白边,实际没起作用int originalSize = 1000; // 生成更大的二维码QRCodeWriter qrCodeWriter = new QRCodeWriter();BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, originalSize, originalSize, hints);int width = bitMatrix.getWidth();int height = bitMatrix.getHeight();// 创建高分辨率的 BufferedImageBufferedImage qrImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics2D graphics = qrImage.createGraphics();// 设置背景为白色graphics.setColor(Color.WHITE);graphics.fillRect(0, 0, width, height);// 绘制二维码graphics.setColor(Color.BLACK);for (int x = 0; x < width; x++) {for (int y = 0; y < height; y++) {if (bitMatrix.get(x, y)) {qrImage.setRGB(x, y, 0xFF000000);}}}graphics.dispose(); // 释放图形资源// 将高质量二维码写入字节流ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ImageIO.write(qrImage, "png", byteArrayOutputStream);// 从字节流中读取为 iText Image 对象Image qrcodeImage = PngImage.getImage(byteArrayOutputStream.toByteArray());// 缩放图片到适合 PDF 的大小qrcodeImage.scaleAbsolute(274, 271);// 设置位置qrcodeImage.setAbsolutePosition(417, 13);cb.addImage(qrcodeImage);
}
二维码裁剪白色边框
hints.put(EncodeHintType.MARGIN, 0)去掉白边代码,实际没起作用
InputStream templateStream = getClass().getResourceAsStream("/template/Autumntemplate.pdf");PdfReader reader = new PdfReader(templateStream);ByteArrayOutputStream outputStream = new ByteArrayOutputStream();PdfStamper stamper = new PdfStamper(reader, outputStream);// 获取第1页的 PdfContentBytePdfContentByte cb = stamper.getOverContent(1);// 传入 PdfContentByte 对象,附加二维码generateQRcode(qrContent, cb);/*** 生成二维码并附加到PDF上* @param content* @param cb* @throws Exception*/private void generateQRcode(String content, PdfContentByte cb) throws Exception {Map<EncodeHintType, Object> hints = new HashMap<>();hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");// 容错级别调为 Lhints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);// 去掉白边,实际没有去掉hints.put(EncodeHintType.MARGIN, 0);// 生成更大的二维码int originalSize = 1000;QRCodeWriter qrCodeWriter = new QRCodeWriter();BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, originalSize, originalSize, hints);// 创建一个与二维码大小相同的 BufferedImageint width = bitMatrix.getWidth();int height = bitMatrix.getHeight();BufferedImage qrImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 填充二维码图像for (int x = 0; x < width; x++) {for (int y = 0; y < height; y++) {qrImage.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);}}// 裁剪掉白色边距BufferedImage croppedImage = cropWhiteBorder(qrImage);ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ImageIO.write(croppedImage, "png", byteArrayOutputStream);Image qrcodeImage = PngImage.getImage(byteArrayOutputStream.toByteArray());// 设置图片大小,最终二维码大小和位置在这里设置qrcodeImage.scaleAbsolute(274, 271);// 设置位置qrcodeImage.setAbsolutePosition(417, 13);cb.addImage(qrcodeImage);}/*** 去二维码白边* @param image* @return*/private BufferedImage cropWhiteBorder(BufferedImage image) {int width = image.getWidth();int height = image.getHeight();int left = width, right = 0, top = height, bottom = 0;for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {// 如果是黑色像素if (image.getRGB(x, y) == 0xFF000000) {if (x < left) left = x;if (x > right) right = x;if (y < top) top = y;if (y > bottom) bottom = y;}}}// 根据检测到的边界裁剪return image.getSubimage(left, top, right - left + 1, bottom - top + 1);}