JAVA 二维码图片生成和base64位加密解密

程谦
2023-12-01

支持带logo图片

引入包

<!--二维码工具类-->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.3</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.3.3</version>
        </dependency>

工具类

import cn.hutool.core.util.StrUtil;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.**.healthcardadapter.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.Base64;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/**
 * 二维码、条形码工具类
 */
@Slf4j
public class QRCodeUtils {

    /**
     * CODE_WIDTH:二维码宽度,单位像素
     */
    private static final int CODE_WIDTH = 200;
    /**
     * CODE_HEIGHT:二维码高度,单位像素
     */
    private static final int CODE_HEIGHT = 200;
    /**
     * FRONT_COLOR:二维码前景色,0x000000 表示黑色
     */
    private static final int FRONT_COLOR = 0x000000;
    /**
     * BACKGROUND_COLOR:二维码背景色,0xFFFFFF 表示白色
     * 演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白
     */
    private static final int BACKGROUND_COLOR = 0xFFFFFF;

    /**
     * 默认图片格式
     */
    private static final String DEFAULT_IMG = "JPG";

    /**
     * LOGO宽度
     */
    private static final int WIDTH = 60;

    /**
     * LOGO高度
     */
    private static final int HEIGHT = 60;


    private static final String CHARSET = "UTF-8";

    private static final String DEFAULT_LOGO_FILE = "./img/logger.JPG";

    /**
     * window 临时存放目录
     */
    private static String WIN_TEMP_PATH = "C:\\Temp\\";
    /**
     * linux临时存放目录
     */
    private static String LINUX_TEMP_PATH = "/temp/";

    @Autowired
    private Environment env;

    @PostConstruct
    public void init() {
        // 初始化配置
        WIN_TEMP_PATH = env.getProperty("ehc.winTempPath");
        LINUX_TEMP_PATH = env.getProperty("ehc.linuxTempPath");
    }

    /**
     * 生成二维码 并 保存为图片:write(RenderedImage im,String formatName,File output)
     *
     * @param codeContent        :二维码参数内容,如果是一个网页地址,如 https://www.baidu.com/ 则 微信扫一扫会直接进入此地址
     *                           如果是一些参数,如 1541656080837,则微信扫一扫会直接回显这些参数值
     * @param codeImgFileSaveDir :二维码图片保存的目录,如 D:/codes
     * @param fileName           :二维码图片文件名称,带格式,如 123.png
     */
    public static void createCodeToFile(String codeContent, File codeImgFileSaveDir, String fileName) {
        try {
            /** 参数检验*/
            if (codeContent == null || "".equals(codeContent.trim())) {
                return;
            }
            codeContent = codeContent.trim();

            if (codeImgFileSaveDir == null || codeImgFileSaveDir.isFile()) {
                codeImgFileSaveDir = FileSystemView.getFileSystemView().getHomeDirectory();
            }
            if (!codeImgFileSaveDir.exists()) {
                codeImgFileSaveDir.mkdirs();
            }
            if (fileName == null || "".equals(fileName)) {
                fileName = System.currentTimeMillis() + "." + DEFAULT_IMG;
            }

            /**com.google.zxing.EncodeHintType:编码提示类型,枚举类型
             * EncodeHintType.CHARACTER_SET:设置字符编码类型
             * EncodeHintType.ERROR_CORRECTION:设置误差校正
             *      ErrorCorrectionLevel:误差校正等级,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
             *      不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的
             * EncodeHintType.MARGIN:设置二维码边距,单位像素,值越小,二维码距离四周越近
             * */
            Map<EncodeHintType, Object> hints = new HashMap();
            hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            hints.put(EncodeHintType.MARGIN, 1);

            /**
             * MultiFormatWriter:多格式写入,这是一个工厂类,里面重载了两个 encode 方法,用于写入条形码或二维码
             *      encode(String contents,BarcodeFormat format,int width, int height,Map<EncodeHintType,?> hints)
             *      contents:条形码/二维码内容
             *      format:编码类型,如 条形码,二维码 等
             *      width:码的宽度
             *      height:码的高度
             *      hints:码内容的编码类型
             * BarcodeFormat:枚举该程序包已知的条形码格式,即创建何种码,如 1 维的条形码,2 维的二维码 等
             * BitMatrix:位(比特)矩阵或叫2D矩阵,也就是需要的二维码
             */
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            BitMatrix bitMatrix = multiFormatWriter.encode(codeContent, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);

            /**java.awt.image.BufferedImage:具有图像数据的可访问缓冲图像,实现了 RenderedImage 接口
             * BitMatrix 的 get(int x, int y) 获取比特矩阵内容,指定位置有值,则返回true,将其设置为前景色,否则设置为背景色
             * BufferedImage 的 setRGB(int x, int y, int rgb) 方法设置图像像素
             *      x:像素位置的横坐标,即列
             *      y:像素位置的纵坐标,即行
             *      rgb:像素的值,采用 16 进制,如 0xFFFFFF 白色
             */
            BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);
            for (int x = 0; x < CODE_WIDTH; x++) {
                for (int y = 0; y < CODE_HEIGHT; y++) {
                    bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
                }
            }

            /**javax.imageio.ImageIO java 扩展的图像IO
             * write(RenderedImage im,String formatName,File output)
             *      im:待写入的图像
             *      formatName:图像写入的格式
             *      output:写入的图像文件,文件不存在时会自动创建
             *
             * 即将保存的二维码图片文件*/
            File codeImgFile = new File(codeImgFileSaveDir, fileName);
            ImageIO.write(bufferedImage, DEFAULT_IMG, codeImgFile);

            log.info("二维码图片生成成功:" + codeImgFile.getPath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成二维码 并 输出到输出流————通常用于输出到网页上进行显示
     * 输出到网页与输出到磁盘上的文件中,区别在于最后一句 ImageIO.write
     * write(RenderedImage im,String formatName,File output):写到文件中
     * write(RenderedImage im,String formatName,OutputStream output):输出到输出流中
     *
     * @param codeContent  :二维码内容
     * @param outputStream :输出流,比如 HttpServletResponse 的 getOutputStream
     */
    public static void createCodeToOutputStream(String codeContent, OutputStream outputStream) {
        try {
            /** 参数检验*/
            if (codeContent == null || "".equals(codeContent.trim())) {
                System.out.println("二维码内容为空,不进行操作...");
                return;
            }
            codeContent = codeContent.trim();

            /**com.google.zxing.EncodeHintType:编码提示类型,枚举类型
             * EncodeHintType.CHARACTER_SET:设置字符编码类型
             * EncodeHintType.ERROR_CORRECTION:设置误差校正
             *      ErrorCorrectionLevel:误差校正等级,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
             *      不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的
             * EncodeHintType.MARGIN:设置二维码边距,单位像素,值越小,二维码距离四周越近
             * */
            Map<EncodeHintType, Object> hints = new HashMap();
            hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            hints.put(EncodeHintType.MARGIN, 1);

            /**
             * MultiFormatWriter:多格式写入,这是一个工厂类,里面重载了两个 encode 方法,用于写入条形码或二维码
             *      encode(String contents,BarcodeFormat format,int width, int height,Map<EncodeHintType,?> hints)
             *      contents:条形码/二维码内容
             *      format:编码类型,如 条形码,二维码 等
             *      width:码的宽度
             *      height:码的高度
             *      hints:码内容的编码类型
             * BarcodeFormat:枚举该程序包已知的条形码格式,即创建何种码,如 1 维的条形码,2 维的二维码 等
             * BitMatrix:位(比特)矩阵或叫2D矩阵,也就是需要的二维码
             */
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            BitMatrix bitMatrix = multiFormatWriter.encode(codeContent, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);

            /**java.awt.image.BufferedImage:具有图像数据的可访问缓冲图像,实现了 RenderedImage 接口
             * BitMatrix 的 get(int x, int y) 获取比特矩阵内容,指定位置有值,则返回true,将其设置为前景色,否则设置为背景色
             * BufferedImage 的 setRGB(int x, int y, int rgb) 方法设置图像像素
             *      x:像素位置的横坐标,即列
             *      y:像素位置的纵坐标,即行
             *      rgb:像素的值,采用 16 进制,如 0xFFFFFF 白色
             */
            BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);
            for (int x = 0; x < CODE_WIDTH; x++) {
                for (int y = 0; y < CODE_HEIGHT; y++) {
                    bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
                }
            }

            /**
             * 区别就是以一句,输出到输出流中,如果第三个参数是 File,则输出到文件中
             */
            ImageIO.write(bufferedImage, DEFAULT_IMG, outputStream);

            log.info("二维码图片生成到输出流成功...");
        } catch (Exception e) {
            e.printStackTrace();

        }
    }

    /**
     * Description 内容转二维码图片并将图片进行Base64编码返回字符串
     *
     * @param codeContent codeContent
     * @return void
     * @date 11:36 2022/8/5
     */
    public static String createImgCodeBase64Str(String codeContent) {
        /** 参数检验*/
        if (codeContent == null || "".equals(codeContent.trim())) {
            System.out.println("二维码内容为空,不进行操作...");
            return "";
        }
        codeContent = codeContent.trim();
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
            Map<EncodeHintType, Object> hints = new HashMap();
            hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            hints.put(EncodeHintType.MARGIN, 1);
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            BitMatrix bitMatrix = multiFormatWriter.encode(codeContent, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);
            BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);
            for (int x = 0; x < CODE_WIDTH; x++) {
                for (int y = 0; y < CODE_HEIGHT; y++) {
                    bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
                }
            }
            ImageIO.write(bufferedImage, DEFAULT_IMG, byteArrayOutputStream);
            String base64Str = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
            log.info("二维码base64输出流:" + base64Str);
            return base64Str;
        } catch (Exception e) {
            log.error("二维码base64转化失败:" + e.getMessage());
        }
        return "";
    }

    /**
     * Description 内容转带logo二维码图片并将图片进行Base64编码返回字符串
     *
     * @param codeContent codeContent
     * @param imgPath     logo图片地址
     * @return void
     * @date 11:36 2022/8/5
     */
    public static String createLogoImgCodeBase64Str(String codeContent, String imgPath) {
        /** 参数检验*/
        if (StrUtil.isEmpty(codeContent)) {
            System.out.println("二维码内容为空,不进行操作...");
            return "";
        }
        if (StrUtil.isEmpty(imgPath)) {
            imgPath = DEFAULT_LOGO_FILE;
        }
        codeContent = codeContent.trim();
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
            BufferedImage bufferedImage = createImageWithLogo(codeContent, imgPath, true);
            ImageIO.write(bufferedImage, DEFAULT_IMG, byteArrayOutputStream);
            String base64Str = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
            log.info("二维码base64输出流:" + base64Str);
            return base64Str;
        } catch (Exception e) {
            log.error("二维码base64转化失败:" + e.getMessage());
        }
        return "";
    }

    /**
     * Description 解码base64位的图片的内容
     *
     * @param base64Str base64Str加密字符串
     * @return void
     * @date 11:36 2022/8/5
     *  
     */
    public static String parseQRCodeFromBase64Str(String base64Str) {
        String resultStr = null;
        try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(Base64.getDecoder().decode(base64Str))) {
            /**ImageIO 的 BufferedImage read(URL input) 方法用于读取网络图片文件转为内存缓冲图像
             * 同理还有:read(File input)、read(InputStream input)、、read(ImageInputStream stream)
             */
            BufferedImage bufferedImage = ImageIO.read(byteArrayInputStream);
            /**
             * com.google.zxing.client.j2se.BufferedImageLuminanceSource:缓冲图像亮度源
             * 将 java.awt.image.BufferedImage 转为 zxing 的 缓冲图像亮度源
             * 关键就是下面这几句:HybridBinarizer 用于读取二维码图像数据,BinaryBitmap 二进制位图
             */
            BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            Hashtable hints = new Hashtable();
            hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
            /**
             * 如果图片不是二维码图片,则 decode 抛异常:com.google.zxing.NotFoundException
             * MultiFormatWriter 的 encode 用于对内容进行编码成 2D 矩阵
             * MultiFormatReader 的 decode 用于读取二进制位图数据
             */
            resultStr = new MultiFormatReader().decode(bitmap, hints).getText();
            log.info("识别base64解码后内容为" + resultStr);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("识别base64字符串失败");
        }
        return resultStr;
    }


    /**
     * 根据本地二维码图片————————解析二维码内容
     * (注:图片必须是二维码图片,但也可以是微信用户二维码名片,上面有名称、头像也是可以的)
     *
     * @param file 本地二维码图片文件,如 E:\\logs\\2.jpg
     * @return
     * @throws Exception
     */
    public static String parseQRCodeByFile(File file) {
        String resultStr = null;
        if (file == null || file.isDirectory() || !file.exists()) {
            return resultStr;
        }
        try {
            /**ImageIO 的 BufferedImage read(URL input) 方法用于读取网络图片文件转为内存缓冲图像
             * 同理还有:read(File input)、read(InputStream input)、、read(ImageInputStream stream)
             */
            BufferedImage bufferedImage = ImageIO.read(file);
            /**
             * com.google.zxing.client.j2se.BufferedImageLuminanceSource:缓冲图像亮度源
             * 将 java.awt.image.BufferedImage 转为 zxing 的 缓冲图像亮度源
             * 关键就是下面这几句:HybridBinarizer 用于读取二维码图像数据,BinaryBitmap 二进制位图
             */
            BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            Hashtable hints = new Hashtable();
            hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
            /**
             * 如果图片不是二维码图片,则 decode 抛异常:com.google.zxing.NotFoundException
             * MultiFormatWriter 的 encode 用于对内容进行编码成 2D 矩阵
             * MultiFormatReader 的 decode 用于读取二进制位图数据
             */
            resultStr = new MultiFormatReader().decode(bitmap, hints).getText();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NotFoundException e) {
            e.printStackTrace();
            log.error("-----图片非二维码图片:" + file.getPath());
        }
        return resultStr;
    }


    /**
     * 根据网络二维码图片————————解析二维码内容
     * (区别仅仅在于 ImageIO.read(url); 这一个重载的方法)
     *
     * @param url 二维码图片网络地址,如 https://res.wx.qq.com/mpres/htmledition/images/mp_qrcode3a7b38.gif
     * @return
     * @throws Exception
     */
    public static String parseQRCodeByUrl(URL url) {
        String resultStr = null;
        if (url == null) {
            return resultStr;
        }
        try {
            /**ImageIO 的 BufferedImage read(URL input) 方法用于读取网络图片文件转为内存缓冲图像
             * 同理还有:read(File input)、read(InputStream input)、、read(ImageInputStream stream)
             *
             * 如果图片网络地址错误,比如不能访问,则 read 抛异常:javax.imageio.IIOException: Can't get input stream from URL!
             */
            BufferedImage bufferedImage = ImageIO.read(url);
            /**
             * com.google.zxing.client.j2se.BufferedImageLuminanceSource:缓冲图像亮度源
             * 将 java.awt.image.BufferedImage 转为 zxing 的 缓冲图像亮度源
             * 关键就是下面这几句:HybridBinarizer 用于读取二维码图像数据,BinaryBitmap 二进制位图
             */
            BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            Hashtable hints = new Hashtable();
            /**
             * 如果内容包含中文,则解码的字符集格式应该和编码时一致
             */
            hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
            /**
             * 如果图片不是二维码图片,则 decode 抛异常:com.google.zxing.NotFoundException
             * MultiFormatWriter 的 encode 用于对内容进行编码成 2D 矩阵
             * MultiFormatReader 的 decode 用于读取二进制位图数据
             */
            resultStr = new MultiFormatReader().decode(bitmap, hints).getText();
        } catch (IOException e) {
            e.printStackTrace();
            log.error("-----二维码图片地址错误:" + url);
        } catch (NotFoundException e) {
            e.printStackTrace();
            log.error(("-----图片非二维码图片:" + url));
        }
        return resultStr;
    }

    /**
     * Description base64存储的图片字节码转出成图片
     *
     * @param base64Str base64Str
     * @return void
     * @date 16:09 2022/8/5
     *  
     */
    public static void parseBase64ImgStrToFile(String base64Str, String filePath) {
        String fileName = System.currentTimeMillis() + "." + DEFAULT_IMG;
        if (StrUtil.isEmpty(filePath)) {
            filePath = getDefaultFileSavePath();
        }
        try (FileOutputStream fileOutputStream = new FileOutputStream(filePath + fileName)) {
            byte[] bytes = Base64.getDecoder().decode(base64Str);
            fileOutputStream.write(bytes);
        } catch (Exception e) {
            e.getMessage();
            log.error("解析base64转图片失败" + e.getMessage());
        }
    }

    // 带logo的二维码图片

    /**
     * Description 生成带logo的二维码图片
     *
     * @param content      图片内容
     * @param imgPath      logo图片地址
     * @param needCompress 是否需要log图片压缩
     * @return java.awt.image.BufferedImage
     * @date 11:13 2022/8/8
     *  
     */
    private static BufferedImage createImageWithLogo(String content, String imgPath, boolean needCompress) {
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT,
                    hints);
        } catch (WriterException e) {
            log.error("创建logo二维码图片失败" + e.getMessage());
            throw BusinessException.create("创建logo二维码图片失败");
        }
        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);
            }
        }
        if (imgPath == null || "".equals(imgPath)) {
            return image;
        }
        // 插入图片
        QRCodeUtils.insertImage(image, imgPath, needCompress);
        return image;
    }

    /**
     * Description 插入logo图片
     *
     * @param source       BufferedImage源
     * @param imgPath      logo图片地址
     * @param needCompress 是否压缩
     * @return void
     * @date 11:45 2022/8/8
     *  
     */
    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) {
        File file = new File(imgPath);
        if (!file.exists()) {
            log.info("logo文件不存在!");
            return;
        }
        try {
            Image src = ImageIO.read(new File(imgPath));
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            if (needCompress) { // 压缩LOGO
                if (width > WIDTH) {
                    width = WIDTH;
                }
                if (height > HEIGHT) {
                    height = HEIGHT;
                }
                Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
                BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                Graphics g = tag.getGraphics();
                g.drawImage(image, 0, 0, null); // 绘制缩小后的图
                g.dispose();
                src = image;
            }
            // 插入LOGO
            Graphics2D graph = source.createGraphics();
            int x = (CODE_WIDTH - width) / 2;
            int y = (CODE_HEIGHT - height) / 2;
            graph.drawImage(src, x, y, width, height, null);
            Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
            graph.setStroke(new BasicStroke(3f));
            graph.draw(shape);
            graph.dispose();
        } catch (IOException e) {
            e.printStackTrace();
            log.error("插入logo图片失败" + e.getMessage());
            throw BusinessException.create("插入logo图片失败");
        }
    }

    /**
     * Description 生成logo二维码
     *
     * @param content      content
     * @param imgPath      logo图片位置
     * @param destPath     生成二维码存储位置
     * @param needCompress needCompress
     * @return void
     * @author 汪少明
     * @date 12:37 2022/8/8
     *  
     */
    public static void createLogoImgToFile(String content, String imgPath, String destPath, boolean needCompress) {
        BufferedImage image = QRCodeUtils.createImageWithLogo(content, imgPath, needCompress);
        mkdirs(destPath);
        String fileName = "";
        if (fileName == null || "".equals(fileName)) {
            fileName = System.currentTimeMillis() + "." + DEFAULT_IMG;
        }
        String path = getDefaultFileSavePath();
        try {
            ImageIO.write(image, DEFAULT_IMG, new File(path + fileName));
        } catch (IOException e) {
            e.printStackTrace();
            throw BusinessException.create("生成二维码失败");
        }
    }

    /**
     * Description 生成logo二维码
     *
     * @param content      二维码内容
     * @param imgPath      logo图片地址
     * @param needCompress needCompress
     * @date 12:39 2022/8/8
     *  
     */
    private static void createLogoImgToFile(String content, String imgPath, boolean needCompress) {
        String destPath = getDefaultFileSavePath();
        createLogoImgToFile(content, imgPath, destPath, needCompress);
    }


    /**
     * Description 生成logo二维码
     *
     * @param content  content
     * @param imgPath  logo图片地址
     * @param destPath 二维码生成存储位置
     * @return void
     * @date 11:43 2022/8/8
     *  
     */
    public static void createLogoImgToFile(String content, String imgPath, String destPath) throws Exception {
        QRCodeUtils.createLogoImgToFile(content, imgPath, destPath, false);
    }

    /**
     * Description 生成logo二维码
     *
     * @param content  content
     * @param destPath 二维码生成存储位置
     * @return void
     * @date 11:43 2022/8/8
     *  
     */
    public static void createLogoImgToFile(String content, String destPath) throws Exception {
        QRCodeUtils.createLogoImgToFile(content, null, destPath, false);
    }

    /**
     * Description 生成logo二维码
     *
     * @param content      content
     * @param imgPath      logo图片地址
     * @param output       输出流
     * @param needCompress 是否压缩
     * @return void
     * @date 11:43 2022/8/8
     *  
     */
    public static void createLogoImgToFile(String content, String imgPath, OutputStream output, boolean needCompress)
            throws Exception {
        BufferedImage image = QRCodeUtils.createImageWithLogo(content, imgPath, needCompress);
        ImageIO.write(image, DEFAULT_IMG, output);
    }

    /**
     * Description 生成logo二维码
     *
     * @param content content
     * @param output  输出流
     * @return void
     * @date 11:43 2022/8/8
     *  
     */
    public static void createLogoImgToFile(String content, OutputStream output) throws Exception {
        QRCodeUtils.createLogoImgToFile(content, null, output, false);
    }

    private static void mkdirs(String destPath) {
        if (StrUtil.isEmpty(destPath)) {
            // win 默认桌面 linux
            destPath = getDefaultFileSavePath();
        }
        File file = new File(destPath);
        // 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    /**
     *   * Description 区分操作系统
     *   * @param
     *   * @return java.lang.String
     *   * @date 11:43 2022/8/8
     *  
     */
    private static String getDefaultFileSavePath() {
        String os = System.getProperties().getProperty("os.name");
        String tempPath = "";
        if (os.startsWith("win") || os.startsWith("Win")) {
            tempPath = WIN_TEMP_PATH;
            mkdirs(tempPath);
        } else {
            tempPath = LINUX_TEMP_PATH;
        }
        return tempPath;
    }


    public static void main(String[] args) {
        //String contentStr = "FEDB812F9F3A7B6AE1584C1132C1A333B1DC3389332FFA0E7C458B2F96323ED0:1";
        // String contentStr = "FEDB812F9F3A7B6AE1584C1132C1A333B1DC3389332FFA0E7C458B2F96323ED0:1";
        // String imgPath = "C:\\Users\\wangsm\\Desktop\\test\\logger.JPG";
        //createCodeToFile(contentStr,new File("C:\\Users\\wangsm\\Desktop\\test"), "");
        // URL url = new URL("https://res.wx.qq.com/mpres/htmledition/images/mp_qrcode3a7b38.gif");
        // String netQRcodeContent = parseQRCodeByUrl(url);
        //System.out.println(url + " 二维码内容:" + netQRcodeContent);
        // String base64Str = createImgCodeBase64Str(contentStr);
        // base64串转图片
        //String base64Str = createImgCodeBase64Str(contentStr);
        // log.info("base64加密串:" + base64Str);
        // base64加密串转图片
        // parseBase64ImgStrToFile(base64Str);
        // 识别base64图片内容
        //String demoBase64Str = "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";
        //parseQRCodeFromBase64Str(base64Str);
        // 读取文件内容
       /* File localFile = new File("C:\\Users\\wangsm\\Desktop\\test\\1659922451114.JPG");
        String localQRcodeContent = parseQRCodeByFile(localFile);
        System.out.println(localFile + " 二维码内容:" + localQRcodeContent);*/
        // 生成带logo的二维码图片
        // createLogoImgToFile(contentStr, imgPath, true);
        // 解析带二维码的图片
        //decodeLogoImg("C:\\Users\\wangsm\\Desktop\\test\\1659936905494.JPG");
        // 带logo图片base64加密
        // String logBase64Str = createLogoImgCodeBase64Str(contentStr, null);
        // 解析带logo的base64字符串内容
        // parseQRCodeFromBase64Str(logBase64Str);
        // 识别带logo二维码图片内容
        // File localFile = new File("C:\\Users\\wangsm\\Desktop\\test\\1659937481369.JPG");
        // String localQRcodeContent = parseQRCodeByFile(localFile);
        // System.out.println(localFile + " 二维码内容:" + localQRcodeContent);
        // 识别带logo的base64串转图片
        //parseBase64ImgStrToFile(logBase64Str, null);
    }
}

 参考:java实现二维码的生成与解析_jam_fanatic的博客-CSDN博客_java二维码解析

在线检验工具:Convert Base64 to Image - Online Image Tools

 类似资料: