java制作带有logo的二维码,解决zxing中文乱码

目标

  1. 使用谷歌zxing生成带有logo二维码
  2. 便捷地解决二维码中文乱码问题

过程

  1. 下载依赖:
    maven坐标:
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.3.3</version>
</dependency>
  1. 编写java代码生成二维码,并绘制logo
/**
     * @description:
     * @param qrUrl 二维码对应url
     * @param logoUrl logo url
     * @param outputPath 输出路径
     * @param note 二维码备注
     * @param width
     * @param height
     * @exception Exception
     */
    public static void drawQrCode(String qrUrl, String logoUrl, String outputPath, String note, int width, int height) throws Exception{
        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        BitMatrix bitMatrix = multiFormatWriter.encode(qrUrl, BarcodeFormat.QR_CODE, width, height, new HashMap<EncodeHintType, Object>() {

            private static final long serialVersionUID = 1L;
            {
                put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
                put(EncodeHintType.CHARACTER_SET, "UTF-8");
                put(EncodeHintType.MARGIN, 0);
            }
        });
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 开始利用二维码数据图片,分别设为黑(0xFFFFFFFF)白(0xFF000000)两色
        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 (logoUrl != null && !"".equals(logoUrl) ){
            //绘制二维码图
            Graphics2D graphics = image.createGraphics();
            //读取logo图
            BufferedImage logoImg = ImageIO.read( new URL(logoUrl) );
            //绘制logo图片
            graphics.drawImage(logoImg, width * 2 / 6, height * 2 / 6, width * 3 / 10, height * 3 / 10, null);
            graphics.dispose();
            logoImg.flush();
        }
        //设置二维码备注
        if (note != null && !"".equals(note)){
            BufferedImage outImage = new BufferedImage(width, height + 45, BufferedImage.TYPE_4BYTE_ABGR);
            Graphics2D outGraphics = outImage.createGraphics();
            // 画二维码到新的面板
            outGraphics.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
            // 画文字到新的面板
            outGraphics.setColor(Color.BLACK);
            outGraphics.setFont( new Font("Arial", Font.BOLD, 26) );
            int noteWidth = outGraphics.getFontMetrics().stringWidth(note);
            // 画文字
            outGraphics.drawString(new QrCodeAttributedCharacter(note), (width - noteWidth) / 2, image.getHeight() + (outImage.getHeight() - image.getHeight()) / 2 + 12);

            outGraphics.dispose();
            outImage.flush();
            image = outImage;
        }
        image.flush();
        ImageIO.write(image, "png", Paths.get(outputPath).toFile());
    }
  1. 编写QrCodeAttributedCharacter解决中文乱码问题
/**
 * 二维码文本wrapper,用来防止中文乱码
 */
public class QrCodeAttributedCharacter implements AttributedCharacterIterator {
    private int index;

    private char[] textChars;

    public QrCodeAttributedCharacter(String text) {
        this.textChars = text.toCharArray();
    }

    @Override
    public int getRunStart() {
        return 0;
    }

    @Override
    public int getRunStart(Attribute attribute) {
        return 0;
    }

    @Override
    public int getRunStart(Set<? extends Attribute> attributes) {
        return 0;
    }

    @Override
    public int getRunLimit() {
        return this.textChars.length;
    }

    @Override
    public int getRunLimit(Attribute attribute) {
        return this.textChars.length;
    }

    @Override
    public int getRunLimit(Set<? extends Attribute> attributes) {
        return this.textChars.length;
    }

    @Override
    public Map<Attribute, Object> getAttributes() {
        return Collections.EMPTY_MAP;
    }

    @Override
    public Object getAttribute(Attribute attribute) {
        return Collections.EMPTY_MAP;
    }

    @Override
    public Set<Attribute> getAllAttributeKeys() {
        return Collections.EMPTY_SET;
    }

    @Override
    public char first() {
        this.index = 0;
        return this.textChars[0];
    }

    @Override
    public char last() {
        return this.textChars[ this.textChars.length - 1 ];
    }

    @Override
    public char current() {
        return this.textChars[this.index];
    }

    @Override
    public char next() {
        if (this.index == this.textChars.length - 1){
            return CharacterIterator.DONE;
        }
        return this.textChars[ ++this.index ];
    }

    @Override
    public char previous() {
        if (this.index == 0){
            return CharacterIterator.DONE;
        }
        return this.textChars[this.index - 1];
    }

    @Override
    public char setIndex(int position) {
        this.index = position;
        return textChars[position];
    }

    @Override
    public int getBeginIndex() {
        return 0;
    }

    @Override
    public int getEndIndex() {
        return this.textChars.length;
    }

    @Override
    public int getIndex() {
        return this.index;
    }

    @Override
    public Object clone() {
        return new String(textChars);
    }
}
  1. 中文乱码问题分析与解决依据
    • 乱码原因:
      通过查看zxing的Encoder类可以发现默认编码方式是ISO-8859-1。
      Encoder类
    • 通过新建QrCodeAttributedCharacter类修复乱码问题原理.
      进入Graphics2D的drawString(AttributedCharacterIterator iterator, int x, int y)方法找到其读取字符串内容逻辑如下:
      读取字符串逻辑1
      读取字符串逻辑2
      从图中可以看出其是通过调用AttributedCharacterIterator的实现类的方法来获取字符串内容的,因此可以通过实现AttributedCharacterIterator接口来控制获取的字符串内容。

测试

  1. 测试代码:
public static void main(String[] args) throws Exception {
        String qrUrl = "https://blog.csdn.net/qq_41633199";
        String logoUrl = "http://www.finac.site/logo.png";
        String outputPath = "B:\\logo.jpg";
        drawQrCode(qrUrl, logoUrl, outputPath, "博文地址", 400, 400);
    }
  1. 测试结果:
    结果二维码图
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值