条形码/二维码生成探索

条形码/二维码生成探索

所用依赖

   
        
            net.sf.barcode4j
            barcode4j-light
            ${barcode4j-light.version}
        
        
        
            com.google.zxing
            javase
            ${google.zxing.version}
        

生成条形码工具类(含条形码下面有字符和没有字符的)

package com.yb.bar.qr.code.utils;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.oned.Code128Writer;
import org.krysalis.barcode4j.impl.code128.Code128Bean;
import org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * 条形码下由字符的条形码生成(推荐使用)
 *
 * @author yunzhi-yangbiao
 * @date 2020/1/9
 */
public class BarCodeUtils {
    private static final String FORMAT = "image/png";

    /**
     * 通过输出流获取条形码(条形码编码的内容就是显示在条形码下的字符)
     * 

* 如果需要解码直接返回字符即可,因为这个是显示出来的 * * @param content 条形码的编码内容 * @param barCodePath 条形码的路径 * @throws Exception */ public static void barCodeFile(String content, String barCodePath) throws Exception { OutputStream outputStream = new FileOutputStream(new File(barCodePath)); getBarCode(content, outputStream); } /** * 通过输出流获取条形码(条形码编码的内容就是显示在条形码下的字符) *

* 如果需要解码直接返回字符即可,因为这个是显示出来的 * * @param content 条形码的编码内容 * @param outputStream 输出流 * @throws Exception */ public static void getBarCode(String content, OutputStream outputStream) throws Exception { //选择条形码类型(好多类型可供选择) Code128Bean bean = new Code128Bean(); //设置长宽 final int resolution = 150; final double moduleWidth = 0.20; bean.setModuleWidth(moduleWidth); bean.doQuietZone(false); //配置画布 BitmapCanvasProvider canvas = new BitmapCanvasProvider(outputStream, FORMAT, resolution, BufferedImage.TYPE_BYTE_BINARY, false, 0); //生成条码 bean.generateBarcode(canvas, content); canvas.finish(); } /** * 解析条形码 * * @param imgPath 条形码路径 * @return */ public static String barCodeDecode(String imgPath) throws Exception { BufferedImage image = ImageIO.read(new File(imgPath)); if (image == null) { throw new RuntimeException("the decode image may be not exists."); } LuminanceSource source = new BufferedImageLuminanceSource(image); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); Result result = new MultiFormatReader().decode(bitmap, null); return result.getText(); } //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /** * 生成条形码(条形码下边没有字符,但是可以解析) *

* 注意:这个只能解析此类里条形码生成后下面没有字符的条形码(用的是zxing依赖) * * @param content 条形码编码内容(使用CODE_128编码) * @return * @throws WriterException */ public static BufferedImage barCodeEncode(String content) throws WriterException { return barCodeEncode(content, BarcodeFormat.CODE_128); } /** * ZXing 条码边距及总宽度-默认计算规则 * codeWidth:自定义的条码宽度 * fullWidth:条码根据编码内容自动生成编码数组长度(new Code128Writer().encode(contents).length)+边距MARGIN * outputWidth:codeWidth 与 fullWidth 的最大值 * 放大倍数(取整) int multiple = outputWidth / fullWidth; * 边距 int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; * 生成条码长度为: outputWidth + 2 * leftPadding *

* 生成条形码(条形码下边没有字符,但是可以解析) * * @param content 条形码编码内容 * @param barcodeFormat 条形码编码方式(推荐使用CODE_128) * @return * @throws WriterException */ public static BufferedImage barCodeEncode(String content, BarcodeFormat barcodeFormat) throws WriterException { //定义二维码内容参数 Map hints = new HashMap<>(2); //设置条码两边空白边距为0,默认为10,如果宽度不是条码自动生成宽度的倍数则MARGIN无效 hints.put(EncodeHintType.MARGIN, 0); //设置字符集编码格式 hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //为了无边距,需设置宽度为条码自动生成规则的宽度 int width = new Code128Writer().encode(content).length; //前端可控制高度,不影响识别 int height = 70; //条码放大倍数(实测1倍,可以生成条形码,但是无法解析) int codeMultiples = 2; //获取条码内容的宽,不含两边距,当EncodeHintType.MARGIN为0时即为条码宽度 int codeWidth = width * codeMultiples; // 生成条形码,参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数 BitMatrix matrix = new MultiFormatWriter().encode(content, barcodeFormat, codeWidth, height, hints); return MatrixToImageWriter.toBufferedImage(matrix); } }

二维码生成工具类(简单点的,也可以设置颜色)

package com.yb.bar.qr.code.utils;

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 com.google.zxing.oned.Code128Writer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/**
 * 生成彩色带图片的二维码
 *
 * @author yunzhi-yangbiao
 * @date 2020/1/7
 */
public class ColourQrCodeUtils {
    private static final int FRAME_WIDTH = 2;
    private static final int IMAGE_WIDTH = 500;
    private static final int IMAGE_HEIGHT = IMAGE_WIDTH;
    private static final int IMAGE_WIDTH_A = 100;
    private static final int IMAGE_HEIGHT_A = IMAGE_WIDTH_A;
    public static final String DEFAULT_IMAGE_SUFFIX = "jpg";
    private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH_A / 2;
    private static MultiFormatWriter multiWriter = new MultiFormatWriter();

    /**
     * 生成彩色的二维码到指定路径,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     *
     * @param content       二维码显示的文本
     * @param widthHeight   二维码的宽高(宽高一致为正方形)
     * @param destImagePath 二维码存放路径
     */
    public static void qrEncodeImageFile(String content, int widthHeight, String destImagePath) throws Exception {
        qrEncodeImageFile(content, widthHeight, null, destImagePath);
    }

    /**
     * 生成彩色的二维码到指定路径,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     *
     * @param content       二维码显示的文本
     * @param destImagePath 二维码存放路径
     */
    public static void qrEncodeImageFile(String content, String destImagePath) throws Exception {
        qrEncodeImageFile(content, IMAGE_WIDTH, null, destImagePath);
    }


    /**
     * 生成彩色的二维码到指定路径,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     *
     * @param content       二维码显示的文本
     * @param widthHeight   二维码的宽高(宽高一致为正方形)
     * @param destImagePath 二维码存放路径
     * @param srcImagePath  加入二维码的图片路径(路径直取用resources后面部分即可)
     */
    public static void qrEncodeImageFile(String content, int widthHeight, String srcImagePath, String destImagePath) throws Exception {
        //获取图片缓冲区
        BufferedImage bufferedImage = genBarcode(content, widthHeight, widthHeight, srcImagePath, BarcodeFormat.QR_CODE);
        //生成二维码图片文件(srcImagePath为不为空时就时生成的就是把图片加入二维码的二维码)
        ImageIO.write(bufferedImage, DEFAULT_IMAGE_SUFFIX, new File(destImagePath));
    }

    /**
     * 生成彩色的二维码,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     * 生成彩色带图片的二维码的图片缓冲区,可用响应流输出到页面
     *
     * @param content     二维码显示的文本
     * @param widthHeight 二维码的宽高(宽高一致为正方形)
     * @return
     * @throws Exception
     */
    public static BufferedImage qrEncodeBufferedImage(String content, int widthHeight) throws Exception {
        return qrEncodeBufferedImage(content, widthHeight, null);
    }

    /**
     * 生成彩色的二维码,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     * 生成彩色带图片的二维码的图片缓冲区,可用响应流输出到页面
     *
     * @param content 二维码显示的文本
     * @return
     * @throws Exception
     */
    public static BufferedImage qrEncodeBufferedImage(String content) throws Exception {
        return qrEncodeBufferedImage(content, IMAGE_WIDTH, null);
    }

    /**
     * 生成彩色的二维码,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     * 生成彩色带图片的二维码的图片缓冲区,可用响应流输出到页面
     *
     * @param content 二维码显示的文本
     * @return
     * @throws Exception
     */
    public static BufferedImage qrEncodeBufferedImage(String content, String srcImagePath) throws Exception {
        return qrEncodeBufferedImage(content, IMAGE_WIDTH, srcImagePath);
    }

    /**
     * 生成彩色的二维码,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     * 生成彩色带图片的二维码的图片缓冲区,可用响应流输出到页面
     *
     * @param content      二维码显示的文本
     * @param widthHeight  二维码的宽高(宽高一致为正方形)
     * @param srcImagePath 加入二维码的图片路径(路径直取用resources后面部分即可)
     * @return
     * @throws Exception
     */
    public static BufferedImage qrEncodeBufferedImage(String content, int widthHeight, String srcImagePath) throws Exception {
        //获取二维码图片缓冲区
        return genBarcode(content, widthHeight, widthHeight, srcImagePath, BarcodeFormat.QR_CODE);
    }

    /**
     * 生成彩色的二维码,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     * 生成彩色带图片的二维码的输入流,可以直接通过输入流上传到fastdfs文件系统
     *
     * @param content     二维码显示的文本
     * @param widthHeight 二维码的宽高(宽高一致为正方形)
     * @return
     * @throws Exception
     */
    public static InputStream qrEncodeInputStream(String content, int widthHeight) throws Exception {
        //获取生成二维码的输入流
        return qrEncodeInputStream(content, widthHeight, null);
    }

    /**
     * 生成彩色的二维码,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     * 生成彩色带图片的二维码的输入流,可以直接通过输入流上传到fastdfs文件系统
     *
     * @param content 二维码显示的文本
     * @return
     * @throws Exception
     */
    public static InputStream qrEncodeInputStream(String content) throws Exception {
        //获取生成二维码的输入流
        return qrEncodeInputStream(content, IMAGE_WIDTH, null);
    }

    /**
     * 生成彩色的二维码,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     * 生成彩色带图片的二维码的输入流,可以直接通过输入流上传到fastdfs文件系统
     *
     * @param content      二维码显示的文本
     * @param srcImagePath 二维码显示的文本(路径直取用resources后面部分即可)
     * @return
     * @throws Exception
     */
    public static InputStream qrEncodeInputStream(String content, String srcImagePath) throws Exception {
        //获取生成二维码的输入流
        return qrEncodeInputStream(content, IMAGE_WIDTH, srcImagePath);
    }

    /**
     * 生成彩色的二维码,如果有srcImagePath不为空,则是带有图片的彩色二维码,否则就只是彩色二维码
     * 生成彩色带图片的二维码的输入流,可以直接通过输入流上传到fastdfs文件系统
     *
     * @param content      二维码显示的文本
     * @param widthHeight  二维码的宽高(宽高一致为正方形)
     * @param srcImagePath 加入二维码的图片路径(路径直取用resources后面部分即可)
     * @return
     * @throws Exception
     */
    public static InputStream qrEncodeInputStream(String content, int widthHeight, String srcImagePath) throws Exception {
        //获取二维码图片缓冲区
        BufferedImage bufferedImage = genBarcode(content, widthHeight, widthHeight, srcImagePath, BarcodeFormat.QR_CODE);
        //获取生成二维码的输入流
        return getInputStream(bufferedImage);
    }

    /**
     * 获取不带插入图片的二维码缓冲图像
     *
     * @param content       二维码显示的文本
     * @param barcodeFormat 条码格式(CODE_128是条形码/QR_CODE是二维码)
     * @return
     * @throws Exception
     */
    public static BufferedImage getBufferedImage(String content, BarcodeFormat barcodeFormat) throws Exception {
        return getBufferedImage(content, IMAGE_WIDTH, IMAGE_HEIGHT, barcodeFormat);
    }

    /**
     * 获取不带插入图片的二维码缓冲图像(像微信插入圆弧矩形图片)
     *
     * @param content 二维码显示的文本
     * @return
     * @throws Exception
     */
    public static BufferedImage getBufferedImage(String content, String logoPath) throws Exception {
        BufferedImage bufferedImage = getBufferedImage(content, BarcodeFormat.QR_CODE);
        return SimpleQrCodeUtils.logoMatrix(bufferedImage, logoPath);
    }

    /**
     * 获取不带插入图片的二维码缓冲图像
     *
     * @param content 二维码显示的文本
     * @return
     * @throws Exception
     */
    public static BufferedImage getBufferedImage(String content) throws Exception {
        return getBufferedImage(content, BarcodeFormat.QR_CODE);
    }

    /**
     * 获取不带插入图片的二维码缓冲图像(像微信插入圆弧矩形图片)
     *
     * @param content     二维码显示的文本
     * @param widthHeight 二维码的宽高(宽高一致为正方形)
     * @return
     * @throws Exception
     */
    public static BufferedImage getBufferedImage(String content, int widthHeight, String logoPath) throws Exception {
        BufferedImage bufferedImage = getBufferedImage(content, widthHeight, widthHeight, BarcodeFormat.QR_CODE);
        return SimpleQrCodeUtils.logoMatrix(bufferedImage, logoPath);
    }

    /**
     * 获取不带插入图片的二维码缓冲图像
     *
     * @param content     二维码显示的文本
     * @param widthHeight 二维码的宽高(宽高一致为正方形)
     * @return
     * @throws Exception
     */
    public static BufferedImage getBufferedImage(String content, int widthHeight) throws Exception {
        return getBufferedImage(content, widthHeight, widthHeight, BarcodeFormat.QR_CODE);
    }

    /**
     * 获取不带插入图片的二维码缓冲图像(设置私有是因为条形码的时候不需要去加logo图)
     *
     * @param content       二维码显示的文本
     * @param width         二维码的宽度
     * @param height        二维码的高度
     * @param barcodeFormat 条码格式(CODE_128是条形码/QR_CODE是二维码)
     * @return
     * @throws Exception
     */
    private static BufferedImage getBufferedImage(String content, int width, int height, BarcodeFormat barcodeFormat, String logoPath) throws Exception {
        BufferedImage bufferedImage = getBufferedImage(content, width, height, barcodeFormat);
        return SimpleQrCodeUtils.logoMatrix(bufferedImage, logoPath);
    }

    /**
     * 获取不带插入图片的二维码缓冲图像
     *
     * @param content       二维码显示的文本
     * @param width         二维码的宽度
     * @param height        二维码的高度
     * @param barcodeFormat 条码格式(CODE_128是条形码/QR_CODE是二维码)
     * @return
     * @throws Exception
     */
    public static BufferedImage getBufferedImage(String content, int width, int height, BarcodeFormat barcodeFormat) throws Exception {
        //定义二维码内容参数
        Map hints = new HashMap<>(2);
        //设置字符集编码格式
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        //设置容错等级,在这里我们使用M级别
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 生成二维码,参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
        BitMatrix matrix = new MultiFormatWriter().encode(content, barcodeFormat, width, height, hints);
        //判断是否是QR_CODE二维码,不是则当成条形码来看待
        if (!BarcodeFormat.QR_CODE.equals(barcodeFormat)) {
            //这样就能更好的兼容条形码了,二维码就使用QR_CODE就OK了
            return MatrixToImageWriter.toBufferedImage(matrix);
        }
        // 二维矩阵转为一维像素数组
        int[] pixels = new int[width * height];
        //设置二维码颜色
        for (int y = 0; y < matrix.getHeight(); y++) {
            for (int x = 0; x < matrix.getWidth(); x++) {
                //设置颜色
                setColor(matrix, y, x, width, pixels);
            }
        }
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        image.getRaster().setDataElements(0, 0, width, height, pixels);
        return image;
    }

    /**
     * 得到BufferedImage
     *
     * @param content       二维码显示的文本
     * @param width         二维码的宽度
     * @param height        二维码的高度
     * @param barcodeFormat 条码格式(CODE_128是条形码/QR_CODE是二维码)
     * @param srcImagePath  插入二维码的图片路径(路径直取用resources后面部分即可)
     * @return
     * @throws WriterException
     * @throws IOException
     */
    private static BufferedImage genBarcode(String content, int width, int height, String srcImagePath, BarcodeFormat barcodeFormat) throws Exception {
        //判断是否是需要加入图片到二维码,如果srcImagePath为空,则表示是生成不带图片的二维码
        if (!StringUtils.hasText(srcImagePath)) {
            //获取不带插入图片的二维码缓冲图像
            return getBufferedImage(content, width, height, barcodeFormat);
        }
        // 读取源图像
        BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH_A, IMAGE_HEIGHT_A, true);
        int[][] srcPixels = new int[IMAGE_WIDTH_A][IMAGE_HEIGHT_A];
        for (int i = 0; i < scaleImage.getWidth(); i++) {
            for (int j = 0; j < scaleImage.getHeight(); j++) {
                //图片的像素点
                srcPixels[i][j] = scaleImage.getRGB(i, j);
            }
        }
        //编码
        Map hints = new Hashtable();
        //这里选择H也就是大的错误纠正级别,也就是二维码的信息变多,M和H就是明显的对比
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        // 生成二维码
        BitMatrix matrix = multiWriter.encode(content, barcodeFormat, width, height, hints);
        // 二维矩阵转为一维像素数组
        int halfW = matrix.getWidth() / 2;
        int halfH = matrix.getHeight() / 2;
        int[] pixels = new int[width * height];
        //设置二维码颜色
        for (int y = 0; y < matrix.getHeight(); y++) {
            for (int x = 0; x < matrix.getWidth(); x++) {
                //获取判断条件否则报黄线,出现复杂判断
                boolean flagA = x > halfW - IMAGE_HALF_WIDTH
                        && x < halfW + IMAGE_HALF_WIDTH
                        && y > halfH - IMAGE_HALF_WIDTH
                        && y < halfH + IMAGE_HALF_WIDTH;
                boolean flagB = x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
                        && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH
                        && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
                        + IMAGE_HALF_WIDTH + FRAME_WIDTH;
                boolean flagC = x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH
                        && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
                        && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
                        + IMAGE_HALF_WIDTH + FRAME_WIDTH;
                boolean flagD = x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
                        && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
                        && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
                        - IMAGE_HALF_WIDTH + FRAME_WIDTH;
                boolean flagE = x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
                        && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
                        && y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
                        + IMAGE_HALF_WIDTH + FRAME_WIDTH;
                // 左上角颜色,根据自己需要调整颜色范围和颜色(500长宽对应H是155,只有长宽是500才在角上配色)
                if (x > 0 && x < 140 && y > 0 && y < 140 && width == 500 && height == 500) {
                    Color color = new Color(68, 34, 231);
                    int colorInt = color.getRGB();
                    pixels[y * width + x] = matrix.get(x, y) ? colorInt : 16777215;
                    // 读取图片
                } else if (x > 360 && x < 500 && y > 0 && y < 140 && width == 500 && height == 500) {
                    Color color = new Color(231, 211, 94);
                    int colorInt = color.getRGB();
                    pixels[y * width + x] = matrix.get(x, y) ? colorInt : 16777215;
                    // 读取图片
                } else if (x > 0 && x < 140 && y > 360 && y < 500 && width == 500 && height == 500) {
                    Color color = new Color(148, 13, 231);
                    int colorInt = color.getRGB();
                    pixels[y * width + x] = matrix.get(x, y) ? colorInt : 16777215;
                    // 读取图片
                } else if (flagA) {
                    pixels[y * width + x] = srcPixels[x - halfW + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH];
                    // 在图片四周形成边框
                } else if (flagB || flagC || flagD || flagE) {
                    pixels[y * width + x] = 0xfffffff;
                } else {
                    //设置颜色
                    setColor(matrix, y, x, width, pixels);
                }
            }
        }
        //获取图片缓冲区对象
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        image.getRaster().setDataElements(0, 0, width, height, pixels);
        return image;
    }

    /**
     * 设置颜色方法--抽取
     *
     * @param matrix
     * @param y
     * @param x
     * @param width
     * @param pixels
     */
    public static void setColor(BitMatrix matrix, int y, int x, int width, int[] pixels) {
        // 二维码颜色(RGB)
        int num1 = (int) (50 - (50.0 - 13.0) / matrix.getHeight() * (y + 1));
        int num2 = (int) (165 - (165.0 - 72.0) / matrix.getHeight() * (y + 1));
        int num3 = (int) (162 - (162.0 - 107.0) / matrix.getHeight() * (y + 1));
        Color color = new Color(num1, num2, num3);
        //查看到colorInt的值为-13523807(大概是草绿色),0xFF000000(黑色)
        int colorInt = color.getRGB();
        // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色//0x000000:0xffffff//16777215(白色)
        pixels[y * width + x] = matrix.get(x, y) ? colorInt : 16777215;
    }

    /**
     * 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标
     *
     * @param srcImageFile 源文件地址(路径直取用resources后面部分即可)
     * @param height       目标高度
     * @param width        目标宽度
     * @param hasFiller    比例不对时是否需要补白:true为补白; false为不补白;
     * @throws IOException
     */
    private static BufferedImage scale(String srcImageFile, int width, int height, boolean hasFiller) throws IOException {
        // 缩放比例
        double ratio;
        //获取指定目录文件(这个是打成jar后获取的方式,如果是在resources下,直接使用对应路径即可,例如/static/a.png)
        ClassPathResource resource = new ClassPathResource(srcImageFile);
        //读取图片文件到图片缓冲区(只有获取输入流的方式不会有问题,getFile在jar的情况有问题)
        BufferedImage srcImage = ImageIO.read(resource.getInputStream());
        Image destImage = srcImage.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH);
        // 计算比例
        if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) {
            if (srcImage.getHeight() > srcImage.getWidth()) {
                ratio = (new Integer(height)).doubleValue()
                        / srcImage.getHeight();
            } else {
                ratio = (new Integer(width)).doubleValue()
                        / srcImage.getWidth();
            }
            AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null);
            destImage = op.filter(srcImage, null);
        }
        // 补白
        if (hasFiller) {
            BufferedImage image = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D graphic = image.createGraphics();
            graphic.setColor(Color.white);
            graphic.fillRect(0, 0, width, height);
            if (width == destImage.getWidth(null)) {
                //画图片
                graphic.drawImage(destImage, 0, (height - destImage.getHeight(null)) / 2,
                        destImage.getWidth(null), destImage.getHeight(null), Color.white, null);
            } else {
                graphic.drawImage(destImage, (width - destImage.getWidth(null)) / 2, 0,
                        destImage.getWidth(null), destImage.getHeight(null), Color.white, null);
                graphic.dispose();
                destImage = image;
            }
        }
        return (BufferedImage) destImage;
    }

    /**
     * 获取BufferedImage的InputStream流
     * 可以通过此输入流直接上传到fastdfs服务器
     *
     * @param bufferedImage 图片缓冲区对象
     * @return
     */
    public static InputStream getInputStream(BufferedImage bufferedImage) throws Exception {
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        ImageOutputStream imOut = ImageIO.createImageOutputStream(bs);
        ImageIO.write(bufferedImage, DEFAULT_IMAGE_SUFFIX, imOut);
        InputStream is = new ByteArrayInputStream(bs.toByteArray());
        return is;
    }

}

二维码生成工具类(稍微复杂点的,可以设置颜色还有其他的部分颜色)

package com.yb.bar.qr.code.utils;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.springframework.core.io.ClassPathResource;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Objects;

/**
 * 二维码生成工具
 *
 * @author yunzhi-yangbiao
 * @date 2020/1/7
 */
public class SimpleQrCodeUtils {
    /**
     * 编码格式,采用utf-8
     */
    private static final String UNICODE = "utf-8";
    /**
     * 图片格式
     */
    private static final String FORMAT = "JPG";
    /**
     * 二维码宽度,单位:像素pixels
     */
    private static int QR_CODE_WIDTH = 300;
    /**
     * 二维码高度,单位:像素pixels
     */
    private static final int QR_CODE_HEIGHT = QR_CODE_WIDTH;
    /**
     * LOGO宽度,单位:像素pixels
     */
    private static final int LOGO_WIDTH = 70;
    /**
     * LOGO高度,单位:像素pixels
     */
    private static final int LOGO_HEIGHT = LOGO_WIDTH;

    /**
     * 生成二维码图片
     * =====如果logoPath为空,则不进行图片插入(不为空插入图片是矩形不是像微信那种圆弧矩形)
     *
     * @param content      二维码内容
     * @param logoPath     图片地址
     * @param needCompress 是否压缩
     * @return
     * @throws Exception
     */
    private static BufferedImage createImage(String content, String logoPath, boolean needCompress) throws Exception {
        Hashtable hints = new Hashtable<>();
        //这里选择H也就是大的错误纠正级别,也就是二维码的信息变多,M和H就是明显的对比
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, UNICODE);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QR_CODE_WIDTH, QR_CODE_HEIGHT, 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++) {
                //黑白配颜色(0xFF000000(二维码颜色,黑色--问好后第一个参数)||0xFFFFFFFF(白色))
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        //如果logo图片不存在则不去执行下面的插入图片操作
        if (logoPath == null || "".equals(logoPath)) {
            return image;
        }
        // 插入图片
        SimpleQrCodeUtils.insertImage(image, logoPath, needCompress);
        return image;
    }

    /**
     * 为二维码添加logo图片(圆弧矩形)---微信就是这种圆弧型的(允许同包下访问)
     *
     * @param matrixImage 源二维码图片
     * @return 返回带有logo的二维码图片
     * @throws IOException
     * @author Administrator sangwenhao
     */
    protected static BufferedImage logoMatrix(BufferedImage matrixImage, String logoPath) throws IOException {
        //读取二维码图片,并构建绘图对象
        Graphics2D g2 = matrixImage.createGraphics();
        //获取图的宽高信息
        int matrixWidth = matrixImage.getWidth();
        int matrixHeight = matrixImage.getHeight();
        //读取Logo图片
        //获取指定目录文件(这个是打成jar后获取的方式,如果是在resources下,直接使用对应路径即可,例如/static/a.png)
        ClassPathResource resource = new ClassPathResource(logoPath);
        //读取图片文件到图片缓冲区
        BufferedImage logo = ImageIO.read(resource.getInputStream());
        //开始绘制图片
        g2.drawImage(logo, matrixWidth / 5 * 2, matrixHeight / 5 * 2, matrixWidth / 5, matrixHeight / 5, null);
        BasicStroke stroke = new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        // 设置笔画对象
        g2.setStroke(stroke);
        //指定弧度的圆角矩形
        RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth / 5 * 2, matrixHeight / 5 * 2, matrixWidth / 5, matrixHeight / 5, 20, 20);
        g2.setColor(Color.white);
        // 绘制圆弧矩形
        g2.draw(round);
        //设置logo 有一道灰色边框
        BasicStroke stroke2 = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        // 设置笔画对象
        g2.setStroke(stroke2);
        RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth / 5 * 2 + 2, matrixHeight / 5 * 2 + 2, matrixWidth / 5 - 4, matrixHeight / 5 - 4, 20, 20);
        g2.setColor(new Color(128, 128, 128));
        // 绘制圆弧矩形
        g2.draw(round2);
        g2.dispose();
        matrixImage.flush();
        return matrixImage;
    }

    /**
     * 插入LOGO
     *
     * @param source       二维码图片
     * @param logoPath     LOGO图片地址
     * @param needCompress 是否压缩
     * @throws Exception
     */
    private static void insertImage(BufferedImage source, String logoPath, boolean needCompress) throws Exception {
        //获取指定目录文件(这个是打成jar后获取的方式,如果是在resources下,直接使用对应路径即可,例如/static/a.png)
        ClassPathResource resource = new ClassPathResource(logoPath);
        //读取图片文件到图片缓冲区(只有获取输入流的方式不会有问题,getFile在jar的情况有问题)
        Image src = ImageIO.read(resource.getInputStream());
        //不使用new File()的方式,是因为(jar情况下)路径问题
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        // 压缩LOGO
        if (needCompress) {
            if (width > LOGO_WIDTH) {
                width = LOGO_WIDTH;
            }
            if (height > LOGO_HEIGHT) {
                height = LOGO_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 = (QR_CODE_WIDTH - width) / 2;
        int y = (QR_CODE_HEIGHT - 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 logoPath     中间图片地址
     * @param destPath     存储路径
     * @param fileName     文件名称
     * @param needCompress 是否压缩
     * @return
     * @throws Exception
     */
    public static String getQrCode(String content, String logoPath, String destPath, String fileName, boolean needCompress) throws Exception {
        BufferedImage image = SimpleQrCodeUtils.createImage(content, logoPath, needCompress);
        mkdirs(destPath);
        //文件名称通过传递
        fileName = fileName.substring(0, fileName.indexOf(".") > 0 ? fileName.indexOf(".") : fileName.length())
                + "." + FORMAT.toLowerCase();
        ImageIO.write(image, FORMAT, new File(destPath + "/" + fileName));
        return fileName;
    }

    /**
     * 生成二维码(内嵌LOGO)
     * 调用者指定二维码文件名
     *
     * @param content      二维码的内容
     * @param logoPath     中间图片地址
     * @param needCompress 是否压缩
     * @return
     */
    public static BufferedImage getQrCode(String content, String logoPath, boolean needCompress) throws Exception {
        //获取缓冲区图像对象(如果logoPath传空过去,则返回的是没有加入logo的BufferedImage(矩形的logo图))
        BufferedImage bufferedImage = SimpleQrCodeUtils.createImage(content, logoPath, needCompress);
        return bufferedImage;
    }

    /**
     * 生成二维码(内嵌LOGO)
     * 调用者指定二维码文件名
     *
     * @param content      二维码的内容
     * @param logoPath     中间图片地址
     * @param needCompress 是否压缩
     * @return
     */
    public static InputStream getQrCodeInputStream(String content, String logoPath, boolean needCompress) throws Exception {
        //获取缓冲区图像对象(如果logoPath传空过去,则返回的是没有加入logo的BufferedImage(矩形的logo图))
        BufferedImage bufferedImage = SimpleQrCodeUtils.createImage(content, logoPath, needCompress);
        return ColourQrCodeUtils.getInputStream(bufferedImage);
    }

    /**
     * 生成二维码(内嵌LOGO)
     * 调用者指定二维码文件名
     *
     * @param content      二维码的内容
     * @param logoPath     中间图片地址
     * @param needCompress 是否压缩
     * @return
     */
    public static BufferedImage getQrCodeAsWeChat(String content, String logoPath, boolean needCompress) throws Exception {
        //获取缓冲区图像对象(如果logoPath传空过去,则返回的是没有加入logo的BufferedImage(矩形的logo图))
        BufferedImage bufferedImage = SimpleQrCodeUtils.createImage(content, null, needCompress);
        //调用圆弧矩形插入logo的方式插入图片
        return logoMatrix(bufferedImage, logoPath);
    }

    /**
     * 生成二维码(内嵌LOGO)
     * 调用者指定二维码文件名
     *
     * @param content      二维码的内容
     * @param widthHeight  二维码的宽和高(生成正方形的二维码,所以宽高相同)
     * @param logoPath     中间图片地址
     * @param needCompress 是否压缩
     * @return
     */
    public static BufferedImage getQrCodeAsWeChat(String content, int widthHeight, String logoPath, boolean needCompress) throws Exception {
        //调用创建图片之前先修改二维码的默认宽高
        QR_CODE_WIDTH = widthHeight;
        //获取缓冲区图像对象(如果logoPath传空过去,则返回的是没有加入logo的BufferedImage(矩形的logo图))
        BufferedImage bufferedImage = SimpleQrCodeUtils.createImage(content, null, needCompress);
        //调用圆弧矩形插入logo的方式插入图片
        return logoMatrix(bufferedImage, logoPath);
    }

    /**
     * 创建文件夹, mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
     *
     * @param destPath
     */
    private static void mkdirs(String destPath) {
        File file = new File(destPath);
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    /**
     * 解析二维码(实测微信扫描可解码内容,如果是网址,则直接跳转到对应网站)
     *
     * @param path 二维码图片路径
     * @return String 二维码内容
     * @throws Exception
     */
    public static String decodeQrCode(String path) throws Exception {
        File file = new File(path);
        BufferedImage image = ImageIO.read(file);
        if (Objects.isNull(image)) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Hashtable hints = new Hashtable<>();
        hints.put(DecodeHintType.CHARACTER_SET, UNICODE);
        Result result = new MultiFormatReader().decode(bitmap, hints);
        return result.getText();
    }

}

工具类有耦合,建议都加上使用,有些方法还没有测试过,具体实际情况看

你可能感兴趣的:(笔记,条形码,二维码)