解决Zxing生成的二维码留白过多问题

发布时间 2023-05-31 18:47:19作者: IamHzc

代码实现

/**
 * 二维码生成
 * 该方法可以有效去除生成的二维码的多余空白
 * @param url 二维码跳转路径
 * @param height 高
 * @param width 宽
 * @param imageType 图片格式
 * @param hint 留白度
 */
public static String generateQRCodeFile(String url, int height, int width, String imageType, int hint){
    try {
        //生成二维码
        BitMatrix matrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, width, height, getHints(hint));
        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, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        //去除多余空白
        BufferedImage distinctImage = removeWhiteBorder(image);
        int disHeight = distinctImage.getHeight();
        int disWidth = distinctImage.getWidth();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        //去除空白后可能导致二维码图片变小,所以放大二维码
        if(disHeight < height || disWidth < width){
            BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics = newImage.createGraphics();
            AffineTransform af = new AffineTransform();
            af.scale(width * 1.0 / disWidth, height * 1.0 / disHeight);
            graphics.drawImage(distinctImage, af, null);
            graphics.dispose();
            ImageIO.write(newImage, imageType, outputStream);
        }else{
            ImageIO.write(distinctImage, imageType, outputStream);
        }
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        FileItem fileItem = MtgiCommUtil.createFileItem(inputStream, "file." + imageType);
        //上传到文件服务
        FileUtil fileUtil = SpringUtil.getBean(FileUtil.class);
        return  fileUtil.getFileId(fileItem);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
/**
 * Zxing二维码参数设置
 * @param hint 白边大小
 */
private static java.util.Map<EncodeHintType, Object> getHints(int hint) {
    java.util.Map<EncodeHintType, Object> hints = new java.util.HashMap<>();
    hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
    hints.put(EncodeHintType.ERROR_CORRECTION, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.H);
    hints.put(EncodeHintType.MARGIN, hint);
    return hints;
}

/**
 * 去除二维码图像多余的白边
 */
private static BufferedImage removeWhiteBorder(BufferedImage image) {
    int width = image.getWidth();
    int height = image.getHeight();
    int leftMost = width;
    int rightMost = 0;
    int topMost = height;
    int bottomMost = 0;

    // 扫描每一行和每一列,找到有色块的最小矩形
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            if (image.getRGB(x, y) != -1) { // 非白色
                leftMost = Math.min(leftMost, x);
                rightMost = Math.max(rightMost, x);
                topMost = Math.min(topMost, y);
                bottomMost = Math.max(bottomMost, y);
            }
        }
    }

    // 计算出最小矩形的宽和高
    int newWidth = rightMost - leftMost + 1;
    int newHeight = bottomMost - topMost + 1;

    // 创建一个新图像并复制原图像的最小矩形部分
    BufferedImage newImage = new BufferedImage(newWidth, newHeight, image.getType());
    for (int y = topMost; y <= bottomMost; y++) {
        for (int x = leftMost; x <= rightMost; x++) {
            newImage.setRGB(x - leftMost, y - topMost, image.getRGB(x, y));
        }
    }

    return newImage;
}