利用ZXing生成二維碼的工具類

jopen 11年前發布 | 125K 次閱讀 條形碼/二維碼開發包 zxing

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageConfig;
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;

/**

  • ZXing工具類
  • @see -----------------------------------------------------------------------------------------------------------------------
  • @see 首頁--https://code.google.com/p/zxing
  • @see 介紹--用于解析多種格式條形碼(EAN-13)和二維碼(QRCode)的開源Java類庫,其提供了多種應用的類庫,如javase/jruby/cpp/csharp/android
  • @see 說明--下載到的ZXing-2.2.zip是它的源碼,我們在JavaSE中使用時需用到其core和javase兩部分
  • @see 可直接引入它倆的源碼到項目中,或將它倆編譯為jar再引入,這是我編譯好的:http://download.csdn.net/detail/jadyer/6245849
  • @see -----------------------------------------------------------------------------------------------------------------------
  • @see 經測試:用微信掃描GBK編碼的中文二維碼時出現亂碼,用UTF-8編碼時微信可正常識別
  • @see 并且MultiFormatWriter.encode()時若傳入hints參數來指定UTF-8編碼中文時,微信壓根就不識別所生成的二維碼
  • @see 所以這里使用的是這種方式new String(content.getBytes("UTF-8"), "ISO-8859-1")
  • @see -----------------------------------------------------------------------------------------------------------------------
  • @see 將logo圖片加入二維碼中間時,需注意以下幾點
  • @see 1)生成二維碼的糾錯級別建議采用最高等級H,這樣可以增加二維碼的正確識別能力(我測試過,不設置級別時,二維碼工具無法讀取生成的二維碼圖片)
  • @see 2)頭像大小最好不要超過二維碼本身大小的1/5,而且只能放在正中間部位,這是由于二維碼本身結構造成的(你就把它理解成圖片水印吧)
  • @see 3)在仿照騰訊微信在二維碼四周增加裝飾框,那么一定要在裝飾框和二維碼之間留出白邊,這是為了二維碼可被識別
  • @see -----------------------------------------------------------------------------------------------------------------------
  • @version v1.0
  • @history v1.0-->方法新建,目前僅支持二維碼的生成和解析,生成二維碼時支持添加logo頭像
  • @editor Sep 10, 2013 9:32:23 PM
  • @create Sep 10, 2013 2:08:16 PM
  • @author 玄玉<http://blog.csdn.net/jadyer&gt; */
    public class ZXingUtil {
    private ZXingUtil(){}

    /**

    • 為二維碼圖片增加logo頭像
    • @see 其原理類似于圖片加水印
    • @param imagePath 二維碼圖片存放路徑(含文件名)
    • @param logoPath logo頭像存放路徑(含文件名) */
      private static void overlapImage(String imagePath, String logoPath) throws IOException {
      BufferedImage image = ImageIO.read(new File(imagePath));
      int logoWidth = image.getWidth()/5; //設置logo圖片寬度為二維碼圖片的五分之一
      int logoHeight = image.getHeight()/5; //設置logo圖片高度為二維碼圖片的五分之一
      int logoX = (image.getWidth()-logoWidth)/2; //設置logo圖片的位置,這里令其居中
      int logoY = (image.getHeight()-logoHeight)/2; //設置logo圖片的位置,這里令其居中
      Graphics2D graphics = image.createGraphics();
      graphics.drawImage(ImageIO.read(new File(logoPath)), logoX, logoY, logoWidth, logoHeight, null);
      graphics.dispose();
      ImageIO.write(image, imagePath.substring(imagePath.lastIndexOf(".") + 1), new File(imagePath));
      }
/** 
 * 生成二維碼 
 * @param content   二維碼內容 
 * @param charset   編碼二維碼內容時采用的字符集(傳null時默認采用UTF-8編碼) 
 * @param imagePath 二維碼圖片存放路徑(含文件名) 
 * @param width     生成的二維碼圖片寬度 
 * @param height    生成的二維碼圖片高度 
 * @param logoPath  logo頭像存放路徑(含文件名,若不加logo則傳null即可) 
 * @return 生成二維碼結果(true or false) 
 */  
public static boolean encodeQRCodeImage(String content, String charset, String imagePath, int width, int height, String logoPath) {  
    Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();  
    //指定編碼格式  
    //hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");  
    //指定糾錯級別(L--7%,M--15%,Q--25%,H--30%)  
    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);  
    //編碼內容,編碼類型(這里指定為二維碼),生成圖片寬度,生成圖片高度,設置參數  
    BitMatrix bitMatrix = null;  
    try {  
        bitMatrix = new MultiFormatWriter().encode(new String(content.getBytes(charset==null?"UTF-8":charset), "ISO-8859-1"), BarcodeFormat.QR_CODE, width, height, hints);  
    } catch (Exception e) {  
        System.out.println("編碼待生成二維碼圖片的文本時發生異常,堆棧軌跡如下");  
        e.printStackTrace();  
        return false;  
    }  
    //生成的二維碼圖片默認背景為白色,前景為黑色,但是在加入logo圖像后會導致logo也變為黑白色,至于是什么原因還沒有仔細去讀它的源碼  
    //所以這里對其第一個參數黑色將ZXing默認的前景色0xFF000000稍微改了一下0xFF000001,最終效果也是白色背景黑色前景的二維碼,且logo顏色保持原有不變  
    MatrixToImageConfig config = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);  
    //這里要顯式指定MatrixToImageConfig,否則還會按照默認處理將logo圖像也變為黑白色(如果打算加logo的話,反之則不須傳MatrixToImageConfig參數)  
    try {  
        MatrixToImageWriter.writeToFile(bitMatrix, imagePath.substring(imagePath.lastIndexOf(".") + 1), new File(imagePath), config);  
    } catch (IOException e) {  
        System.out.println("生成二維碼圖片[" + imagePath + "]時遇到異常,堆棧軌跡如下");  
        e.printStackTrace();  
        return false;  
    }  
    //此時二維碼圖片已經生成了,只不過沒有logo頭像,所以接下來根據傳入的logoPath參數來決定是否加logo頭像  
    if(null == logoPath){  
        return true;  
    }else{  
        //如果此時最終生成的二維碼不是我們想要的,那么可以擴展MatrixToImageConfig類(反正ZXing提供了源碼)  
        //擴展時可以重寫其writeToFile方法,令其返回toBufferedImage()方法所生成的BufferedImage對象(盡管這種做法未必能解決為題,故需根據實際情景測試)  
        //然后替換這里overlapImage()里面的第一行BufferedImage image = ImageIO.read(new File(imagePath));  
        //即private static void overlapImage(BufferedImage image, String imagePath, String logoPath)  
        try {  
            //這里不需要判斷logoPath是否指向了一個具體的文件,因為這種情景下overlapImage會拋IO異常  
            overlapImage(imagePath, logoPath);  
            return true;  
        } catch (IOException e) {  
            System.out.println("為二維碼圖片[" + imagePath + "]添加logo頭像[" + logoPath + "]時遇到異常,堆棧軌跡如下");  
            e.printStackTrace();  
            return false;  
        }  
    }  
}  


/** 
 * 解析二維碼 
 * @param imagePath 二維碼圖片存放路徑(含文件名) 
 * @param charset   解碼二維碼內容時采用的字符集(傳null時默認采用UTF-8編碼) 
 * @return 解析成功后返回二維碼文本,否則返回空字符串 
 */  
public static String decodeQRCodeImage(String imagePath, String charset) {  
    BufferedImage image = null;  
    try {  
        image = ImageIO.read(new File(imagePath));  
    } catch (IOException e) {  
        e.printStackTrace();  
        return "";  
    }  
    if(null == image){  
        System.out.println("Could not decode QRCodeImage");  
        return "";  
    }  
    BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(image)));  
    Map<DecodeHintType, String> hints = new HashMap<DecodeHintType, String>();  
    hints.put(DecodeHintType.CHARACTER_SET, charset==null ? "UTF-8" : charset);  
    Result result = null;  
    try {  
        result = new MultiFormatReader().decode(bitmap, hints);  
        return result.getText();  
    } catch (NotFoundException e) {  
        System.out.println("二維碼圖片[" + imagePath + "]解析失敗,堆棧軌跡如下");  
        e.printStackTrace();  
        return "";  
    }  
}  

} </pre>測試:

    public static void main(String[] args) {  
        encodeQRCodeImage("我的博客:http://blog.csdn.net/jadyer", null, "C:/Users/Jadyer/Desktop/myQRCodeImage.png", 300, 300, "C:/Users/Jadyer/Desktop/玄玉.png");  
        System.out.println(decodeQRCodeImage("C:/Users/Jadyer/Desktop/myQRCodeImage.png", null));  
    }  

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!