首先上工具类(其实不是所有方法全用到):
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