java生成二维码代码,并且插入logo,因为要大批量生成,所以加入了线程池以及队列,并且尽可能的减少了代码内部的计算,在提高代码效率时发现几点注意事项
1.内部logo图尽量使用恰好大小的,否则需要压缩图片会增加许多不必要的计算。
2.二维码的宽高很大的影响生成速度,200x200px 与600x600px之间速度能差将近10倍,不完全测试 200x200px生成每千张可达到10s以下
3.加了一个简单的读图缓存,但是效果貌似没那么明显。。。就当是心理作用好了
删除了其中的一些业务逻辑,但是核心代码都在这里,如有错误欢迎指出。
import javax.imageio.ImageIO;
//logo线程
public class LogoThread implements Runnable{
private File file;
private String name;
private int height;
private int width;
private int dw;
@Override
public void run() {
BufferedImage image;
long start = 0;
try {
start = System.currentTimeMillis();
image = QRCodeUtil.createImage(QRCodeUtil.URL+name,QRCodeUtil.LogoPath,width,height,dw);
ImageIO.write(image,"png",file);
file=null;
image=null;
if(QRCodeUtil.DEBUG){
}
} catch (Exception e) {
e.printStackTrace();
}
}
public File getFile() {
return file;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setFile(File file) {
this.file = file;
}
public int getDw() {
return dw;
}
public void setDw(int dw) {
this.dw = dw;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
}
</pre><pre name="code" class="java">
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
/**
* 二维码工具类
*
*/
public class QRCodeUtil {
private static Map<String, Image> picCache = new HashMap<String, Image>();
// 容错率
private static final double rate = 0.30;
private static final ErrorCorrectionLevel E_RATE = ErrorCorrectionLevel.L;
// 二维码宽
private static final int QRCODE_WIDTH = 200;
// 二维码高
private static final int QRCODE_HEIGHT = 200;// 默认宽高相同
// logo地址
public static final String LogoPath = "D:" + File.separator + "xiaojuhua.jpg";
// 二维码url地址
public static final String URL = "http://test.com?param=";
// 生成路径
private static final String rootPath = "D:" + File.separator + "picFolder2";
// 是否debug
public static final boolean DEBUG = false;
public static void main(String[] args) throws IOException,
InterruptedException {
double d_w = Math.sqrt(QRCODE_WIDTH * QRCODE_HEIGHT * rate) / 2; // 计算内部logo宽
int dw = (int) d_w;
BlockingQueue queue = new ArrayBlockingQueue(40);
ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 8, 1,
TimeUnit.DAYS, queue);
int max=10000000;
String str_j = "";
for (int j = 0; j < max; j++) {
try {
if (executor.getQueue().size() > 30) {
Thread.sleep(200);
}
str_j = String.valueOf(j+1);
File f1 = new File(rootPath + File.separator
+ str_j.substring(0, 3) + File.separator
+ str_j.substring(3, 6));
if (!f1.exists()) {
f1.mkdirs();
}
File f2 = new File(f1, str_j + ".png");
LogoThread lt = new LogoThread();
lt.setFile(f2);
lt.setName(str_j);
lt.setDw(dw);
lt.setWidth(QRCODE_WIDTH);
lt.setHeight(QRCODE_HEIGHT);
executor.execute(lt);
Thread.sleep(20);
if (DEBUG) {
System.out.println("线程池中线程数目:"+executor.getPoolSize()+
",队列中等待执行的任务数目:"+
executor.getQueue().size()+",已执行玩别的任务数目:"
+executor.getCompletedTaskCount());
System.out.println(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory());
}
} catch (Exception e) {
System.out.println(e.getMessage() + "," + str_j);
Thread.sleep(500);
continue;
}
}
executor.shutdown();
}
/**
* 创建二维码
*
* @param content
* 文字内容
* @param imgPath
* 读取logo图片路径
* @param QRCODE_WIDTH
* 二维码宽
* @param QRCODE_HEIGHT
* 二维码高
* @param dw
* 内部logo宽
* @return
* @throws Exception
*/
public static BufferedImage createImage(String content, String imgPath,
int QRCODE_WIDTH, int QRCODE_HEIGHT, int dw) throws Exception {
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
hints.put(EncodeHintType.ERROR_CORRECTION, E_RATE);
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
BarcodeFormat.QR_CODE, QRCODE_WIDTH, QRCODE_HEIGHT, hints);
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
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);
}
}
// 插入logo
QRCodeUtil.insertImage(image, imgPath, QRCODE_WIDTH, QRCODE_HEIGHT, dw);
return image;
}
/**
* 插入LOGO
*
* @param source
* 二维码图片
* @param imgPath
* LOGO图片地址
* @throws Exception
*/
private static void insertImage(BufferedImage source, String imgPath,
int QRCODE_WIDTH, int QRCODE_HEIGHT, int dw) throws Exception {
Image src;
if (picCache.get("cache") != null) {
src = picCache.get("cache");
} else {
File file = new File(imgPath);
if (!file.exists()) {
System.err.println("" + imgPath + " 该文件不存在!");
return;
}
src = ImageIO.read(new File(imgPath));
picCache.put("cache", src);// 缓存
System.out.println("未读缓存");
}
/*
* double d_w=Math.sqrt(QRCODE_WIDTH*QRCODE_HEIGHT*rate)/2; int
* int_w=(int)d_w;
*/
// double d_h=Math.sqrt(QRCODE_WIDTH*QRCODE_HEIGHT*rate)/2.5;
Image image = src.getScaledInstance(dw, dw, Image.SCALE_SMOOTH);
BufferedImage tag = new BufferedImage(dw, dw,
BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(image, 0, 0, null); // 绘制缩小后的图
g.dispose();
src = image;
// 插入LOGO
Graphics2D graph = source.createGraphics();
int x = (QRCODE_WIDTH - dw) / 2;
// int y = (QRCODE_HEIGHT - int_w) / 2;
graph.drawImage(src, x, x, dw, dw, null); // y
Shape shape = new RoundRectangle2D.Float(x, x, dw, dw, 6, 6);// y
graph.setStroke(new BasicStroke(12f));
graph.draw(shape);
graph.dispose();
}
}