目标
- 使用谷歌zxing生成带有logo二维码
- 便捷地解决二维码中文乱码问题
过程
- 下载依赖:
maven坐标:
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.3</version>
</dependency>
- 编写java代码生成二维码,并绘制logo
public static void drawQrCode(String qrUrl, String logoUrl, String outputPath, String note, int width, int height) throws Exception{
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
BitMatrix bitMatrix = multiFormatWriter.encode(qrUrl, BarcodeFormat.QR_CODE, width, height, new HashMap<EncodeHintType, Object>() {
private static final long serialVersionUID = 1L;
{
put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
put(EncodeHintType.CHARACTER_SET, "UTF-8");
put(EncodeHintType.MARGIN, 0);
}
});
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
if (logoUrl != null && !"".equals(logoUrl) ){
Graphics2D graphics = image.createGraphics();
BufferedImage logoImg = ImageIO.read( new URL(logoUrl) );
graphics.drawImage(logoImg, width * 2 / 6, height * 2 / 6, width * 3 / 10, height * 3 / 10, null);
graphics.dispose();
logoImg.flush();
}
if (note != null && !"".equals(note)){
BufferedImage outImage = new BufferedImage(width, height + 45, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D outGraphics = outImage.createGraphics();
outGraphics.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
outGraphics.setColor(Color.BLACK);
outGraphics.setFont( new Font("Arial", Font.BOLD, 26) );
int noteWidth = outGraphics.getFontMetrics().stringWidth(note);
outGraphics.drawString(new QrCodeAttributedCharacter(note), (width - noteWidth) / 2, image.getHeight() + (outImage.getHeight() - image.getHeight()) / 2 + 12);
outGraphics.dispose();
outImage.flush();
image = outImage;
}
image.flush();
ImageIO.write(image, "png", Paths.get(outputPath).toFile());
}
- 编写QrCodeAttributedCharacter解决中文乱码问题
public class QrCodeAttributedCharacter implements AttributedCharacterIterator {
private int index;
private char[] textChars;
public QrCodeAttributedCharacter(String text) {
this.textChars = text.toCharArray();
}
@Override
public int getRunStart() {
return 0;
}
@Override
public int getRunStart(Attribute attribute) {
return 0;
}
@Override
public int getRunStart(Set<? extends Attribute> attributes) {
return 0;
}
@Override
public int getRunLimit() {
return this.textChars.length;
}
@Override
public int getRunLimit(Attribute attribute) {
return this.textChars.length;
}
@Override
public int getRunLimit(Set<? extends Attribute> attributes) {
return this.textChars.length;
}
@Override
public Map<Attribute, Object> getAttributes() {
return Collections.EMPTY_MAP;
}
@Override
public Object getAttribute(Attribute attribute) {
return Collections.EMPTY_MAP;
}
@Override
public Set<Attribute> getAllAttributeKeys() {
return Collections.EMPTY_SET;
}
@Override
public char first() {
this.index = 0;
return this.textChars[0];
}
@Override
public char last() {
return this.textChars[ this.textChars.length - 1 ];
}
@Override
public char current() {
return this.textChars[this.index];
}
@Override
public char next() {
if (this.index == this.textChars.length - 1){
return CharacterIterator.DONE;
}
return this.textChars[ ++this.index ];
}
@Override
public char previous() {
if (this.index == 0){
return CharacterIterator.DONE;
}
return this.textChars[this.index - 1];
}
@Override
public char setIndex(int position) {
this.index = position;
return textChars[position];
}
@Override
public int getBeginIndex() {
return 0;
}
@Override
public int getEndIndex() {
return this.textChars.length;
}
@Override
public int getIndex() {
return this.index;
}
@Override
public Object clone() {
return new String(textChars);
}
}
- 中文乱码问题分析与解决依据
- 乱码原因:
通过查看zxing的Encoder类可以发现默认编码方式是ISO-8859-1。
- 通过新建QrCodeAttributedCharacter类修复乱码问题原理.
进入Graphics2D的drawString(AttributedCharacterIterator iterator, int x, int y)方法找到其读取字符串内容逻辑如下:
从图中可以看出其是通过调用AttributedCharacterIterator的实现类的方法来获取字符串内容的,因此可以通过实现AttributedCharacterIterator接口来控制获取的字符串内容。
测试
- 测试代码:
public static void main(String[] args) throws Exception {
String qrUrl = "https://blog.csdn.net/qq_41633199";
String logoUrl = "http://www.finac.site/logo.png";
String outputPath = "B:\\logo.jpg";
drawQrCode(qrUrl, logoUrl, outputPath, "博文地址", 400, 400);
}
- 测试结果: