赞
踩
参考资料:Hutool参考文档
maven引入依赖包及示例代码
- <dependency>
- <groupId>cn.hutool</groupId>
- <artifactId>hutool-all</artifactId>
- <version>5.7.4</version>
- </dependency>
- package io.renren.demo;
-
- import cn.hutool.core.io.FastByteArrayOutputStream;
- import cn.hutool.extra.qrcode.QrCodeUtil;
- import cn.hutool.extra.qrcode.QrConfig;
-
- import javax.imageio.ImageIO;
- import java.awt.*;
- import java.awt.image.BufferedImage;
- import java.io.IOException;
- import java.util.Base64;
-
- public class Demo14 {
- public static void main(String[] args) {
- // 二维码内容
- String url = "https://www.baidu.com/";
- QrConfig config = new QrConfig(300, 300);//二维码宽/高
- // 设置边距,既二维码和背景之间的边距(即白边大小)
- config.setMargin(2);
- // 设置前景色,既二维码颜色(青色)
- config.setForeColor(Color.CYAN.getRGB());
- // 设置背景色(灰色)
- config.setBackColor(Color.GRAY.getRGB());
- // 生成二维码并指定宽高
- BufferedImage generate = QrCodeUtil.generate(url, config);
- // 转换流信息写出
- FastByteArrayOutputStream os = new FastByteArrayOutputStream();
- try {
- ImageIO.write(generate, "png", os);
- } catch (IOException e) {
- e.getMessage();
- }
- //如果二维码要在前端显示需要转成Base64
- System.out.println("图片二维码:"+ Base64.getEncoder().encodeToString(os.toByteArray()));
- }
- }
maven引入依赖包:
- <!-- 二维码工具-->
- <dependency>
- <groupId>com.google.zxing</groupId>
- <artifactId>core</artifactId>
- <version>3.3.3</version>
- </dependency>
- <dependency>
- <groupId>com.google.zxing</groupId>
- <artifactId>javase</artifactId>
- <version>3.3.3</version>
- </dependency>
推荐直接copy使用,功能比较齐全,因为我也是copy的
包结构:
conf包下的QrCodeConfig.java文件
- import com.google.zxing.EncodeHintType;
- import com.google.zxing.WriterException;
- import com.google.zxing.client.j2se.MatrixToImageConfig;
- import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
- import com.mh.jishi.util.qrcode.QrCodeGenWrapper;
- import lombok.Getter;
- import lombok.Setter;
- import lombok.ToString;
-
- import java.awt.image.BufferedImage;
- import java.io.IOException;
- import java.util.HashMap;
- import java.util.Map;
-
- /**
- * 二维吗配置信息
- */
- @Getter
- @Setter
- @ToString
- public class QrCodeConfig {
- /**
- * 塞入二维码的信息
- */
- private String msg;
-
-
- /**
- * 二维码中间的logo
- */
- private String logo;
-
-
- /**
- * 生成二维码的宽
- */
- private Integer w;
-
-
- /**
- * 生成二维码的高
- */
- private Integer h;
-
-
- /**
- * 生成二维码的颜色
- */
- private MatrixToImageConfig matrixToImageConfig;
-
-
- private Map<EncodeHintType, Object> hints;
-
-
- /**
- * 生成二维码图片的格式 png, jpg
- */
- private String picType;
-
-
- @ToString
- public static class QrCodeConfigBuilder {
- private static final MatrixToImageConfig DEFAULT_CONFIG = new MatrixToImageConfig();
-
- /**
- * The message to put into QrCode
- */
- private String msg;
-
-
- /**
- * qrcode center logo
- */
- private String logo;
-
-
- /**
- * qrcode image width
- */
- private Integer w;
-
-
- /**
- * qrcode image height
- */
- private Integer h;
-
-
- /**
- * qrcode bgcolor, default white
- */
- private Integer offColor;
-
-
- /**
- * qrcode msg color, default black
- */
- private Integer onColor;
-
-
- /**
- * qrcode message's code, default UTF-8
- */
- private String code;
-
-
- /**
- * 0 - 4
- */
- private Integer padding;
-
-
- /**
- * error level, default H
- */
- private ErrorCorrectionLevel errorCorrection;
-
-
- /**
- * output qrcode image type, default png
- */
- private String picType;
-
-
- public String getMsg() {
- return msg;
- }
-
- public QrCodeConfigBuilder setMsg(String msg) {
- this.msg = msg;
- return this;
- }
-
- public String getLogo() {
- return logo;
- }
-
- public QrCodeConfigBuilder setLogo(String logo) {
- this.logo = logo;
- return this;
- }
-
- public Integer getW() {
- return w == null ? (h == null ? 200 : h) : w;
- }
-
- public QrCodeConfigBuilder setW(Integer w) {
- if (w != null && w < 0) {
- throw new IllegalArgumentException("???????????0");
- }
- this.w = w;
- return this;
- }
-
- public Integer getH() {
- if (w != null && w < 0) {
- throw new IllegalArgumentException("???????????0");
- }
- return h == null ? (w == null ? 200 : w) : h;
- }
-
- public QrCodeConfigBuilder setH(Integer h) {
- this.h = h;
- return this;
- }
-
- public Integer getOffColor() {
- return offColor == null ? MatrixToImageConfig.WHITE : offColor;
- }
-
- public QrCodeConfigBuilder setOffColor(Integer offColor) {
- this.offColor = offColor;
- return this;
- }
-
- public Integer getOnColor() {
- return onColor == null ? MatrixToImageConfig.BLACK : onColor;
- }
-
- public QrCodeConfigBuilder setOnColor(Integer onColor) {
- this.onColor = onColor;
- return this;
- }
-
- public String getCode() {
- return code == null ? "UTF-8" : code;
- }
-
- public QrCodeConfigBuilder setCode(String code) {
- this.code = code;
- return this;
- }
-
- public Integer getPadding() {
- if (padding == null) {
- return 1;
- }
-
- if (padding < 0) {
- return 0;
- }
-
- if (padding > 4) {
- return 4;
- }
-
- return padding;
- }
-
- public QrCodeConfigBuilder setPadding(Integer padding) {
- this.padding = padding;
- return this;
- }
-
-
- public String getPicType() {
- return picType == null ? "png" : picType;
- }
-
- public QrCodeConfigBuilder setPicType(String picType) {
- this.picType = picType;
- return this;
- }
-
- public ErrorCorrectionLevel getErrorCorrection() {
- return errorCorrection == null ? ErrorCorrectionLevel.H : errorCorrection;
- }
-
- public QrCodeConfigBuilder setErrorCorrection(ErrorCorrectionLevel errorCorrection) {
- this.errorCorrection = errorCorrection;
- return this;
- }
-
- private void validate() {
- if (msg == null || msg.length() == 0) {
- throw new IllegalArgumentException("????????????!");
- }
- }
-
-
- private QrCodeConfig create() {
- this.validate();
-
- QrCodeConfig qrCodeConfig = new QrCodeConfig();
- qrCodeConfig.setMsg(getMsg());
- qrCodeConfig.setH(getH());
- qrCodeConfig.setW(getW());
- qrCodeConfig.setLogo(getLogo());
- qrCodeConfig.setPicType(getPicType());
-
- Map<EncodeHintType, Object> hints = new HashMap<>(3);
- hints.put(EncodeHintType.ERROR_CORRECTION, this.getErrorCorrection());
- hints.put(EncodeHintType.CHARACTER_SET, this.getCode());
- hints.put(EncodeHintType.MARGIN, this.getPadding());
- qrCodeConfig.setHints(hints);
-
-
- MatrixToImageConfig config;
- if (getOnColor() == MatrixToImageConfig.BLACK
- && getOffColor() == MatrixToImageConfig.WHITE) {
- config = DEFAULT_CONFIG;
- } else {
- config = new MatrixToImageConfig(getOnColor(), getOffColor());
- }
- qrCodeConfig.setMatrixToImageConfig(config);
-
-
- return qrCodeConfig;
- }
-
- /**
- * create qrcodeConfig
- *
- * @return 返回构造的 QrCodeConfig 对象
- */
- public QrCodeConfig build() {
- return create();
- }
-
-
- public BufferedImage asBufferedImage() throws IOException, WriterException {
- return QrCodeGenWrapper.asBufferedImage(create());
- }
-
-
- public boolean asFile(String absFileName) throws IOException, WriterException {
- return QrCodeGenWrapper.asFile(create(), absFileName);
- }
- }
- }
util包:FileUtil.java
- import java.io.File;
- import java.io.FileNotFoundException;
-
- /**
- * 文件工具类
- */
- public class FileUtil {
- /**
- * 递归生成目录, file 为根据相对路径创建时, 会抛npe
- * @param file {@link File}file对象
- */
- public static void mkDir(File file) throws FileNotFoundException {
- if (file.getParentFile() == null) {
- file = file.getAbsoluteFile();
- }
-
- if (file.getParentFile().exists()) {
- if (!file.exists() && !file.mkdir()) {
- throw new FileNotFoundException();
- }
- } else {
- mkDir(file.getParentFile());
- if (!file.exists() && !file.mkdir()) {
- throw new FileNotFoundException();
- }
- }
- }
-
-
- /**
- * 创建文件
- *
- * @param filename 文件名称
- * @return {@link File} file对象
- */
- public static File createFile(String filename) throws FileNotFoundException {
- if (filename == null || "".equals(filename)) {
- return null;
- }
-
- int index = filename.lastIndexOf('/');
- if (index <= 0) {
- return new File(filename);
- }
-
- String path = filename.substring(0, index);
- mkDir(new File(path));
- return new File(filename);
- }
- }
图片工具类:ImageUtil.java
- import java.awt.*;
- import java.awt.geom.RoundRectangle2D;
- import java.awt.image.BufferedImage;
- import java.io.File;
- import java.io.IOException;
- import java.net.URL;
-
- /**
- * Image工具类
- */
- public class ImageUtil {
-
- /**
- * 在图片中间,插入圆角的logo
- *
- * @param qrCode 原图
- * @param logo logo地址
- */
- public static void insertLogo(BufferedImage qrCode, String logo) throws IOException {
- int QRCODE_WIDTH = qrCode.getWidth();
- int QRCODE_HEIGHT = qrCode.getHeight();
-
- // 获取logo图片
- BufferedImage bf = getImageByPath(logo);
- int size = bf.getWidth() > QRCODE_WIDTH * 2 / 10 ? QRCODE_WIDTH * 2 / 50 : bf.getWidth() / 5;
- bf = ImageUtil.makeRoundBorder(bf, 60, size, Color.WHITE); // 边距为二维码图片的1/10
-
- // logo的宽高
- int w = Math.min(bf.getWidth(), QRCODE_WIDTH * 2 / 10);
- int h = Math.min(bf.getHeight(), QRCODE_HEIGHT * 2 / 10);
-
- // 插入LOGO
- Graphics2D graph = qrCode.createGraphics();
-
- int x = (QRCODE_WIDTH - w) / 2;
- int y = (QRCODE_HEIGHT - h) / 2;
-
- graph.drawImage(bf, x, y, w, h, null);
- graph.dispose();
- bf.flush();
- }
-
-
- /**
- * 根据路径图片图片
- *
- * @param path 本地路径 or 网络地址
- * @return 图片
- */
- public static BufferedImage getImageByPath(String path) throws IOException {
- if (path.startsWith("http")) { // 从网络获取logo
- return ImageIO.read(new URL(path));
- } else if (path.startsWith("/")) { // 绝对地址获取logo
- return ImageIO.read(new File(path));
- } else { // 从资源目录下获取logo
- return ImageIO.read(new File(path));
- }
- }
-
-
- /**
- * 生成圆角图片 & 圆角边框
- *
- * @param image 原图
- * @param cornerRadius 圆角的角度
- * @param size 边框的边距
- * @param color 边框的颜色
- * @return 返回带边框的圆角图
- */
- public static BufferedImage makeRoundBorder(BufferedImage image, int cornerRadius, int size, Color color) {
- // 将图片变成圆角
- image = makeRoundedCorner(image, cornerRadius);
-
- int borderSize = size << 1;
- int w = image.getWidth() + borderSize;
- int h = image.getHeight() + borderSize;
- BufferedImage output = new BufferedImage(w, h,
- BufferedImage.TYPE_INT_ARGB);
-
- Graphics2D g2 = output.createGraphics();
- g2.setComposite(AlphaComposite.Src);
- g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON);
- g2.setColor(color == null ? Color.WHITE : color);
- g2.fill(new RoundRectangle2D.Float(0, 0, w, h, cornerRadius,
- cornerRadius));
-
- // ... then compositing the image on top,
- // using the white shape from above as alpha source
- g2.setComposite(AlphaComposite.SrcAtop);
- g2.drawImage(image, size, size, null);
- g2.dispose();
-
- return output;
- }
-
-
- /**
- * 生成圆角图片
- *
- * @param image 原始图片
- * @param cornerRadius 圆角的弧度
- * @return 返回圆角图
- */
- public static BufferedImage makeRoundedCorner(BufferedImage image,
- int cornerRadius) {
- int w = image.getWidth();
- int h = image.getHeight();
- BufferedImage output = new BufferedImage(w, h,
- BufferedImage.TYPE_INT_ARGB);
-
- Graphics2D g2 = output.createGraphics();
-
- // This is what we want, but it only does hard-clipping, i.e. aliasing
- // g2.setClip(new RoundRectangle2D ...)
-
- // so instead fake soft-clipping by first drawing the desired clip shape
- // in fully opaque white with antialiasing enabled...
- g2.setComposite(AlphaComposite.Src);
- g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON);
- g2.setColor(Color.WHITE);
- g2.fill(new RoundRectangle2D.Float(0, 0, w, h, cornerRadius,
- cornerRadius));
-
- // ... then compositing the image on top,
- // using the white shape from above as alpha source
- g2.setComposite(AlphaComposite.SrcAtop);
- g2.drawImage(image, 0, 0, null);
-
- g2.dispose();
-
- return output;
- }
-
- }
-
-
Matrix转Image工具类:MatrixToImageUtil.java
- package com.mh.jishi.util.qrcode.util;
-
- import com.google.zxing.common.BitMatrix;
- import com.mh.jishi.util.qrcode.conf.QrCodeConfig;
-
- import java.awt.*;
- import java.awt.image.BufferedImage;
- import java.io.IOException;
-
- /**
- * Matrix转工具类
- */
- public class MatrixToImageUtil {
-
- /**
- * 根据二维码配置 & 二维码矩阵生成二维码图片
- *
- * @param qrCodeConfig {@link QrCodeConfig}配置
- * @param bitMatrix {@link BitMatrix}
- * @return {@link BufferedImage}
- */
- public static BufferedImage toBufferedImage(QrCodeConfig qrCodeConfig, BitMatrix bitMatrix) throws IOException {
- int qrCodeWidth = bitMatrix.getWidth();
- int qrCodeHeight = bitMatrix.getHeight();
- BufferedImage qrCode = new BufferedImage(qrCodeWidth, qrCodeHeight, BufferedImage.TYPE_INT_RGB);
-
- for (int x = 0; x < qrCodeWidth; x++) {
- for (int y = 0; y < qrCodeHeight; y++) {
- qrCode.setRGB(x, y,
- bitMatrix.get(x, y) ?
- qrCodeConfig.getMatrixToImageConfig().getPixelOnColor() :
- qrCodeConfig.getMatrixToImageConfig().getPixelOffColor());
- }
- }
-
- // 插入logo
- if (!(qrCodeConfig.getLogo() == null || "".equals(qrCodeConfig.getLogo()))) {
- ImageUtil.insertLogo(qrCode, qrCodeConfig.getLogo());
- }
-
- // 若二维码的实际宽高和预期的宽高不一致, 则缩放
- int realQrCodeWidth = qrCodeConfig.getW();
- int realQrCodeHeight = qrCodeConfig.getH();
- if (qrCodeWidth != realQrCodeWidth || qrCodeHeight != realQrCodeHeight) {
- BufferedImage tmp = new BufferedImage(realQrCodeWidth, realQrCodeHeight, BufferedImage.TYPE_INT_RGB);
- tmp.getGraphics().drawImage(
- qrCode.getScaledInstance(realQrCodeWidth, realQrCodeHeight,
- Image.SCALE_SMOOTH), 0, 0, null);
- qrCode = tmp;
- }
-
- return qrCode;
- }
-
- }
-
主类:
QrCodeGenWrapper.java
生成工具类
- import cn.hutool.core.img.ImgUtil;
- import com.google.zxing.BarcodeFormat;
- import com.google.zxing.EncodeHintType;
- import com.google.zxing.WriterException;
- import com.google.zxing.common.BitMatrix;
- import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
- import com.google.zxing.qrcode.encoder.ByteMatrix;
- import com.google.zxing.qrcode.encoder.Encoder;
- import com.google.zxing.qrcode.encoder.QRCode;
- import com.mh.jishi.util.qrcode.conf.QrCodeConfig;
- import com.mh.jishi.util.qrcode.util.FileUtil;
- import com.mh.jishi.util.qrcode.util.MatrixToImageUtil;
- import org.apache.commons.lang3.StringUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- import javax.imageio.ImageIO;
- import java.awt.image.BufferedImage;
- import java.io.File;
- import java.io.IOException;
- import java.util.Map;
-
- /**
- * 对 zxing 的 QRCodeWriter 进行扩展, 解决白边过多的问题,原参考 <a href="https://my.oschina.net/u/566591/blog/872770">...</a>
- */
- public class QrCodeGenWrapper {
- private static final Logger logger = LoggerFactory.getLogger(QrCodeGenWrapper.class);
-
- private static final int QUIET_ZONE_SIZE = 4;
-
-
- /**
- * 构造 二维吗配置信息
- * @return QrCodeConfig
- */
- public static QrCodeConfig.QrCodeConfigBuilder createQrCodeConfig() {
- return new QrCodeConfig.QrCodeConfigBuilder();
- }
-
- /**
- * 生成base64格式二维吗
- * @param content 二维吗内容
- * @param width 宽度 默认 300
- * @param height 高度 默认 300
- * @param imageType 图片类型默认 ong
- * @return 返回base64格式二维码信息
- */
- public static String generateAsBase64(String content, Integer width, Integer height, String imageType) throws IOException, WriterException {
- QrCodeConfig qrConfig = QrCodeGenWrapper.createQrCodeConfig()
- .setMsg(content)
- .setH(width == null ? 300 : width)
- .setW(height == null ? 300 : height)
- .setPadding(1)
- .setErrorCorrection(ErrorCorrectionLevel.L)
- .build();
- BufferedImage img = asBufferedImage(qrConfig);
- return ImgUtil.toBase64DataUri(img, StringUtils.isBlank(imageType) ? "png" : imageType);
- }
-
-
-
- public static BufferedImage asBufferedImage(QrCodeConfig qrCodeConfig) throws WriterException, IOException {
- BitMatrix bitMatrix = encode(qrCodeConfig);
- return MatrixToImageUtil.toBufferedImage(qrCodeConfig, bitMatrix);
- }
-
-
-
- public static boolean asFile(QrCodeConfig qrCodeConfig, String absFileName) throws WriterException, IOException {
- File file = FileUtil.createFile(absFileName);
- if (file == null) {
- throw new IllegalArgumentException("file not exists! absFile: " + absFileName);
- }
-
- BufferedImage bufferedImage = asBufferedImage(qrCodeConfig);
- if (!ImageIO.write(bufferedImage, qrCodeConfig.getPicType(), file)) {
- throw new IOException("save qrcode image error!");
- }
- return true;
- }
-
-
- /**
- * 对 zxing 的 QRCodeWriter 进行扩展, 解决白边过多的问题
- * <p/>
- * 源码参考 {@link com.google.zxing.qrcode.QRCodeWriter#encode(String, BarcodeFormat, int, int, Map)}
- */
- private static BitMatrix encode(QrCodeConfig qrCodeConfig) throws WriterException {
- ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;
- int quietZone = 1;
- if (qrCodeConfig.getHints() != null) {
- if (qrCodeConfig.getHints().containsKey(EncodeHintType.ERROR_CORRECTION)) {
- errorCorrectionLevel = ErrorCorrectionLevel.valueOf(qrCodeConfig.getHints().get(EncodeHintType.ERROR_CORRECTION).toString());
- }
- if (qrCodeConfig.getHints().containsKey(EncodeHintType.MARGIN)) {
- quietZone = Integer.parseInt(qrCodeConfig.getHints().get(EncodeHintType.MARGIN).toString());
- }
-
- if (quietZone > QUIET_ZONE_SIZE) {
- quietZone = QUIET_ZONE_SIZE;
- } else if (quietZone < 0) {
- quietZone = 0;
- }
- }
-
- QRCode code = Encoder.encode(qrCodeConfig.getMsg(), errorCorrectionLevel, qrCodeConfig.getHints());
- return renderResult(code, qrCodeConfig.getW(), qrCodeConfig.getH(), quietZone);
- }
-
-
- /**
- * 对 zxing 的 QRCodeWriter 进行扩展, 解决白边过多的问题
- * <p/>
- * 源码参考
- *
- * @param code {@link QRCode}
- * @param width 高
- * @param height 宽
- * @param quietZone 取值 [0, 4]
- * @return {@link BitMatrix}
- */
- private static BitMatrix renderResult(QRCode code, int width, int height, int quietZone) {
- ByteMatrix input = code.getMatrix();
- if (input == null) {
- throw new IllegalStateException();
- }
-
- // xxx 二维码宽高相等, 即 qrWidth == qrHeight
- int inputWidth = input.getWidth();
- int inputHeight = input.getHeight();
- int qrWidth = inputWidth + (quietZone * 2);
- int qrHeight = inputHeight + (quietZone * 2);
-
-
- // 白边过多时, 缩放
- int minSize = Math.min(width, height);
- int scale = calculateScale(qrWidth, minSize);
- if (scale > 0) {
- if (logger.isDebugEnabled()) {
- logger.debug("qrCode scale enable! scale: {}, qrSize:{}, expectSize:{}x{}", scale, qrWidth, width, height);
- }
-
- int padding, tmpValue;
- // 计算边框留白
- padding = (minSize - qrWidth * scale) / QUIET_ZONE_SIZE * quietZone;
- tmpValue = qrWidth * scale + padding;
- if (width == height) {
- width = tmpValue;
- height = tmpValue;
- } else if (width > height) {
- width = width * tmpValue / height;
- height = tmpValue;
- } else {
- height = height * tmpValue / width;
- width = tmpValue;
- }
- }
-
- int outputWidth = Math.max(width, qrWidth);
- int outputHeight = Math.max(height, qrHeight);
-
- int multiple = Math.min(outputWidth / qrWidth, outputHeight / qrHeight);
- int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
- int topPadding = (outputHeight - (inputHeight * multiple)) / 2;
-
- BitMatrix output = new BitMatrix(outputWidth, outputHeight);
-
- for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
- // Write the contents of this row of the barcode
- for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
- if (input.get(inputX, inputY) == 1) {
- output.setRegion(outputX, outputY, multiple, multiple);
- }
- }
- }
-
- return output;
- }
-
-
- /**
- * 如果留白超过15% , 则需要缩放
- * (15% 可以根据实际需要进行修改)
- *
- * @param qrCodeSize 二维码大小
- * @param expectSize 期望输出大小
- * @return 返回缩放比例, <= 0 则表示不缩放, 否则指定缩放参数
- */
- private static int calculateScale(int qrCodeSize, int expectSize) {
- if (qrCodeSize >= expectSize) {
- return 0;
- }
-
- int scale = expectSize / qrCodeSize;
- int abs = expectSize - scale * qrCodeSize;
- if (abs < expectSize * 0.15) {
- return 0;
- }
-
- return scale;
- }
- }
-
-
测试:
- @Test
- public void qrCodeStrTest() throws IOException, WriterException {
- StringBuilder sb = new StringBuilder();
- for(int i = 0; i < 150; i ++){
- sb.append("12345678910").append("\r\n");
- }
- System.out.printf("二维码输出: %s%n \r 二维码内容字符数量: %s%n", QrCodeGenWrapper.generateAsBase64(sb.toString(), null, null, null), sb.length());
- System.out.printf("二维码输出: %s%n \r 二维码内容字符数量: %s%n", QrCodeGenWrapper.generateAsBase64("www.baidu.com", null, null, null), sb.length());
- }
附加条形码工具
BarCodeUtils .java
条形码工具类
- import com.google.zxing.BarcodeFormat;
- import com.google.zxing.EncodeHintType;
- import com.google.zxing.Writer;
- 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.pdf417.PDF417Writer;
- import com.mh.jishi.constants.RedisKeyPrefix;
- import org.apache.commons.lang3.StringUtils;
-
- import javax.imageio.ImageIO;
- import java.awt.*;
- import java.awt.image.BufferedImage;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.util.Base64;
- import java.util.HashMap;
- import java.util.Map;
-
- /**
- * <h2>条形码工具类</h2>
- * <p>
- * <a href="https://blog.51cto.com/u_15127597/4390771"> 原参考 </a>
- * </p>
- *
- * @author Evan <1922802352@qq.com>
- * @since 2022年06月09日 16:09
- */
- public class BarCodeUtils {
- /**
- * 默认图片宽度
- */
- private static final int DEFAULT_PICTURE_WIDTH = 270;
-
- /**
- * 默认图片高度
- */
- private static final int DEFAULT_PICTURE_HEIGHT = 130;
-
- /**
- * 默认条形码宽度
- */
- private static final int DEFAULT_BAR_CODE_WIDTH = 310;
-
- /**
- * 默认条形码高度
- */
- private static final int DEFAULT_BAR_CODE_HEIGHT = 80;
-
- /**
- * 默认字体大小
- */
- private static final int DEFAULT_FONT_SIZE = 15;
-
- /**
- * 设置 条形码参数
- */
- private static final Map<EncodeHintType, Object> hints = new HashMap<>();
-
-
- static {
- hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
- }
-
- /**
- * 获取条形码图片
- *
- * @param codeValue 条形码内容
- * @return 条形码图片
- */
- public static BufferedImage getBarCodeImage(String codeValue) {
- return getBarCodeImage(codeValue, DEFAULT_BAR_CODE_WIDTH, DEFAULT_BAR_CODE_HEIGHT);
- }
-
- /**
- * 获取条形码图片
- *
- * @param codeValue 条形码内容
- * @param width 宽度
- * @param height 高度
- * @return 条形码图片
- */
- public static BufferedImage getBarCodeImage(String codeValue, int width, int height) {
- // CODE_128是最常用的条形码格式
- return getBarCodeImage(codeValue, width, height, BarcodeFormat.CODE_128);
- }
-
- /**
- * 获取条形码图片
- *
- * @param codeValue 条形码内容
- * @param width 宽度
- * @param height 高度
- * @param barcodeFormat 条形码编码格式
- * @return 条形码图片
- */
- public static BufferedImage getBarCodeImage(String codeValue, int width, int height, BarcodeFormat barcodeFormat) {
- Writer writer;
- switch (barcodeFormat) {
- case PDF_417:
- // 支持中文的条形码格式
- writer = new PDF417Writer();
- break;
- case CODE_128:
-
- // 最常见的条形码,但是不支持中文
- // 如果使用到其他格式,可以在这里添加
- default:
- writer = new Code128Writer();
- }
-
- // 编码内容, 编码类型, 宽度, 高度, 设置参数
- BitMatrix bitMatrix;
- try {
- bitMatrix = writer.encode(codeValue, barcodeFormat, width, height, hints);
- } catch (WriterException e) {
- throw new RuntimeException("条形码内容写入失败");
- }
- return MatrixToImageWriter.toBufferedImage(bitMatrix);
- }
-
- /**
- * 获取条形码
- *
- * @param codeValue 条形码内容
- * @param bottomStr 底部文字
- * @return
- */
- public static BufferedImage getBarCodeWithWords(String codeValue, String bottomStr) {
- return getBarCodeWithWords(codeValue, bottomStr, "", "");
- }
-
- /**
- * 获取条形码
- *
- * @param codeValue 条形码内容
- * @param bottomStr 底部文字
- * @param topLeftStr 左上角文字
- * @param topRightStr 右上角文字
- * @return
- */
- public static BufferedImage getBarCodeWithWords(String codeValue, String bottomStr, String topLeftStr,
- String topRightStr) {
- return getCodeWithWords(getBarCodeImage(codeValue), bottomStr, null, topLeftStr, topRightStr,
- DEFAULT_PICTURE_WIDTH, DEFAULT_PICTURE_HEIGHT, 0, 0, 0, 0, 0, 0, DEFAULT_FONT_SIZE);
- }
-
- /**
- * 获取条形码,返回字符串base64图片
- *
- * @param codeValue 条形码内容
- * @param topStr 顶部文字
- * @param bottomStr 底部文字
- * @param topLeftStr 左上角文字
- * @param topRightStr 右上角文字
- * @return base64格式条形码图片
- */
- public static String getBarCodeWithWordsAsBase64(String codeValue, String topStr, String bottomStr,
- String topLeftStr, String topRightStr) throws IOException {
- String result;
- BufferedImage image = getCodeWithWords(getBarCodeImage(codeValue), bottomStr, topStr, topLeftStr, topRightStr,
- DEFAULT_PICTURE_WIDTH, DEFAULT_PICTURE_HEIGHT, 0, 0, 0, 0, 0, 0, DEFAULT_FONT_SIZE);
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- ImageIO.write(image, "jpeg", outputStream);
- String base64 = Base64.getEncoder().encodeToString(outputStream.toByteArray());
- result = "data:image/jpeg;base64," + base64.replaceAll("\r\n", "");
- return result;
- }
-
- /**
- * 获取条形码,返回字符串base64图片, 可以缓存
- *
- * @param codeValue 条形码内容
- * @param bottomStr 底部文字
- * @param topLeftStr 左上角文字
- * @param topRightStr 右上角文字
- * @param cache 是否使用缓存
- */
- public static String getBarCodeWithWordsAsBase64ByCache(String codeValue, String topStr, String bottomStr,
- String topLeftStr, String topRightStr, boolean cache)
- throws IOException {
-
- String result = getBarCodeWithWordsAsBase64(codeValue, topStr, bottomStr, topLeftStr, topRightStr)
- return result;
- }
-
- /**
- * 获取条形码
- *
- * @param codeImage 条形码图片
- * @param bottomStr 底部文字
- * @param topStr 顶部文字
- * @param topLeftStr 左上角文字
- * @param topRightStr 右上角文字
- * @param pictureWidth 图片宽度
- * @param pictureHeight 图片高度
- * @param codeOffsetX 条形码宽度
- * @param codeOffsetY 条形码高度
- * @param topLeftOffsetX 左上角文字X轴偏移量
- * @param topLeftOffsetY 左上角文字Y轴偏移量
- * @param topRightOffsetX 右上角文字X轴偏移量
- * @param topRightOffsetY 右上角文字Y轴偏移量
- * @param fontSize 字体大小
- * @return 条形码图片
- */
- public static BufferedImage getCodeWithWords(BufferedImage codeImage, String bottomStr, String topStr,
- String topLeftStr, String topRightStr, int pictureWidth,
- int pictureHeight, int codeOffsetX,
- int codeOffsetY, int topLeftOffsetX, int topLeftOffsetY,
- int topRightOffsetX, int topRightOffsetY,
- int fontSize) {
- BufferedImage picImage = new BufferedImage(pictureWidth, pictureHeight, BufferedImage.TYPE_INT_RGB);
-
- Graphics2D g2d = picImage.createGraphics();
- // 抗锯齿
- setGraphics2D(g2d);
- // 设置白色
- setColorWhite(g2d, picImage.getWidth(), picImage.getHeight());
-
- // 条形码默认居中显示
- int codeStartX = (pictureWidth - codeImage.getWidth()) / 2 + codeOffsetX;
- int codeStartY = (pictureHeight - codeImage.getHeight()) / 2 + codeOffsetY;
- // 画条形码到新的面板
- g2d.drawImage(codeImage, codeStartX, codeStartY, codeImage.getWidth(), codeImage.getHeight(), null);
-
- // 画文字到新的面板
- g2d.setColor(Color.BLACK);
- // 字体、字型、字号
- g2d.setFont(new Font("微软雅黑", Font.PLAIN, fontSize));
- // 文字与条形码之间的间隔
- int wordAndCodeSpacing = 3;
-
- if (StringUtils.isNotEmpty(bottomStr)) {
- // 文字长度
- int strWidth = g2d.getFontMetrics().stringWidth(bottomStr);
- // 文字X轴开始坐标,这里是居中
- int strStartX = codeStartX + (codeImage.getWidth() - strWidth) / 2;
- // 文字Y轴开始坐标
- int strStartY = codeStartY + codeImage.getHeight() + fontSize + wordAndCodeSpacing;
- // 画文字
- g2d.drawString(bottomStr, strStartX, strStartY);
- }
-
- if (StringUtils.isNotEmpty(topStr)) {
- // 文字长度
- int strWidth = g2d.getFontMetrics().stringWidth(topStr);
- // 文字X轴开始坐标,这里是居中
- int strStartX = codeStartX + (codeImage.getWidth() - strWidth) / 2;
- // 文字Y轴开始坐标
- int strStartY = codeStartY + topLeftOffsetY - wordAndCodeSpacing;
- // 画文字
- g2d.drawString(topStr, strStartX, strStartY);
- }
-
- if (StringUtils.isNotEmpty(topLeftStr)) {
- // 文字长度
- int strWidth = g2d.getFontMetrics().stringWidth(topLeftStr);
- // 文字X轴开始坐标
- int strStartX = codeStartX + topLeftOffsetX;
- // 文字Y轴开始坐标
- int strStartY = codeStartY + topLeftOffsetY - wordAndCodeSpacing;
- // 画文字
- g2d.drawString(topLeftStr, strStartX, strStartY);
- }
-
- if (StringUtils.isNotEmpty(topRightStr)) {
- // 文字长度
- int strWidth = g2d.getFontMetrics().stringWidth(topRightStr);
- // 文字X轴开始坐标,这里是居中
- int strStartX = codeStartX + codeImage.getWidth() - strWidth + topRightOffsetX;
- // 文字Y轴开始坐标
- int strStartY = codeStartY + topRightOffsetY - wordAndCodeSpacing;
- // 画文字
- g2d.drawString(topRightStr, strStartX, strStartY);
- }
-
- g2d.dispose();
- picImage.flush();
-
- return picImage;
- }
-
- /**
- * 设置 Graphics2D 属性 (抗锯齿)
- *
- * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
- */
- private static void setGraphics2D(Graphics2D g2d) {
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
- Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
- g2d.setStroke(s);
- }
-
- /**
- * 设置背景为白色
- *
- * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
- */
- private static void setColorWhite(Graphics2D g2d, int width, int height) {
- g2d.setColor(Color.WHITE);
- // 填充整个屏幕
- g2d.fillRect(0, 0, width, height);
- // 设置笔刷
- g2d.setColor(Color.BLACK);
- }
- }
-
测试:
- @Test
- public void test1() throws IOException {
- String base64Image = BarCodeUtils.getBarCodeWithWordsAsBase64("1231213", "我是卧的那个龙", "CF 墨心", null, null);
- System.out.println(base64Image);
- }
1、使用上面的缩放办法:参考资料:zxing 二维码大白边一步一步修复指南 - 小灰灰Blog的个人空间 - OSCHINA - 中文开源技术交流社区
2、想办法将二维码的背景色设置成透明色(什么,你对背景色有要求,请采用第一个办法)
- package io.renren.utils;
-
- import javax.imageio.ImageIO;
- import javax.swing.*;
- import java.awt.*;
- import java.awt.image.BufferedImage;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
-
- public class ImagebackColorUtil {
- /**
- * 将背景替换为透明
- *
- * @param imgBytes the img bytes
- * @return
- * @throws IOException the io exception
- * @author Jack Que
- * @created 2021 -07-08 10:25:10 Change img color.
- */
- public static byte[] changeImgColor(byte[] imgBytes) throws IOException {
-
- BufferedImage bi = ImageIO.read(new ByteArrayInputStream(imgBytes));
- Image image = (Image) bi;
- //将原图片的二进制转化为ImageIcon
- ImageIcon imageIcon = new ImageIcon(image);
- int width = imageIcon.getIconWidth();
- int height = imageIcon.getIconHeight();
- //
- //图片缓冲流
- BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
- Graphics2D graphics2D = (Graphics2D) bufferedImage.getGraphics();
- graphics2D.drawImage(imageIcon.getImage(), 0, 0, imageIcon.getImageObserver());
-
- int alpha = 255;
-
- //这个背景底色的选择,我这里选择的是比较偏的位置,可以修改位置。背景色选择不知道有没有别的更优的方式(比如先过滤一遍获取颜色次数最多的,但是因为感觉做起来会比较复杂没去实现),如果有可以评论。
- int RGB=bufferedImage.getRGB(width-1, height-1);
-
- for(int i = bufferedImage.getMinX(); i < width; i++) {
- for(int j = bufferedImage.getMinY(); j < height; j++) {
-
- int rgb = bufferedImage.getRGB(i, j);
-
- int r = (rgb & 0xff0000) >>16;
- int g = (rgb & 0xff00) >> 8;
- int b = (rgb & 0xff);
- int R = (RGB & 0xff0000) >>16;
- int G = (RGB & 0xff00) >> 8;
- int B = (RGB & 0xff);
- //a为色差范围值,渐变色边缘处理,数值需要具体测试,50左右的效果比较可以
- int a = 45;
- if(Math.abs(R-r) < a && Math.abs(G-g) < a && Math.abs(B-b) < a ) {
- alpha = 0;
- } else {
- alpha = 255;
- }
- rgb = (alpha << 24)|(rgb & 0x00ffffff);
- bufferedImage.setRGB(i,j,rgb);
- }
- }
-
- // graphics2D.drawImage(bufferedImage, 0, 0, imageIcon.getImageObserver());
-
- //新建字节输出流,用来存放替换完背景的图片
- ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
- ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
- return byteArrayOutputStream.toByteArray();
- // String[] split = fileName.split("\\.");
- // fileName = split[0]+"(已转换)."+split[1];
- // ImageIO.write(bufferedImage, "png", new File("D:\\"+fileName));
- }
-
- public static String convertRgbStr(int color) {
- int red = (color & 0xff0000) >> 16;// 获取color(RGB)中R位
- int green = (color & 0x00ff00) >> 8;// 获取color(RGB)中G位
- int blue = (color & 0x0000ff);// 获取color(RGB)中B位
- return red + "," + green + "," + blue;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。