Java實現高可定製的二維碼生成
阿新 • • 發佈:2019-01-08
開篇廢話
不是第一次寫二維碼生成的程式碼,但是是第一次把它整理清晰並做成高可定製的。具體生成實現都是和網上的差不多用了com.swetake.util.Qrcode進行關鍵處理。但是這篇文章的不同之處在於不是為了簡單的實現,而是為了實現高可定製的功能。很多時候要用二維碼,但是實際上二維碼的場景還是很多的。列印在紙巾上的是二維碼,做成大海報的也是二維碼,嵌入logo的是二維碼,不嵌入logo的也是二維碼。
為了讓這個工具類使用場景更廣,特地封裝了一個配置類,根據配置進行更多的處理,最終定製二維碼的生成。
額,個人比較懶,就不貼全部程式碼了,這裡之列出一些關鍵實現,沒啥技術難點,只是註釋得多,方便理解。
ok,開始……
關鍵程式碼
1、模式設定
// 設定編碼容錯級別
qrcode.setQrcodeErrorCorrect(c.getLevel());
// 設定編碼模式
qrcode.setQrcodeVersion(c.getEncodeMode());
// 設定編碼版本
qrcode.setQrcodeVersion(c.getVersion());
2、字元轉化
// 轉化字串為byte陣列,用於二維碼編碼作為引數 byte[] buff = source.getBytes(charset); boolean[][] bRect; try { // 進行編碼處理,超長將會在這裡丟擲異常 bRect = qrcode.calQrcode(buff); } catch (Exception e) { // 這裡如果出現異常,一般是超長了,所以這裡丟擲異常 throw new QRCodeGenerateException("Generate qrcode exception." + "Please check your generate config and check the source string." + "The exception offen by the source string is too long." + "The source string is : " + source + "[" + source.getBytes(charset).length + "]", e); }
3、繪圖設定
// 預設使用BufferedImage.TYPE_INT_RGB生成影象,暫不支援自定義 BufferedImage bi = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_RGB); // 建立影象 Graphics2D g = bi.createGraphics(); if(c.getBackgroundColor() != null){ // 設定背景色為白色 g.setBackground(c.getBackgroundColor()); } // 清空區域 g.clearRect(0, 0, c.getWidth(), c.getHeight()); // 設定前景色為黑色,即填充色 g.setColor(c.getColor());
4、進行繪圖
try {
// 根據byte矩陣進行繪圖
for (int i = 0; i < bRect.length; i++) {
for (int j = 0; j < bRect.length; j++) {
if (bRect[j][i]) {
// 這裡的fill影響邊
g.fillRect(j * c.getOffset() + c.getPixoff(), i * c.getOffset() + c.getPixoff(), c.getOffset(), c.getOffset());
}
}
}
//如果設定嵌入的logo檔案不為空,則執行嵌入操作
if(logo != null){
insertLogo(logo, c, g);
}
//這裡不進行異常處理,直接丟擲,但要進行釋放處理
} finally {
// 釋放影象
g.dispose();
// 重新整理快取區
bi.flush();
}
5、儲存圖片
//根據uri協議獲取對應輸出流
OutputStream os = getOutputStream(target);
//寫入io,預設jepg壓縮,暫不支援其他格式影象
ImageIO.write(bi, c.getFormat(), os);
其他功能實現
1、插入logo的實現
/**
* 插入logo到二維碼中央
* @param logo logo源
* @param config 二維碼生成配置
* @param g 繪製Graphics2D物件
* @throws IOException 繪製時可能產生的IO一場
* @throws MalformedURLException 解析logo源可能出現的URL地址錯誤異常
* @see #build(URI, String, String, URI, QRCodeGenerateConfig)
*/
private void insertLogo(URI logo, QRCodeGenerateConfig config, Graphics2D g) throws IOException, MalformedURLException {
//獲取Image物件。
Image img = getLogoResource(logo);
//定義logo繪製引數
int logoX,logoY,logoW,logoH;
//獲取logo大小
logoW = config.getLogoWidth();
logoH = config.getLogoHeight();
//計算logo座標
logoX = (config.getWidth() - logoW) / 2;
logoY = (config.getHeight() - logoH) / 2;
//這裡不驗證實際數值是否為負數,因此如果由配置不當造成的異常,就不管了
//繪製logo
try{
g.drawImage(img, logoX, logoY, logoW, logoH, null);
}catch(Exception ee){
// 這裡如果出現異常,一般是超長了,所以這裡丟擲異常
throw new QRCodeGenerateException("Draw logo exception,please check your generate config.",ee);
}
}
2、getLogoResource的實現
/**
* 根據logo源URI獲取logo的Image物件
* @param logo logo源URI
* @return Image物件
* @throws IOException 獲取時可能產生的IO異常
* @throws MalformedURLException 解析URL類logo資源時可能出現的URL地址錯誤異常
* @see #build(URI, String, String, URI, QRCodeGenerateConfig)
*/
private Image getLogoResource(URI logo) throws IOException, MalformedURLException {
Image img;
if ("http".equalsIgnoreCase(logo.getScheme())) {
img = ImageIO.read(logo.toURL());
} else if ("https".equalsIgnoreCase(logo.getScheme())) {
img = ImageIO.read(logo.toURL());
} else if ("file".equalsIgnoreCase(logo.getScheme())) {
File f = new File(logo);
img = ImageIO.read(f);
} else {
//不支援的協議直接丟擲異常
throw new QRCodeGenerateException("Insert logo image into qrcode exception,the uri scheme is not support.We only support the scheme such as http,https and file.\n" + logo.toString());
}
return img;
}
3、getOutputStream的實現
/**
* 根據目標URI地址獲取輸出流
* @param target 目標URI
* @return 輸出流
* @throws MalformedURLException 解析目標URI可能出現的URL地址錯誤異常
* @throws IOException 開啟輸出流可能出現的IO異常
* @throws FileNotFoundException 開啟檔案型別的URI時可能出現的檔案不存在異常
* @see #build(URI, String, String, URI, QRCodeGenerateConfig)
*/
private OutputStream getOutputStream(URI target) throws MalformedURLException, IOException,
FileNotFoundException {
OutputStream os;
if ("http".equalsIgnoreCase(target.getScheme())) {
os = getHttpOutputStream(target);
} else if ("https".equalsIgnoreCase(target.getScheme())) {
os = getHttpOutputStream(target);
} else if ("file".equalsIgnoreCase(target.getScheme())) {
File f = new File(target);
os = new FileOutputStream(f);
} else {
//不支援的協議直接丟擲異常
throw new QRCodeGenerateException("Save qrcode image exception,the uri scheme is not support.We only support the scheme such as http,https and file.\n" + target.toString());
}
return os;
}
相關定義
1、引用
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import javax.imageio.ImageIO;
import com.swetake.util.Qrcode;
2、核心實現方法定義
/**
* 生成帶Logo的二維碼,自定義配置的生成方式
* @param logo 嵌入中間的logo來源Uri
* @param source 源字串
* @param charset 編碼
* @param target 生成的二維碼圖片要儲存的目標URI
* @param config 二維碼生成配置
* @throws QRCodeGenerateException 二維碼生成異常
* @throws UnsupportedEncodingException 指定的編碼不支援
* @throws IOException 二維碼圖片儲存產生的IO異常
*/
public void build(URI logo, String source, String charset, URI target, QRCodeGenerateConfig config)
throws QRCodeGenerateException, UnsupportedEncodingException, IOException;
3、config類關鍵欄位
/**
* 二維碼版本,預設為5
*/
private int version = 5;
/**
* 二維碼編碼模式,預設為B
*/
private QRCodeEncodeMode encodeMode = QRCodeEncodeMode.B;
/**
* 二維碼容錯級別,預設為M
*/
private QRCodeLevel level = QRCodeLevel.M;
/**
* 生成二維碼的寬度
*/
private int width = 115;
/**
* 生成二維碼的高度
*/
private int height = 115;
/**
* 生成二維碼嵌入的logo寬度
*/
private int logoWidth = 30;
/**
* 生成二維碼嵌入的logo高度
*/
private int logoHeight = 30;
/**
* 畫素大小
*/
private int offset = 3;
/**
* 偏移量
*/
private int pixoff = 2;
/**
* 二維碼影象儲存格式
*/
private String format = "jpeg";
/**
* 二維碼影象背景色
*/
private Color backgroundColor = Color.WHITE;
/**
* 二維碼影象前景色
*/
private Color color = Color.BLACK;
其它說明
1、建議的寬高及偏移量配置比例[適用預設版本和容錯級別*]
二維碼影象本身寬度和高度 —— 1:1
二維碼LOGO影象寬度和高度 —— 1:1
二維碼影象本身寬度和LOGO影象寬度 —— 23:6[115:30]
二維碼影象本身高度和LOGO影象高度 —— 23:6[115:30]
二維碼影象本身寬度和畫素大小 —— 115:3
二維碼影象本身高度和畫素大小 —— 115:3
二維碼影象本身寬度和偏移量 —— 115:2
二維碼影象本身高度和偏移量 —— 115:2
二維碼畫素大小和偏移量 —— 3:2
2、參考資料
備註
預設配置說明
版本5,容錯級別為M,寬高115,logo寬高30,畫素大小3,偏移量2,生成jpeg格式圖片,背景色白色,畫筆顏色黑色
說明
由於預設寬高是115,因此打印出來可能會比較小,如果需要列印大圖片,則需要參考比例進行影象放大。
結果示例圖: