Java生成二维码带LOGO&底部标题&竖版字体

前言

Java后端生成二维码 底部 侧面带有标题,可调节字号

参考文章

使用Java生成二维码图片(亲测)
Reborn_YY使用Java生成二维码图片
图标素材库
Java后台生成图片,前台实现图片下载

jar

保持和spring同时期版本即可

	<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
    <!-- 二维码生成工具-->
    <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 com.google.zxing.LuminanceSource;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
public class BufferedImageLuminanceSource extends LuminanceSource {
    private final BufferedImage image;
    private final int left;
    private final int top;

    public BufferedImageLuminanceSource(BufferedImage image) {
        this(image, 0, 0, image.getWidth(), image.getHeight());
    }

    public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {
        super(width, height);
        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();
        if (left + width > sourceWidth || top + height > sourceHeight) {
            throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
        }
        for (int y = top; y < top + height; y++) {
            for (int x = left; x < left + width; x++) {
                if ((image.getRGB(x, y) & 0xFF000000) == 0) {
                    image.setRGB(x, y, 0xFFFFFFFF); // = white
                }
            }
        }
        this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
        this.image.getGraphics().drawImage(image, 0, 0, null);
        this.left = left;
        this.top = top;
    }

    @Override
    public byte[] getRow(int y, byte[] row) {
        if (y < 0 || y >= getHeight()) {
            throw new IllegalArgumentException("Requested row is outside the image: " + y);
        }
        int width = getWidth();
        if (row == null || row.length < width) {
            row = new byte[width];
        }
        image.getRaster().getDataElements(left, top + y, width, 1, row);
        return row;
    }

    @Override
    public byte[] getMatrix() {
        int width = getWidth();
        int height = getHeight();
        int area = width * height;
        byte[] matrix = new byte[area];
        image.getRaster().getDataElements(left, top, width, height, matrix);
        return matrix;
    }

    @Override
    public boolean isCropSupported() {
        return true;
    }

    @Override
    public LuminanceSource crop(int left, int top, int width, int height) {
        return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);
    }

    @Override
    public boolean isRotateSupported() {
        return true;
    }

    @Override
    public LuminanceSource rotateCounterClockwise() {
        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();
        AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);
        BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D g = rotatedImage.createGraphics();
        g.drawImage(image, transform, null);
        g.dispose();
        int width = getWidth();
        return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
    }
}

工具类设置




import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.StringUtils;
import sun.font.FontDesignMetrics;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Hashtable;
import java.util.UUID;

/**
 * 二维码生成类
 *
 * @author 18316
 *
 */
public class QRCodeUtils {
    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "jpg";
    // 二维码尺寸
    private static final int QRCODE_SIZE = 300;
    // LOGO宽度
    private static final int WIDTH = 60;
    // LOGO高度
    private static final int HEIGHT = 60;
    // 字体大小
    private static final int FONT_SIZE = 18;


    /**
     * 生成包含 标题说明 LOGO 的二维码图片
     *
     * @param title        标题 底部显示
     * @param content      二维码内容
     * @param imgPath      LOGO文件路径
     * @param needCompress LOGO 是否压缩
     * @return 二维码图片流
     * @throws Exception
     */
    private static BufferedImage createImage(String title, String content, String imgPath, boolean needCompress) throws Exception {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
                hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();

        int tempHeight = height;
        // 二维码图片大小 有文字放大
        boolean notEmptyTitle = StringUtils.isNotEmpty(title);
        if (notEmptyTitle) {
            tempHeight += 20;
        }

        BufferedImage image = new BufferedImage(width, tempHeight, 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);
            }
        }

        // 插入图片LOGO
        if (StringUtils.isNotEmpty(imgPath)) {
            QRCodeUtils.insertImage(image, imgPath, needCompress);
        }
        //插入文字
        if (notEmptyTitle) {
            addFontImage(image, "【" + title + "】");
        }
        return image;
    }

    /**
     * 添加 底部图片文字
     *
     * @param source      图片源
     * @param declareText 文字本文
     */
    private static void addFontImage(BufferedImage source, String declareText) {
        //设置文本图片宽高
        BufferedImage textImage = strToImage(declareText, QRCODE_SIZE, 40);
        Graphics2D graph = source.createGraphics();
        //开启文字抗锯齿
        graph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        int width = textImage.getWidth(null);
        int height = textImage.getHeight(null);

        Image src = textImage;
        //画图 文字图片最终显示位置 在Y轴偏移量 从上往下算
        graph.drawImage(src, 0, QRCODE_SIZE - 20, width, height, null);
        graph.dispose();
    }

    /**
     * 处理文字大小 生成文字图片
     *
     * @param str
     * @param width
     * @param height
     * @return 文本图片
     */
    private static BufferedImage strToImage(String str, int width, int height) {
        BufferedImage textImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) textImage.getGraphics();
        //开启文字抗锯齿
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2.setBackground(Color.WHITE);
        g2.clearRect(0, 0, width, height);
        g2.setPaint(Color.BLACK);
        FontRenderContext context = g2.getFontRenderContext();
        Font font = new Font("微软雅黑", Font.BOLD, FONT_SIZE);
        g2.setFont(font);
        LineMetrics lineMetrics = font.getLineMetrics(str, context);
        FontMetrics fontMetrics = FontDesignMetrics.getMetrics(font);
        float offset = (width - fontMetrics.stringWidth(str)) / 2;
        float y = (height + lineMetrics.getAscent() - lineMetrics.getDescent() - lineMetrics.getLeading()) / 2;

        g2.drawString(str, (int) offset, (int) y);

        return textImage;
    }


    /**
     * 插入LOGO
     *
     * @param source       二维码图片
     * @param imgPath      LOGO图片地址
     * @param needCompress 是否压缩
     * @throws Exception
     */
    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
        File file = new File(imgPath);
        if (!file.exists()) {
            System.err.println("" + imgPath + "   该文件不存在!");
            return;
        }
        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 = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - 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();
    }

    /**
     * 生成二维码(内嵌LOGO) 本地保存
     *
     * @param content      内容
     * @param imgPath      LOGO地址
     * @param destPath     存放目录
     * @param needCompress 是否压缩LOGO
     * @throws Exception
     */
    public static String encode(String content, String imgPath, String destPath, boolean needCompress)
            throws Exception {
        BufferedImage image = QRCodeUtils.createImage(null,content, imgPath, needCompress);
        mkdirs(destPath);
        // 随机生成二维码图片文件名
        String file = UUID.randomUUID() + ".jpg";
        ImageIO.write(image, FORMAT_NAME, new File(destPath + "/" + file));
        return destPath + file;
    }



    /**
     * 创建二维码 底部有标题 LOGO
     *
     * @param title        标题
     * @param content      二维码内容
     * @param imgPath      图片地址
     * @param needCompress LOGO是否压缩 推荐为True
     * @param response     响应流
     */
    public static void createTitleImage(String title, String content, String imgPath, boolean needCompress, HttpServletResponse response) {

        BufferedImage image = null;
        ImageOutputStream imageOutput = null;
        long length = 0;
        try {
            //创建二维码
            image = QRCodeUtils.createImage(title, content, imgPath, needCompress);
            //步骤一:BufferedImage 转 InputStream
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            imageOutput = ImageIO.createImageOutputStream(byteArrayOutputStream);
            ImageIO.write(image, "png", imageOutput);
            //步骤二:获得文件长度
            length = imageOutput.length();
            // 文件名 类型需要注明
            String fileName = "6S-【" + title + "】点检.png";
            //设置文件长度
            response.setContentLength((int) length);
            //输入流
            InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            //步骤三:传入文件名、输入流、响应
            fileDownload(fileName, inputStream, response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    //文件下载方法,工具类
    public static void fileDownload(String filename, InputStream input, HttpServletResponse response) {
        try {
            byte[] buffer = new byte[input.available()];
            input.read(buffer);
            input.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes("utf-8"), "ISO-8859-1"));
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();
            //关闭,即下载
            toClient.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
     *
     * @author lanyuan Email: mmm333zzz520@163.com
     * @date 2013-12-11 上午10:16:36
     * @param destPath 存放目录
     */
    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        // 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

}

调用

有无LOGO调用

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class Test {
    //二维码内容
    private  static   String content = "https://www.baidu.com";
    // 二维码保存的路径
    private   static String path = "D:/Test/";
    //LOGO本地路径
    private   static String logopath = "D:/Test/6s1.png";

    public static void main(String[] args) {
        //创建有LOGO的二维码
        System.out.println("开始生成...");
        QRCode();
        QRCodeLogo();
        System.out.println("生成完毕!");
        //创建有标题的二维码
         QRCodeUtils.createTitleImage("压机上线工序","https://www.baidu.com","",true,response);

    }

    /**
     * 生成带有LOGO的二维码
     */
    public static void QRCodeLogo() {
        try {
            System.out.println(QRCodeUtils.encode(content,logopath,path,true));
        } catch (WriterException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }catch (Exception e){

        }
    }

    /**
     * 生成纯二维码
     */
    public static void QRCode() {
        try {
            String codeName = UUID.randomUUID().toString();// 二维码的图片名
            String imageType = "jpg";// 图片类型
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            Map<EncodeHintType, String> hints = new HashMap<EncodeHintType, String>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 400, 400, hints);
            File file1 = new File(path, codeName + "." + imageType);
            MatrixToImageWriter.writeToFile(bitMatrix, imageType, file1);
        } catch (WriterException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }catch (Exception e){

        }
    }
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

竖版字体(可调字号)

java 字体大小 像素_字体的大小(pt)和像素(px)如何转换?

     /**
     * 生成包含 标题说明 LOGO 的二维码图片
     *
     * @param title        标题 底部显示
     * @param content      二维码内容
     * @param imgPath      LOGO文件路径
     * @param needCompress LOGO 是否压缩
     * @return 二维码图片流
     * @throws Exception
     */
    private static BufferedImage createImage(String title, String content, String imgPath, boolean needCompress) throws Exception {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();

        int tempWidth = width;
        // 二维码图片大小 有文字按照所在位置加长加宽
        boolean notEmptyTitle = StringUtils.isNotEmpty(title);
        if (notEmptyTitle) {
            tempWidth+=50;
        }
        //制作白板 填充二维码
        BufferedImage image = new BufferedImage(tempWidth, 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);
            }
        }

        // 插入图片LOGO
        if (StringUtils.isNotEmpty(imgPath)) {
            QRCodeUtils.insertImage(image, imgPath, needCompress);
        }
        //插入文字
        if (notEmptyTitle) {
            addFontImage(image, "︻" + title + "︼");
        }
        return image;
    }
     /**
     * 添加 底部图片文字
     *
     * @param source      图片源
     * @param declareText 文字本文
     */
    private static void addFontImage(BufferedImage source, String declareText) {
        //设置文本图片宽高
        BufferedImage textImage = strToImage(declareText, 50, QRCODE_SIZE);
        Graphics2D graph = source.createGraphics();
        //开启文字抗锯齿
        graph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        int width = textImage.getWidth(null);
        int height = textImage.getHeight(null);

        Image src = textImage;
        //画图 文字图片最终显示位置 在Y轴偏移量 从上往下算
        graph.drawImage(src, QRCODE_SIZE, 0, width, height, null);
        graph.dispose();
    }
    /**
     * 处理文字大小 生成文字图片
     *
     * @param str
     * @param width
     * @param height
     * @return 文本图片
     */
    private static BufferedImage strToImage(String str, int width, int height) {
        BufferedImage textImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) textImage.getGraphics();
        //开启文字抗锯齿
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2.setBackground(Color.GREEN);
        g2.clearRect(0, 0, width, height);
        g2.setPaint(Color.BLACK);
        int length = str.length();
        //字体大小
        int fontSize=0;
        //字体间距 最多支持32个字 超长可追加设置
        int fontSpacing=0;
        if(length<8) {
            fontSize=FONT_SIZE;
            fontSpacing=5;
        }else if(8<length&&length<16){
            fontSize=12;
            fontSpacing=3;
        }else if(16<length&&length<32){
            fontSize=7;
            fontSpacing=1;
        }
        //加入字体
        Font font = new Font("微软雅黑", Font.BOLD, fontSize);
        g2.setFont(font);

        //字体像素大小  1/2.8
        float fontPx= (float)(fontSize/72.0)*96;

        //计算第一个文字书写Y轴位置 从上往下
        float y=height/2-((length/2) *fontPx);
        //X轴补偿系数 留白 保证对齐
        float offset=(width-fontPx)/2;
        //截取单个字符 循环排列每个字竖坐标
        String[] split = str.split("");
        for (String fontStr : split) {
            g2.drawString(fontStr, (int) offset, (int) y);
            //下一个字体位置
            y+=(fontPx+fontSpacing);
        }

        return textImage;
    }

在这里插入图片描述

下载

及时性生成推荐IO流,没必要本地存储

     /**
     * 测试下载
     * @param response
     */
    @ApiOperation("下载二维码")
    @GetMapping("/downloadQRImag")
    public void downloadQRImag(HttpServletResponse response){
        try {
            QRCodeUtils.downloadQRImag("https://www.baidu.com","D:/Test/6s3.png",response,true);
        }catch (Exception e){
            logger.error(e.getMessage());
        }
    }

注意

二维码的复杂程度决定了是否能填充完全

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过使用Apache POI库来读取Word文档中的横版和竖版数据。Apache POI是一个开源的Java库,它提供了读取和写入Microsoft Office文档格式的API,包括Word文档。 以下是获取Word文档中横版和竖版数据的基本步骤: 1. 导入Apache POI库到Java项目中。 2. 使用XWPFDocument类来打开Word文档。 3. 使用XWPFParagraph和XWPFRun类来获取文档中的段落和文本内容。 4. 使用XWPFTable类来获取文档中的表格内容。 5. 判断表格是否为横版或竖版,可以通过比较表格的行数和列数来判断。 6. 获取表格中的数据,可以使用XWPFTableRow和XWPFTableCell类来获取行和单元格内容。 下面是一个简单的示例代码,演示如何获取Word文档中的表格数据: ```java import java.io.FileInputStream; import java.io.IOException; import org.apache.poi.xwpf.usermodel.*; public class ReadWordDoc { public static void main(String[] args) { try { // 打开Word文档 String filename = "test.docx"; FileInputStream fis = new FileInputStream(filename); XWPFDocument doc = new XWPFDocument(fis); // 获取文档中的表格 for (XWPFTable table : doc.getTables()) { // 判断表格是否为横版或竖版 if (table.getNumberOfRows() > table.getNumberOfColumns()) { System.out.println("横版表格:"); } else { System.out.println("竖版表格:"); } // 获取表格中的数据 for (XWPFTableRow row : table.getRows()) { for (XWPFTableCell cell : row.getTableCells()) { System.out.print(cell.getText() + "\t"); } System.out.println(); } } doc.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 在上面的示例代码中,我们使用了XWPFDocument类来打开Word文档,然后使用getTables()方法获取文档中的表格。接着,我们判断表格是否为横版或竖版,并使用getNumberOfRows()和getNumberOfColumns()方法来获取表格的行数和列数。最后,我们使用XWPFTableRow和XWPFTableCell类来获取表格中的数据,并输出到控制台中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值