add svg support

This commit is contained in:
Looly
2024-05-24 17:22:17 +08:00
parent abb87d530b
commit e2bb215387

View File

@@ -12,13 +12,18 @@
package org.dromara.hutool.extra.qrcode; package org.dromara.hutool.extra.qrcode;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.swing.img.ImgUtil;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType; import com.google.zxing.DecodeHintType;
import com.google.zxing.common.BitMatrix; import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.GlobalHistogramBinarizer; import com.google.zxing.common.GlobalHistogramBinarizer;
import com.google.zxing.common.HybridBinarizer; import com.google.zxing.common.HybridBinarizer;
import org.dromara.hutool.core.codec.binary.Base64;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.io.file.FileNameUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.net.url.UrlUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.swing.img.ImgUtil;
import java.awt.Image; import java.awt.Image;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@@ -58,16 +63,23 @@ public class QrCodeUtil {
* *
* @param content 内容 * @param content 内容
* @param qrConfig 二维码配置,包括宽度、高度、边距、颜色等 * @param qrConfig 二维码配置,包括宽度、高度、边距、颜色等
* @param imageType 图片类型(图片扩展名),见{@link ImgUtil} * @param imageType 类型(图片扩展名),见{@link #QR_TYPE_SVG}、 {@link #QR_TYPE_TXT}、{@link ImgUtil}
* @return 图片 Base64 编码字符串 * @return 图片 Base64 编码字符串
*/ */
public static String generateAsBase64DataUri(final String content, final QrConfig qrConfig, final String imageType) { public static String generateAsBase64DataUri(final String content, final QrConfig qrConfig, final String imageType) {
BufferedImage img = null; switch (imageType) {
try{ case QR_TYPE_SVG:
img = generate(content, qrConfig); return svgToBase64DataUri(generateAsSvg(content, qrConfig));
return ImgUtil.toBase64DataUri(img, imageType); case QR_TYPE_TXT:
} finally { return txtToBase64DataUri(generateAsAsciiArt(content, qrConfig));
ImgUtil.flush(img); default:
BufferedImage img = null;
try {
img = generate(content, qrConfig);
return ImgUtil.toBase64DataUri(img, imageType);
} finally {
ImgUtil.flush(img);
}
} }
} }
@@ -104,20 +116,13 @@ public class QrCodeUtil {
* 生成二维码到文件,二维码图片格式取决于文件的扩展名 * 生成二维码到文件,二维码图片格式取决于文件的扩展名
* *
* @param content 文本内容 * @param content 文本内容
* @param width 宽度 * @param width 宽度单位类型为一般图片或SVG时单位是像素类型为 Ascii Art 字符画时,单位是字符▄或▀的大小)
* @param height 高度 * @param height 高度单位类型为一般图片或SVG时单位是像素类型为 Ascii Art 字符画时,单位是字符▄或▀的大小)
* @param targetFile 目标文件,扩展名决定输出格式 * @param targetFile 目标文件,扩展名决定输出格式
* @return 目标文件 * @return 目标文件
*/ */
public static File generate(final String content, final int width, final int height, final File targetFile) { public static File generate(final String content, final int width, final int height, final File targetFile) {
BufferedImage image = null; return generate(content, QrConfig.of(width, height), targetFile);
try{
image = generate(content, width, height);
ImgUtil.write(image, targetFile);
} finally {
ImgUtil.flush(image);
}
return targetFile;
} }
/** /**
@@ -130,13 +135,24 @@ public class QrCodeUtil {
* @since 4.1.2 * @since 4.1.2
*/ */
public static File generate(final String content, final QrConfig config, final File targetFile) { public static File generate(final String content, final QrConfig config, final File targetFile) {
BufferedImage image = null; final String extName = FileNameUtil.extName(targetFile);
try{ switch (extName) {
image = generate(content, config); case QR_TYPE_SVG:
ImgUtil.write(image, targetFile); FileUtil.writeUtf8String(generateAsSvg(content, config), targetFile);
} finally { break;
ImgUtil.flush(image); case QR_TYPE_TXT:
FileUtil.writeUtf8String(generateAsAsciiArt(content, config), targetFile);
break;
default:
BufferedImage image = null;
try {
image = generate(content, config);
ImgUtil.write(image, targetFile);
} finally {
ImgUtil.flush(image);
}
} }
return targetFile; return targetFile;
} }
@@ -144,19 +160,13 @@ public class QrCodeUtil {
* 生成二维码到输出流 * 生成二维码到输出流
* *
* @param content 文本内容 * @param content 文本内容
* @param width 宽度 * @param width 宽度单位类型为一般图片或SVG时单位是像素类型为 Ascii Art 字符画时,单位是字符▄或▀的大小)
* @param height 高度 * @param height 高度单位类型为一般图片或SVG时单位是像素类型为 Ascii Art 字符画时,单位是字符▄或▀的大小)
* @param imageType 图片类型(图片扩展名),见{@link ImgUtil} * @param imageType 类型(图片扩展名),见{@link #QR_TYPE_SVG}、 {@link #QR_TYPE_TXT}、{@link ImgUtil}
* @param out 目标流 * @param out 目标流
*/ */
public static void generate(final String content, final int width, final int height, final String imageType, final OutputStream out) { public static void generate(final String content, final int width, final int height, final String imageType, final OutputStream out) {
BufferedImage img = null; generate(content, QrConfig.of(width, height), imageType, out);
try{
img = generate(content, width, height);
ImgUtil.write(img, imageType, out);
} finally {
ImgUtil.flush(img);
}
} }
/** /**
@@ -169,12 +179,21 @@ public class QrCodeUtil {
* @since 4.1.2 * @since 4.1.2
*/ */
public static void generate(final String content, final QrConfig config, final String imageType, final OutputStream out) { public static void generate(final String content, final QrConfig config, final String imageType, final OutputStream out) {
BufferedImage image = null; switch (imageType) {
try{ case QR_TYPE_SVG:
image = generate(content, config); IoUtil.writeUtf8(out, false, generateAsSvg(content, config));
ImgUtil.write(image, imageType, out); break;
} finally { case QR_TYPE_TXT:
ImgUtil.flush(image); IoUtil.writeUtf8(out, false, generateAsAsciiArt(content, config));
break;
default:
BufferedImage img = null;
try {
img = generate(content, config);
ImgUtil.write(img, imageType, out);
} finally {
ImgUtil.flush(img);
}
} }
} }
@@ -227,7 +246,7 @@ public class QrCodeUtil {
*/ */
public static String decode(final InputStream qrCodeInputstream) { public static String decode(final InputStream qrCodeInputstream) {
BufferedImage image = null; BufferedImage image = null;
try{ try {
image = ImgUtil.read(qrCodeInputstream); image = ImgUtil.read(qrCodeInputstream);
return decode(image); return decode(image);
} finally { } finally {
@@ -243,7 +262,7 @@ public class QrCodeUtil {
*/ */
public static String decode(final File qrCodeFile) { public static String decode(final File qrCodeFile) {
BufferedImage image = null; BufferedImage image = null;
try{ try {
image = ImgUtil.read(qrCodeFile); image = ImgUtil.read(qrCodeFile);
return decode(image); return decode(image);
} finally { } finally {
@@ -359,4 +378,29 @@ public class QrCodeUtil {
public static String toAsciiArt(final BitMatrix bitMatrix, final QrConfig qrConfig) { public static String toAsciiArt(final BitMatrix bitMatrix, final QrConfig qrConfig) {
return new QrAsciiArt(bitMatrix, qrConfig).toString(); return new QrAsciiArt(bitMatrix, qrConfig).toString();
} }
// region ----- Private Methods
/**
* 将文本转换为Base64编码的Data URI。
*
* @param txt 需要转换为Base64编码Data URI的文本。
* @return 转换后的Base64编码Data URI字符串。
*/
private static String txtToBase64DataUri(final String txt) {
return UrlUtil.getDataUriBase64("text/plain", Base64.encode(txt));
}
/**
* 将SVG字符串转换为Base64数据URI格式。
* <p>此方法通过将SVG内容编码为Base64并将其封装在数据URI中以便于在HTML或CSS中直接嵌入SVG图像。</p>
*
* @param svg SVG图像的内容为字符串形式。
* @return 转换后的Base64数据URI字符串可用于直接在HTML或CSS中显示SVG图像。
*/
private static String svgToBase64DataUri(final String svg) {
return UrlUtil.getDataUriBase64("image/svg+xml", Base64.encode(svg));
}
// endregion
} }