QrCodeUtil新增SVG格式、Ascii Art字符画格式

This commit is contained in:
Looly 2022-08-26 16:56:02 +08:00
parent 0d96bec4cb
commit 2b9da605a7
3 changed files with 54 additions and 48 deletions

View File

@ -15,6 +15,7 @@
* 【core 】 增加替换字符串中第一个指定字符串和最后一个指定字符串方法pr#2533@Github * 【core 】 增加替换字符串中第一个指定字符串和最后一个指定字符串方法pr#2533@Github
* 【jwt 】 JWT补充部分算法pr#2546@Github * 【jwt 】 JWT补充部分算法pr#2546@Github
* 【core 】 NumberUtil.roundStr() 修改为使用toPlainStringpr#775@Gitee * 【core 】 NumberUtil.roundStr() 修改为使用toPlainStringpr#775@Gitee
* 【extra 】 QrCodeUtil新增SVG格式、Ascii Art字符画格式pr#763@Gitee
* *
### 🐞Bug修复 ### 🐞Bug修复
* 【http 】 修复https下可能的Patch、Get请求失效问题issue#I3Z3DH@Gitee * 【http 】 修复https下可能的Patch、Get请求失效问题issue#I3Z3DH@Gitee

View File

@ -130,7 +130,7 @@ public class QrCodeUtil {
* @since 5.8.6 * @since 5.8.6
*/ */
public static String generateAsSvg(String content, QrConfig qrConfig) { public static String generateAsSvg(String content, QrConfig qrConfig) {
BitMatrix bitMatrix = encode(content, qrConfig); final BitMatrix bitMatrix = encode(content, qrConfig);
return toSVG(bitMatrix, qrConfig); return toSVG(bitMatrix, qrConfig);
} }
@ -154,7 +154,7 @@ public class QrCodeUtil {
* @since 5.8.6 * @since 5.8.6
*/ */
public static String generateAsAsciiArt(String content, QrConfig qrConfig) { public static String generateAsAsciiArt(String content, QrConfig qrConfig) {
BitMatrix bitMatrix = encode(content, qrConfig); final BitMatrix bitMatrix = encode(content, qrConfig);
return toAsciiArt(bitMatrix, qrConfig); return toAsciiArt(bitMatrix, qrConfig);
} }
@ -627,12 +627,12 @@ public class QrCodeUtil {
* @since 5.8.6 * @since 5.8.6
*/ */
public static String toAsciiArt(BitMatrix bitMatrix, QrConfig qrConfig) { public static String toAsciiArt(BitMatrix bitMatrix, QrConfig qrConfig) {
int width = bitMatrix.getWidth(); final int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight(); final int height = bitMatrix.getHeight();
AnsiElement foreground = qrConfig.foreColor == null ? null : Ansi8BitColor.foreground(rgbToAnsi8BitValue(qrConfig.foreColor)); final AnsiElement foreground = qrConfig.foreColor == null ? null : Ansi8BitColor.foreground(rgbToAnsi8BitValue(qrConfig.foreColor));
AnsiElement background = qrConfig.backColor == null ? null : Ansi8BitColor.background(rgbToAnsi8BitValue(qrConfig.backColor)); final AnsiElement background = qrConfig.backColor == null ? null : Ansi8BitColor.background(rgbToAnsi8BitValue(qrConfig.backColor));
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
for (int i = 0; i <= height; i += 2) { for (int i = 0; i <= height; i += 2) {
@ -663,15 +663,13 @@ public class QrCodeUtil {
* @since 5.8.6 * @since 5.8.6
*/ */
private static int rgbToAnsi8BitValue(int rgb) { private static int rgbToAnsi8BitValue(int rgb) {
int l; final int r = (rgb >> 16) & 0xff;
int r = (rgb >> 16) & 0xff; final int g = (rgb >> 8) & 0xff;
int g = (rgb >> 8) & 0xff; final int b = (rgb) & 0xff;
int b = (rgb) & 0xff;
if (r < 0) r += 256; final int l;
if (g < 0) g += 256;
if (b < 0) b += 256;
if (r == g && g == b) { if (r == g && g == b) {
int i = (int) (NumberUtil.div(NumberUtil.mul(r - 10.625, 23), (255 - 10.625), 0)); final int i = (int) (NumberUtil.div(NumberUtil.mul(r - 10.625, 23), (255 - 10.625), 0));
l = i >= 0 ? 232 + i : 0; l = i >= 0 ? 232 + i : 0;
} else { } else {
l = 16 + (int) (36 * NumberUtil.div(NumberUtil.mul(r, 5), 255, 0)) + (int) (6.0 * (g / 256.0 * 6.0)) + (int) (b / 256.0 * 6.0); l = 16 + (int) (36 * NumberUtil.div(NumberUtil.mul(r, 5), 255, 0)) + (int) (6.0 * (g / 256.0 * 6.0)) + (int) (b / 256.0 * 6.0);

View File

@ -33,35 +33,35 @@ public class QrCodeUtilTest {
} }
@Test @Test
// @Ignore @Ignore
public void generateCustomTest() { public void generateCustomTest() {
QrConfig config = new QrConfig(); final QrConfig config = new QrConfig();
config.setMargin(0); config.setMargin(0);
config.setForeColor(Color.CYAN); config.setForeColor(Color.CYAN);
// 背景色透明 // 背景色透明
config.setBackColor(null); config.setBackColor(null);
config.setErrorCorrection(ErrorCorrectionLevel.H); config.setErrorCorrection(ErrorCorrectionLevel.H);
String path = FileUtil.isWindows() ? "d:/test/qrcodeCustom.png" : "~/Desktop/hutool/qrcodeCustom.png"; final String path = FileUtil.isWindows() ? "d:/test/qrcodeCustom.png" : "~/Desktop/hutool/qrcodeCustom.png";
QrCodeUtil.generate("https://hutool.cn/", config, FileUtil.touch(path)); QrCodeUtil.generate("https://hutool.cn/", config, FileUtil.touch(path));
} }
@Test @Test
// @Ignore @Ignore
public void generateNoCustomColorTest() { public void generateNoCustomColorTest() {
QrConfig config = new QrConfig(); final QrConfig config = new QrConfig();
config.setMargin(0); config.setMargin(0);
config.setForeColor(null); config.setForeColor(null);
// 背景色透明 // 背景色透明
config.setBackColor(null); config.setBackColor(null);
config.setErrorCorrection(ErrorCorrectionLevel.H); config.setErrorCorrection(ErrorCorrectionLevel.H);
String path = FileUtil.isWindows() ? "d:/test/qrcodeCustom.png" : "~/Desktop/hutool/qrcodeCustom.png"; final String path = FileUtil.isWindows() ? "d:/test/qrcodeCustom.png" : "~/Desktop/hutool/qrcodeCustom.png";
QrCodeUtil.generate("https://hutool.cn/", config, FileUtil.touch(path)); QrCodeUtil.generate("https://hutool.cn/", config, FileUtil.touch(path));
} }
@Test @Test
@Ignore @Ignore
public void generateWithLogoTest() { public void generateWithLogoTest() {
String icon = FileUtil.isWindows() ? "d:/test/pic/face.jpg" : "~/Desktop/hutool/pic/face.jpg"; final String icon = FileUtil.isWindows() ? "d:/test/pic/face.jpg" : "~/Desktop/hutool/pic/face.jpg";
String targetPath = FileUtil.isWindows() ? "d:/test/qrcodeWithLogo.jpg" : "~/Desktop/hutool/qrcodeWithLogo.jpg"; final String targetPath = FileUtil.isWindows() ? "d:/test/qrcodeWithLogo.jpg" : "~/Desktop/hutool/qrcodeWithLogo.jpg";
QrCodeUtil.generate(// QrCodeUtil.generate(//
"https://hutool.cn/", // "https://hutool.cn/", //
QrConfig.create().setImg(icon), // QrConfig.create().setImg(icon), //
@ -71,7 +71,7 @@ public class QrCodeUtilTest {
@Test @Test
@Ignore @Ignore
public void decodeTest() { public void decodeTest() {
String decode = QrCodeUtil.decode(FileUtil.file("d:/test/pic/qr.png")); final String decode = QrCodeUtil.decode(FileUtil.file("d:/test/pic/qr.png"));
Console.log(decode); Console.log(decode);
} }
@ -79,29 +79,29 @@ public class QrCodeUtilTest {
@Ignore @Ignore
public void decodeTest2() { public void decodeTest2() {
// 条形码 // 条形码
String decode = QrCodeUtil.decode(FileUtil.file("d:/test/90.png")); final String decode = QrCodeUtil.decode(FileUtil.file("d:/test/90.png"));
Console.log(decode); Console.log(decode);
} }
@Test @Test
public void generateAsBase64Test() { public void generateAsBase64Test() {
String base64 = QrCodeUtil.generateAsBase64("https://hutool.cn/", new QrConfig(400, 400), "png"); final String base64 = QrCodeUtil.generateAsBase64("https://hutool.cn/", new QrConfig(400, 400), "png");
Assert.assertNotNull(base64); Assert.assertNotNull(base64);
} }
@Test @Test
@Ignore @Ignore
public void generateAsBase64Test2() { public void generateAsBase64Test2() {
byte[] bytes = FileUtil.readBytes( final byte[] bytes = FileUtil.readBytes(
new File("d:/test/qr.png")); new File("d:/test/qr.png"));
String encode = Base64.encode(bytes); final String encode = Base64.encode(bytes);
String base641 = QrCodeUtil.generateAsBase64("https://hutool.cn/", new QrConfig(400, 400), "png", encode); final String base641 = QrCodeUtil.generateAsBase64("https://hutool.cn/", new QrConfig(400, 400), "png", encode);
Assert.assertNotNull(base641); Assert.assertNotNull(base641);
} }
@Test @Test
public void generateAsBase64Test3() { public void generateAsBase64Test3() {
String base64 = QrCodeUtil.generateAsBase64("https://hutool.cn/", new QrConfig(400, 400), "svg"); final String base64 = QrCodeUtil.generateAsBase64("https://hutool.cn/", new QrConfig(400, 400), "svg");
Assert.assertNotNull(base64); Assert.assertNotNull(base64);
System.out.println(base64); System.out.println(base64);
} }
@ -121,84 +121,91 @@ public class QrCodeUtilTest {
@Test @Test
public void generateDataMatrixTest() { public void generateDataMatrixTest() {
QrConfig qrConfig = QrConfig.create(); final QrConfig qrConfig = QrConfig.create();
qrConfig.setShapeHint(SymbolShapeHint.FORCE_RECTANGLE); qrConfig.setShapeHint(SymbolShapeHint.FORCE_RECTANGLE);
final BufferedImage image = QrCodeUtil.generate("content111", BarcodeFormat.DATA_MATRIX, qrConfig); final BufferedImage image = QrCodeUtil.generate("content111", BarcodeFormat.DATA_MATRIX, qrConfig);
Assert.assertNotNull(image); Assert.assertNotNull(image);
QrConfig config = QrConfig.create(); final QrConfig config = QrConfig.create();
config.setShapeHint(SymbolShapeHint.FORCE_SQUARE); config.setShapeHint(SymbolShapeHint.FORCE_SQUARE);
final BufferedImage imageSquare = QrCodeUtil.generate("content111", BarcodeFormat.DATA_MATRIX, qrConfig); final BufferedImage imageSquare = QrCodeUtil.generate("content111", BarcodeFormat.DATA_MATRIX, qrConfig);
Assert.assertNotNull(imageSquare); Assert.assertNotNull(imageSquare);
} }
@Test @Test
@Ignore
public void generateSvgTest() { public void generateSvgTest() {
QrConfig qrConfig = QrConfig.create().setImg("d:/test/logo.png") final QrConfig qrConfig = QrConfig.create()
.setImg("d:/test/logo.png")
.setForeColor(Color.blue) .setForeColor(Color.blue)
.setBackColor(Color.pink) .setBackColor(Color.pink)
.setRatio(8) .setRatio(8)
.setErrorCorrection(ErrorCorrectionLevel.M) .setErrorCorrection(ErrorCorrectionLevel.M)
.setMargin(1); .setMargin(1);
String svg = QrCodeUtil.generateAsSvg("https://hutool.cn/", qrConfig); final String svg = QrCodeUtil.generateAsSvg("https://hutool.cn/", qrConfig);
Assert.assertNotNull(svg); Assert.assertNotNull(svg);
FileUtil.writeString(svg, FileUtil.touch("d:/test/hutool_qr.svg"),StandardCharsets.UTF_8); FileUtil.writeString(svg, FileUtil.touch("d:/test/hutool_qr.svg"),StandardCharsets.UTF_8);
} }
@Test @Test
public void generateAsciiArtTest() { public void generateAsciiArtTest() {
QrConfig qrConfig = QrConfig.create() final QrConfig qrConfig = QrConfig.create()
.setForeColor(Color.BLUE) .setForeColor(Color.BLUE)
.setBackColor(Color.MAGENTA) .setBackColor(Color.MAGENTA)
.setWidth(0) .setWidth(0)
.setHeight(0).setMargin(1); .setHeight(0).setMargin(1);
String asciiArt = QrCodeUtil.generateAsAsciiArt("https://hutool.cn/",qrConfig); final String asciiArt = QrCodeUtil.generateAsAsciiArt("https://hutool.cn/",qrConfig);
Assert.assertNotNull(asciiArt); Assert.assertNotNull(asciiArt);
System.out.println(asciiArt); //Console.log(asciiArt);
} }
@Test @Test
public void generateAsciiArtNoCustomColorTest() { public void generateAsciiArtNoCustomColorTest() {
QrConfig qrConfig = QrConfig.create() final QrConfig qrConfig = QrConfig.create()
.setForeColor(null) .setForeColor(null)
.setBackColor(null) .setBackColor(null)
.setWidth(0) .setWidth(0)
.setHeight(0).setMargin(1); .setHeight(0).setMargin(1);
String asciiArt = QrCodeUtil.generateAsAsciiArt("https://hutool.cn/",qrConfig); final String asciiArt = QrCodeUtil.generateAsAsciiArt("https://hutool.cn/",qrConfig);
Assert.assertNotNull(asciiArt); Assert.assertNotNull(asciiArt);
System.out.println(asciiArt); //Console.log(asciiArt);
} }
@Test @Test
@Ignore
public void generateToFileTest() { public void generateToFileTest() {
QrConfig qrConfig = QrConfig.create() final QrConfig qrConfig = QrConfig.create()
.setForeColor(Color.BLUE) .setForeColor(Color.BLUE)
.setBackColor(new Color(0,200,255)) .setBackColor(new Color(0,200,255))
.setWidth(0) .setWidth(0)
.setHeight(0).setMargin(1); .setHeight(0).setMargin(1);
File qrFile = QrCodeUtil.generate("https://hutool.cn/", qrConfig, FileUtil.touch("d:/test/ascii_art_qr_code.txt")); final File qrFile = QrCodeUtil.generate("https://hutool.cn/", qrConfig, FileUtil.touch("d:/test/ascii_art_qr_code.txt"));
BufferedReader reader = FileUtil.getReader(qrFile, StandardCharsets.UTF_8); final BufferedReader reader = FileUtil.getReader(qrFile, StandardCharsets.UTF_8);
reader.lines().forEach(System.out::println); reader.lines().forEach(System.out::println);
} }
@Test @Test
@Ignore
public void generateToStreamTest() { public void generateToStreamTest() {
QrConfig qrConfig = QrConfig.create() final QrConfig qrConfig = QrConfig.create()
.setForeColor(Color.BLUE) .setForeColor(Color.BLUE)
.setBackColor(new Color(0,200,255)) .setBackColor(new Color(0,200,255))
.setWidth(0) .setWidth(0)
.setHeight(0).setMargin(1); .setHeight(0).setMargin(1);
String filepath = "d:/test/qr_stream_to_txt.txt"; final String filepath = "d:/test/qr_stream_to_txt.txt";
try (BufferedOutputStream outputStream = FileUtil.getOutputStream(filepath)) { try (final BufferedOutputStream outputStream = FileUtil.getOutputStream(filepath)) {
QrCodeUtil.generate("https://hutool.cn/", qrConfig,"txt", outputStream); QrCodeUtil.generate("https://hutool.cn/", qrConfig,"txt", outputStream);
}catch (IOException e){ }catch (final IOException e){
e.printStackTrace(); e.printStackTrace();
} }
BufferedReader reader = FileUtil.getReader(filepath, StandardCharsets.UTF_8); final BufferedReader reader = FileUtil.getReader(filepath, StandardCharsets.UTF_8);
reader.lines().forEach(System.out::println); reader.lines().forEach(System.out::println);
} }
@Test @Test
@Ignore
public void comparePngAndAsciiArtTest() { public void comparePngAndAsciiArtTest() {
QrConfig qrConfig = QrConfig.create() final QrConfig qrConfig = QrConfig.create()
.setForeColor(null) .setForeColor(null)
.setBackColor(null) .setBackColor(null)
.setWidth(0) .setWidth(0)