近期一直忙於開發微信商城項目,應客戶要求,要開發個有圖標的二維碼。經過兩次改版,終於實現了該功能(第一次沒有小圖標,這次才整合好的),如下是完整代碼 。
該代碼使用Java7開發,另外使用 core-2.2.jar jar[http://pan.baidu.com/s/1skTwHQ1] 包 。
1 package com.rick.common.utils; 2 3 4 import java.awt.Color; 5 import java.awt.Graphics2D; 6 import java.awt.Image; 7 import java.awt.geom.AffineTransform; 8 import java.awt.image.AffineTransformOp; 9 import java.awt.image.BufferedImage; 10 import java.io.File; 11 import java.io.IOException; 12 import java.util.Date; 13 import java.util.HashMap; 14 import java.util.Map; 15 16 import javax.imageio.ImageIO; 17 18 import com.google.zxing.BarcodeFormat; 19 import com.google.zxing.EncodeHintType; 20 import com.google.zxing.MultiFormatWriter; 21 import com.google.zxing.WriterException; 22 import com.google.zxing.common.BitMatrix; 23 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 24 25 /** 26 * 二維碼生成工具類【帶小圖標】 27 * <br> QRCodeUtils 類的提升版本 28 * @author bxw 29 * @time 2016-07-17 22:13:45 30 * @version v1.1 31 */ 32 public class BarcodeFactory { 33 34 /** 35 * 圖片格式定義 36 * @value Array 37 */ 38 private static String[] IMAGE_TYPE = {"BMP", "bmp", "jpg", "JPG", "wbmp", "jpeg", "png", "PNG", "JPEG", "WBMP", "GIF", "gif","ICON","icon"}; 39 40 /** 41 * 二維碼寬度 42 */ 43 public static final int WIDTH = 260; 44 45 /** 46 * 二維碼高度 47 */ 48 public static final int HEIGHT = 260; 49 50 /** 51 * 圖標寬度 52 */ 53 private static final int IMAGE_WIDTH = 68; 54 /** 55 * 圖標高度 56 */ 57 private static final int IMAGE_HEIGHT = 68; 58 /** 59 * 底圖大小【正方形】 60 */ 61 private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2; 62 /** 63 * 底圖邊框 64 */ 65 private static final int FRAME_WIDTH = 5; 66 67 /** 68 * 二維碼寫碼器 69 */ 70 private static MultiFormatWriter mutiWriter = new MultiFormatWriter(); 71 72 /** 73 * 二維碼生成-方法入口 74 * @param content 內容 75 * @param width 寬度 76 * @param height 高度 77 * @param iconImagePath 圖標原路徑 78 * @param qrcodeImagePath 二維碼存放路徑 79 * @param hasFiller 80 * 比例不對時是否需要補白:true為補白; false為不補白 81 * @return 82 * 成功:返回輸出圖片絕對路徑;失敗:返回null 83 */ 84 public static String encode(String content, int width, int height, 85 String iconImagePath, String qrcodeImagePath,boolean hasFiller) { 86 try { 87 /** 88 * 圖標格式校驗 89 */ 90 File icon = new File(iconImagePath); 91 if(!icon.exists()){ 92 System.err.println("系統找不到圖標所在文件 !"); 93 return null; 94 } 95 String iconFileName = icon.getName(); 96 // 得到上傳文件的擴展名 97 String fileExtName = iconFileName.substring(iconFileName.lastIndexOf(".") + 1); 98 if(!checkIMGType(fileExtName)){ 99 System.err.println("圖標格式有誤 !"); 100 return null; 101 } 102 103 if(width<260||height<260){ 104 width = BarcodeFactory.WIDTH; 105 height = BarcodeFactory.HEIGHT; 106 } 107 ImageIO.write(genBarcode(content, width, height, iconImagePath,hasFiller), 108 "png", new File(qrcodeImagePath)); 109 System.err.println("二維碼已生成 "+qrcodeImagePath); 110 return qrcodeImagePath; 111 } catch (IOException e) { 112 System.err.println("圖片讀取異常 : "+e.getMessage()); 113 } catch (WriterException e) { 114 System.err.println("圖片輸出異常 :"+e.getMessage()); 115 } 116 return null; 117 } 118 119 /** 120 * 圖片處理方法 121 * @param content 122 * @param width 123 * @param height 124 * @param iconImagePath 125 * @param hasFiller 126 * 比例不對時是否需要補白:true為補白; false為不補白; 127 * @return 128 * @throws WriterException 129 * @throws IOException 130 */ 131 private static BufferedImage genBarcode(String content, int width, 132 int height, String iconImagePath,boolean hasFiller) throws WriterException, 133 IOException { 134 // 讀取源圖像 135 BufferedImage scaleImage = scale(iconImagePath, IMAGE_WIDTH, 136 IMAGE_HEIGHT, hasFiller); 137 int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT]; 138 for (int i = 0; i < scaleImage.getWidth(); i++) { 139 for (int j = 0; j < scaleImage.getHeight(); j++) { 140 srcPixels[i][j] = scaleImage.getRGB(i, j); 141 } 142 } 143 144 Map<EncodeHintType, Object> hint = new HashMap<EncodeHintType, Object>(); 145 hint.put(EncodeHintType.CHARACTER_SET, "utf-8"); 146 hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 147 // 生成二維碼 148 BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE, 149 width, height, hint); 150 151 // 二維矩陣轉為一維像素數組 152 int halfW = matrix.getWidth() / 2; 153 int halfH = matrix.getHeight() / 2; 154 int[] pixels = new int[width * height]; 155 156 for (int y = 0; y < matrix.getHeight(); y++) { 157 for (int x = 0; x < matrix.getWidth(); x++) { 158 // 讀取圖片 159 if (x > halfW - IMAGE_HALF_WIDTH 160 && x < halfW + IMAGE_HALF_WIDTH 161 && y > halfH - IMAGE_HALF_WIDTH 162 && y < halfH + IMAGE_HALF_WIDTH) { 163 pixels[y * width + x] = srcPixels[x - halfW 164 + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH]; 165 } 166 // 在圖片四周形成邊框 167 else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH 168 && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH 169 && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH 170 + IMAGE_HALF_WIDTH + FRAME_WIDTH) 171 || (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH 172 && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH 173 && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH 174 + IMAGE_HALF_WIDTH + FRAME_WIDTH) 175 || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH 176 && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH 177 && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH 178 - IMAGE_HALF_WIDTH + FRAME_WIDTH) 179 || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH 180 && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH 181 && y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH 182 + IMAGE_HALF_WIDTH + FRAME_WIDTH)) { 183 pixels[y * width + x] = 0xfffffff; 184 } else { 185 // 此處可以修改二維碼的顏色,可以分別制定二維碼和背景的顏色; 186 pixels[y * width + x] = matrix.get(x, y) ? 0xff000000 187 : 0xfffffff; 188 } 189 } 190 } 191 192 BufferedImage image = new BufferedImage(width, height, 193 BufferedImage.TYPE_INT_RGB); 194 image.getRaster().setDataElements(0, 0, width, height, pixels); 195 196 return image; 197 } 198 199 /** 200 * 把傳入的原始圖像按高度和寬度進行縮放,生成符合要求的圖標 201 * 202 * @param iconImagePath 203 * 小圖標源文件地址 204 * @param height 205 * 目標高度 206 * @param width 207 * 目標寬度 208 * @param hasFiller 209 * 比例不對時是否需要補白:true為補白; false為不補白; 210 * @throws IOException 211 */ 212 private static BufferedImage scale(String iconImagePath, int height, 213 int width, boolean hasFiller) throws IOException { 214 double ratio = 0.0; // 縮放比例 215 File file = new File(iconImagePath); 216 BufferedImage srcImage = ImageIO.read(file); 217 Image destImage = srcImage.getScaledInstance(width, height, 218 BufferedImage.SCALE_SMOOTH); 219 // 計算比例 220 if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) { 221 if (srcImage.getHeight() > srcImage.getWidth()) { 222 ratio = (new Integer(height)).doubleValue() 223 / srcImage.getHeight(); 224 } else { 225 ratio = (new Integer(width)).doubleValue() 226 / srcImage.getWidth(); 227 } 228 AffineTransformOp op = new AffineTransformOp( 229 AffineTransform.getScaleInstance(ratio, ratio), null); 230 destImage = op.filter(srcImage, null); 231 } 232 if (hasFiller) {// 補白 233 BufferedImage image = new BufferedImage(width, height, 234 BufferedImage.TYPE_INT_RGB); 235 Graphics2D graphic = image.createGraphics(); 236 graphic.setColor(Color.white); 237 graphic.fillRect(0, 0, width, height); 238 if (width == destImage.getWidth(null)) 239 graphic.drawImage(destImage, 0, 240 (height - destImage.getHeight(null)) / 2, 241 destImage.getWidth(null), destImage.getHeight(null), 242 Color.white, null); 243 else 244 graphic.drawImage(destImage, 245 (width - destImage.getWidth(null)) / 2, 0, 246 destImage.getWidth(null), destImage.getHeight(null), 247 Color.white, null); 248 graphic.dispose(); 249 destImage = image; 250 System.err.println("INFO 圖標補白已完成 "); 251 } 252 return (BufferedImage) destImage; 253 } 254 255 /** 256 * 圖片格式校驗 257 * @param fileExtName 258 * @return 259 */ 260 private static boolean checkIMGType(String fileExtName){ 261 boolean flag = false; 262 for (String type : IMAGE_TYPE) { 263 //-- 圖片格式正確 264 if(type.toLowerCase().equals(fileExtName.toLowerCase())){ 265 flag = true; 266 break; 267 } 268 } 269 //------------圖片格式校驗結束 270 return flag; 271 } 272 273 /** 274 * 測試主方法入口 275 * @param args 276 */ 277 public static void main(String[] args) { 278 String codeIconPath = "C:/Users/rick/Desktop/1.jpg"; 279 String codePath = "C:/Users/rick/Desktop/"+new Date().getTime()+".png"; 280 281 /** 282 * 測試方法入口 283 */ 284 BarcodeFactory.encode("項目:晚餐定制",300, 300, codeIconPath, codePath,false); 285 } 286 }
著名: 代碼只作為學習用途,謝謝 !