二维码图片生成(带文字显示)

需要引用谷歌的jar包:com.google.zxing.core-3.3.0.jar 

/**
 * @Author: JSONLiu
 * @Description: 二维码操作类
 * @Date Created in 2021-03-29 11:35
 * @Modified By:
 */
public class QRCodeUtils {
    /**
     * CODE_WIDTH:二维码宽度,单位像素
     * CODE_HEIGHT:二维码高度,单位像素
     * FRONT_COLOR:二维码前景色,0x000000 表示黑色
     * BACKGROUND_COLOR:二维码背景色,0xFFFFFF 表示白色
     * 演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白
     */
    private static final int CODE_WIDTH = 400;
    private static final int CODE_HEIGHT = 400;
    private static final int FRONT_COLOR = 0x000000;
    private static final int BACKGROUND_COLOR = 0xFFFFFF;

    /**
     * 创建二维码本地图片文件
     *
     * @param content    二维码保存内容
     * @param topFont    二维码顶部文字
     * @param centerFont 二维码中心区域文字
     * @param bottomFont 二维码底部文字
     * @param filePath   二维码保存路径
     * @return 二维码文件是否创建成功
     * @throws WriterException
     * @throws IOException
     */
    public static boolean createImageFile(String content, String topFont, String centerFont, String bottomFont, String filePath) throws WriterException, IOException {
        //创建二维码区域,默认长宽
        BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_RGB);
        if (content == null || "".equals(content)) {
            return false;
        }
        topFont = topFont == null ? "" : topFont;
        centerFont = centerFont == null ? "" : centerFont;
        bottomFont = bottomFont == null ? "" : bottomFont;
        //将文字加入图像中
        bufferedImage = pressTextInImage(bufferedImage, content, topFont, centerFont, bottomFont);
        //字节数组输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        //将图像内容写到输出流
        ImageIO.write(bufferedImage, "jpg", outputStream);
        //得到所有要输出字节
        byte[] bytes = outputStream.toByteArray();
        //得到文件输出流并输出文件
        OutputStream os = new FileOutputStream(filePath);
        os.write(bytes);
        os.close();
        return true;
    }

    /**
     * 创建二维码本地图片文件
     *
     * @param content    二维码保存信息
     * @param showInfo   需要在图片右侧显示文字信息
     * @param bottomFont 二维码底部展示信息
     * @param filePath   保存文件路径
     * @return 文件是否创建成功
     * @throws WriterException
     * @throws IOException
     */
    public static boolean createImageFile(String content, HashMap<String, String> showInfo, String bottomFont, String filePath) throws WriterException, IOException {
        //创建二维码区域,默认长宽
        BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_RGB);
        if (content == null || "".equals(content)) {
            return false;
        }
        bottomFont = bottomFont == null ? "" : bottomFont;
        //将文字加入图像中
        bufferedImage = pressTextInImage(bufferedImage, content, showInfo, bottomFont);
        //字节数组输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        //将图像内容写到输出流
        ImageIO.write(bufferedImage, "jpg", outputStream);
        //转换成字节
        byte[] bytes = outputStream.toByteArray();
        //得到文件输出流并输出文件
        OutputStream os = new FileOutputStream(filePath);
        os.write(bytes);
        os.close();
        return true;
    }

    /**
     * 得到二维码对象输入字节流
     *
     * @param content    二维码保存信息
     * @param showInfo   需要在图片右侧显示文字信息
     * @param bottomFont 二维码底部展示信息
     * @return 文件对象
     * @throws WriterException
     * @throws IOException
     */
    public static ByteArrayInputStream getImageInputStream(String content, HashMap<String, String> showInfo, String bottomFont) throws WriterException, IOException {
        //创建二维码区域,默认长宽
        BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_RGB);
        if (content == null || "".equals(content)) {
            return null;
        }
        bottomFont = bottomFont == null ? "" : bottomFont;
        //将文字加入图像中
        bufferedImage = pressTextInImage(bufferedImage, content, showInfo, bottomFont);
        //字节数组输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        //将图像内容写到输出流
        ImageIO.write(bufferedImage, "jpg", outputStream);
        //转换成字节
        byte[] bytes = outputStream.toByteArray();
        return new ByteArrayInputStream(bytes);
    }

    /**
     * 将文字添加到图片上
     *
     * @param bufferedImage 二维码图像对象
     * @param content       需要保存到二维码中的信息
     * @param topFont       二维码顶部文字
     * @param centerFont    二维码中心区域文字
     * @param bottomFont    二维码底部文字
     * @return 添加了文字信息后的二维码图像
     * @throws WriterException
     */
    public static BufferedImage pressTextInImage(BufferedImage bufferedImage, String content, String topFont, String centerFont, String bottomFont) throws WriterException {
        if (bufferedImage == null) {
            return null;
        }
        //图片绘制对象
        Graphics graphics = bufferedImage.createGraphics();
        Font font = new Font("宋体", 5, 32);
        Font font1 = new Font("宋体", 5, 23);
        FontMetrics metrics = graphics.getFontMetrics(font);
        FontMetrics metrics1 = graphics.getFontMetrics(font1);
        //获取中心字体的宽和高
        int centerFontWidth = metrics.stringWidth(centerFont);
        int centerFontHeight = metrics.getHeight();
        //获取底部字体的宽和高
        int bottomFontWidth = metrics1.stringWidth(bottomFont);
        int bottomFontHeight = metrics1.getHeight();
        //获取顶部字体的宽和高
        int topFontWidth = metrics1.stringWidth(topFont);
        int topFontHeight = metrics1.getHeight();
        //将image生成二维码图片对象
        bufferedImage = createQRCode(content, bufferedImage, topFontWidth, topFontHeight, centerFontWidth, centerFontHeight, bottomFontWidth, bottomFontHeight);
        //获取二维码图片的宽和高
        int imageW = bufferedImage.getWidth();
        int imageH = bufferedImage.getHeight();
        //计算顶部文字填充位置
        int topStartX = (imageW - topFontWidth) / 2; //居中显示
        int topStartY = topFontHeight;
        //计算中心文字填充位置
        int centerStartX = (imageW - centerFontWidth) / 2 + 10;  //居中显示
        int centerStartY = imageH / 2 + centerFontHeight / 2 - (centerFontHeight / 4) + 10;
        //计算底部文字填充位置
        int bottomStartX = (imageW - bottomFontWidth) / 2; //居中显示
        int bottomStartY = (imageH - bottomFontHeight) + 2;

        //文字图片对象
        BufferedImage textImag = new BufferedImage(imageW, imageH, BufferedImage.TYPE_INT_RGB);
        Graphics textGraphics = textImag.createGraphics();
        //画图
        textGraphics.drawImage(bufferedImage, 0, 0, imageW, imageH, null);
        //
        //设置中心画笔的颜色
        textGraphics.setColor(Color.BLACK);
        textGraphics.setFont(font);
        //  写中心字体
        textGraphics.drawString(centerFont, centerStartX, centerStartY);
        // 写底部文字
        textGraphics.setColor(Color.BLACK);
        textGraphics.setFont(font1);
        textGraphics.drawString(bottomFont, bottomStartX, bottomStartY);
        //写顶部字体
        textGraphics.setColor(Color.BLACK);
        textGraphics.setFont(font1);
        textGraphics.drawString(topFont, topStartX, topStartY);
        graphics.dispose();
        return textImag;
    }

    /**
     * 将文字添加到图片上
     *
     * @param bufferedImage 二维码图像对象
     * @param content       需要保存到二维码中的信息
     * @param showInfo      二维码右边区域文字
     * @param bottomFont    二维码底部文字
     * @return 添加了文字信息后的二维码图像
     * @throws WriterException
     */
    public static BufferedImage pressTextInImage(BufferedImage bufferedImage, String content, HashMap<String, String> showInfo, String bottomFont) throws WriterException {
        if (bufferedImage == null) {
            return null;
        }
        //图片绘制对象
        Graphics graphics = bufferedImage.createGraphics();
        Font font = new Font("楷体", Font.BOLD, 32);//大字体
        Font font1 = new Font("楷体", Font.PLAIN, 23);//小字体
        Font font2 = new Font("楷体", Font.BOLD, 23);//小字体
        FontMetrics metrics = graphics.getFontMetrics(font);
        FontMetrics metrics1 = graphics.getFontMetrics(font1);
        //获取底部字体的宽和高
        int bottomFontWidth = metrics.stringWidth(bottomFont);
        int bottomFontHeight = metrics.getHeight();
        //计算右部字体的宽和高
        int maxRightWidth = 0;
        int maxRightHeight = 0;
        for (Map.Entry<String, String> me : showInfo.entrySet()) {
            if (metrics1.stringWidth(me.getKey()) > maxRightWidth) {//key长
                maxRightWidth = metrics1.stringWidth(me.getKey());
            }
            if (metrics1.stringWidth(me.getValue()) > maxRightWidth) {//value长
                maxRightWidth = metrics1.stringWidth(me.getValue());
            }
            maxRightHeight += (metrics1.getHeight() * 2);
        }

        //将image生成二维码图片对象
        bufferedImage = createQRCode(content, bufferedImage, maxRightWidth, maxRightHeight, bottomFontWidth, bottomFontHeight);

        //获取二维码图片的宽和高
        int imageW = bufferedImage.getWidth();
        int imageH = bufferedImage.getHeight();
        //计算底部文字填充位置
        int bottomStartX = (imageW - bottomFontWidth - maxRightWidth - 10 -10) / 2 + 30; //居中显示
        int bottomStartY = (imageH - bottomFontHeight);
        //文字图片对象
        BufferedImage textImag = new BufferedImage(imageW, imageH, BufferedImage.TYPE_INT_RGB);
        Graphics2D textGraphics = textImag.createGraphics();
        //画图
        textGraphics.drawImage(bufferedImage, 0, 0, imageW, imageH, null);
        textGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        //写右边字体(动态计算的过程)
        textGraphics.setColor(Color.BLACK);
        int rightStartX = (imageW - maxRightWidth - 10); //向右偏移10
        int rightStartY = 10;
        for (Map.Entry<String, String> me : showInfo.entrySet()) {
            //输出key
            textGraphics.setFont(font2);
            rightStartY += metrics1.getHeight() + 20;
            textGraphics.drawString(me.getKey(), rightStartX, rightStartY);
            //输出value
            textGraphics.setFont(font1);
            rightStartY += metrics1.getHeight();
            textGraphics.drawString(me.getValue(), rightStartX, rightStartY);
        }
        // 写底部文字
        textGraphics.setColor(Color.BLACK);
        textGraphics.setFont(font1);
        textGraphics.drawString(bottomFont, bottomStartX, bottomStartY);
        graphics.dispose();
        return textImag;
    }

    /**
     * 创建二维码对象
     *
     * @param content          二维码保存内容信息
     * @param bufferedImage    二维码图像信息
     * @param topFontWidth     顶部文字宽
     * @param topFontHeight    顶部文字高
     * @param centerFontWidth  中心区域文字宽
     * @param centerFontHeight 中心区域文字高
     * @param bottomFontWidth  底部文字宽
     * @param bottomFontHeight 底部文字高
     * @return 添加文字区域后的图像
     * @throws WriterException
     */
    public static BufferedImage createQRCode(String content, BufferedImage bufferedImage, int topFontWidth, int topFontHeight, int centerFontWidth, int centerFontHeight, int bottomFontWidth, int bottomFontHeight) throws WriterException {
        //检验参数
        if (content == null || "".equals(content)) {
            return null;
        }
        if (bufferedImage == null) {
            return null;
        }
        content = content.trim();
        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();
        int startBottomY = height + topFontHeight;
        height = startBottomY + bottomFontHeight;
        //计算中文文字空白区域
        int centerFontStartX = (width - centerFontWidth) / 2 + 5;   // x轴起始坐标
        int centerFontEndX = centerFontStartX + centerFontWidth + 5;    // x轴终点坐标
        int centerFontStartY = (height - centerFontHeight) / 2 + 5; // y轴起始坐标
        int centerFontEndY = centerFontStartY + centerFontHeight + 5;   // y轴终点坐标

        /**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, "UTF-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);
        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(content, BarcodeFormat.QR_CODE, width, 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 newBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                //顶部文字填充区域设置为空白
                if (y <= topFontHeight) {
                    newBufferedImage.setRGB(x, y, BACKGROUND_COLOR);
                }
                //中心文字填充区域设置为空白
                else if (x > centerFontStartX && x < centerFontEndX && y > centerFontStartY && y < centerFontEndY) {
                    newBufferedImage.setRGB(x, y, BACKGROUND_COLOR);
                }
                //底部文字填充区域设置为空白
                else if (y > startBottomY) {
                    newBufferedImage.setRGB(x, y, BACKGROUND_COLOR);
                } else {
                    newBufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
                }
            }
        }
        bufferedImage = null; //主动释放
        return newBufferedImage;
    }

    /**
     * 创建二维码对象
     *
     * @param content          二维码保存内容信息
     * @param bufferedImage    二维码图像信息
     * @param maxRightWidth    右部文字宽
     * @param bottomFontWidth  右部文字高
     * @param bottomFontWidth  底部文字宽
     * @param bottomFontHeight 底部文字高
     * @return 添加文字区域后的图像
     * @throws WriterException
     */
    public static BufferedImage createQRCode(String content, BufferedImage bufferedImage, int maxRightWidth, int maxRightHeight, int bottomFontWidth, int bottomFontHeight) throws WriterException {
        //检验参数
        if (content == null || "".equals(content)) {
            return null;
        }
        if (bufferedImage == null) {
            return null;
        }
        content = content.trim();
        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();
        int startBottomY = height;
        //计算右边空白区域
        int rightFontStartX = width + 10;   // x轴起始坐标
        int rightFontEndX = rightFontStartX + maxRightWidth;    // x轴终点坐标
        int rightFontStartY = 10; // y轴起始坐标
        int rightFontEndY = rightFontStartY + maxRightHeight;   // y轴终点坐标

        int newWidth = width + maxRightWidth + 10 +10; //右边多空10个像素
        int newHeight = height + bottomFontHeight;
        /**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, "UTF-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);
        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(content, BarcodeFormat.QR_CODE, width, 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 newBufferedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_BGR);
        for (int x = 0; x < newWidth; x++) {
            for (int y = 0; y < newHeight; y++) {
                if (x < width && y < height) {
                    newBufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
                }
                //右部区域设置为空白
                else if (x > rightFontStartX && x < rightFontEndX && y > rightFontStartY && y < rightFontEndY) {
                    newBufferedImage.setRGB(x, y, BACKGROUND_COLOR);
                }
                //底部文字填充区域设置为空白
                else {
                    newBufferedImage.setRGB(x, y, BACKGROUND_COLOR);
                }
            }
        }
        bufferedImage = null; //主动释放
        return newBufferedImage;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑谈子云亭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值