java大批量生成二維碼
阿新 • • 發佈:2019-01-03
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(); } }