Java 二维码生成工具类

/**
 * 二维码 工具
 *
 * @author Rubekid
 *
 */
public class QRcodeUtils {
    
    /**
     * 默认version
     */
    public static final int DEFAULT_VERSION = 9;

    /**
     * 图片类型 png (默认) 比较小
     */
    public static final String IMAGE_TYPE_PNG = "png";

    /**
     * 图片类型 jpg
     */
    public static final String IMAGE_TYPE_JPEG = "jpg";

    /**
     * 容错率等级 L
     */
    public static final char CORRECT_L = 'L';

    /**
     * 容错率等级 M
     */
    public static final char CORRECT_M = 'M';

    /**
     * 容错率等级 Q
     */
    public static final char CORRECT_Q = 'Q';

    /**
     * 容错率等级 H
     */
    public static final char CORRECT_H = 'H';

    /**
     * 旁白占用比率
     */
    public static final double PADDING_RATIO = 0.02;

    /**
     * 生成二维码
     *
     * @param content
     *            要生成的内容
     * @param size
     *            要生成的尺寸
     * @param versoin
     *            二维码尺寸,取值范围1-40,值越大尺寸越大,可存储的信息越大
     * @param ecc
     *            二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%)
     * @return
     * @throws Exception
     */
    public static BufferedImage encode(String content, int size, int version, char ecc) throws Exception {
        BufferedImage image = null;
        Qrcode qrcode = new Qrcode();
        // 设置二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%),排错率越高可存储的信息越少,但对二维码清晰度的要求越小
        qrcode.setQrcodeErrorCorrect(ecc);
        qrcode.setQrcodeEncodeMode('B');
        // 设置设置二维码尺寸,取值范围1-40,值越大尺寸越大,可存储的信息越大
        qrcode.setQrcodeVersion(version);
        // 获得内容的字节数组,设置编码格式
        byte[] contentBytes = content.getBytes("utf-8");

        double ratio = 3;// 默认放大三倍
        int qrcodeSize = 21 + 4 * (version - 1);
        if (size > 0) {
            ratio = (double) size / qrcodeSize;
        }
        int intRatio = (int) Math.ceil(ratio);

        // 旁白
        int padding = (int) Math.ceil(qrcodeSize * intRatio * PADDING_RATIO);
        if (padding < 5) {
            padding = 5;
        }
        // 图片尺寸
        int imageSize = qrcodeSize * intRatio + padding * 2;

        // 图片边长 调整(10的倍数)
        if (intRatio > ratio) {
            int newSize = (int) Math.ceil(ratio * imageSize / intRatio);
            int r = newSize % 10;
            newSize += 10 - r;
            int newImageSize = (int) Math.floor(intRatio * newSize / ratio);
            padding += (newImageSize - imageSize) / 2;
            imageSize = newImageSize;
        } else {
            int r = imageSize % 10;
            int d = 10 - r;
            padding += d / 2;
            imageSize += d;
        }

        image = new BufferedImage(imageSize, imageSize, BufferedImage.TYPE_INT_RGB);
        Graphics2D gs = image.createGraphics();
        // 设置背景颜色
        gs.setBackground(Color.WHITE);
        gs.clearRect(0, 0, imageSize, imageSize);

        // 设定图像颜色 BLACK
        gs.setColor(Color.BLACK);

        // 输出内容 二维码
        if (contentBytes.length > 0 && contentBytes.length < 800) {
            boolean[][] codeOut = qrcode.calQrcode(contentBytes);
            for (int i = 0; i < codeOut.length; i++) {
                for (int j = 0; j < codeOut.length; j++) {
                    if (codeOut[j][i]) {
                        gs.fillRect(j * intRatio + padding, i * intRatio + padding, intRatio, intRatio);
                    }
                }
            }
        } else {
            throw new Exception("QRCode content bytes length = " + contentBytes.length + " not in [0, 800].");
        }
        gs.dispose();
        image.flush();

        if (intRatio > ratio) {
            image = resize(image, (int) Math.ceil(ratio * imageSize / intRatio));
        }
        return image;
    }

    /**
     * 生成二维码
     *
     * @param content
     * @param size
     * @return
     * @throws Exception
     */
    public static BufferedImage encode(String content, int size) throws Exception {
        return encode(content, size, DEFAULT_VERSION, CORRECT_Q);
    }

    /**
     * 生成二维码
     *
     * @param content
     * @param size
     * @param version
     * @return
     */
    public static BufferedImage encode(String content, int size, int version) throws Exception {
        return encode(content, size, version, CORRECT_Q);
    }

    /**
     * 生成二维码
     *
     * @param content
     * @param size
     * @param ecc
     * @return
     */
    public static BufferedImage encode(String content, int size, char ecc) throws Exception {
        return encode(content, size, DEFAULT_VERSION, ecc);
    }

    /**
     * 生成二维码
     *
     * @param content
     * @return
     */
    public static BufferedImage encode(String content) throws Exception {
        return encode(content, 0, DEFAULT_VERSION, CORRECT_Q);
    }

    /**
     * 解析二维码
     *
     * @throws UnsupportedEncodingException
     * @throws DecodingFailedException
     */
    public static String decode(BufferedImage bufferedImage) throws DecodingFailedException,
            UnsupportedEncodingException {
        QRCodeDecoder decoder = new QRCodeDecoder();
        return new String(decoder.decode(new MyQRCodeImage(bufferedImage)), "utf-8");
    }

    /**
     * 下载二维码
     *
     * @param response
     * @param filename
     * @param content
     * @param size
     * @param imageType
     * @throws Exception`
     */
    public static void download(HttpServletResponse response, String filename, String content, int size,
            String imageType, String logoPath) throws Exception {
        if (size > 2000) {
            size = 2000;
        }
        BufferedImage image = QRcodeUtils.encode(content, size);
        if(logoPath !=null){
            markLogo(image, logoPath);
        }
        // 替换占位符
        filename = filename.replace("{size}", String.valueOf(image.getWidth()));
        InputStream inputStream = toInputStream(image, imageType);
        int length = inputStream.available();

        // 设置response
        response.setContentType("application/x-msdownload");
        response.setContentLength(length);
        response.setHeader("Content-Disposition", "attachment;filename="
                + new String(filename.getBytes("gbk"), "iso-8859-1"));

        // 输出流
        byte[] bytes = new byte[1024];
        OutputStream outputStream = response.getOutputStream();
        while (inputStream.read(bytes) != -1) {
            outputStream.write(bytes);
        }
        outputStream.flush();
    }
    
    /**
     * 下载二维码
     * @param response
     * @param filename
     * @param content
     * @param size
     * @param imageType
     * @throws Exception
     */
    public static void download(HttpServletResponse response, String filename, String content, int size,
            String imageType) throws Exception {
        download(response, filename, content, size, imageType, null);
    }

    /**
     * 下载二维码
     *
     * @param response
     * @param filename
     * @param content
     * @param size
     * @throws Exception
     */
    public static void download(HttpServletResponse response, String filename, String content, int size)
            throws Exception {
        download(response, filename, content, size, IMAGE_TYPE_PNG);
    }
    
    /**
     * 生成二维码文件
     * @param destFile
     * @param content
     * @param size
     * @param logoPath
     * @throws Exception
     */
    public static void createQrcodeFile(File destFile, String content, int size, String logoPath) throws Exception{
        if(!destFile.exists() || !destFile.isFile()){
            destFile.createNewFile();
        }
        OutputStream outputStream = new FileOutputStream(destFile);
        BufferedImage image = QRcodeUtils.encode(content, size);
        if(logoPath !=null){
            markLogo(image, logoPath);
        }
        InputStream inputStream = toInputStream(image, QRcodeUtils.IMAGE_TYPE_PNG);
        // 输出流
        byte[] bytes = new byte[1024];
        while (inputStream.read(bytes) != -1) {
            outputStream.write(bytes);
        }
        inputStream.close();
        outputStream.close();
    }
    
    /**
     * 生成二维码文件
     * @param destFile
     * @param content
     * @param size
     * @throws Exception
     */
    public static void createQrcodeFile(File destFile, String content, int size) throws Exception{
        createQrcodeFile(destFile, content, size, null);
    }
    
    /**
     * logo水印
     * @param qrcode
     * @param logoPath
     * @throws IOException
     */
    public static void markLogo(BufferedImage qrcode, String logoPath) throws IOException{
        File logoFile = new File(logoPath);
        if(logoFile.exists()){
            Graphics2D gs = qrcode.createGraphics();
            int width = qrcode.getWidth();
            int height = qrcode.getHeight();
            Image logo = ImageIO.read(logoFile);
            
            
            int scale = 6; //显示为图片的 1/n;
            
            //logo显示大小
            int lw = width / scale;
            int lh = height / scale;
            int wx = (width - lw) /2;
            int wy = (height -lh) / 2;
            gs.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1));
            gs.drawImage(logo, wx, wy, lw, lh, null); // 图片水印文件结束
            gs.dispose();
            qrcode.flush();
        }
        
    }

    /**
     * 获取内容二维码图片出流
     *
     * @param content
     * @param size
     * @param imageType
     * @return
     * @throws Exception
     * InputStream
     */
    public static InputStream getQrcodeImageStream(String content, int size, String imageType, String logoPath) throws Exception {
        if (size > 2000) {
            size = 2000;
        }
        BufferedImage image = QRcodeUtils.encode(content, size);
        if(logoPath!=null){
            markLogo(image, logoPath);
        }
        return toInputStream(image, imageType);
    }
    
    public static InputStream getQrcodeImageStream(String content, int size, String imageType) throws Exception {
        return getQrcodeImageStream(content, size, imageType, null);
    }
    
    /**
     * 转成InputStream
     * @param image
     * @param imageType
     * @return
     * @throws IOException
     */
    private static InputStream toInputStream(BufferedImage image, String imageType) throws IOException{
        // BufferedImage 转 InputStream
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageOutputStream imageOutput = ImageIO.createImageOutputStream(byteArrayOutputStream);

        // 生成jpg格式
        if (IMAGE_TYPE_JPEG.equals(imageType)) {
            Iterator<ImageWriter> iterator = ImageIO.getImageWritersByFormatName("jpeg");
            ImageWriter imageWriter = iterator.next();
            ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
            imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            imageWriteParam.setCompressionQuality(1); // 设置质量
            imageWriter.setOutput(imageOutput);
            IIOImage iioImage = new IIOImage(image, null, null);
            imageWriter.write(null, iioImage, imageWriteParam);
            imageWriter.dispose();
        } else {
            ImageIO.write(image, "png", imageOutput);
        }
        return  new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }

    /**
     * 图片缩放
     */
    private static BufferedImage resize(BufferedImage image, int size) {
        int imageSize = (size % 2) > 0 ? (size + 1) : size;

        BufferedImage bufferedImage = new BufferedImage(imageSize, imageSize, BufferedImage.TYPE_INT_RGB);
        Graphics2D gs = bufferedImage.createGraphics();
        gs.setBackground(Color.WHITE);
        gs.clearRect(0, 0, imageSize, imageSize);
        gs.setColor(Color.BLACK);
        gs.fillRect(0, 0, imageSize, imageSize);
        gs.drawImage(image, 0, 0, size, size, null);
        gs.dispose();
        image.flush();
        return bufferedImage;
    }

}

 

posted @ 2014-10-24 00:43  rubekid  阅读(430)  评论(0编辑  收藏  举报