Java生成中间带有logo的二维码

时间:2022-11-17 20:36:48

介绍基于java的中间带有logo的二维码生成方法

所需jar包:QRCode.jar


import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.imageio.ImageIO;

import jp.sourceforge.qrcode.QRCodeDecoder;

import com.swetake.util.Qrcode;

public class QRCodeUtils
{
    private static final int WIDTH = 30;
    
    private static final int HEIGHT = 30;
    
    /**
    * encoderQRCode(生成二维码)  
    * @param content 生成的二维码内容
    * @param imgPath 生成的二维码文件路径  
    * @param logoPath logo文件路径
    * @param needCompress logo是否需要压缩
     */
    public void encoderQRCode(String content, String imgPath, String logoPath, boolean needCompress)
    {
        this.encoderQRCode(content, imgPath, "png", logoPath, 7, needCompress);
    }
    
    /**
    * encoderQRCode(生成二维码)  
    * @param content 生成的二维码内容
    * @param imgPath 生成的二维码文件路径  
    * @param logoPath logo文件路径
     */
    public void encoderQRCode(String content, String imgPath, String logoPath)
    {
        this.encoderQRCode(content, imgPath, "png", logoPath, 7, true);
    }

    /**
    * encoderQRCode(生成二维码)  
    * @param content 生成的二维码内容
    * @param os 生成二维码文件流  
    * @param logoPath logo文件路径
     */
    public void encoderQRCode(String content, OutputStream os, String logoPath)
    {
        this.encoderQRCode(content, os, "png", logoPath, 7, true);
    }
    
    /**
    * encoderQRCode(生成二维码)  
    * @param content 生成的二维码内容
    * @param os 生成二维码文件流  
    * @param imgType 生成的二维码文件类型  
    * @param logoPath logo文件路径
    * @param needCompress logo是否需要压缩
     */
    public void encoderQRCode(String content, OutputStream os, String imgType,
            String logoPath, boolean needCompress)
    {
        this.encoderQRCode(content, os, imgType, logoPath, 7, needCompress);
    }

    /**
    * encoderQRCode(生成二维码)  
    * @param content 生成的二维码内容
    * @param imgPath 生成的二维码文件路径  
    * @param imgType 生成的二维码文件类型  
    * @param logoPath logo文件路径
    * @param size 二维码版本号
    * @param needCompress logo是否需要压缩
     */
    public void encoderQRCode(String content, String imgPath, String imgType, String logoPath,
            int size, boolean needCompress)
    {
        try
        {
            BufferedImage image = this.drawImageCode(content, imgType, logoPath, size, needCompress);
            File imgFile = new File(imgPath);
            ImageIO.write(image, imgType, imgFile);
        }
        catch (IOException e)
        {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
    * encoderQRCode(生成二维码)  
    * @param content  
    * @param os 二维码文件流
    * @param imgType 二维码文件类型  
    * @param logoPath logo图片路径
    * @param size 二维码版本号
    * @param needCompress logo是否需要压缩
     */
    public void encoderQRCode(String content, OutputStream os, String imgType, String logoPath,
            int size, boolean needCompress)
    {
        try
        {
            BufferedImage image = this.drawImageCode(content, imgType, logoPath, size, needCompress);
            ImageIO.write(image, imgType, os);
        }
        catch (IOException e)
        {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
    * drawImageCode(创建二维码)  
    * @param content 生成的二维码内容
    * @param imgType 生成的二维码格式
    * @param logoPath 二维码logo路径  
    * @param size 二维码版本号
    * @param needCompress 是否压缩logo图片
     */
    public BufferedImage drawImageCode(String content, String imgType, String logoPath, int size, boolean needCompress)
    {
        BufferedImage image = null;
        try
        {
            Qrcode qrCode = new Qrcode();
            
            //设置二维码的纠错率,包括L(7%)、M(15%)、Q(25%)、H(30%),默认为M
            //纠错率设置的越高,允许的内容越少:L允许的数组长度为156,M允许的数组长度为124,Q允许的数组长度为88,M允许的数组长度为66
            qrCode.setQrcodeErrorCorrect('M');
            
            //设置二维码的编码方式,有A,B, N三个可选,默认为B
            qrCode.setQrcodeEncodeMode('B');
            
            //设置二维码版本号,象征二维码信息容量,可选为1-40.粗略可理解为二维码的长宽
            qrCode.setQrcodeVersion(size);
            
            byte[] contentBytes = content.getBytes("utf-8");
            int imgSize = 67 + 12 * (size - 1);
            image = new BufferedImage(imgSize, imgSize, BufferedImage.TYPE_INT_RGB);
            
            Graphics2D gs = image.createGraphics();
            gs.setBackground(Color.WHITE);
            gs.clearRect(0, 0, imgSize, imgSize);
            
            gs.setColor(Color.BLACK);
            
            //设置偏移量
            int pixoff = 2;
            
            if(contentBytes.length > 0 && contentBytes.length < 800)
            {
                boolean[][] codeOut = qrCode.calQrcode(contentBytes);
                for(int x=0; x<codeOut.length; x++)
                {
                    for(int y=0; y<codeOut.length; y++)
                    {
                        if(codeOut[y][x])
                        {
                            gs.fillRect(y*3+pixoff, x*3+pixoff, 3, 3);
                        }
                    }
                }
            }
            insertImage(image, logoPath, needCompress);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        
        return image;
    }
    
    /**
    * insertImage(向二维码中插入logo)  
    * @param image 二维码对象
    * @param logoPath logo图片路径   
    * @param needCompress 是否需要压缩logo  
     */
    private void insertImage(BufferedImage image, String logoPath, boolean needCompress) throws IOException
    {
        File file = new File(logoPath);
        if(!file.exists())
        {
            System.err.print("该文件不存在"+logoPath);
        }
        Image src = ImageIO.read(file);
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        if(needCompress)
        {
            if(width > WIDTH)
            {
                width = WIDTH;
            }
            if(height > HEIGHT)
            {
                height = HEIGHT;
            }
        }
        Image img = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics gs = bufImg.getGraphics();
        gs.drawImage(img, 0, 0, null);
        gs.dispose();
        src = img;
        
        //插入logo
        Graphics2D gs2d = image.createGraphics();
        int x = (image.getWidth() - width) / 2;
        int y = (image.getHeight() - height) / 2;
        gs2d.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, height, 6, 6);
        gs2d.setStroke(new BasicStroke(3f));
        gs2d.draw(shape);
        gs2d.dispose();
    }
    
    /**
    * decodeQRCode(以文件形式解析二维码)  
    * @param imgPath 二维码文件路径
     */
    public String decodeQRCode(String imgPath)
    {
        File imgFile = new File(imgPath);
        BufferedImage image = null;
        String content = null;
        try {
            image = ImageIO.read(imgFile);
            QRCodeDecoder decoder = new QRCodeDecoder();
            content = new String(decoder.decode(new QRCodeImages(image)), "utf-8");
        } catch (IOException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return content;
    }
    
    /**
     * @param decodeQRCode(以文件流形式解析二维码)  
     * @param is 二维码文件输入流
     */
    public String decodeQRCode(InputStream is)
    {
        BufferedImage image = null;
        String content = null;
        try
        {
            image = ImageIO.read(is);
            QRCodeDecoder decoder = new QRCodeDecoder();
            content = new String(decoder.decode(new QRCodeImages(image)), "utf-8");
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        return content;
    }
    
}




import java.awt.image.BufferedImage;

import jp.sourceforge.qrcode.data.QRCodeImage;

public class QRCodeImages implements QRCodeImage
{
    private BufferedImage image;

    public QRCodeImages(BufferedImage image)
    {
        this.image = image;
    }
    
    public int getHeight()
    {
        return image.getHeight();
    }

    public int getPixel(int i, int j)
    {
        return image.getRGB(i, j);
    }

    public int getWidth()
    {
        return image.getWidth();
    }
}



import java.io.File;

public class QRCodeTest
{
    public static void main(String[] args)
    {
        QRCodeUtils tdc = new QRCodeUtils();
        String content = "Hello World";
        String imgPath = "d:"+File.separator+"new.png";
        String logoPath = "d:/123.jpg";
        tdc.encoderQRCode(content, imgPath, logoPath, true);
        
        String filePath = "d:"+File.separator+"new3.png";
        String fileContent = tdc.decodeQRCode(filePath);
        System.out.println(fileContent);
    }
}


注:1.生成二维码时文件内容的大小有限制,具体在代码中有注释说明;

        2.方法有简单的封装,如有需要,可自行扩展;

        3.用Zxing.jar 这个工具类生成的二维码内容大小好像限制不是特别大,具体还没有研究,后续准备研究之后发上来;

        4.本文是在学习前人的基础上整合起来的,如有雷同,纯属应该。