二维码工具类,提供多种生成二维码、解析二维码的方法,包括中间logo的二维码等方法。
源码如下:(点击下载 - QrcodeUtils.java、MatrixToImageWriterEx.java、MatrixToLogoImageConfig.java、commons-io-2.4.jar、commons-lang-2.6.jar、slf4j-api-1.7.12.jar、javase-3.1.0.jar、core-3.1.0.jar 、FolderUtils.java)
QrcodeUtils.java 源码:
1 import java.awt.Color; 2 import java.awt.image.BufferedImage; 3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.File; 6 import java.io.FileInputStream; 7 import java.io.FileNotFoundException; 8 import java.io.FileOutputStream; 9 import java.io.IOException; 10 import java.io.InputStream; 11 import java.io.OutputStream; 12 import java.net.URL; 13 import java.util.HashMap; 14 import java.util.Map; 15 import java.util.UUID; 16 import javax.imageio.ImageIO; 17 import org.apache.commons.io.FilenameUtils; 18 import org.apache.commons.io.IOUtils; 19 import org.apache.commons.lang.ArrayUtils; 20 import org.apache.commons.lang.StringUtils; 21 import org.apache.commons.lang.SystemUtils; 22 import org.slf4j.Logger; 23 import org.slf4j.LoggerFactory; 24 import com.google.zxing.BinaryBitmap; 25 import com.google.zxing.DecodeHintType; 26 import com.google.zxing.LuminanceSource; 27 import com.google.zxing.MultiFormatReader; 28 import com.google.zxing.Reader; 29 import com.google.zxing.ReaderException; 30 import com.google.zxing.client.j2se.BufferedImageLuminanceSource; 31 import com.google.zxing.client.j2se.MatrixToImageWriter; 32 import com.google.zxing.common.BitMatrix; 33 import com.google.zxing.common.HybridBinarizer; 34 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 35 36 /** 37 * 二维码工具类 38 * 39 */ 40 public class QrcodeUtils { 41 42 private static final transient Logger LOGGER = LoggerFactory.getLogger(QrcodeUtils.class); 43 44 private static transient String DEFAULT_FORMAT = "jpg"; 45 private static transient int DEFAULT_WIDTH = 200; 46 private static transient int DEFAULT_HEIGHT = 200; 47 48 static { 49 try { 50 final String[] foo = new String[] { "240", "240" }; 51 final String format = "jpg"; 52 if (StringUtils.isNotBlank(format)) { 53 DEFAULT_FORMAT = StringUtils.strip(format).toLowerCase(); 54 } 55 56 if (ArrayUtils.isNotEmpty(foo) && foo.length == 2) { 57 Integer tmpWidth = Integer.valueOf(foo[0]); 58 Integer tmpHeight = Integer.valueOf(foo[1]); 59 if (tmpWidth > 0 && tmpHeight > 0) { 60 DEFAULT_WIDTH = tmpWidth; 61 DEFAULT_HEIGHT = tmpHeight; 62 } else { 63 LOGGER.warn("qrcode size must be lager than zero."); 64 } 65 } 66 } catch (Throwable e) { 67 LOGGER.warn("read default qrcode size config error: ", e); 68 } 69 } 70 71 /** 72 * 生成二维码(无中间logo) 73 * 74 * @param content 75 * 二维码文本内容 76 * @param destFile 77 * 输出文件 78 */ 79 public static final void gen(final String content, File destFile) throws Exception { 80 gen(content, destFile, DEFAULT_WIDTH, DEFAULT_HEIGHT); 81 } 82 83 /** 84 * 生成二维码 85 * 86 * @param content 87 * 二维码文本内容 88 * @param destFile 89 * 目的文件 90 * @param logoFile 91 * 中间logo文件 92 * 93 */ 94 public static final void gen(final String content, final File destFile, final File logoFile) throws Exception { 95 gen(content, destFile, logoFile, DEFAULT_WIDTH, DEFAULT_HEIGHT); 96 } 97 98 /** 99 * 生成二维码 100 * 101 * @param content 102 * 二维码文本内容 103 * @param destFile 104 * 目的文件 105 * @param logoFile 106 * 中间logo文件 107 * @param width 108 * 宽度 109 * @param height 110 * 高度 111 */ 112 public static final void gen(final String content, final File destFile, 113 final File logoFile, int width, int height) throws Exception { 114 FolderUtils.mkdirs(destFile.getParent()); 115 OutputStream output = null; 116 InputStream input = null; 117 try { 118 output = new BufferedOutputStream(new FileOutputStream(destFile)); 119 if (logoFile != null && logoFile.exists() && logoFile.isFile()) { 120 input = new BufferedInputStream(new FileInputStream(logoFile)); 121 } 122 gen(content, output, input, width, height); 123 } catch (FileNotFoundException e) { 124 e.printStackTrace(); 125 throw new Exception(e); 126 } finally { 127 IOUtils.closeQuietly(output); 128 IOUtils.closeQuietly(input); 129 } 130 } 131 132 /** 133 * 生成二维码(无中间logo) 134 * 135 * @param content 136 * 二维码文本内容 137 * @param destFile 138 * 输出文件 139 * @param width 140 * 宽度 141 * @param height 142 * 高度 143 */ 144 public static final void gen(final String content, File destFile, int width, int height) throws Exception { 145 FolderUtils.mkdirs(destFile.getParent()); 146 OutputStream output = null; 147 try { 148 output = new BufferedOutputStream(new FileOutputStream(destFile)); 149 gen(content, output, width, height); 150 } catch (FileNotFoundException e) { 151 e.printStackTrace(); 152 throw new Exception(e); 153 } catch (Exception e) { 154 throw e; 155 } finally { 156 IOUtils.closeQuietly(output); 157 } 158 } 159 160 /** 161 * 生成二维码 162 * 163 * @param content 164 * 二维码文本内容 165 * @param output 166 * 输出流 167 */ 168 public static final void gen(final String content, final OutputStream output) throws Exception { 169 gen(content, output, DEFAULT_WIDTH, DEFAULT_HEIGHT); 170 } 171 172 /** 173 * 生成二维码 174 * 175 * @param content 176 * 二维码文本内容 177 * @param output 178 * 输出流 179 * @param logoInput 180 * 中间logo输入流,为空时中间无logo 181 */ 182 public static final void gen(final String content, 183 final OutputStream output, final InputStream logoInput) throws Exception { 184 gen(content, output, logoInput, DEFAULT_WIDTH, DEFAULT_HEIGHT); 185 } 186 187 /** 188 * 生成二维码 189 * 190 * @param content 191 * 二维码文本内容 192 * @param output 193 * 输出流 194 * @param logoInput 195 * 中间logo输入流,为空时中间无logo 196 * @param width 197 * 宽度 198 * @param height 199 * 高度 200 */ 201 public static final void gen(final String content, 202 final OutputStream output, final InputStream logoInput, int width, int height) throws Exception { 203 gen(content, output, logoInput, width, height, ErrorCorrectionLevel.M); 204 } 205 206 /** 207 * 生成二维码 208 * 209 * @param content 210 * 二维码文本内容 211 * @param output 212 * 输出流 213 * @param logoInput 214 * 中间logo输入流,为空时中间无logo 215 * @param width 216 * 宽度 217 * @param height 218 * 高度 219 * @param errorCorrectionLevel 220 * 容错级别 221 */ 222 public static final void gen(final String content, 223 final OutputStream output, final InputStream logoInput, int width, 224 int height, ErrorCorrectionLevel errorCorrectionLevel) throws Exception { 225 if (StringUtils.isEmpty(content)) { 226 throw new IllegalArgumentException("qr code content cannot be empty."); 227 } 228 if (output == null) { 229 throw new IllegalArgumentException("qr code output stream cannot be null."); 230 } 231 232 final BitMatrix matrix = MatrixToImageWriterEx.createQRCode(content, width, height, errorCorrectionLevel); 233 234 if (logoInput == null) { 235 try { 236 MatrixToImageWriter.writeToStream(matrix, DEFAULT_FORMAT, output); 237 return; 238 } catch (IOException e) { 239 e.printStackTrace(); 240 throw new Exception(e); 241 } 242 } 243 244 final MatrixToLogoImageConfig logoConfig = new MatrixToLogoImageConfig(Color.BLUE, 4); 245 246 final String destPath = FilenameUtils.normalizeNoEndSeparator(SystemUtils.getJavaIoTmpDir() 247 + File.separator + UUID.randomUUID().toString() 248 + ".tmp"); 249 InputStream tmpInput = null; 250 final File destFile = new File(destPath); 251 try { 252 MatrixToImageWriterEx.writeToFile(matrix, DEFAULT_FORMAT, destPath, logoInput, logoConfig); 253 tmpInput = new BufferedInputStream(new FileInputStream(destFile)); 254 IOUtils.copy(tmpInput, output); 255 } catch (IOException e) { 256 e.printStackTrace(); 257 throw new Exception(e); 258 } finally { 259 IOUtils.closeQuietly(tmpInput); 260 destFile.delete(); 261 } 262 } 263 264 /** 265 * 生成二维码 266 * 267 * @param content 268 * 二维码文本内容 269 * @param output 270 * 输出流 271 * @param width 272 * 宽度 273 * @param height 274 * 高度 275 */ 276 public static final void gen(final String content, final OutputStream output, int width, int height) throws Exception { 277 gen(content, output, null, width, height); 278 } 279 280 /** 281 * 生成二维码 282 * 283 * @param content 284 * 二维码文本内容 285 * @param destPath 286 * 输出文件路径 287 */ 288 public static final void gen(final String content, final String destPath) throws Exception { 289 gen(content, destPath, DEFAULT_WIDTH, DEFAULT_HEIGHT); 290 } 291 292 /** 293 * 生成二维码 294 * 295 * @param content 296 * 二维码文本内容 297 * @param destPath 298 * 输出文件路径 299 * @param width 300 * 宽度 301 * @param height 302 * 高度 303 */ 304 public static final void gen(final String content, final String destPath, int width, int height) throws Exception { 305 gen(content, new File(destPath), width, height); 306 } 307 308 /** 309 * 生成二维码 310 * 311 * @param content 312 * 二维码文本内容 313 * @param destPath 314 * 目的文件路径 315 * @param logoPath 316 * 中间logo文件路径 317 */ 318 public static final void gen(final String content, final String destPath, final String logoPath) throws Exception { 319 gen(content, destPath, logoPath, DEFAULT_WIDTH, DEFAULT_HEIGHT); 320 } 321 322 /** 323 * 生成二维码 324 * 325 * @param content 326 * 二维码文本内容 327 * @param destPath 328 * 目的文件路径 329 * @param logoPath 330 * 中间logo文件路径 331 * @param width 332 * 宽度 333 * @param height 334 * 高度 335 */ 336 public static final void gen(final String content, final String destPath, 337 final String logoPath, int width, int height) throws Exception { 338 File foo = new File(destPath); 339 File bar = new File(logoPath); 340 gen(content, foo, bar, width, height); 341 } 342 343 /** 344 * 解析二维码 345 * 346 * @param input 347 * 二维码输入流 348 */ 349 public static final String parse(InputStream input) throws Exception { 350 Reader reader = null; 351 BufferedImage image; 352 try { 353 image = ImageIO.read(input); 354 if (image == null) { 355 throw new Exception("cannot read image from inputstream."); 356 } 357 final LuminanceSource source = new BufferedImageLuminanceSource(image); 358 final BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); 359 final Map<DecodeHintType, String> hints = new HashMap<DecodeHintType, String>(); 360 hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); 361 // 解码设置编码方式为:utf-8, 362 reader = new MultiFormatReader(); 363 return reader.decode(bitmap, hints).getText(); 364 } catch (IOException e) { 365 e.printStackTrace(); 366 throw new Exception("parse QR code error: ", e); 367 } catch (ReaderException e) { 368 e.printStackTrace(); 369 throw new Exception("parse QR code error: ", e); 370 } 371 } 372 373 /** 374 * 解析二维码 375 * 376 * @param url 377 * 二维码url 378 */ 379 public static final String parse(URL url) throws Exception { 380 InputStream in = null; 381 try { 382 in = url.openStream(); 383 return parse(in); 384 } catch (IOException e) { 385 e.printStackTrace(); 386 throw new Exception("parse QR code error: ", e); 387 } finally { 388 IOUtils.closeQuietly(in); 389 } 390 } 391 392 /** 393 * 解析二维码 394 * 395 * @param file 396 * 二维码图片文件 397 */ 398 public static final String parse(File file) throws Exception { 399 InputStream in = null; 400 try { 401 in = new BufferedInputStream(new FileInputStream(file)); 402 return parse(in); 403 } catch (FileNotFoundException e) { 404 e.printStackTrace(); 405 throw new Exception("parse QR code error: ", e); 406 } finally { 407 IOUtils.closeQuietly(in); 408 } 409 } 410 411 /** 412 * 解析二维码 413 * 414 * @param filePath 415 * 二维码图片文件路径 416 */ 417 public static final String parse(String filePath) throws Exception { 418 InputStream in = null; 419 try { 420 in = new BufferedInputStream(new FileInputStream(filePath)); 421 return parse(in); 422 } catch (FileNotFoundException e) { 423 e.printStackTrace(); 424 throw new Exception("parse QR code error: ", e); 425 } finally { 426 IOUtils.closeQuietly(in); 427 } 428 } 429 } 430 431 432 433 434 MatrixToImageWriterEx.java 源码: 435 436 import java.awt.BasicStroke; 437 import java.awt.Graphics2D; 438 import java.awt.image.BufferedImage; 439 import java.io.BufferedInputStream; 440 import java.io.File; 441 import java.io.FileInputStream; 442 import java.io.IOException; 443 import java.io.InputStream; 444 import java.util.Hashtable; 445 import javax.imageio.ImageIO; 446 import org.apache.commons.io.IOUtils; 447 import com.google.zxing.BarcodeFormat; 448 import com.google.zxing.EncodeHintType; 449 import com.google.zxing.MultiFormatWriter; 450 import com.google.zxing.WriterException; 451 import com.google.zxing.client.j2se.MatrixToImageConfig; 452 import com.google.zxing.client.j2se.MatrixToImageWriter; 453 import com.google.zxing.common.BitMatrix; 454 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 455 456 class MatrixToImageWriterEx { 457 458 private static final MatrixToLogoImageConfig DEFAULT_CONFIG = new MatrixToLogoImageConfig(); 459 460 /** 461 * 根据内容生成二维码数据 462 * 463 * @param content 464 * 二维码文字内容[为了信息安全性,一般都要先进行数据加密] 465 * @param width 466 * 二维码照片宽度 467 * @param height 468 * 二维码照片高度 469 * @param errorCorrectionLevel 470 * 纠错等级 471 * @return a {@link com.google.zxing.common.BitMatrix} object. 472 * @since 0.0.7 473 */ 474 public static BitMatrix createQRCode(String content, int width, int height, 475 ErrorCorrectionLevel errorCorrectionLevel) { 476 Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); 477 // 设置字符编码 478 hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 479 // 指定纠错等级 480 hints.put(EncodeHintType.ERROR_CORRECTION, errorCorrectionLevel); 481 BitMatrix matrix = null; 482 try { 483 matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints); 484 } catch (WriterException e) { 485 e.printStackTrace(); 486 } 487 return matrix; 488 } 489 490 /** 491 * 根据内容生成二维码数据 492 * 493 * @param content 494 * 二维码文字内容[为了信息安全性,一般都要先进行数据加密] 495 * @param width 496 * 二维码照片宽度 497 * @param height 498 * 二维码照片高度 499 * @return a {@link com.google.zxing.common.BitMatrix} object. 500 * @since 0.0.7 501 */ 502 public static BitMatrix createQRCode(String content, int width, int height) { 503 return createQRCode(content, width, height, ErrorCorrectionLevel.H); 504 } 505 506 /** 507 * 写入二维码、以及将照片logo写入二维码中 508 * 509 * @param matrix 510 * 要写入的二维码 511 * @param format 512 * 二维码照片格式 513 * @param imagePath 514 * 二维码照片保存路径 515 * @param logoPath 516 * logo路径 517 * @throws java.io.IOException 518 * if any. 519 * @since 0.0.7 520 */ 521 public static void writeToFile(BitMatrix matrix, String format, 522 String imagePath, String logoPath) throws IOException { 523 InputStream input = null; 524 try { 525 input = new BufferedInputStream(new FileInputStream(logoPath)); 526 writeToFile(matrix, format, imagePath, input); 527 } catch (IOException e) { 528 throw e; 529 } finally { 530 IOUtils.closeQuietly(input); 531 } 532 533 } 534 535 /** 536 * <p> 537 * writeToFile. 538 * </p> 539 * 540 * @param matrix 541 * a {@link com.google.zxing.common.BitMatrix} object. 542 * @param format 543 * a {@link java.lang.String} object. 544 * @param imagePath 545 * a {@link java.lang.String} object. 546 * @param logoInputStream 547 * a {@link java.io.InputStream} object. 548 * @throws java.io.IOException 549 * if any. 550 * @since 0.0.7 551 */ 552 public static void writeToFile(BitMatrix matrix, String format, 553 String imagePath, InputStream logoInputStream) throws IOException { 554 MatrixToImageWriter.writeToPath(matrix, format, new File(imagePath).toPath(), new MatrixToImageConfig()); 555 // 添加logo图片, 此处一定需要重新进行读取,而不能直接使用二维码的BufferedImage 对象 556 BufferedImage img = ImageIO.read(new File(imagePath)); 557 MatrixToImageWriterEx.overlapImage(img, format, imagePath, logoInputStream, DEFAULT_CONFIG); 558 } 559 560 /** 561 * 写入二维码、以及将照片logo写入二维码中 562 * 563 * @param matrix 564 * 要写入的二维码 565 * @param format 566 * 二维码照片格式 567 * @param imagePath 568 * 二维码照片保存路径 569 * @param logoPath 570 * logo路径 571 * @param logoConfig 572 * logo配置对象 573 * @throws java.io.IOException 574 * if any. 575 * @since 0.0.7 576 */ 577 public static void writeToFile(BitMatrix matrix, String format, String imagePath, InputStream logoPath, 578 MatrixToLogoImageConfig logoConfig) throws IOException { 579 MatrixToImageWriter.writeToPath(matrix, format, new File(imagePath).toPath(), new MatrixToImageConfig()); 580 // 添加logo图片, 此处一定需要重新进行读取,而不能直接使用二维码的BufferedImage 对象 581 BufferedImage img = ImageIO.read(new File(imagePath)); 582 MatrixToImageWriterEx.overlapImage(img, format, imagePath, logoPath, logoConfig); 583 } 584 585 /** 586 * 将照片logo添加到二维码中间 587 * 588 * @param image 589 * 生成的二维码照片对象 590 * @param imagePath 591 * 照片保存路径 592 * @param imagePath 593 * 照片保存路径 594 * @param imagePath 595 * 照片保存路径 596 * @param imagePath 597 * 照片保存路径 598 * @param imagePath 599 * 照片保存路径 600 * @param imagePath 601 * 照片保存路径 602 * @param logoInputStream 603 * logo输入流 604 * @param formate 605 * 照片格式 606 * @param logoConfig 607 * a {@link cn.yicha.commons.qrcode.MatrixToLogoImageConfig} 608 * object. 609 * @since 0.0.7 610 */ 611 public static void overlapImage(BufferedImage image, String formate, 612 String imagePath, InputStream logoInputStream, 613 MatrixToLogoImageConfig logoConfig) { 614 try { 615 BufferedImage logo = ImageIO.read(logoInputStream); 616 Graphics2D g = image.createGraphics(); 617 // 考虑到logo照片贴到二维码中,建议大小不要超过二维码的1/5; 618 int width = image.getWidth() / logoConfig.getLogoPart(); 619 int height = image.getHeight() / logoConfig.getLogoPart(); 620 // logo起始位置,此目的是为logo居中显示 621 int x = (image.getWidth() - width) / 2; 622 int y = (image.getHeight() - height) / 2; 623 // 绘制图 624 g.drawImage(logo, x, y, width, height, null); 625 626 // 给logo画边框 627 // 构造一个具有指定线条宽度以及 cap 和 join 风格的默认值的实心 BasicStroke 628 g.setStroke(new BasicStroke(logoConfig.getBorder())); 629 g.setColor(logoConfig.getBorderColor()); 630 g.drawRect(x, y, width, height); 631 632 g.dispose(); 633 // 写入logo照片到二维码 634 ImageIO.write(image, formate, new File(imagePath)); 635 } catch (Exception e) { 636 e.printStackTrace(); 637 } 638 } 639 640 }
MatrixToLogoImageConfig.java 源码:
1 import java.awt.Color; 2 3 class MatrixToLogoImageConfig { 4 // logo默认边框颜色 5 /** Constant <code>DEFAULT_BORDERCOLOR</code> */ 6 public static final Color DEFAULT_BORDERCOLOR = Color.RED; 7 // logo默认边框宽度 8 /** Constant <code>DEFAULT_BORDER=2</code> */ 9 public static final int DEFAULT_BORDER = 2; 10 // logo大小默认为照片的1/5 11 /** Constant <code>DEFAULT_LOGOPART=5</code> */ 12 public static final int DEFAULT_LOGOPART = 5; 13 14 private final int border = DEFAULT_BORDER; 15 private final Color borderColor; 16 private final int logoPart; 17 18 /** 19 * Creates a default config with on color {@link #BLACK} and off color 20 * {@link #WHITE}, generating normal black-on-white barcodes. 21 * 22 * @since 0.0.7 23 */ 24 public MatrixToLogoImageConfig() { 25 this(DEFAULT_BORDERCOLOR, DEFAULT_LOGOPART); 26 } 27 28 /** 29 * <p> 30 * Constructor for MatrixToLogoImageConfig. 31 * </p> 32 * 33 * @param borderColor 34 * a {@link java.awt.Color} object. 35 * @param logoPart 36 * a int. 37 * @since 0.0.7 38 */ 39 public MatrixToLogoImageConfig(Color borderColor, int logoPart) { 40 this.borderColor = borderColor; 41 this.logoPart = logoPart; 42 } 43 44 /** 45 * <p> 46 * Getter for the field <code>borderColor</code>. 47 * </p> 48 * 49 * @return a {@link java.awt.Color} object. 50 * @since 0.0.7 51 */ 52 public Color getBorderColor() { 53 return borderColor; 54 } 55 56 /** 57 * <p> 58 * Getter for the field <code>border</code>. 59 * </p> 60 * 61 * @return a int. 62 * @since 0.0.7 63 */ 64 public int getBorder() { 65 return border; 66 } 67 68 /** 69 * <p> 70 * Getter for the field <code>logoPart</code>. 71 * </p> 72 * 73 * @return a int. 74 * @since 0.0.7 75 */ 76 public int getLogoPart() { 77 return logoPart; 78 } 79 }
原文:http://www.cnblogs.com/zhoubang521/p/5200118.html