首先上工具類(其實不是所有方法全用到):
1 2 import java.awt.BasicStroke; 3 import java.awt.Graphics; 4 import java.awt.Graphics2D; 5 import java.awt.Image; 6 import java.awt.Shape; 7 import java.awt.geom.RoundRectangle2D; 8 import java.awt.image.BufferedImage; 9 import java.io.File; 10 import java.io.IOException; 11 import java.util.HashMap; 12 import java.util.Hashtable; 13 import java.util.Map; 14 15 import javax.imageio.ImageIO; 16 17 import com.google.zxing.BarcodeFormat; 18 import com.google.zxing.BinaryBitmap; 19 import com.google.zxing.DecodeHintType; 20 import com.google.zxing.EncodeHintType; 21 import com.google.zxing.MultiFormatReader; 22 import com.google.zxing.MultiFormatWriter; 23 import com.google.zxing.NotFoundException; 24 import com.google.zxing.Result; 25 import com.google.zxing.client.j2se.BufferedImageLuminanceSource; 26 import com.google.zxing.client.j2se.MatrixToImageConfig; 27 import com.google.zxing.client.j2se.MatrixToImageWriter; 28 import com.google.zxing.common.BitMatrix; 29 import com.google.zxing.common.HybridBinarizer; 30 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 31 public class ZxingUtil { 32 private ZxingUtil(){} 33 private static final String CHARSET = "utf-8"; 34 private static final String FORMAT_NAME = "JPG"; 35 // 二維碼尺寸 36 private static final int QRCODE_SIZE = 300; 37 // LOGO寬度 38 private static final int WIDTH = 60; 39 // LOGO高度 40 private static final int HEIGHT = 60; 41 /** 42 * 為二維碼圖片增加logo頭像 43 * @see 其原理類似於圖片加水印 44 * @param imagePath 二維碼圖片存放路徑(含文件名) 45 * @param logoPath logo頭像存放路徑(含文件名) 46 */ 47 private static void overlapImage(String imagePath, String logoPath) throws IOException { 48 BufferedImage image = ImageIO.read(new File(imagePath)); 49 int logoWidth = image.getWidth()/5; //設置logo圖片寬度為二維碼圖片的五分之一 50 int logoHeight = image.getHeight()/5; //設置logo圖片高度為二維碼圖片的五分之一 51 int logoX = (image.getWidth()-logoWidth)/2; //設置logo圖片的位置,這里令其居中 52 int logoY = (image.getHeight()-logoHeight)/2; //設置logo圖片的位置,這里令其居中 53 Graphics2D graphics = image.createGraphics(); 54 graphics.drawImage(ImageIO.read(new File(logoPath)), logoX, logoY, logoWidth, logoHeight, null); 55 graphics.dispose(); 56 ImageIO.write(image, imagePath.substring(imagePath.lastIndexOf(".") + 1), new File(imagePath)); 57 } 58 59 60 /** 61 * 生成二維碼 62 * @param content 二維碼內容 63 * @param charset 編碼二維碼內容時采用的字符集(傳null時默認采用UTF-8編碼) 64 * @param imagePath 二維碼圖片存放路徑(含文件名) 65 * @param width 生成的二維碼圖片寬度 66 * @param height 生成的二維碼圖片高度 67 * @param logoPath logo頭像存放路徑(含文件名,若不加logo則傳null即可) 68 * @return 生成二維碼結果(true or false) 69 */ 70 public static boolean encodeQRCodeImage(String content, String charset, String imagePath, int width, int height, String logoPath) { 71 Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); 72 //指定編碼格式 73 //hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); 74 //指定糾錯級別(L--7%,M--15%,Q--25%,H--30%) 75 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 76 //編碼內容,編碼類型(這里指定為二維碼),生成圖片寬度,生成圖片高度,設置參數 77 BitMatrix bitMatrix = null; 78 try { 79 bitMatrix = new MultiFormatWriter().encode(new String(content.getBytes(charset==null?"UTF-8":charset), "ISO-8859-1"), BarcodeFormat.QR_CODE, width, height, hints); 80 } catch (Exception e) { 81 System.out.println("編碼待生成二維碼圖片的文本時發生異常,堆棧軌跡如下"); 82 e.printStackTrace(); 83 return false; 84 } 85 //生成的二維碼圖片默認背景為白色,前景為黑色,但是在加入logo圖像后會導致logo也變為黑白色,至於是什么原因還沒有仔細去讀它的源碼 86 //所以這里對其第一個參數黑色將ZXing默認的前景色0xFF000000稍微改了一下0xFF000001,最終效果也是白色背景黑色前景的二維碼,且logo顏色保持原有不變 87 MatrixToImageConfig config = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF); 88 //這里要顯式指定MatrixToImageConfig,否則還會按照默認處理將logo圖像也變為黑白色(如果打算加logo的話,反之則不須傳MatrixToImageConfig參數) 89 try { 90 MatrixToImageWriter.writeToFile(bitMatrix, imagePath.substring(imagePath.lastIndexOf(".") + 1), new File(imagePath), config); 91 } catch (IOException e) { 92 System.out.println("生成二維碼圖片[" + imagePath + "]時遇到異常,堆棧軌跡如下"); 93 e.printStackTrace(); 94 return false; 95 } 96 //此時二維碼圖片已經生成了,只不過沒有logo頭像,所以接下來根據傳入的logoPath參數來決定是否加logo頭像 97 if(null == logoPath){ 98 return true; 99 }else{ 100 //如果此時最終生成的二維碼不是我們想要的,那么可以擴展MatrixToImageConfig類(反正ZXing提供了源碼) 101 //擴展時可以重寫其writeToFile方法,令其返回toBufferedImage()方法所生成的BufferedImage對象(盡管這種做法未必能解決為題,故需根據實際情景測試) 102 //然后替換這里overlapImage()里面的第一行BufferedImage image = ImageIO.read(new File(imagePath)); 103 //即private static void overlapImage(BufferedImage image, String imagePath, String logoPath) 104 try { 105 //這里不需要判斷logoPath是否指向了一個具體的文件,因為這種情景下overlapImage會拋IO異常 106 overlapImage(imagePath, logoPath); 107 return true; 108 } catch (IOException e) { 109 System.out.println("為二維碼圖片[" + imagePath + "]添加logo頭像[" + logoPath + "]時遇到異常,堆棧軌跡如下"); 110 e.printStackTrace(); 111 return false; 112 } 113 } 114 } 115 116 117 /** 118 * 解析二維碼 119 * @param imagePath 二維碼圖片存放路徑(含文件名) 120 * @param charset 解碼二維碼內容時采用的字符集(傳null時默認采用UTF-8編碼) 121 * @return 解析成功后返回二維碼文本,否則返回空字符串 122 */ 123 public static String decodeQRCodeImage(String imagePath, String charset) { 124 BufferedImage image = null; 125 try { 126 image = ImageIO.read(new File(imagePath)); 127 } catch (IOException e) { 128 e.printStackTrace(); 129 return ""; 130 } 131 if(null == image){ 132 System.out.println("Could not decode QRCodeImage"); 133 return ""; 134 } 135 BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(image))); 136 Map<DecodeHintType, String> hints = new HashMap<DecodeHintType, String>(); 137 hints.put(DecodeHintType.CHARACTER_SET, charset==null ? "UTF-8" : charset); 138 Result result = null; 139 try { 140 result = new MultiFormatReader().decode(bitmap, hints); 141 return result.getText(); 142 } catch (NotFoundException e) { 143 System.out.println("二維碼圖片[" + imagePath + "]解析失敗,堆棧軌跡如下"); 144 e.printStackTrace(); 145 return ""; 146 } 147 } 148 static BufferedImage createImage(String content, String imgPath, 149 boolean needCompress) throws Exception { 150 Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); 151 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 152 hints.put(EncodeHintType.CHARACTER_SET, CHARSET); 153 // hints.put(EncodeHintType.MARGIN, 1); 154 BitMatrix bitMatrix = new MultiFormatWriter().encode(content, 155 BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints); 156 int width = bitMatrix.getWidth(); 157 int height = bitMatrix.getHeight(); 158 BufferedImage image = new BufferedImage(width, height, 159 BufferedImage.TYPE_INT_RGB); 160 for (int x = 0; x < width; x++) { 161 for (int y = 0; y < height; y++) { 162 image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 163 : 0xFFFFFFFF); 164 } 165 } 166 if (imgPath == null || "".equals(imgPath)) { 167 return image; 168 } 169 // 插入圖片 170 ZxingUtil.insertImage(image, imgPath, needCompress); 171 return image; 172 } 173 174 175 /** 176 * 插入LOGO 177 * 178 * @param source 179 * 二維碼圖片 180 * @param imgPath 181 * LOGO圖片地址 182 * @param needCompress 183 * 是否壓縮 184 * @throws Exception 185 */ 186 private static void insertImage(BufferedImage source, String imgPath, 187 boolean needCompress) throws Exception { 188 File file = new File(imgPath); 189 if (!file.exists()) { 190 System.err.println("" + imgPath + " 該文件不存在!"); 191 return; 192 } 193 Image src = ImageIO.read(new File(imgPath)); 194 int width = src.getWidth(null); 195 int height = src.getHeight(null); 196 if (needCompress) { // 壓縮LOGO 197 if (width > WIDTH) { 198 width = WIDTH; 199 } 200 if (height > HEIGHT) { 201 height = HEIGHT; 202 } 203 Image image = src.getScaledInstance(width, height, 204 Image.SCALE_SMOOTH); 205 BufferedImage tag = new BufferedImage(width, height, 206 BufferedImage.TYPE_INT_RGB); 207 Graphics g = tag.getGraphics(); 208 g.drawImage(image, 0, 0, null); // 繪制縮小后的圖 209 g.dispose(); 210 src = image; 211 } 212 // 插入LOGO 213 Graphics2D graph = source.createGraphics(); 214 int x = (QRCODE_SIZE - width) / 2; 215 int y = (QRCODE_SIZE - height) / 2; 216 graph.drawImage(src, x, y, width, height, null); 217 Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6); 218 graph.setStroke(new BasicStroke(3f)); 219 graph.draw(shape); 220 graph.dispose(); 221 } 222 }
而后調用實現:
1 import java.awt.Color; 2 import java.awt.Font; 3 import java.awt.Graphics; 4 import java.awt.Image; 5 import java.awt.image.BufferedImage; 6 import java.io.File; 7 import java.io.FileOutputStream; 8 9 import javax.imageio.ImageIO; 10 11 12 import org.junit.Test; 13 14 import com.sun.image.codec.jpeg.JPEGCodec; 15 import com.sun.image.codec.jpeg.JPEGImageEncoder; 16 17 18 public class generatePicture { 19 20 @Test 21 public void test() { 22 String ewm = "http://t.cn/RSFurq5";//壓縮后的地址,即二維碼地址 23 //頭像地址 24 String logo = "F:\\辦公\\關於項目\\頭像\\朱勝男.jpg"; 25 File logoFile =new File(logo);//頭像 26 // File bgFile =new File("c:\\qr_code.jpg"); 27 //背景圖地址 28 File bgFile =new File("F:\\辦公\\關於項目\\qr_code.jpg"); 29 //生成后的二維碼存放地址 30 String outputPath = "F:/辦公/關於項目/test/test.png"; 31 32 try { 33 BufferedImage biQR = ZxingUtil.createImage(ewm, logo, true); //輸出二維碼到緩沖區 34 //BufferedImage biQR2 = ZxingUtil.encode(ewm, logo, outputPath, true); 35 Image bgSrc = ImageIO.read(bgFile); 36 Image logoSrc = ImageIO.read(logoFile); 37 int width = bgSrc.getWidth(null); 38 int height = bgSrc.getHeight(null); 39 BufferedImage image = new BufferedImage(width, height, 40 BufferedImage.TYPE_INT_RGB); 41 Graphics g = image.createGraphics(); 42 g.drawImage(bgSrc, 0, 0, width, height, null); // 繪制背景圖 43 //g.drawImage(logoSrc, 277, 283, 162,162, null); // 繪制微信頭像logo 44 //參數分別為image,x,y, width, height, x表示離背景圖左邊框距離,y表示離下邊框距離,w和h表示二維碼大小,大致是這樣 45 g.drawImage(biQR, 90, 260, 540, 540, null);// 繪制二維碼 46 g.setColor(Color.BLACK); 47 Font f = new Font("宋體",Font.BOLD,45);//bold表示粗體,后面45是字體大小 48 Color mycolor = new Color(136, 135, 135);//new Color(0, 0, 255); 49 g.setColor(mycolor); 50 g.setFont(f); 51 g.drawString("共享專車",260,840); 52 // g.drawString(("我是"+xm),360,210); 53 // g.drawString("我為元翔專車代言",360,260); 54 g.dispose(); 55 56 FileOutputStream out = new FileOutputStream(outputPath); 57 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); 58 encoder.encode(image); 59 out.close(); 60 } catch (Exception e) { 61 e.printStackTrace(); 62 } 63 } 64 65 }
以上是個人整理之后的,參考鏈接:http://blog.csdn.net/mmm333zzz/article/details/17259513