1.首先引入maven依赖:
1 <dependency> 2 <groupId>com.google.zxing</groupId> 3 <artifactId>core</artifactId> 4 <optional>true</optional> 5 </dependency> 6 <dependency> 7 <groupId>com.google.zxing</groupId> 8 <artifactId>javase</artifactId> 9 <optional>true</optional> 10 </dependency>
2.直接上代码:
1 package itfeng.util; 2 3 import java.awt.Color; 4 import java.awt.Graphics2D; 5 import java.awt.Image; 6 import java.awt.geom.AffineTransform; 7 import java.awt.image.AffineTransformOp; 8 import java.awt.image.BufferedImage; 9 import java.io.File; 10 import java.io.IOException; 11 import java.io.OutputStream; 12 import java.net.HttpURLConnection; 13 import java.net.URL; 14 import java.nio.file.Path; 15 import java.util.HashMap; 16 import java.util.Hashtable; 17 18 import javax.imageio.ImageIO; 19 20 import com.google.zxing.BarcodeFormat; 21 import com.google.zxing.BinaryBitmap; 22 import com.google.zxing.DecodeHintType; 23 import com.google.zxing.EncodeHintType; 24 import com.google.zxing.MultiFormatReader; 25 import com.google.zxing.MultiFormatWriter; 26 import com.google.zxing.Result; 27 import com.google.zxing.WriterException; 28 import com.google.zxing.client.j2se.BufferedImageLuminanceSource; 29 import com.google.zxing.client.j2se.MatrixToImageWriter; 30 import com.google.zxing.common.BitMatrix; 31 import com.google.zxing.common.HybridBinarizer; 32 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 33 34 public class QRcodeUtil { 35 36 //注意:图片的宽度和高度占比会影响生成的二维码内容是否解析成功 37 private static final int IMAGE_WIDTH = 120; 38 39 private static final int IMAGE_HEIGHT = 120; 40 41 private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2; 42 43 private static final int FRAME_WIDTH = 0; 44 45 private static final String IMAGE_FORMAT = "jpg"; 46 47 //二维码外边距 48 private static final int IMAGE_MARGIN = 0; 49 50 private static final String CHARSET = "UTF-8"; 51 52 // 二维码写码器 53 private static MultiFormatWriter mutiWriter = new MultiFormatWriter(); 54 55 public static void main(String[] args) throws Exception { 56 encode("https://hanyu.baidu.com/s?wd=%E7%99%BD%E6%97%A5%E6%A2%A6", 300, 300, "D:/cow.jpg", 57 "D:/cow二维码.jpg");//"D:/jjsd.jpg" 58 System.out.println("二维码生成完毕!"); 59 System.out.println(decode("D:/cow二维码.jpg")); 60 } 61 62 @SuppressWarnings({ "rawtypes", "unchecked" }) 63 public static String decode(File file) throws Exception { 64 BufferedImage image; 65 image = ImageIO.read(file); 66 if (image == null) { 67 return null; 68 } 69 BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image); 70 BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); 71 Result result; 72 Hashtable hints = new Hashtable(); 73 hints.put(DecodeHintType.CHARACTER_SET, CHARSET); 74 result = new MultiFormatReader().decode(bitmap, hints); 75 String resultStr = result.getText(); 76 return resultStr; 77 } 78 79 public static String decode(String path) throws Exception { 80 return decode(new File(path)); 81 } 82 83 /** 84 * 85 * @param content 86 * 二维码显示的文本 87 * @param width 88 * 二维码的宽度 89 * @param height 90 * 二维码的高度 91 * @param srcImagePath 92 * 中间嵌套的图片 93 * @param destImagePath 94 * 二维码生成的地址 95 */ 96 public static void encode(String content, int width, int height, String srcImagePath, 97 String destImagePath) { 98 try { 99 if (null != srcImagePath) { 100 ImageIO.write(genBarcode(content, width, height, srcImagePath), IMAGE_FORMAT, 101 new File(destImagePath)); 102 } else { 103 // 定义二维码的参数 104 HashMap<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); 105 // 定义字符集编码格式 106 hints.put(EncodeHintType.CHARACTER_SET, CHARSET); 107 // 纠错的等级 L > M > Q > H 纠错的能力越高可存储的越少,一般使用M 108 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); 109 // 设置图片边距 110 hints.put(EncodeHintType.MARGIN, IMAGE_MARGIN); 111 BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, 112 width, height, hints); 113 Path file = new File(destImagePath).toPath(); 114 MatrixToImageWriter.writeToPath(matrix, IMAGE_FORMAT, file); 115 } 116 } catch (IOException e) { 117 e.printStackTrace(); 118 } catch (WriterException e) { 119 e.printStackTrace(); 120 } 121 } 122 123 /** 124 * 125 * @param content 126 * 二维码显示的文本 127 * @param width 128 * 二维码的宽度 129 * @param height 130 * 二维码的高度 131 * @param srcImagePath 132 * 中间嵌套的路径 133 * @param out 134 * 输入到流中 135 */ 136 public static void encode(String content, int width, int height, String srcImagePath, 137 OutputStream out) { 138 try { 139 if (null != srcImagePath) { 140 ImageIO.write(genBarcode(content, width, height, srcImagePath), IMAGE_FORMAT, out); 141 } else { 142 143 // 定义二维码的参数 144 HashMap<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); 145 // 定义字符集编码格式 146 hints.put(EncodeHintType.CHARACTER_SET, CHARSET); 147 // 纠错的等级 L > M > Q > H 纠错的能力越高可存储的越少,一般使用M 148 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); 149 // 设置图片边距 150 hints.put(EncodeHintType.MARGIN, IMAGE_MARGIN); 151 BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, 152 width, height, hints); 153 MatrixToImageWriter.writeToStream(matrix, IMAGE_FORMAT, out); 154 } 155 } catch (IOException e) { 156 e.printStackTrace(); 157 } catch (WriterException e) { 158 e.printStackTrace(); 159 } 160 } 161 162 /** 163 * 得到BufferedImage 164 * 165 * @param content 166 * 二维码显示的文本 167 * @param width 168 * 二维码的宽度 169 * @param height 170 * 二维码的高度 171 * @param srcImagePath 172 * 中间嵌套的图片 173 * @return 174 * @throws WriterException 175 * @throws IOException 176 */ 177 @SuppressWarnings({ "rawtypes", "unchecked" }) 178 private static BufferedImage genBarcode(String content, int width, int height, 179 String srcImagePath) throws WriterException, IOException { 180 // 读取源图像 181 BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH, IMAGE_HEIGHT, true); 182 183 int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT]; 184 for (int i = 0; i < scaleImage.getWidth(); i++) { 185 for (int j = 0; j < scaleImage.getHeight(); j++) { 186 srcPixels[i][j] = scaleImage.getRGB(i, j); 187 } 188 } 189 Hashtable hint = new Hashtable(); 190 hint.put(EncodeHintType.CHARACTER_SET, CHARSET); 191 hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 192 hint.put(EncodeHintType.MARGIN, IMAGE_MARGIN); 193 // 生成二维码 194 BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hint); 195 196 // 二维矩阵转为一维像素数组 197 int halfW = matrix.getWidth() / 2; 198 int halfH = matrix.getHeight() / 2; 199 int[] pixels = new int[width * height]; 200 201 // System.out.println(matrix.getHeight()); 202 for (int y = 0; y < matrix.getHeight(); y++) { 203 for (int x = 0; x < matrix.getWidth(); x++) { 204 // 读取图片 205 if (x > halfW - IMAGE_HALF_WIDTH && x < halfW + IMAGE_HALF_WIDTH 206 && y > halfH - IMAGE_HALF_WIDTH && y < halfH + IMAGE_HALF_WIDTH) { 207 pixels[y * width + x] = srcPixels[x - halfW + IMAGE_HALF_WIDTH][y - halfH 208 + IMAGE_HALF_WIDTH]; 209 } 210 // 在图片四周形成边框 211 else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH 212 && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH 213 && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH 214 && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH) 215 || (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH 216 && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH 217 && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH 218 && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH) 219 || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH 220 && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH 221 && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH 222 && y < halfH - IMAGE_HALF_WIDTH + FRAME_WIDTH) 223 || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH 224 && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH 225 && y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH 226 && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH)) { 227 pixels[y * width + x] = 0xfffffff; 228 } else { 229 // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色; 230 pixels[y * width + x] = matrix.get(x, y) ? 0xff000000 : 0xfffffff; 231 } 232 } 233 } 234 235 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 236 image.getRaster().setDataElements(0, 0, width, height, pixels); 237 238 return image; 239 } 240 241 /** 242 * 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标 243 * 244 * @param srcImageFile 245 * 源文件地址 246 * @param height 247 * 目标高度 248 * @param width 249 * 目标宽度 250 * @param hasFiller 251 * 比例不对时是否需要补白:true为补白; false为不补白; 252 * @throws IOException 253 */ 254 private static BufferedImage scale(String srcImageFile, int height, int width, 255 boolean hasFiller) throws IOException { 256 double ratio = 0.0; // 缩放比例 257 258 // URL url = new URL(srcImageFile); 259 // HttpURLConnection httpUrl = (HttpURLConnection) url.openConnection(); 260 // httpUrl.connect(); 261 262 File file = new File(srcImageFile); 263 BufferedImage srcImage = ImageIO.read(file); 264 // BufferedImage srcImage = ImageIO.read(httpUrl.getInputStream()); 265 Image destImage = srcImage.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH); 266 // 计算比例 267 if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) { 268 if (srcImage.getHeight() > srcImage.getWidth()) { 269 ratio = (new Integer(height)).doubleValue() / srcImage.getHeight(); 270 } else { 271 ratio = (new Integer(width)).doubleValue() / srcImage.getWidth(); 272 } 273 AffineTransformOp op = new AffineTransformOp( 274 AffineTransform.getScaleInstance(ratio, ratio), null); 275 destImage = op.filter(srcImage, null); 276 } 277 if (hasFiller) {// 补白 278 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 279 Graphics2D graphic = image.createGraphics(); 280 graphic.setColor(Color.white); 281 graphic.fillRect(0, 0, width, height); 282 if (width == destImage.getWidth(null)) 283 graphic.drawImage(destImage, 0, (height - destImage.getHeight(null)) / 2, 284 destImage.getWidth(null), destImage.getHeight(null), Color.white, null); 285 else 286 graphic.drawImage(destImage, (width - destImage.getWidth(null)) / 2, 0, 287 destImage.getWidth(null), destImage.getHeight(null), Color.white, null); 288 graphic.dispose(); 289 destImage = image; 290 } 291 return (BufferedImage) destImage; 292 } 293 }
最终生成的二维码: