java生成、识别条形码和二维码

一、概述

  • 使用 zxing 开源库

    • Zxing主要是Google出品的,用于识别一维码和二维码的第三方库
    • 主要类:
    • BitMatrix 位图矩阵
    • MultiFormatWriter 位图编写器
    • MatrixToImageWriter 写入图片
  • 可以生成、识别条形码和二维码

  • 内置三种尺寸:enum Size {SMALL, MIDDLE, BIG}

  • 依赖

<dependency>
    <groupId>com.google.zxinggroupId>
    <artifactId>javaseartifactId>
    <version>3.5.1version>
dependency>
<dependency>
    <groupId>com.google.zxinggroupId>
    <artifactId>coreartifactId>
    <version>3.5.1version>
dependency>

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
    <version>2.6.7version>
dependency>
<dependency>
    <groupId>commons-langgroupId>
    <artifactId>commons-langartifactId>
    <version>2.6version>
dependency>

二、效果图

java生成、识别条形码和二维码_第1张图片

三、条形码

  • 将宽度不等的多个黑条和白条,按照一定的编码规则排序,用以表达一组信息的图像标识符
  • 通常代表一串数字 / 字母,每一位有特殊含义
  • 一般数据容量30个数字 / 字母

1、生成简单条形码(无文字)

/**
 * 生成简单条形码(无文字)
 *
 * @param content
 * @param width
 * @param height
 * @return
*/
public static BufferedImage create(String content, int width, int height) {
    // 定义位图矩阵BitMatrix
    BitMatrix matrix = null;

    try {
        // 定义二维码参数
        Map<EncodeHintType, Object> hints = new HashMap<>(3);
        // 设置编码
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 设置容错等级
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 设置边距,默认为5
        hints.put(EncodeHintType.MARGIN, 3);

        // 使用code_128格式进行编码生成条形码
        MultiFormatWriter writer = new MultiFormatWriter();
        matrix = writer.encode(content, BarcodeFormat.CODE_128, width, height, hints);
    } catch (WriterException e) {
        e.printStackTrace();
        //throw new RuntimeException("条形码内容写入失败");
    }

    return MatrixToImageWriter.toBufferedImage(matrix);
}

2、生成条形码(含文字)

  • 生成条形码(含文字)
/**
 * 生成条形码(含文字)
 * ****************************************************
 * ----------------------------------------------
 * |                         2023-06-10 10:55   |
 * |                                            |
 * |            商品名称 /超出不显示/              |
 * |                                            |
 * |    | || ||| | || |||| | | | ||| | | ||     |
 * |    | || ||| | || |||| | | | ||| | | ||     |
 * |    | || ||| | || |||| | | | ||| | | ||     |
 * |    | || ||| | || |||| | | | ||| | | ||     |
 * |               13800000000                  |
 * ----------------------------------------------
 * ===================================================
 * 1、日期:顶部右侧
 * 2、商品名称:居中
 * 3、条形码:商品名称下方,且居中
 * 4、条码内容:条形码下方,且居中
 * *****************************************************
 *
 * @param codeImage     条形码图片
 * @param bottomStr     底部文字
 * @param titleStr      标题文字
 * @param topRightStr   右上角文字
 * @param pictureWidth  图片宽度
 * @param pictureHeight 图片高度
 * @param margin        边距
 * @param fontSize      字体大小
 * @return 条形码图片
 */
private static BufferedImage createWithWords(
    BufferedImage codeImage,
    String bottomStr,
    String titleStr,
    String topRightStr,
    int pictureWidth,
    int pictureHeight,
    int margin,
    int fontSize) {
    BufferedImage picImage = new BufferedImage(pictureWidth, pictureHeight, BufferedImage.TYPE_INT_RGB);

    Graphics2D g2d = picImage.createGraphics();
    // 抗锯齿
    setGraphics2D(g2d);
    // 设置白色
    setColorWhite(g2d, picImage.getWidth(), picImage.getHeight());

    // 条形码默认居中显示
    int codeStartX = (pictureWidth - codeImage.getWidth()) / 2;
    int codeStartY = (pictureHeight - codeImage.getHeight()) / 2 + 2 * margin;
    // 画条形码到新的面板
    g2d.drawImage(codeImage, codeStartX, codeStartY, codeImage.getWidth(), codeImage.getHeight(), null);

    // 给条码上下各画一条线
    // 设置颜色
    g2d.setColor(Color.LIGHT_GRAY);
    int y1 = 2 * margin + codeImage.getHeight();
    int y2 = 2 * margin + 2 * codeImage.getHeight();
    g2d.drawLine(0, y1, pictureWidth, y1);
    g2d.drawLine(0, y2, pictureWidth, y2);

    // 画文字到新的面板
    g2d.setColor(Color.BLACK);
    // 字体、字型、字号
    g2d.setFont(new Font("微软雅黑", Font.PLAIN, fontSize));
    // 文字与条形码之间的间隔
    int wordAndCodeSpacing = 3;

    // 底部文字(居中)
    if (StringUtils.isNotEmpty(bottomStr)) {
        // 文字长度
        int strWidth = g2d.getFontMetrics().stringWidth(bottomStr);
        // 文字X轴开始坐标
        int strStartX = (pictureWidth - strWidth) / 2;
        if (strStartX < margin) {
            strStartX = margin;
        }
        // 文字Y轴开始坐标
        int strStartY = codeStartY + codeImage.getHeight() + fontSize + wordAndCodeSpacing;
        // 画文字
        g2d.drawString(bottomStr, strStartX, strStartY);
    }

    // 右上角文字
    if (StringUtils.isNotEmpty(topRightStr)) {
        // 文字长度
        int strWidth = g2d.getFontMetrics().stringWidth(topRightStr);
        // 文字X轴开始坐标
        int strStartX = pictureWidth - strWidth - margin;
        // 文字Y轴开始坐标
        int strStartY = margin + fontSize;
        // 画文字
        g2d.drawString(topRightStr, strStartX, strStartY);
    }

    // 标题文字(居中)
    if (StringUtils.isNotEmpty(titleStr)) {
    	if (titleStr.length() > 11) {
            titleStr = titleStr.substring(0, 11);
        }
        // 字体、字型、字号
        int fs = (int) Math.ceil(fontSize * 1.5);
        g2d.setFont(new Font("微软雅黑", Font.PLAIN, fs));
        // 文字长度
        int strWidth = g2d.getFontMetrics().stringWidth(titleStr);
        // 文字X轴开始坐标
        int strStartX = (pictureWidth - strWidth) / 2;
        if (strStartX < margin) {
            strStartX = margin;
        }
        // 文字Y轴开始坐标
        int strStartY = codeStartY - margin;
        // 画文字
        g2d.drawString(titleStr, strStartX, strStartY);
    }

    g2d.dispose();
    picImage.flush();

    return picImage;
}
  • 设置 Graphics2D 属性 (抗锯齿)
/**
 * 设置 Graphics2D 属性 (抗锯齿)
 *
 * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
 */
private static void setGraphics2D(Graphics2D g2d) {
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
    Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
    g2d.setStroke(s);
}
  • 设置背景为白色
/**
 * 设置背景为白色
 *
 * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
 */
private static void setColorWhite(Graphics2D g2d, int width, int height) {
    g2d.setColor(Color.WHITE);
    // 填充整个屏幕
    g2d.fillRect(0, 0, width, height);
    // 设置笔刷
    g2d.setColor(Color.BLACK);
}
  • 创建小号条形码(250x150)
/**
 * 创建小号条形码(250x150)
 *
 * @param code
 * @param name
 * @return
 */
private static BufferedImage createSmallWithWords(@NonNull String code, @NonNull String name) {
    // 条形码底部内容
    String bottomStr = code;
    // 条形码左上角内容
    //String topLeftStr = name.length() < 11 ? name : name.substring(0, 11);
    String topLeftStr = name;
    // 条形码右上角内容
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    String topRightStr = dtf.format(LocalDateTime.now());

    // 生成条形码
    BufferedImage barCodeImage = create(bottomStr, 250, 50);

    return createWithWords(
        barCodeImage,
        bottomStr,
        topLeftStr,
        topRightStr,
        250,
        150,
        10,
        14);
}
  • 创建中号条形码(350x210)
/**
 * 创建中号条形码(350x210)
 *
 * @param code
 * @param name
 * @return
 */
private static BufferedImage createMiddleWithWords(@NonNull String code, @NonNull String name) {
    // 条形码底部内容
    String bottomStr = code;
    // 条形码左上角内容
    //String topLeftStr = name.length() < 11 ? name : name.substring(0, 11);
    String topLeftStr = name;
    // 条形码右上角内容
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    String topRightStr = dtf.format(LocalDateTime.now());

    // 生成条形码
    BufferedImage barCodeImage = create(bottomStr, 350, 70);

    return createWithWords(
        barCodeImage,
        bottomStr,
        topLeftStr,
        topRightStr,
        350,
        210,
        14,
        20);
}
  • 创建大号条形码(500x300)
/**
 * 创建大号条形码(500x300)
 *
 * @param code
 * @param name
 * @return
 */
private static BufferedImage createBigWithWords(@NonNull String code, @NonNull String name) {
    // 条形码底部内容
    String bottomStr = code;
    // 条形码左上角内容
    //String topLeftStr = name.length() < 11 ? name : name.substring(0, 11);
    String topLeftStr = name;
    // 条形码右上角内容
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    String topRightStr = dtf.format(LocalDateTime.now());

    // 生成条形码
    BufferedImage barCodeImage = create(bottomStr, 500, 100);

    return createWithWords(
        barCodeImage,
        bottomStr,
        topLeftStr,
        topRightStr,
        500,
        300,
        20,
        28);
}
  • 创建内置尺寸(小/中/大)条形码
/**
 * 生成条形码(带文字)
 *
 * @param code 编码内容
 * @param name 名称
 * @param size 规格:小中大
 * @return
 */
public static BufferedImage createWithWords(
    @NonNull String code,
    @NonNull String name,
    @NonNull Size size
) {
    switch (size) {
        case SMALL:
            return createSmallWithWords(code, name);
        case MIDDLE:
            return createMiddleWithWords(code, name);
        case BIG:
        default:
            return createBigWithWords(code, name);
    }
}

四、二维码

  • 用某种特定几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息
  • 比一维条形码能存储更多信息,表示更多数据类型
  • 能够存储数字 / 字母 / 汉字 / 图片等信息
  • 可存储几百到几十KB字符

1、生成指定尺寸二维码

/**
 * 生成二维码(正方形)
 * @param content
 * @param sideLength 边长(px)
 * @return
 */
public static BufferedImage create(String content, int sideLength) {
    BitMatrix matrix = null;
    // 定义二维码参数
    Map<EncodeHintType, Object> hints = new HashMap<>(3);
    // 设置编码
    hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
    // 设置容错等级
    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
    // 设置边距,默认为5
    hints.put(EncodeHintType.MARGIN, 3);

    try {
        matrix = new MultiFormatWriter()
            .encode(content, BarcodeFormat.QR_CODE, sideLength, sideLength, hints);
    } catch (Exception e) {
        e.printStackTrace();
        //throw new RuntimeException("条形码内容写入失败");
    }
    return MatrixToImageWriter.toBufferedImage(matrix);
}

2、生成内置尺寸(小/中/大)二维码

小号:250px;中号:350px;大号:500px;

public static BufferedImage create(String content, Size size) {
    switch (size) {
        case SMALL:
            return create(content, 250);
        case MIDDLE:
            return create(content, 350);
        case BIG:
        default:
            return create(content, 500);
    }
}

五、保存

  • 存入文件
/**
 * 存入文件
 *
 * @param barCodeImage
 * @return 文件名
 */
public static String toFile(BufferedImage barCodeImage) {
    String fileName = getFileName();
    boolean isWrite = false;
    try {
        FileOutputStream outputStream = new FileOutputStream(new File(getImageDir(), fileName));
        isWrite = ImageIO.write(barCodeImage, "png", outputStream);
    } catch (IOException e) {
        e.printStackTrace();
    }

    if (isWrite) {
        return fileName;
    }
    return "";
}
  • 存放目录
/**
 * 得到图片存放目录
 * 类路径下的image文件夹
 *
 * @return
 */
private static String getImageDir() {
    String imageDir = "";
    Resource resource = new ClassPathResource("");
    try {
        String _dir = resource.getFile().getAbsolutePath();
        File file = new File(_dir, "image");
        if (!file.exists()) {
            file.mkdirs();
        }
        imageDir = file.getAbsolutePath();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return imageDir;
}
  • 文件名
/**
 * 生成文件名
 * 当前时间戳 + 两位随机数
 *
 * @return
 */
private static String getFileName() {
    // 当前时间戳
    long second = Instant.now().getEpochSecond();

    // 两位随机数
    ThreadLocalRandom r = ThreadLocalRandom.current();
    int rand = r.nextInt(10, 99);

    return new StringBuffer().append(second).append(rand).append(".png").toString();
}

六、识别

/**
 * 识别图形码(条形码/二维码)
 * ***********************************************
 * ------ 条形码 ----------------------------------
 * 可以识别内容:手机号、纯数字、字母数字、网址(中大号)
 * 识别不了小号(250x150)含文字的网址条形码
 * 存储网址时用二维码,不要使用条形码
 * ***********************************************
 * ------ 二维码 ----------------------------------
 * 比条形码有优势;能识别三种尺寸的网址二维码
 * ***********************************************
 *
 * @param imageCode 图形码文件
 * @return void
 */
public static String scan(File imageCode) {
    String text = "";
    try {
        BufferedImage image = ImageIO.read(imageCode);
        if (image == null) {
            return text;
        }
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

        Map<DecodeHintType, Object> hints = new HashMap<>(3);
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
        hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
        Result result = new MultiFormatReader().decode(bitmap, hints);
        text = result.getText();
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("无法识别");
    }
    return text;
}

public static String scan(String fileName) {
    return scan(new File(getImageDir(), fileName));
}

public static String scan(String fileName, String fileParent) {
    return scan(new File(fileParent, fileName));
}

七、测试类

package com.tuwer.util;

/**
 * 

描述...

* * @author 土味儿 * @version 1.0 * @Date 2023/6/10 */
public class ImageCodeTest { public static void main(String[] args) { cr(); //sc(); } /** * 创建 */ private static void cr() { //String code = "13800000000"; String code = "1667320863285510145"; //String code = "abcdefg123456789012"; //String code = "http://www.baidu.com"; String title = "商品名称(超出不显示)"; System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.BarCode.createWithWords(code, title, ImageCodeUtil.Size.SMALL))); System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.BarCode.createWithWords(code, title, ImageCodeUtil.Size.MIDDLE))); System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.BarCode.createWithWords(code, title, ImageCodeUtil.Size.BIG))); //System.out.println(toFile(QrCode.create(code, 500))); //System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.QrCode.create(code, ImageCodeUtil.Size.SMALL))); //System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.QrCode.create(code, ImageCodeUtil.Size.MIDDLE))); //System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.QrCode.create(code, ImageCodeUtil.Size.BIG))); } /** * 识别 */ private static void sc() { // 扫描 // 13800000000 //String[] fs = {"168636218096.png", "168636218180.png", "168636218127.png"}; // 1667320863285510145 //String[] fs = {"168636260651.png", "168636260766.png", "168636260794.png"}; // abcdefg123456789012 //String[] fs = {"168636320566.png", "168636320750.png", "168636320743.png"}; // http://www.baidu.com String[] fs = {"168636738387.png", "168636738545.png", "168636738539.png"}; for (String f : fs) { System.out.println("-----------------"); System.out.println(ImageCodeUtil.scan(f)); } } }

八、完整源码

package com.tuwer.util;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.lang.NonNull;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 

图形码工具类

* * @author 土味儿 * @version 1.0 * @Date 2023/6/9 */
public class ImageCodeUtil { /** * 尺寸 */ enum Size {SMALL, MIDDLE, BIG} // ====================== 条形码内部类 ======================== /** * 条形码 */ public static class BarCode { /** * 生成简单条形码(无文字) * * @param content * @param width * @param height * @return */ public static BufferedImage create(String content, int width, int height) { // 定义位图矩阵BitMatrix BitMatrix matrix = null; try { // 定义二维码参数 Map<EncodeHintType, Object> hints = new HashMap<>(3); // 设置编码 hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 设置容错等级 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 设置边距,默认为5 hints.put(EncodeHintType.MARGIN, 3); // 使用code_128格式进行编码生成条形码 MultiFormatWriter writer = new MultiFormatWriter(); matrix = writer.encode(content, BarcodeFormat.CODE_128, width, height, hints); } catch (WriterException e) { e.printStackTrace(); //throw new RuntimeException("条形码内容写入失败"); } return MatrixToImageWriter.toBufferedImage(matrix); } /** * 生成条形码(含文字) * **************************************************** * ---------------------------------------------- * | 2023-06-10 10:55 | * | | * | 商品名称 /超出不显示/ | * | | * | | || ||| | || |||| | | | ||| | | || | * | | || ||| | || |||| | | | ||| | | || | * | | || ||| | || |||| | | | ||| | | || | * | | || ||| | || |||| | | | ||| | | || | * | 13800000000 | * ---------------------------------------------- * =================================================== * 1、日期:顶部右侧 * 2、商品名称:居中 * 3、条形码:商品名称下方,且居中 * 4、条码内容:条形码下方,且居中 * ***************************************************** * * @param codeImage 条形码图片 * @param bottomStr 底部文字 * @param titleStr 标题文字 * @param topRightStr 右上角文字 * @param pictureWidth 图片宽度 * @param pictureHeight 图片高度 * @param margin 边距 * @param fontSize 字体大小 * @return 条形码图片 */ private static BufferedImage createWithWords( BufferedImage codeImage, String bottomStr, String titleStr, String topRightStr, int pictureWidth, int pictureHeight, int margin, int fontSize) { BufferedImage picImage = new BufferedImage(pictureWidth, pictureHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = picImage.createGraphics(); // 抗锯齿 setGraphics2D(g2d); // 设置白色 setColorWhite(g2d, picImage.getWidth(), picImage.getHeight()); // 条形码默认居中显示 int codeStartX = (pictureWidth - codeImage.getWidth()) / 2; int codeStartY = (pictureHeight - codeImage.getHeight()) / 2 + 2 * margin; // 画条形码到新的面板 g2d.drawImage(codeImage, codeStartX, codeStartY, codeImage.getWidth(), codeImage.getHeight(), null); // 给条码上下各画一条线 // 设置颜色 g2d.setColor(Color.LIGHT_GRAY); int y1 = 2 * margin + codeImage.getHeight(); int y2 = 2 * margin + 2 * codeImage.getHeight(); g2d.drawLine(0, y1, pictureWidth, y1); g2d.drawLine(0, y2, pictureWidth, y2); // 画文字到新的面板 g2d.setColor(Color.BLACK); // 字体、字型、字号 g2d.setFont(new Font("微软雅黑", Font.PLAIN, fontSize)); // 文字与条形码之间的间隔 int wordAndCodeSpacing = 3; // 底部文字(居中) if (StringUtils.isNotEmpty(bottomStr)) { // 文字长度 int strWidth = g2d.getFontMetrics().stringWidth(bottomStr); // 文字X轴开始坐标 int strStartX = (pictureWidth - strWidth) / 2; if (strStartX < margin) { strStartX = margin; } // 文字Y轴开始坐标 int strStartY = codeStartY + codeImage.getHeight() + fontSize + wordAndCodeSpacing; // 画文字 g2d.drawString(bottomStr, strStartX, strStartY); } // 右上角文字 if (StringUtils.isNotEmpty(topRightStr)) { // 文字长度 int strWidth = g2d.getFontMetrics().stringWidth(topRightStr); // 文字X轴开始坐标 int strStartX = pictureWidth - strWidth - margin; // 文字Y轴开始坐标 int strStartY = margin + fontSize; // 画文字 g2d.drawString(topRightStr, strStartX, strStartY); } // 标题文字(居中) if (StringUtils.isNotEmpty(titleStr)) { // 字体、字型、字号 int fs = (int) Math.ceil(fontSize * 1.5); g2d.setFont(new Font("微软雅黑", Font.PLAIN, fs)); // 文字长度 int strWidth = g2d.getFontMetrics().stringWidth(titleStr); // 文字X轴开始坐标 int strStartX = (pictureWidth - strWidth) / 2; if (strStartX < margin) { strStartX = margin; } // 文字Y轴开始坐标 int strStartY = codeStartY - margin; // 画文字 g2d.drawString(titleStr, strStartX, strStartY); } g2d.dispose(); picImage.flush(); return picImage; } /** * 设置 Graphics2D 属性 (抗锯齿) * * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制 */ private static void setGraphics2D(Graphics2D g2d) { g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT); Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER); g2d.setStroke(s); } /** * 设置背景为白色 * * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制 */ private static void setColorWhite(Graphics2D g2d, int width, int height) { g2d.setColor(Color.WHITE); // 填充整个屏幕 g2d.fillRect(0, 0, width, height); // 设置笔刷 g2d.setColor(Color.BLACK); } /** * 创建小号条形码(250x150) * * @param code * @param name * @return */ private static BufferedImage createSmallWithWords(@NonNull String code, @NonNull String name) { // 条形码底部内容 String bottomStr = code; // 条形码左上角内容 //String topLeftStr = name.length() < 11 ? name : name.substring(0, 11); String topLeftStr = name; // 条形码右上角内容 DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); String topRightStr = dtf.format(LocalDateTime.now()); // 生成条形码 BufferedImage barCodeImage = create(bottomStr, 250, 50); return createWithWords( barCodeImage, bottomStr, topLeftStr, topRightStr, 250, 150, 10, 14); } /** * 创建中号条形码(350x210) * * @param code * @param name * @return */ private static BufferedImage createMiddleWithWords(@NonNull String code, @NonNull String name) { // 条形码底部内容 String bottomStr = code; // 条形码左上角内容 //String topLeftStr = name.length() < 11 ? name : name.substring(0, 11); String topLeftStr = name; // 条形码右上角内容 DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); String topRightStr = dtf.format(LocalDateTime.now()); // 生成条形码 BufferedImage barCodeImage = create(bottomStr, 350, 70); return createWithWords( barCodeImage, bottomStr, topLeftStr, topRightStr, 350, 210, 14, 20); } /** * 创建大号条形码(500x300) * * @param code * @param name * @return */ private static BufferedImage createBigWithWords(@NonNull String code, @NonNull String name) { // 条形码底部内容 String bottomStr = code; // 条形码左上角内容 //String topLeftStr = name.length() < 11 ? name : name.substring(0, 11); String topLeftStr = name; // 条形码右上角内容 DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); String topRightStr = dtf.format(LocalDateTime.now()); // 生成条形码 BufferedImage barCodeImage = create(bottomStr, 500, 100); return createWithWords( barCodeImage, bottomStr, topLeftStr, topRightStr, 500, 300, 20, 28); } /** * 生成条形码(带文字) * * @param code 编码内容 * @param name 名称 * @param size 规格:小中大 * @return */ public static BufferedImage createWithWords( @NonNull String code, @NonNull String name, @NonNull Size size ) { switch (size) { case SMALL: return createSmallWithWords(code, name); case MIDDLE: return createMiddleWithWords(code, name); case BIG: default: return createBigWithWords(code, name); } } } // ====================== 二维码内部类 ======================== /** * 二维码 */ public static class QrCode { /** * 生成二维码(正方形) * * @param content * @param sideLength 边长(px) * @return */ public static BufferedImage create(String content, int sideLength) { BitMatrix matrix = null; // 定义二维码参数 Map<EncodeHintType, Object> hints = new HashMap<>(3); // 设置编码 hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 设置容错等级 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 设置边距,默认为5 hints.put(EncodeHintType.MARGIN, 3); try { matrix = new MultiFormatWriter() .encode(content, BarcodeFormat.QR_CODE, sideLength, sideLength, hints); } catch (Exception e) { e.printStackTrace(); //throw new RuntimeException("条形码内容写入失败"); } return MatrixToImageWriter.toBufferedImage(matrix); } public static BufferedImage create(String content, Size size) { switch (size) { case SMALL: return create(content, 250); case MIDDLE: return create(content, 350); case BIG: default: return create(content, 500); } } } // ======================== 存入文件 ========================= /** * 存入文件 * * @param barCodeImage * @return 文件名 */ public static String toFile(BufferedImage barCodeImage) { String fileName = getFileName(); boolean isWrite = false; try { FileOutputStream outputStream = new FileOutputStream(new File(getImageDir(), fileName)); isWrite = ImageIO.write(barCodeImage, "png", outputStream); } catch (IOException e) { e.printStackTrace(); } if (isWrite) { return fileName; } return ""; } /** * 得到图片存放目录 * 类路径下的image文件夹 * * @return */ private static String getImageDir() { String imageDir = ""; Resource resource = new ClassPathResource(""); try { String _dir = resource.getFile().getAbsolutePath(); File file = new File(_dir, "image"); if (!file.exists()) { file.mkdirs(); } imageDir = file.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); } return imageDir; } /** * 生成文件名 * 当前时间戳 + 两位随机数 * * @return */ private static String getFileName() { // 当前时间戳 long second = Instant.now().getEpochSecond(); // 两位随机数 ThreadLocalRandom r = ThreadLocalRandom.current(); int rand = r.nextInt(10, 99); return new StringBuffer().append(second).append(rand).append(".png").toString(); } // ======================= 识别图形码 ======================== /** * 识别图形码(条形码/二维码) * *********************************************** * ------ 条形码 ---------------------------------- * 可以识别内容:手机号、纯数字、字母数字、网址(中大号) * 识别不了小号(250x150)含文字的网址条形码 * 存储网址时用二维码,不要使用条形码 * *********************************************** * ------ 二维码 ---------------------------------- * 比条形码有优势;能识别三种尺寸的网址二维码 * *********************************************** * * @param imageCode 图形码文件 * @return void */ public static String scan(File imageCode) { String text = ""; try { BufferedImage image = ImageIO.read(imageCode); if (image == null) { return text; } LuminanceSource source = new BufferedImageLuminanceSource(image); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); Map<DecodeHintType, Object> hints = new HashMap<>(3); hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE); hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE); Result result = new MultiFormatReader().decode(bitmap, hints); text = result.getText(); } catch (Exception e) { e.printStackTrace(); System.out.println("无法识别"); } return text; } public static String scan(String fileName) { return scan(new File(getImageDir(), fileName)); } public static String scan(String fileName, String fileParent) { return scan(new File(fileParent, fileName)); } }

参考自:Java生成读取条形码及二维码

你可能感兴趣的:(Spring,#,SpringBoot,Java,java,开发语言)