java生成二維碼,二維碼中間可帶圖片

    主要使用了goole的zxing包,生成二維碼比較簡單,在常規二維碼的基礎上封裝了可以在二維碼中間添加圖片的功能,代碼都屬於初步框架,功能有了,需要根據實際使用情況完善優化。

 

效果圖:

 

源碼如下:

 

package com.thatway.qr;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
 * 2013-7-23
 * @author thatway
 * 二維碼圖片工具類
 * 使用了兩張工具圖,路徑分別是D:\qr\heihei.png   D:\qr\qr_bg.png
 */
public class QRUtil {

 /**
   * 編碼(將文本生成二維碼)
  * 
  * @param content 二維碼中的內容
  * @param width 二維碼圖片寬度
  * @param height 二維碼圖片高度
  * @param imagePath 二維碼圖片存放位置
  * @return 圖片地址
  */
 public static String encode(String content, int width, int height, String imagePath) {

  Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
  // 設置編碼類型爲utf-8
  hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
  // 設置二維碼糾錯能力級別爲H(最高)
  hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

  BitMatrix byteMatrix = null;
  try {
   // 生成二維碼
   byteMatrix = new MultiFormatWriter().encode(content,
     BarcodeFormat.QR_CODE, width, height, hints);
   File file = new File(imagePath);
   MatrixToImageWriter.writeToFile(byteMatrix, "png", file);
  } catch (IOException e) {
   e.printStackTrace();
  } catch (WriterException e) {
   e.printStackTrace();
  }

  return imagePath;

 }

 /**
  * 解碼(讀取二維碼圖片中的文本信息)
  * @param imagePath 二維碼圖片路徑
  * @return 文本信息
  */
 public static String decode(String imagePath) {
  // 返回的文本信息
  String content = "";

  try {
   // 創建圖片文件
   File file = new File(imagePath);
   if (!file.exists()) {
    return content;
   }
   BufferedImage image = null;
   image = ImageIO.read(file);
   if (null == image) {
    return content;
   }
   // 解碼
   LuminanceSource source = new BufferedImageLuminanceSource(image);
   BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
   Hashtable hints = new Hashtable();
   hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
   Result rs = new MultiFormatReader().decode(bitmap, hints);
   content = rs.getText();
  } catch (IOException e) {
   e.printStackTrace();
  } catch (ReaderException e) {
   e.printStackTrace();
  }
  return content;
 }

 /**
  * 圖片打水印
  * @param bgImage 背景圖
  * @param waterImg 水印圖
  * @param uniqueFlag 生成的新圖片名稱中的唯一標識,用來保證生成的圖片名稱不重複,如果爲空或爲null,將使用當前時間作爲標識
  * @return 新圖片路徑
  */
 public static String addImageWater(String bgImage, String waterImg ,String uniqueFlag) {

  int x = 0;
  int y = 0;
  String newImgPath = "";

  if(null == uniqueFlag){
   uniqueFlag = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
  }else if(uniqueFlag.trim().length() < 1){
   uniqueFlag = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
  }

  try {
   File file = new File(bgImage);
   String fileName = file.getName();
   Image image = ImageIO.read(file);
   int width = image.getWidth(null);
   int height = image.getHeight(null);
   BufferedImage bufferedImage = new BufferedImage(width, height,
     BufferedImage.TYPE_INT_RGB);
   Graphics2D g = bufferedImage.createGraphics();
   g.drawImage(image, 0, 0, width, height, null);

   Image waterImage = ImageIO.read(new File(waterImg)); // 水印文件
   int width_water = waterImage.getWidth(null);
   int height_water = waterImage.getHeight(null);
   g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
     1));

   int widthDiff = width - width_water;
   int heightDiff = height - height_water;

   x = widthDiff / 2;
   y = heightDiff / 2;

   g.drawImage(waterImage, x, y, width_water, height_water, null); // 水印文件結束
   g.dispose();



   if(bgImage.contains(fileName)){
    newImgPath = bgImage.replace(fileName, uniqueFlag+fileName);
   }
   File newImg = new File(newImgPath);
   ImageIO.write(bufferedImage, "png", newImg);

   File waterFile = new File(waterImg);

   if(file.exists()){
    file.delete();
   }

   if(waterFile.exists()){
    waterFile.delete();
   }
  } catch (IOException e) {
   e.printStackTrace();
  }

  return newImgPath;
 }

 /**
   * 圖片縮放
  * @param filePath 圖片路徑
  * @param height 縮放到高度
  * @param width 縮放寬度
  * @param fill 比例足時是否填白 true爲填白,二維碼是黑白色,這裏調用時建議設爲true
  * @return 新圖片路徑
  */
 public static String resizeImg(String filePath, int width,int height, boolean fill) {

  String newImgPath = "";

  try {
   double ratio = 0; // 縮放比例
   File f = new File(filePath);
   String fileName = f.getName();
   BufferedImage bi = ImageIO.read(f);
   Image itemp = bi.getScaledInstance(width, height,BufferedImage.SCALE_SMOOTH);

   if(height != 0 && width!= 0 ){
    // 計算比例
    if ((bi.getHeight() > height) || (bi.getWidth() > width)) {
     if (bi.getHeight() > bi.getWidth()) {
      ratio = (new Integer(height)).doubleValue()
        / bi.getHeight();
     } else {
      ratio = (new Integer(width)).doubleValue() / bi.getWidth();
     }
     AffineTransformOp op = new AffineTransformOp(AffineTransform
       .getScaleInstance(ratio, ratio), null);
     itemp = op.filter(bi, null);
    }
   }

   if (fill) {
    BufferedImage image = new BufferedImage(width, height,
      BufferedImage.TYPE_INT_RGB);
    Graphics2D g = image.createGraphics();
    g.setColor(Color.white);
    g.fillRect(0, 0, width, height);
    if (width == itemp.getWidth(null)){
     g.drawImage(itemp, 0, (height - itemp.getHeight(null)) / 2,
       itemp.getWidth(null), itemp.getHeight(null),
       Color.white, null);
    }else{
     g.drawImage(itemp, (width - itemp.getWidth(null)) / 2, 0,
       itemp.getWidth(null), itemp.getHeight(null),
       Color.white, null);
    }

    g.dispose();
    itemp = image;
   }
   String now = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
   if(filePath.contains(fileName)){
    newImgPath = filePath.replace(fileName, now+fileName);
   }

   File newImg = new File(newImgPath);
   ImageIO.write((BufferedImage)itemp, "png", newImg);
  } catch (IOException e) {
   e.printStackTrace();
  }

  return newImgPath;
 }


 /**
  * 圖片添加邊框
  * @param mainImgPath 要加邊框的圖片
  * @param bgImgPath 背景圖(實際上是將圖片放在背景圖上,只利用背景圖的邊框效果)
  * @return 製作完成的圖片路徑
  */
 public static String addWaterBorder(String mainImgPath,String bgImgPath){

  String borderImgPath = "";

  try {
   File f = new File(mainImgPath);

   BufferedImage bi;

   bi = ImageIO.read(f);

   //背景圖長寬都比主圖多4像素,這是因爲我畫的背景圖的邊框效果的大小正好是4像素,
   //主圖周邊比背景圖少4像素正好能把背景圖的邊框效果完美顯示出來
   int width = bi.getWidth();
   int height = bi.getHeight();

   int bgWidth = width+4;
   int bgHeight = height+4;

   String now = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
   borderImgPath = QRUtil.addImageWater(QRUtil.resizeImg(bgImgPath, bgHeight, bgWidth, true), mainImgPath,now);

   if(f.exists()){
    f.delete();
   }
  } catch (IOException e) {
   e.printStackTrace();
  }


  return borderImgPath;
 }

 public static void main(String[] args) {

  /**部分一開始***********生成常規二維碼*************/
  //二維碼內容
  String content = "介個是內容,
http://weibo.com/sdtvwp";
  //二維碼寬度
  int width = 300;
  //二維碼高度
  int height = 300;
  //二維碼存放地址
  String imagePath = "d:/qr/thatway_weibo.png";
  //生成二維碼,返回的是生成好的二維碼圖片的所在路徑
  String qrImgPath = QRUtil.encode(content, width, height, imagePath);
  /**部分一結束***********如果生成不帶圖片的二維碼,到這步已經完成了*************/


  /**部分二開始***********如果生成帶圖片但圖片不帶邊框的二維碼,解開這部分註釋*************/

  //縮放水印圖片,爲保證二維碼的讀取正確,圖片不超過二維碼圖片的五分之一,這裏設爲六分之一
//  String waterImgPath = QRUtil.resizeImg("d:/qr/heihei.jpg", width/6, height/6, true);
//  
//  //生成帶有圖片的二維碼,返回的是生成好的二維碼圖片的所在路徑
//  String qrImage = QRUtil.addImageWater(qrImgPath, waterImgPath,"thatway");
  /**部分二結束***********如果生成帶圖片但圖片不帶邊框的二維碼,解開這部分註釋*************/


  /**部分三開始(部分三不能和部分二共存)***********如果生成帶圖片且圖片帶邊框的二維碼,解開這部分註釋****/

  //縮放水印圖片,爲保證二維碼的讀取正確,圖片不超過二維碼圖片的五分之一,這裏設爲六分之一
  //d:/qr/heihei.png 這圖片是要加在二維碼中間的那張圖
  String waterImgPath = QRUtil.resizeImg("d:/qr/heihei.png", width/6, height/6, true);

  //d:/qr/qr_bg.png這種圖片是自己畫好邊框光暈效果的邊框底圖
  String tempImg = QRUtil.addWaterBorder(waterImgPath, "d:/qr/qr_bg.png");

  //生成帶有邊框圖片的二維碼,返回的是生成好的二維碼圖片的所在路徑
  String qrImage = QRUtil.addImageWater(qrImgPath, tempImg,"thatway");
  /**部分三結束***********如果生成帶圖片且圖片帶邊框的二維碼,解開這部分註釋*************/



  /*******測試一下解碼******/
  System.out.println(QRUtil.decode(qrImage));;

 }

}

 

 

需要的圖片和zxing包在附件中,zxing包修改過字符編碼的源碼,如果自己去google下載的話,需要改一下com.google.zxing.qrcode.encoder.Encoder類中: static final String DEFAULT_BYTE_MODE_ENCODING = "UTF-8";  //默認是iso8859-1,不支持中文

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章