Java生成二维码后,带logo图片时,需要在新生成的二维码图片中,画对应的logo;带备注信息时,需要先准备一张画布,将画布分为二维码信息和备注信息两部分,一部分画二维码信息,一部分写备注信息。
二维码带logo图片
想做个类似支付宝或微信收款码这样的二维码,二维码中间有用户的图像logo
使用谷歌zxing技术来实现
先看代码,代码中有详细注释
/**
* 生成二维码
* 二维码中内嵌图片logo
* @param content 二维码携带内容信息
* @param width 二维码宽/高
* @param picFormat 二维码图片格式
* @param logoImgPath 内嵌logo图片路径
* @param needCompress logo图片是否压缩
* @return 二维码字节数组
*/
public static byte[] generateQRcodeByte(String content, int width, String picFormat,
String logoImgPath, boolean needCompress) {
// 编码提示信息,设置二维码纠错级别、编码字符、边框等信息
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN, 1);
byte[] codeBytes = null;
try {
// 构造二维字节矩阵,将二位字节矩阵渲染为二维缓存图片
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, width, hints);
BufferedImage sourceImg = toBufferedImage(bitMatrix);
// 读取logo图片,并判断logo图片的宽高必须相等
Image logoImg = ImageIO.read(new File(logoImgPath));
int logoWidth = logoImg.getWidth(null);
int logoHeight = logoImg.getHeight(null);
if (logoWidth != logoHeight) {
return codeBytes;
}
// 对logo图片实施压缩
// 若logo图片宽高大于二维码宽高,必须对logo图片进行压缩
// 否则,过大的照片会撑爆二维码,生成的二维码只能看到部分的logo图片信息
if (needCompress) {
if (logoWidth > LOGO_WIDTH && logoHeight > LOGO_HEIGHT) {
logoWidth = LOGO_WIDTH;
logoHeight = LOGO_HEIGHT;
}
// 创建缩微版本的logo图片
Image image = logoImg.getScaledInstance(logoWidth, logoHeight,
Image.SCALE_SMOOTH);
BufferedImage tag = new BufferedImage(logoWidth, logoHeight,
BufferedImage.TYPE_INT_RGB);
// 绘制缩微版logo图片,并将新的logo图片赋给原logo图片变量
Graphics g = tag.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
logoImg = image;
}
// 在原二维码中计算位置,插入新的logo图片
Graphics2D graph = sourceImg.createGraphics();
int x = (QRCODE_SIZE - logoWidth) / 2;
int y = (QRCODE_SIZE - logoHeight) / 2;
graph.drawImage(logoImg, x, y, logoWidth, logoWidth, null);
Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoWidth, 6, 6);
graph.setStroke(new BasicStroke(3f));
graph.draw(shape);
graph.dispose();
// 定义输出流,将二维缓存图片写到指定输出流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(sourceImg, picFormat, out);
// 将输出流转换为字节数组
codeBytes = out.toByteArray();
} catch (WriterException | IOException e) {
e.printStackTrace();
}
return codeBytes;
}
toBufferedImage( ) 方法与上篇博文相同,这里不再贴代码了。
二维码中内嵌logo图片时,需要先生成二维码图片,然后再将logo图片画到二维码中间,其它的与普通二维码无异。
二维码带备注信息
经常会看到共享单车的二维码下面有一个单车的编号,那么这个带编号的二维码怎么用Java生成呢?
正常生成一个二维码,然后新画一张画布,画布分两块内容,一块画二维码,一块写备注信息就可以啦。
先看看代码实现
/**
* 生成二维码
* 带有备注信息字样
* 二维码的宽高受备注信息字体大小影响,这里没有抽取公共参数
* @throws WriterException
* @throws IOException
*/
public static void generateQRcodeRemark() throws IOException, WriterException {
// 创建输出画布,由于有备注信息,这里个二维码宽高不等
// 通常情况下,建议设置宽高相等
BufferedImage logoReamarkImage = new BufferedImage(300, 325, BufferedImage.TYPE_INT_RGB);
Graphics graphics = logoReamarkImage.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, 300, 325);
graphics.dispose();
// 设置二维码纠错信息
HashMap<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.MARGIN, 0);
// 定义二维码位图矩阵
BitMatrix m = new MultiFormatWriter().encode(CONTENT, BarcodeFormat.QR_CODE, 300, 300,
hints);
BufferedImage imageNew = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < 300; x++) {
for (int y = 0; y < 300; y++) {
imageNew.setRGB(x, y, m.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
// 将生成的二维码转化为像素数组,并将数组写到画布logoReamarkImage上
int[] imageNewArray = new int[300 * 300];
imageNewArray = imageNew.getRGB(0, 0, 300, 300, imageNewArray, 0, 300);
logoReamarkImage.setRGB(0, 0, 300, 300, imageNewArray, 0, 300);
// 设置二维码备注信息
Graphics graphicsText = logoReamarkImage.createGraphics();
graphicsText.setColor(Color.black);
graphicsText.setFont(new Font(null, Font.PLAIN, 18));
graphicsText.drawString("二维码备注", 100, 320);
graphicsText.dispose();
// 定义输出流,将二维缓存图片写到指定输出流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(logoReamarkImage, "jpg", out);
// 二维码图片最终输出
String path = "D:\\DEV_ENV" + File.separator + "image" + File.separator + sf.format(new Date());
File pathDir = new File(path);
if (!pathDir.exists()) {
pathDir.mkdirs();
}
File pathFile = new File(path + File.separator + "qrcodeRemark.jpg");
byte[] fileIo = out.toByteArray();
try {
OutputStream os = new FileOutputStream(pathFile);
os.write(fileIo);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
内容都在代码和注释中了,关键点在于将二维码转化为数组,并重新写到画布上
// 将生成的二维码转化为像素数组,并将数组写到画布logoReamarkImage上
int[] imageNewArray = new int[300 * 300];
imageNewArray = imageNew.getRGB(0, 0, 300, 300, imageNewArray, 0, 300);
logoReamarkImage.setRGB(0, 0, 300, 300, imageNewArray, 0, 300);
执行代码,可以生成二维码