diff --git a/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java index 36e048d2b..c5a0f5780 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java @@ -4,6 +4,7 @@ import cn.hutool.core.codec.Base64; import cn.hutool.core.img.Img; import cn.hutool.core.img.ImgUtil; import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; import com.google.zxing.BarcodeFormat; import com.google.zxing.Binarizer; import com.google.zxing.BinaryBitmap; @@ -18,8 +19,7 @@ import com.google.zxing.common.BitMatrix; import com.google.zxing.common.GlobalHistogramBinarizer; import com.google.zxing.common.HybridBinarizer; -import java.awt.Image; -import java.awt.Rectangle; +import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; @@ -97,6 +97,17 @@ public class QrCodeUtil { return ImgUtil.toBase64DataUri(img, imageType); } + /** + * @param content 内容 + * @param qrConfig 二维码配置,包括长、宽、边距、颜色等 + * @return SVG矢量图(字符串) + * @since 5.8.6 + */ + public static String generateAsSvg(String content, QrConfig qrConfig) { + BitMatrix bitMatrix = encode(content, qrConfig); + return toSVG(bitMatrix, qrConfig); + } + /** * 生成PNG格式的二维码图片,以byte[]形式表示 * @@ -420,6 +431,70 @@ public class QrCodeUtil { return image; } + /** + * @param matrix BitMatrix + * @param qrConfig 二维码配置,包括长、宽、边距、颜色等 + * @return SVG矢量图(字符串) + * @since 5.8.6 + */ + public static String toSVG(BitMatrix matrix,QrConfig qrConfig) { + return toSVG(matrix, qrConfig.getForeColor(), qrConfig.getBackColor(),qrConfig.img,qrConfig.getRatio()); + } + + /** + * BitMatrix转SVG(字符串) + * + * @param matrix BitMatrix + * @param foreColor 前景色 + * @param backColor 背景色(null表示透明背景) + * @param ratio 二维码中的Logo缩放的比例系数,如5表示长宽最小值的1/5 + * @return SVG矢量图(字符串) + * @since 5.8.6 + */ + public static String toSVG(BitMatrix matrix,int foreColor, Integer backColor,Image logoImg,int ratio) { + StringBuilder sb = new StringBuilder(); + int qrWidth = matrix.getWidth(); + int qrHeight = matrix.getHeight(); + int moduleHeight = (qrHeight == 1) ? qrWidth / 2 : 1; + for (int y = 0; y < qrHeight; y++) { + for (int x = 0; x < qrWidth; x++) { + if (matrix.get(x, y)) { + sb.append(" M" + x + "," + y + "h1v" + moduleHeight + "h-1z"); + } + } + } + qrHeight *= moduleHeight; + String logoBase64 = ""; + int logoWidth = 0; + int logoHeight = 0; + int logoX = 0; + int logoY = 0; + if (logoImg != null) { + logoBase64 = ImgUtil.toBase64DataUri(logoImg, "png"); + // 按照最短的边做比例缩放 + if (qrWidth < qrHeight) { + logoWidth = qrWidth / ratio; + logoHeight = logoImg.getHeight(null) * logoWidth / logoImg.getWidth(null); + } else { + logoHeight = qrHeight / ratio; + logoWidth = logoImg.getWidth(null) * logoHeight / logoImg.getHeight(null); + } + logoX = (qrWidth - logoWidth) / 2; + logoY = (qrHeight - logoHeight) / 2; + + } + Color fore = new Color(foreColor, true); + Color back = new Color(backColor, true); + return "\n" + + " \n" + + (StrUtil.isBlank(logoBase64) ? "" : "\n") + + ""; + } + /** * 创建解码选项 * diff --git a/hutool-extra/src/test/java/cn/hutool/extra/qrcode/QrCodeUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/qrcode/QrCodeUtilTest.java index 735f15db3..04ab35dcf 100755 --- a/hutool-extra/src/test/java/cn/hutool/extra/qrcode/QrCodeUtilTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/qrcode/QrCodeUtilTest.java @@ -5,6 +5,7 @@ import cn.hutool.core.img.ImgUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Console; import com.google.zxing.BarcodeFormat; +import com.google.zxing.common.BitMatrix; import com.google.zxing.datamatrix.encoder.SymbolShapeHint; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import org.junit.Assert; @@ -14,6 +15,7 @@ import org.junit.Test; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; +import java.nio.charset.StandardCharsets; /** * 二维码工具类单元测试 @@ -108,5 +110,12 @@ public class QrCodeUtilTest { Assert.assertNotNull(imageSquare); } + @Test + public void generateSvgTest() { + QrConfig qrConfig = QrConfig.create().setImg("d:/test/logo.png").setForeColor(Color.GREEN).setBackColor(Color.pink); + String svg = QrCodeUtil.generateAsSvg("https://hutool.cn/", qrConfig); + Assert.assertNotNull(svg); + FileUtil.writeString(svg, "d:/test/qr.svg", StandardCharsets.UTF_8); + } }