zxing二维码生成工具类

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了zxing二维码生成工具类相关的知识,希望对你有一定的参考价值。

图片生成工具生成

  1.支持多中形式的图片,二维码,条形码

  2.支持一张图片多个二维码

  3.支持二维码图片上加logo

  4.支持图片头部底部添加文字描述

public class ZxingEncoderUtil {
    private static final String CHARSET = "utf-8";
    private static final String FORMAT = "JPG";

    private static Font font = null;


    /**
     * 二维码生成,支持一张图上多个二维码,支持图片添加字体(上下位置),支持二维码中间加logo,
     *
     * @param content
     * @param qrWidth
     * @param qrHeight
     * @param barcodeFormat
     * @param logoPath
     * @param multiImgs
     * @param options       key image_top_1 *** 表示图片要加的内容
     * @return
     */
    public static byte[] createImage(String content, int qrWidth, int qrHeight, BarcodeFormat barcodeFormat, String logoPath, Boolean multiImgs, Map<String, String> options) {
        //每个图片之间的间隔
        int gap = 0;
        //每行的行距
        int lineHeight = 0;
        //字符串的高度
        int strHeight = 15;

        List<String> contents = new ArrayList<>();
        try {
            HashMap<EncodeHintType, Object> hints = new HashMap<>();
            if (StringUtils.isNotBlank(logoPath)) {
                hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //容错等级 L、M、Q、H 其中 L 为最低, H 为最高
            } else {
                hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); //容错等级 L、M、Q、H 其中 L 为最低, H 为最高
            }
            hints.put(EncodeHintType.CHARACTER_SET, CHARSET); // 字符编码
            hints.put(EncodeHintType.MARGIN, 0); // 二维码与图片边距
            if (multiImgs != null && multiImgs) {
                String[] str = content.split(",");
                contents = Arrays.asList(str);
                gap = 15;
            } else {
                contents.add(content);
            }
            //去重
            ArrayList<String> result = new ArrayList<>();
            for (String item : contents) {
                if (Collections.frequency(result, item) < 1) result.add(item);
            }
            Map<String, SortedMap<String, String>> addImage = addOnImage(options);
            SortedMap<String, String> topMap = addImage.get("top");
            SortedMap<String, String> bottomMap = addImage.get("bottom");
            //行距
            if (topMap != null && !topMap.isEmpty() || bottomMap != null && !bottomMap.isEmpty()) {
                lineHeight = 5;
            }
            //画布的宽,高
            int bWidth = qrWidth;
            int bHeight = qrHeight + gap + lineHeight * 2;

            //如果是条形码,需要增加源字符串在画布上
            if (barcodeFormat.equals(BarcodeFormat.CODE_128)) {
                bHeight += strHeight;
            }
            //如果要加头文字,需要加上头部的高度
            if (topMap != null && !topMap.isEmpty()) {
                bHeight += strHeight * topMap.size();
            }
            //如果要加上底部描述,需要加上底部高度
            if (bottomMap != null && !bottomMap.isEmpty()) {
                bHeight += strHeight * bottomMap.size();
            }
            //整个画布的高度
            bHeight = bHeight * result.size() - gap;
            //设置画布
            BufferedImage source = new BufferedImage(bWidth, bHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D graph = source.createGraphics();
            //设置背景颜色
            graph.setBackground(Color.WHITE);
            graph.clearRect(0, 0, bWidth, bHeight);
            if (font == null) {
                FileInputStream inputStream = new FileInputStream(new File(ZxingEncoderUtil.class.getResource("/font/msyh.ttf").getFile()));
                font = Font.createFont(Font.TRUETYPE_FONT, inputStream).deriveFont(Font.BOLD, 14f);
                inputStream.close();
            }
            graph.setFont(font);
            graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            graph.setColor(Color.BLACK);
            //下一次起始Y位置
            int nextPosY = 0;
            //汇总一次的高度
            int singleHeight;
            int topHeight;
            for (String item : result) {
                singleHeight = 0;
                topHeight = 0;
                BufferedImage image = printImage(item, barcodeFormat, qrWidth, qrHeight, logoPath, hints);
                //画图片上部分
                if (topMap != null && !topMap.isEmpty()) {
                    for (SortedMap.Entry<String, String> entry : topMap.entrySet()) {
                        int strWidth = graph.getFontMetrics().stringWidth(entry.getValue());
                        int strX = (image.getWidth(null) - strWidth) / 2;
                        int strY = strHeight * Integer.valueOf(entry.getKey()) + nextPosY;
                        graph.drawString(entry.getValue(), strX, strY);
                    }
                    topHeight = strHeight * topMap.size();
                }
                //图片坐标
                int imageX = 0;
                int imageY = topHeight + lineHeight + nextPosY;
                //画图片
                graph.drawImage(image, imageX, imageY, image.getWidth(null), image.getHeight(null), null);
                singleHeight += topHeight + lineHeight + image.getHeight(null);
                if (barcodeFormat.equals(BarcodeFormat.CODE_128)) {
                    int strWidth = graph.getFontMetrics().stringWidth(item);
                    int strX = (image.getWidth(null) - strWidth) / 2;
                    int strY = imageY + strHeight + image.getHeight(null);
                    graph.drawString(item, strX, strY);
                    singleHeight += strHeight;
                }

                //画图片下部分
                if (bottomMap != null && !bottomMap.isEmpty()) {
                    for (SortedMap.Entry<String, String> entry : bottomMap.entrySet()) {
                        int strWidth = graph.getFontMetrics().stringWidth(entry.getValue());
                        int strX = (image.getWidth(null) - strWidth) / 2;
                        int strY = strHeight * Integer.valueOf(entry.getKey()) + nextPosY + singleHeight;
                        graph.drawString(entry.getValue(), strX, strY);
                    }
                    singleHeight += strHeight * bottomMap.size();
                }
                //设置下次画图的位置
                int i = result.indexOf(item);
                nextPosY = (singleHeight + gap) * (i + 1);
            }
            graph.setStroke(new BasicStroke(3f));
            graph.dispose();
            return imageIO(source);
        } catch (Exception e) {

        }
        return null;
    }


    /**
     * BufferedImage 转字节流
     *
     * @param source
     * @return
     */
    private static byte[] imageIO(BufferedImage source) {
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ImageIO.write(source, "jpg", os);
            return os.toByteArray();
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 插入LOGO
     *
     * @param source
     * @param logoPath
     * @throws Exception
     */
    private static void insertImage(BufferedImage source, String logoPath) throws Exception {
        File file = new File(ZxingEncoderUtil.class.getResource(String.format("/image/%s", logoPath)).getFile());
        if (!file.exists()) {
            throw new Exception("logo file not found.");
        }
        Image src = ImageIO.read(file);
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = (source.getWidth() - width) / 2;
        int y = (source.getHeight() - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, height, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }

    /**
     * zxing工具生成BufferedImage
     *
     * @param content
     * @param barcodeFormat
     * @param qrWidth
     * @param qrHeight
     * @param logoPath
     * @param hints
     * @return
     * @throws Exception
     */
    private static BufferedImage printImage(String content, BarcodeFormat barcodeFormat, int qrWidth, int qrHeight, String logoPath, HashMap<EncodeHintType, Object> hints) throws Exception {
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, barcodeFormat, qrWidth, qrHeight, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, 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);
            }
        }
        if (StringUtils.isNotBlank(logoPath)) {
            insertImage(image, logoPath);
        }
        return image;
    }

    /**
     * 获取位置参数
     *
     * @param options key image_AA_BB  value ***  AA位置(top,bottom) BB 排序
     * @return
     */
    private static Map<String, SortedMap<String, String>> addOnImage(Map<String, String> options) {
        Map<String, SortedMap<String, String>> result = Collections.synchronizedMap(new HashMap<String, SortedMap<String, String>>());
        SortedMap<String, String> topMap = Collections.synchronizedSortedMap(new TreeMap<String, String>());
        SortedMap<String, String> bottomMap = Collections.synchronizedSortedMap(new TreeMap<String, String>());
        try {
            if (options != null && !options.isEmpty())
                for (Map.Entry<String, String> entry : options.entrySet()) {
                    if (StringUtils.isNotBlank(entry.getValue())) {
                        //top
                        if (entry.getKey().startsWith("image_top")) {
                            topMap.put(entry.getKey().replace("image_top_", ""), entry.getValue());
                        }
                        //bottom
                        if (entry.getKey().startsWith("image_bottom")) {
                            bottomMap.put(entry.getKey().replace("image_bottom_", ""), entry.getValue());
                        }
                        ClogManager.info("内容", entry.getValue());
                    }
                }
        } catch (Exception e) {
            
        }
        result.put("top", topMap);
        result.put("bottom", bottomMap);
        return result;
    }
}

 

在开发这个工具的途中遇到问题:在本地win系统上图片drawString时,中文显示正常,但是到linux系统时,中文就显示不出来,显示的是方框,造成这种问题是由于操作系统不支持中文字体导致,最终最佳的解决方案是,下载需要的字体,放根目录,通过读取文件的方式获得字体,

java.awt.Font类方法createFont获取文件的方式获得字体,从而改变drawString画中文不异常,此解决方案不必改动linux系统字体

以上是关于zxing二维码生成工具类的主要内容,如果未能解决你的问题,请参考以下文章

Java通过Zxing生成和解析二维码

Java通过Zxing生成和解析二维码

java 通过zxing生成二维码

Java通过Zxing生成二维码

zxing解析生成一维码二维码

ZXing-core生成二维码和解析