mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
增加QrXXX
This commit is contained in:
parent
eba3332eaf
commit
37e971c4bc
@ -0,0 +1,57 @@
|
|||||||
|
package cn.hutool.extra.qrcode;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.ansi.AnsiElement;
|
||||||
|
import cn.hutool.core.lang.ansi.AnsiEncoder;
|
||||||
|
import cn.hutool.swing.img.color.ColorUtil;
|
||||||
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 二维码的AsciiArt表示
|
||||||
|
*
|
||||||
|
* @author Tom Xin
|
||||||
|
*/
|
||||||
|
public class QrAsciiArt {
|
||||||
|
|
||||||
|
private final BitMatrix matrix;
|
||||||
|
private final QrConfig qrConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
* @param matrix {@link BitMatrix}
|
||||||
|
* @param qrConfig {@link QrConfig}
|
||||||
|
*/
|
||||||
|
public QrAsciiArt(BitMatrix matrix, QrConfig qrConfig) {
|
||||||
|
this.matrix = matrix;
|
||||||
|
this.qrConfig = qrConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final int width = matrix.getWidth();
|
||||||
|
final int height = matrix.getHeight();
|
||||||
|
|
||||||
|
|
||||||
|
final AnsiElement foreground = qrConfig.foreColor == null ? null : ColorUtil.toAnsiColor(qrConfig.foreColor, true, false);
|
||||||
|
final AnsiElement background = qrConfig.backColor == null ? null : ColorUtil.toAnsiColor(qrConfig.backColor, true, true);
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (int i = 0; i <= height; i += 2) {
|
||||||
|
StringBuilder rowBuilder = new StringBuilder();
|
||||||
|
for (int j = 0; j < width; j++) {
|
||||||
|
boolean tp = matrix.get(i, j);
|
||||||
|
boolean bt = i + 1 >= height || matrix.get(i + 1, j);
|
||||||
|
if (tp && bt) {
|
||||||
|
rowBuilder.append(' ');//'\u0020'
|
||||||
|
} else if (tp) {
|
||||||
|
rowBuilder.append('▄');//'\u2584'
|
||||||
|
} else if (bt) {
|
||||||
|
rowBuilder.append('▀');//'\u2580'
|
||||||
|
} else {
|
||||||
|
rowBuilder.append('█');//'\u2588'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.append(AnsiEncoder.encode(foreground, background, rowBuilder)).append('\n');
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -1,31 +1,20 @@
|
|||||||
package cn.hutool.extra.qrcode;
|
package cn.hutool.extra.qrcode;
|
||||||
|
|
||||||
import cn.hutool.core.codec.Base64;
|
import cn.hutool.core.codec.Base64;
|
||||||
import cn.hutool.swing.img.Img;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.hutool.swing.img.ImgUtil;
|
import cn.hutool.swing.img.ImgUtil;
|
||||||
import cn.hutool.core.util.CharsetUtil;
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
import com.google.zxing.BarcodeFormat;
|
||||||
import com.google.zxing.Binarizer;
|
|
||||||
import com.google.zxing.BinaryBitmap;
|
|
||||||
import com.google.zxing.DecodeHintType;
|
import com.google.zxing.DecodeHintType;
|
||||||
import com.google.zxing.LuminanceSource;
|
|
||||||
import com.google.zxing.MultiFormatReader;
|
|
||||||
import com.google.zxing.MultiFormatWriter;
|
|
||||||
import com.google.zxing.NotFoundException;
|
|
||||||
import com.google.zxing.Result;
|
|
||||||
import com.google.zxing.WriterException;
|
|
||||||
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 java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,17 +29,20 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class QrCodeUtil {
|
public class QrCodeUtil {
|
||||||
|
|
||||||
|
public static final String QR_TYPE_SVG = "svg";// SVG矢量图格式
|
||||||
|
public static final String QR_TYPE_TXT = "txt";// Ascii Art字符画文本
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成代 logo 图片的 Base64 编码格式的二维码,以 String 形式表示
|
* 生成代 logo 图片的 Base64 编码格式的二维码,以 String 形式表示
|
||||||
*
|
*
|
||||||
* @param content 内容
|
* @param content 内容
|
||||||
* @param qrConfig 二维码配置,包括宽度、高度、边距、颜色等
|
* @param qrConfig 二维码配置,包括宽度、高度、边距、颜色等
|
||||||
* @param imageType 图片类型(图片扩展名),见{@link ImgUtil}
|
* @param targetType 类型(图片扩展名),见{@link #QR_TYPE_SVG}、 {@link #QR_TYPE_TXT}、{@link ImgUtil}
|
||||||
* @param logoBase64 logo 图片的 base64 编码
|
* @param logoBase64 logo 图片的 base64 编码
|
||||||
* @return 图片 Base64 编码字符串
|
* @return 图片 Base64 编码字符串
|
||||||
*/
|
*/
|
||||||
public static String generateAsBase64(final String content, final QrConfig qrConfig, final String imageType, final String logoBase64) {
|
public static String generateAsBase64(String content, QrConfig qrConfig, String targetType, String logoBase64) {
|
||||||
return generateAsBase64(content, qrConfig, imageType, Base64.decode(logoBase64));
|
return generateAsBase64DataUri(content, qrConfig, targetType, Base64.decode(logoBase64));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,26 +50,12 @@ public class QrCodeUtil {
|
|||||||
*
|
*
|
||||||
* @param content 内容
|
* @param content 内容
|
||||||
* @param qrConfig 二维码配置,包括宽度、高度、边距、颜色等
|
* @param qrConfig 二维码配置,包括宽度、高度、边距、颜色等
|
||||||
* @param imageType 图片类型(图片扩展名),见{@link ImgUtil}
|
* @param targetType 类型(图片扩展名),见{@link #QR_TYPE_SVG}、 {@link #QR_TYPE_TXT}、{@link ImgUtil}
|
||||||
* @param logo logo 图片的byte[]
|
* @param logo logo 图片的byte[]
|
||||||
* @return 图片 Base64 编码字符串
|
* @return 图片 Base64 编码字符串
|
||||||
*/
|
*/
|
||||||
public static String generateAsBase64(final String content, final QrConfig qrConfig, final String imageType, final byte[] logo) {
|
public static String generateAsBase64DataUri(String content, QrConfig qrConfig, String targetType, byte[] logo) {
|
||||||
return generateAsBase64(content, qrConfig, imageType, ImgUtil.toImage(logo));
|
return generateAsBase64DataUri(content, qrConfig.setImg(ImgUtil.toImage(logo)), targetType);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成代 logo 图片的 Base64 编码格式的二维码,以 String 形式表示
|
|
||||||
*
|
|
||||||
* @param content 内容
|
|
||||||
* @param qrConfig 二维码配置,包括宽度、高度、边距、颜色等
|
|
||||||
* @param imageType 图片类型(图片扩展名),见{@link ImgUtil}
|
|
||||||
* @param logo logo 图片的byte[]
|
|
||||||
* @return 图片 Base64 编码字符串
|
|
||||||
*/
|
|
||||||
public static String generateAsBase64(final String content, final QrConfig qrConfig, final String imageType, final Image logo) {
|
|
||||||
qrConfig.setImg(logo);
|
|
||||||
return generateAsBase64(content, qrConfig, imageType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,7 +70,7 @@ public class QrCodeUtil {
|
|||||||
* @param imageType 图片类型(图片扩展名),见{@link ImgUtil}
|
* @param imageType 图片类型(图片扩展名),见{@link ImgUtil}
|
||||||
* @return 图片 Base64 编码字符串
|
* @return 图片 Base64 编码字符串
|
||||||
*/
|
*/
|
||||||
public static String generateAsBase64(final String content, final QrConfig qrConfig, final String imageType) {
|
public static String generateAsBase64DataUri(final String content, final QrConfig qrConfig, final String imageType) {
|
||||||
final BufferedImage img = generate(content, qrConfig);
|
final BufferedImage img = generate(content, qrConfig);
|
||||||
return ImgUtil.toBase64DataUri(img, imageType);
|
return ImgUtil.toBase64DataUri(img, imageType);
|
||||||
}
|
}
|
||||||
@ -193,32 +171,7 @@ public class QrCodeUtil {
|
|||||||
* @return 二维码图片(黑白)
|
* @return 二维码图片(黑白)
|
||||||
*/
|
*/
|
||||||
public static BufferedImage generate(final String content, final int width, final int height) {
|
public static BufferedImage generate(final String content, final int width, final int height) {
|
||||||
return generate(content, new QrConfig(width, height));
|
return generate(content, QrConfig.of(width, height));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成二维码或条形码图片
|
|
||||||
*
|
|
||||||
* @param content 文本内容
|
|
||||||
* @param format 格式,可选二维码或者条形码
|
|
||||||
* @param width 宽度
|
|
||||||
* @param height 高度
|
|
||||||
* @return 二维码图片(黑白)
|
|
||||||
*/
|
|
||||||
public static BufferedImage generate(final String content, final BarcodeFormat format, final int width, final int height) {
|
|
||||||
return generate(content, format, new QrConfig(width, height));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成二维码图片
|
|
||||||
*
|
|
||||||
* @param content 文本内容
|
|
||||||
* @param config 二维码配置,包括宽度、高度、边距、颜色等
|
|
||||||
* @return 二维码图片(黑白)
|
|
||||||
* @since 4.1.2
|
|
||||||
*/
|
|
||||||
public static BufferedImage generate(final String content, final QrConfig config) {
|
|
||||||
return generate(content, BarcodeFormat.QR_CODE, config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,102 +179,26 @@ public class QrCodeUtil {
|
|||||||
* 只有二维码时QrConfig中的图片才有效
|
* 只有二维码时QrConfig中的图片才有效
|
||||||
*
|
*
|
||||||
* @param content 文本内容
|
* @param content 文本内容
|
||||||
* @param format 格式,可选二维码、条形码等
|
|
||||||
* @param config 二维码配置,包括宽度、高度、边距、颜色等
|
* @param config 二维码配置,包括宽度、高度、边距、颜色等
|
||||||
* @return 二维码图片(黑白)
|
* @return 二维码图片(黑白)
|
||||||
* @since 4.1.14
|
* @since 4.1.14
|
||||||
*/
|
*/
|
||||||
public static BufferedImage generate(final String content, final BarcodeFormat format, final QrConfig config) {
|
public static BufferedImage generate(final String content, final QrConfig config) {
|
||||||
final BitMatrix bitMatrix = encode(content, format, config);
|
return new QrImage(content, ObjUtil.defaultIfNull(config, QrConfig::new));
|
||||||
final BufferedImage image = toImage(bitMatrix, config.foreColor, config.backColor);
|
|
||||||
final Image logoImg = config.img;
|
|
||||||
if (null != logoImg && BarcodeFormat.QR_CODE == format) {
|
|
||||||
// 只有二维码可以贴图
|
|
||||||
final int qrWidth = image.getWidth();
|
|
||||||
final int qrHeight = image.getHeight();
|
|
||||||
final int width;
|
|
||||||
final int height;
|
|
||||||
// 按照最短的边做比例缩放
|
|
||||||
if (qrWidth < qrHeight) {
|
|
||||||
width = qrWidth / config.ratio;
|
|
||||||
height = logoImg.getHeight(null) * width / logoImg.getWidth(null);
|
|
||||||
} else {
|
|
||||||
height = qrHeight / config.ratio;
|
|
||||||
width = logoImg.getWidth(null) * height / logoImg.getHeight(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
Img.from(image).pressImage(//
|
|
||||||
Img.from(logoImg).round(0.3).getImg(), // 圆角
|
|
||||||
new Rectangle(width, height), //
|
|
||||||
1//
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------------------------- encode
|
// ------------------------------------------------------------------------------------------------------------------- encode
|
||||||
|
|
||||||
/**
|
|
||||||
* 将文本内容编码为二维码
|
|
||||||
*
|
|
||||||
* @param content 文本内容
|
|
||||||
* @param width 宽度
|
|
||||||
* @param height 高度
|
|
||||||
* @return {@link BitMatrix}
|
|
||||||
*/
|
|
||||||
public static BitMatrix encode(final String content, final int width, final int height) {
|
|
||||||
return encode(content, BarcodeFormat.QR_CODE, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将文本内容编码为二维码
|
|
||||||
*
|
|
||||||
* @param content 文本内容
|
|
||||||
* @param config 二维码配置,包括宽度、高度、边距、颜色等
|
|
||||||
* @return {@link BitMatrix}
|
|
||||||
* @since 4.1.2
|
|
||||||
*/
|
|
||||||
public static BitMatrix encode(final String content, final QrConfig config) {
|
|
||||||
return encode(content, BarcodeFormat.QR_CODE, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将文本内容编码为条形码或二维码
|
* 将文本内容编码为条形码或二维码
|
||||||
*
|
*
|
||||||
* @param content 文本内容
|
* @param content 文本内容
|
||||||
* @param format 格式枚举
|
* @param config 二维码配置,包括宽度、高度、边距、颜色、格式等
|
||||||
* @param width 宽度
|
|
||||||
* @param height 高度
|
|
||||||
* @return {@link BitMatrix}
|
|
||||||
*/
|
|
||||||
public static BitMatrix encode(final String content, final BarcodeFormat format, final int width, final int height) {
|
|
||||||
return encode(content, format, new QrConfig(width, height));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将文本内容编码为条形码或二维码
|
|
||||||
*
|
|
||||||
* @param content 文本内容
|
|
||||||
* @param format 格式枚举
|
|
||||||
* @param config 二维码配置,包括宽度、高度、边距、颜色等
|
|
||||||
* @return {@link BitMatrix}
|
* @return {@link BitMatrix}
|
||||||
* @since 4.1.2
|
* @since 4.1.2
|
||||||
*/
|
*/
|
||||||
public static BitMatrix encode(final String content, final BarcodeFormat format, QrConfig config) {
|
public static BitMatrix encode(final CharSequence content, final QrConfig config) {
|
||||||
final MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
|
return QrEncoder.of(config).encode(content);
|
||||||
if (null == config) {
|
|
||||||
// 默认配置
|
|
||||||
config = new QrConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
final BitMatrix bitMatrix;
|
|
||||||
try {
|
|
||||||
bitMatrix = multiFormatWriter.encode(content, format, config.width, config.height, config.toHints(format));
|
|
||||||
} catch (final WriterException e) {
|
|
||||||
throw new QrCodeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bitMatrix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------------------------- decode
|
// ------------------------------------------------------------------------------------------------------------------- decode
|
||||||
@ -368,7 +245,7 @@ public class QrCodeUtil {
|
|||||||
* @since 4.3.1
|
* @since 4.3.1
|
||||||
*/
|
*/
|
||||||
public static String decode(final Image image, final boolean isTryHarder, final boolean isPureBarcode) {
|
public static String decode(final Image image, final boolean isTryHarder, final boolean isPureBarcode) {
|
||||||
return decode(image, buildHints(isTryHarder, isPureBarcode));
|
return QrDecoder.of(isTryHarder, isPureBarcode).decode(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -382,17 +259,7 @@ public class QrCodeUtil {
|
|||||||
* @since 5.7.12
|
* @since 5.7.12
|
||||||
*/
|
*/
|
||||||
public static String decode(final Image image, final Map<DecodeHintType, Object> hints) {
|
public static String decode(final Image image, final Map<DecodeHintType, Object> hints) {
|
||||||
final MultiFormatReader formatReader = new MultiFormatReader();
|
return QrDecoder.of(hints).decode(image);
|
||||||
formatReader.setHints(hints);
|
|
||||||
|
|
||||||
final LuminanceSource source = new BufferedImageLuminanceSource(ImgUtil.toBufferedImage(image));
|
|
||||||
|
|
||||||
Result result = _decode(formatReader, new HybridBinarizer(source));
|
|
||||||
if (null == result) {
|
|
||||||
result = _decode(formatReader, new GlobalHistogramBinarizer(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null != result ? result.getText() : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -421,39 +288,46 @@ public class QrCodeUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建解码选项
|
* @param content 内容
|
||||||
*
|
* @param qrConfig 二维码配置,包括宽度、高度、边距、颜色等
|
||||||
* @param isTryHarder 是否优化精度
|
* @return SVG矢量图(字符串)
|
||||||
* @param isPureBarcode 是否使用复杂模式,扫描带logo的二维码设为true
|
* @since 5.8.6
|
||||||
* @return 选项Map
|
|
||||||
*/
|
*/
|
||||||
private static Map<DecodeHintType, Object> buildHints(final boolean isTryHarder, final boolean isPureBarcode) {
|
public static String generateAsSvg(String content, QrConfig qrConfig) {
|
||||||
final HashMap<DecodeHintType, Object> hints = new HashMap<>();
|
return toSVG(encode(content, qrConfig), qrConfig);
|
||||||
hints.put(DecodeHintType.CHARACTER_SET, CharsetUtil.NAME_UTF_8);
|
|
||||||
|
|
||||||
// 优化精度
|
|
||||||
if (isTryHarder) {
|
|
||||||
hints.put(DecodeHintType.TRY_HARDER, true);
|
|
||||||
}
|
|
||||||
// 复杂模式,开启PURE_BARCODE模式
|
|
||||||
if (isPureBarcode) {
|
|
||||||
hints.put(DecodeHintType.PURE_BARCODE, true);
|
|
||||||
}
|
|
||||||
return hints;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解码多种类型的码,包括二维码和条形码
|
* BitMatrix转SVG(字符串)
|
||||||
*
|
*
|
||||||
* @param formatReader {@link MultiFormatReader}
|
* @param matrix BitMatrix
|
||||||
* @param binarizer {@link Binarizer}
|
* @param config {@link QrConfig}
|
||||||
* @return {@link Result}
|
* @return SVG矢量图(字符串)
|
||||||
*/
|
*/
|
||||||
private static Result _decode(final MultiFormatReader formatReader, final Binarizer binarizer) {
|
public static String toSVG(BitMatrix matrix, QrConfig config) {
|
||||||
try {
|
return new QrSVG(matrix, config).toString();
|
||||||
return formatReader.decodeWithState(new BinaryBitmap(binarizer));
|
}
|
||||||
} catch (final NotFoundException e) {
|
|
||||||
return null;
|
/**
|
||||||
}
|
* 生成ASCII Art字符画形式的二维码
|
||||||
|
*
|
||||||
|
* @param content 内容
|
||||||
|
* @param qrConfig 二维码配置,仅宽度、高度、边距配置有效
|
||||||
|
* @return ASCII Art字符画形式的二维码
|
||||||
|
* @since 5.8.6
|
||||||
|
*/
|
||||||
|
public static String generateAsAsciiArt(String content, QrConfig qrConfig) {
|
||||||
|
return toAsciiArt(encode(content, qrConfig), qrConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BitMatrix转ASCII Art字符画形式的二维码
|
||||||
|
*
|
||||||
|
* @param bitMatrix BitMatrix
|
||||||
|
* @return ASCII Art字符画形式的二维码
|
||||||
|
* @since 5.8.6
|
||||||
|
*/
|
||||||
|
public static String toAsciiArt(BitMatrix bitMatrix, QrConfig qrConfig) {
|
||||||
|
return new QrAsciiArt(bitMatrix, qrConfig).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,33 +25,59 @@ public class QrConfig {
|
|||||||
private static final int BLACK = 0xFF000000;
|
private static final int BLACK = 0xFF000000;
|
||||||
private static final int WHITE = 0xFFFFFFFF;
|
private static final int WHITE = 0xFFFFFFFF;
|
||||||
|
|
||||||
/** 宽度 */
|
/**
|
||||||
|
* 宽度
|
||||||
|
*/
|
||||||
protected int width;
|
protected int width;
|
||||||
/** 高度 */
|
/**
|
||||||
|
* 高度
|
||||||
|
*/
|
||||||
protected int height;
|
protected int height;
|
||||||
/** 前景色(二维码颜色) */
|
/**
|
||||||
|
* 前景色(二维码颜色)
|
||||||
|
*/
|
||||||
protected Integer foreColor = BLACK;
|
protected Integer foreColor = BLACK;
|
||||||
/** 背景色,默认白色,null表示透明 */
|
/**
|
||||||
|
* 背景色,默认白色,null表示透明
|
||||||
|
*/
|
||||||
protected Integer backColor = WHITE;
|
protected Integer backColor = WHITE;
|
||||||
/** 边距0~4 */
|
/**
|
||||||
|
* 边距0~4
|
||||||
|
*/
|
||||||
protected Integer margin = 2;
|
protected Integer margin = 2;
|
||||||
/** 设置二维码中的信息量,可设置0-40的整数 */
|
/**
|
||||||
|
* 设置二维码中的信息量,可设置0-40的整数
|
||||||
|
*/
|
||||||
protected Integer qrVersion;
|
protected Integer qrVersion;
|
||||||
/** 纠错级别 */
|
/**
|
||||||
|
* 纠错级别
|
||||||
|
*/
|
||||||
protected ErrorCorrectionLevel errorCorrection = ErrorCorrectionLevel.M;
|
protected ErrorCorrectionLevel errorCorrection = ErrorCorrectionLevel.M;
|
||||||
/** 编码 */
|
/**
|
||||||
|
* 编码
|
||||||
|
*/
|
||||||
protected Charset charset = CharsetUtil.UTF_8;
|
protected Charset charset = CharsetUtil.UTF_8;
|
||||||
/** 二维码中的Logo */
|
/**
|
||||||
|
* 二维码中的Logo
|
||||||
|
*/
|
||||||
protected Image img;
|
protected Image img;
|
||||||
/** 二维码中的Logo缩放的比例系数,如5表示长宽最小值的1/5 */
|
/**
|
||||||
|
* 二维码中的Logo缩放的比例系数,如5表示长宽最小值的1/5
|
||||||
|
*/
|
||||||
protected int ratio = 6;
|
protected int ratio = 6;
|
||||||
/**
|
/**
|
||||||
* DATA_MATRIX的符号形状
|
* DATA_MATRIX的符号形状
|
||||||
*/
|
*/
|
||||||
protected SymbolShapeHint shapeHint = SymbolShapeHint.FORCE_NONE;
|
protected SymbolShapeHint shapeHint = SymbolShapeHint.FORCE_NONE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成码的格式,默认为二维码
|
||||||
|
*/
|
||||||
|
protected BarcodeFormat format = BarcodeFormat.QR_CODE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建QrConfig
|
* 创建QrConfig
|
||||||
|
*
|
||||||
* @return QrConfig
|
* @return QrConfig
|
||||||
* @since 4.1.14
|
* @since 4.1.14
|
||||||
*/
|
*/
|
||||||
@ -59,6 +85,18 @@ public class QrConfig {
|
|||||||
return new QrConfig();
|
return new QrConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建QrConfig
|
||||||
|
*
|
||||||
|
* @param width 宽
|
||||||
|
* @param height 高
|
||||||
|
* @return QrConfig
|
||||||
|
* @since 4.1.14
|
||||||
|
*/
|
||||||
|
public static QrConfig of(final int width, final int height) {
|
||||||
|
return new QrConfig(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造,默认长宽为300
|
* 构造,默认长宽为300
|
||||||
*/
|
*/
|
||||||
@ -70,7 +108,7 @@ public class QrConfig {
|
|||||||
* 构造
|
* 构造
|
||||||
*
|
*
|
||||||
* @param width 宽
|
* @param width 宽
|
||||||
* @param height 长
|
* @param height 高
|
||||||
*/
|
*/
|
||||||
public QrConfig(final int width, final int height) {
|
public QrConfig(final int width, final int height) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
@ -318,22 +356,33 @@ public class QrConfig {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取码格式
|
||||||
|
*
|
||||||
|
* @return 码格式,默认为二维码
|
||||||
|
*/
|
||||||
|
public BarcodeFormat getFormat() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置码格式,默认二维码
|
||||||
|
*
|
||||||
|
* @param format 码格式
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public QrConfig setFormat(BarcodeFormat format) {
|
||||||
|
this.format = format;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为Zxing的二维码配置
|
* 转换为Zxing的二维码配置
|
||||||
*
|
*
|
||||||
* @return 配置
|
* @return 配置
|
||||||
*/
|
*/
|
||||||
public HashMap<EncodeHintType, Object> toHints() {
|
public HashMap<EncodeHintType, Object> toHints() {
|
||||||
return toHints(BarcodeFormat.QR_CODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Zxing的二维码配置
|
|
||||||
*
|
|
||||||
* @param format 格式,根据格式不同,{@link #errorCorrection}的值类型有所不同
|
|
||||||
* @return 配置
|
|
||||||
*/
|
|
||||||
public HashMap<EncodeHintType, Object> toHints(final BarcodeFormat format) {
|
|
||||||
// 配置
|
// 配置
|
||||||
final HashMap<EncodeHintType, Object> hints = new HashMap<>();
|
final HashMap<EncodeHintType, Object> hints = new HashMap<>();
|
||||||
if (null != this.charset) {
|
if (null != this.charset) {
|
||||||
|
111
hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrDecoder.java
Normal file
111
hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrDecoder.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package cn.hutool.extra.qrcode;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Decoder;
|
||||||
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
|
import cn.hutool.swing.img.ImgUtil;
|
||||||
|
import com.google.zxing.Binarizer;
|
||||||
|
import com.google.zxing.BinaryBitmap;
|
||||||
|
import com.google.zxing.DecodeHintType;
|
||||||
|
import com.google.zxing.LuminanceSource;
|
||||||
|
import com.google.zxing.MultiFormatReader;
|
||||||
|
import com.google.zxing.NotFoundException;
|
||||||
|
import com.google.zxing.Result;
|
||||||
|
import com.google.zxing.common.GlobalHistogramBinarizer;
|
||||||
|
import com.google.zxing.common.HybridBinarizer;
|
||||||
|
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 二维码(条形码等)解码器
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class QrDecoder implements Decoder<Image, String> {
|
||||||
|
|
||||||
|
private final Map<DecodeHintType, Object> hints;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建二维码(条形码等)解码器,用于将二维码(条形码等)解码为所代表的内容字符串
|
||||||
|
*
|
||||||
|
* @param isTryHarder 是否优化精度
|
||||||
|
* @param isPureBarcode 是否使用复杂模式,扫描带logo的二维码设为true
|
||||||
|
* @return QrDecoder
|
||||||
|
*/
|
||||||
|
public static QrDecoder of(final boolean isTryHarder, final boolean isPureBarcode) {
|
||||||
|
return of(buildHints(isTryHarder, isPureBarcode));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建二维码(条形码等)解码器
|
||||||
|
*
|
||||||
|
* @param hints 自定义扫码配置,包括算法、编码、复杂模式等
|
||||||
|
* @return QrDecoder
|
||||||
|
*/
|
||||||
|
public static QrDecoder of(final Map<DecodeHintType, Object> hints) {
|
||||||
|
return new QrDecoder(hints);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param hints 自定义扫码配置,包括算法、编码、复杂模式等
|
||||||
|
*/
|
||||||
|
public QrDecoder(Map<DecodeHintType, Object> hints) {
|
||||||
|
this.hints = hints;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decode(Image image) {
|
||||||
|
final MultiFormatReader formatReader = new MultiFormatReader();
|
||||||
|
formatReader.setHints(hints);
|
||||||
|
|
||||||
|
final LuminanceSource source = new BufferedImageLuminanceSource(ImgUtil.toBufferedImage(image));
|
||||||
|
|
||||||
|
Result result = _decode(formatReader, new HybridBinarizer(source));
|
||||||
|
if (null == result) {
|
||||||
|
result = _decode(formatReader, new GlobalHistogramBinarizer(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null != result ? result.getText() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解码多种类型的码,包括二维码和条形码
|
||||||
|
*
|
||||||
|
* @param formatReader {@link MultiFormatReader}
|
||||||
|
* @param binarizer {@link Binarizer}
|
||||||
|
* @return {@link Result}
|
||||||
|
*/
|
||||||
|
private static Result _decode(final MultiFormatReader formatReader, final Binarizer binarizer) {
|
||||||
|
try {
|
||||||
|
return formatReader.decodeWithState(new BinaryBitmap(binarizer));
|
||||||
|
} catch (final NotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建解码选项
|
||||||
|
*
|
||||||
|
* @param isTryHarder 是否优化精度
|
||||||
|
* @param isPureBarcode 是否使用复杂模式,扫描带logo的二维码设为true
|
||||||
|
* @return 选项Map
|
||||||
|
*/
|
||||||
|
private static Map<DecodeHintType, Object> buildHints(final boolean isTryHarder, final boolean isPureBarcode) {
|
||||||
|
final HashMap<DecodeHintType, Object> hints = new HashMap<>(3, 1);
|
||||||
|
hints.put(DecodeHintType.CHARACTER_SET, CharsetUtil.NAME_UTF_8);
|
||||||
|
|
||||||
|
// 优化精度
|
||||||
|
if (isTryHarder) {
|
||||||
|
hints.put(DecodeHintType.TRY_HARDER, true);
|
||||||
|
}
|
||||||
|
// 复杂模式,开启PURE_BARCODE模式
|
||||||
|
if (isPureBarcode) {
|
||||||
|
hints.put(DecodeHintType.PURE_BARCODE, true);
|
||||||
|
}
|
||||||
|
return hints;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package cn.hutool.extra.qrcode;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Encoder;
|
||||||
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import com.google.zxing.MultiFormatWriter;
|
||||||
|
import com.google.zxing.WriterException;
|
||||||
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 二维码(条形码等)编码器,用于将文本内容转换为二维码
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class QrEncoder implements Encoder<CharSequence, BitMatrix> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建QrEncoder
|
||||||
|
*
|
||||||
|
* @param config {@link QrConfig}
|
||||||
|
* @return QrEncoder
|
||||||
|
*/
|
||||||
|
public static QrEncoder of(QrConfig config) {
|
||||||
|
return new QrEncoder(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final QrConfig config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param config {@link QrConfig}
|
||||||
|
*/
|
||||||
|
public QrEncoder(QrConfig config) {
|
||||||
|
this.config = ObjUtil.defaultIfNull(config, QrConfig::of);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BitMatrix encode(CharSequence content) {
|
||||||
|
final MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
|
||||||
|
|
||||||
|
final BitMatrix bitMatrix;
|
||||||
|
try {
|
||||||
|
bitMatrix = multiFormatWriter.encode(
|
||||||
|
StrUtil.toString(content),
|
||||||
|
config.format, config.width, config.height,
|
||||||
|
config.toHints());
|
||||||
|
} catch (final WriterException e) {
|
||||||
|
throw new QrCodeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitMatrix;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package cn.hutool.extra.qrcode;
|
||||||
|
|
||||||
|
import cn.hutool.swing.img.Img;
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 二维码图片封装
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class QrImage extends BufferedImage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param content 文本内容
|
||||||
|
* @param config {@link QrConfig} 二维码配置,包括宽度、高度、边距、颜色、格式等
|
||||||
|
*/
|
||||||
|
public QrImage(final String content, final QrConfig config) {
|
||||||
|
this(QrCodeUtil.encode(content, config), config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param matrix {@link BitMatrix}
|
||||||
|
* @param config {@link QrConfig},非空
|
||||||
|
*/
|
||||||
|
public QrImage(final BitMatrix matrix, final QrConfig config) {
|
||||||
|
super(matrix.getWidth(), matrix.getHeight(), null == config.backColor ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
|
||||||
|
init(matrix, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*
|
||||||
|
* @param matrix {@link BitMatrix}
|
||||||
|
* @param config {@link QrConfig}
|
||||||
|
*/
|
||||||
|
private void init(final BitMatrix matrix, final QrConfig config) {
|
||||||
|
final int width = matrix.getWidth();
|
||||||
|
final int height = matrix.getHeight();
|
||||||
|
final Integer foreColor = config.foreColor;
|
||||||
|
final Integer backColor = config.backColor;
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
if (matrix.get(x, y)) {
|
||||||
|
setRGB(x, y, foreColor);
|
||||||
|
} else if (null != backColor) {
|
||||||
|
setRGB(x, y, backColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final Image logoImg = config.img;
|
||||||
|
if (null != logoImg && BarcodeFormat.QR_CODE == config.format) {
|
||||||
|
// 只有二维码可以贴图
|
||||||
|
final int qrWidth = getWidth();
|
||||||
|
final int qrHeight = getHeight();
|
||||||
|
final int imgWidth;
|
||||||
|
final int imgHeight;
|
||||||
|
// 按照最短的边做比例缩放
|
||||||
|
if (qrWidth < qrHeight) {
|
||||||
|
imgWidth = qrWidth / config.ratio;
|
||||||
|
imgHeight = logoImg.getHeight(null) * imgWidth / logoImg.getWidth(null);
|
||||||
|
} else {
|
||||||
|
imgHeight = qrHeight / config.ratio;
|
||||||
|
imgWidth = logoImg.getWidth(null) * imgHeight / logoImg.getHeight(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Img.from(this).pressImage(//
|
||||||
|
Img.from(logoImg).round(0.3).getImg(), // 圆角
|
||||||
|
new Rectangle(imgWidth, imgHeight), // 位置
|
||||||
|
1//不透明
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,11 @@ public class QrSVG {
|
|||||||
private final BitMatrix matrix;
|
private final BitMatrix matrix;
|
||||||
private final QrConfig qrConfig;
|
private final QrConfig qrConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
* @param matrix {@link BitMatrix}
|
||||||
|
* @param qrConfig {@link QrConfig}
|
||||||
|
*/
|
||||||
public QrSVG(BitMatrix matrix, QrConfig qrConfig) {
|
public QrSVG(BitMatrix matrix, QrConfig qrConfig) {
|
||||||
this.matrix = matrix;
|
this.matrix = matrix;
|
||||||
this.qrConfig = qrConfig;
|
this.qrConfig = qrConfig;
|
||||||
|
@ -2,7 +2,9 @@ package cn.hutool.extra.qrcode;
|
|||||||
|
|
||||||
import cn.hutool.core.codec.Base64;
|
import cn.hutool.core.codec.Base64;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.lang.Console;
|
import cn.hutool.core.lang.Console;
|
||||||
|
import cn.hutool.core.text.StrUtil;
|
||||||
import cn.hutool.swing.img.ImgUtil;
|
import cn.hutool.swing.img.ImgUtil;
|
||||||
import com.google.zxing.BarcodeFormat;
|
import com.google.zxing.BarcodeFormat;
|
||||||
import com.google.zxing.datamatrix.encoder.SymbolShapeHint;
|
import com.google.zxing.datamatrix.encoder.SymbolShapeHint;
|
||||||
@ -14,6 +16,7 @@ import org.junit.Test;
|
|||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 二维码工具类单元测试
|
* 二维码工具类单元测试
|
||||||
@ -31,7 +34,7 @@ public class QrCodeUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
public void generateCustomTest() {
|
public void generateCustomTest() {
|
||||||
final QrConfig config = new QrConfig();
|
final QrConfig config = QrConfig.of();
|
||||||
config.setMargin(0);
|
config.setMargin(0);
|
||||||
config.setForeColor(Color.CYAN);
|
config.setForeColor(Color.CYAN);
|
||||||
// 背景色透明
|
// 背景色透明
|
||||||
@ -44,7 +47,7 @@ public class QrCodeUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
public void generateWithLogoTest() {
|
public void generateWithLogoTest() {
|
||||||
final String icon = FileUtil.isWindows() ? "d:/test/pic/face.jpg" : "~/Desktop/hutool/pic/face.jpg";
|
final String icon = FileUtil.isWindows() ? "d:/test/pic/logo.jpg" : "~/Desktop/hutool/pic/logo.jpg";
|
||||||
final 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/", //
|
||||||
@ -68,17 +71,22 @@ public class QrCodeUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void generateAsBase64Test() {
|
public void generateAsBase64AndDecodeTest() {
|
||||||
final String base64 = QrCodeUtil.generateAsBase64("https://hutool.cn/", new QrConfig(400, 400), "png");
|
final String url = "https://hutool.cn/";
|
||||||
|
String base64 = QrCodeUtil.generateAsBase64DataUri(url, new QrConfig(400, 400), "png");
|
||||||
Assert.assertNotNull(base64);
|
Assert.assertNotNull(base64);
|
||||||
|
|
||||||
|
base64 = StrUtil.removePrefix(base64, "data:image/png;base64,");
|
||||||
|
final String decode = QrCodeUtil.decode(IoUtil.toStream(Base64.decode(base64)));
|
||||||
|
Assert.assertEquals(url, decode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
public void generateAsBase64Test2() {
|
public void generateAsBase64Test2() {
|
||||||
final byte[] bytes = FileUtil.readBytes(new File("d:/test/qr.png"));
|
final byte[] bytes = FileUtil.readBytes(new File("d:/test/qr.png"));
|
||||||
final String encode = Base64.encode(bytes);
|
final String base641 = QrCodeUtil.generateAsBase64DataUri("https://hutool.cn/",
|
||||||
final String base641 = QrCodeUtil.generateAsBase64("https://hutool.cn/", new QrConfig(400, 400), "png", encode);
|
new QrConfig(400, 400), "png", bytes);
|
||||||
Assert.assertNotNull(base641);
|
Assert.assertNotNull(base641);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +99,7 @@ public class QrCodeUtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void pdf417Test() {
|
public void pdf417Test() {
|
||||||
final BufferedImage image = QrCodeUtil.generate("content111", BarcodeFormat.PDF_417, QrConfig.of());
|
final BufferedImage image = QrCodeUtil.generate("content111", QrConfig.of().setFormat(BarcodeFormat.PDF_417));
|
||||||
Assert.assertNotNull(image);
|
Assert.assertNotNull(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,11 +107,50 @@ public class QrCodeUtilTest {
|
|||||||
public void generateDataMatrixTest() {
|
public void generateDataMatrixTest() {
|
||||||
final QrConfig qrConfig = QrConfig.of();
|
final QrConfig qrConfig = QrConfig.of();
|
||||||
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", qrConfig.setFormat(BarcodeFormat.DATA_MATRIX));
|
||||||
Assert.assertNotNull(image);
|
Assert.assertNotNull(image);
|
||||||
final QrConfig config = QrConfig.of();
|
final QrConfig config = QrConfig.of();
|
||||||
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", qrConfig.setFormat(BarcodeFormat.DATA_MATRIX));
|
||||||
Assert.assertNotNull(imageSquare);
|
Assert.assertNotNull(imageSquare);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void generateSvgTest() {
|
||||||
|
final QrConfig qrConfig = QrConfig.of()
|
||||||
|
.setImg("d:/test/pic/logo.jpg")
|
||||||
|
.setForeColor(Color.blue)
|
||||||
|
.setBackColor(Color.pink)
|
||||||
|
.setRatio(8)
|
||||||
|
.setErrorCorrection(ErrorCorrectionLevel.M)
|
||||||
|
.setMargin(1);
|
||||||
|
final String svg = QrCodeUtil.generateAsSvg("https://hutool.cn/", qrConfig);
|
||||||
|
Assert.assertNotNull(svg);
|
||||||
|
FileUtil.writeString(svg, FileUtil.touch("d:/test/hutool_qr.svg"), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generateAsciiArtTest() {
|
||||||
|
final QrConfig qrConfig = QrConfig.of()
|
||||||
|
.setForeColor(Color.BLUE)
|
||||||
|
.setBackColor(Color.MAGENTA)
|
||||||
|
.setWidth(0)
|
||||||
|
.setHeight(0).setMargin(1);
|
||||||
|
final String asciiArt = QrCodeUtil.generateAsAsciiArt("https://hutool.cn/",qrConfig);
|
||||||
|
Assert.assertNotNull(asciiArt);
|
||||||
|
//Console.log(asciiArt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generateAsciiArtNoCustomColorTest() {
|
||||||
|
final QrConfig qrConfig = QrConfig.of()
|
||||||
|
.setForeColor(null)
|
||||||
|
.setBackColor(null)
|
||||||
|
.setWidth(0)
|
||||||
|
.setHeight(0).setMargin(1);
|
||||||
|
final String asciiArt = QrCodeUtil.generateAsAsciiArt("https://hutool.cn/",qrConfig);
|
||||||
|
Assert.assertNotNull(asciiArt);
|
||||||
|
//Console.log(asciiArt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,6 @@ import java.util.LinkedHashMap;
|
|||||||
* @author Tom Xin
|
* @author Tom Xin
|
||||||
*/
|
*/
|
||||||
public class Ansi8bitMapping extends AnsiLabMapping {
|
public class Ansi8bitMapping extends AnsiLabMapping {
|
||||||
public static final Ansi8bitMapping INSTANCE = new Ansi8bitMapping();
|
|
||||||
|
|
||||||
private static final int[] ANSI_8BIT_COLOR_CODE_LOOKUP = new int[] { 0x000000, 0x800000, 0x008000, 0x808000,
|
private static final int[] ANSI_8BIT_COLOR_CODE_LOOKUP = new int[] { 0x000000, 0x800000, 0x008000, 0x808000,
|
||||||
0x000080, 0x800080, 0x008080, 0xc0c0c0, 0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff,
|
0x000080, 0x800080, 0x008080, 0xc0c0c0, 0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff,
|
||||||
0x00ffff, 0xffffff, 0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
|
0x00ffff, 0xffffff, 0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
|
||||||
@ -40,6 +38,8 @@ public class Ansi8bitMapping extends AnsiLabMapping {
|
|||||||
0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e, 0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada,
|
0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e, 0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada,
|
||||||
0xe4e4e4, 0xeeeeee };
|
0xe4e4e4, 0xeeeeee };
|
||||||
|
|
||||||
|
public static final Ansi8bitMapping INSTANCE = new Ansi8bitMapping();
|
||||||
|
|
||||||
public Ansi8bitMapping() {
|
public Ansi8bitMapping() {
|
||||||
ansiLabMap = new LinkedHashMap<>(256, 1);
|
ansiLabMap = new LinkedHashMap<>(256, 1);
|
||||||
for (int i = 0; i < ANSI_8BIT_COLOR_CODE_LOOKUP.length; i++) {
|
for (int i = 0; i < ANSI_8BIT_COLOR_CODE_LOOKUP.length; i++) {
|
||||||
|
@ -197,6 +197,18 @@ public class ColorUtil {
|
|||||||
return new Color(random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND));
|
return new Color(random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AWT的{@link Color}颜色转换为ANSI颜色,由于取最接近颜色,故可能有色差
|
||||||
|
*
|
||||||
|
* @param rgb RGB颜色
|
||||||
|
* @param is8Bit 是否8bit的ANSI颜色
|
||||||
|
* @param isBackground 是否背景色
|
||||||
|
* @return ANSI颜色
|
||||||
|
*/
|
||||||
|
public static AnsiElement toAnsiColor(int rgb, boolean is8Bit, boolean isBackground) {
|
||||||
|
return toAnsiColor(getColor(rgb), is8Bit, isBackground);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AWT的{@link Color}颜色转换为ANSI颜色,由于取最接近颜色,故可能有色差
|
* AWT的{@link Color}颜色转换为ANSI颜色,由于取最接近颜色,故可能有色差
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user