這是整理之後的二維碼生成、解析工具類,並且可以生成含logo的二維碼;使用的是Google的zxing工具包。在理解代碼時可以把我寫的多重重載注掉,不然代碼太長不利於理解。細的不多說,看代碼:
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
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.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
/***
* <p><strong>二維碼工具類</strong></p>
* 功能實現:<br>
* 1)生成不同格式(bmp/jpg/jpeg/gif/png)的二維碼,
* 並且可以生成包含logo的二維碼,
* 也可以生成彩色的二維碼(此工具類默認採用utf-8編碼)<br>
* (注:不能使用白色作爲填充色,會導致無法解析,使用此方法時需要注意測試生成後的二維碼是否可用)<br>
* 2)解析二維碼(可以是圖片文件,也可以是圖片數據流)
*/
public class QRCodeUtil {
private static final int BLANK = 0xFF000000;//RGB黑色對應值
private static final int WHITE = 0xFFFFFFFF;//RGB白色對應值
private static final String CHARTSET = "utf-8";//
//圖片格式
private static final String PNG = "png";
private static final String JPG = "jpg";
private static final String GIF = "gif";
private static final String JPEG = "jpeg";
private static final String BMP = "bmp";
//默認值
private static final int QRCODE_SIZE = 300;
private static final int LOGO_SIZE = 60;
/**
* 生成二維碼編碼,字符集默認採用utf-8
* @param content 二維碼內容(可以是url,也可以是文本)
* @param width 生成二維碼的長度
* @param height 生成二維碼的高度
* @return WriterException
* @version 1.0.0
*/
public BitMatrix encode(String content, int width, int height) throws WriterException {
//用於設置QR二維碼參數
Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
// 設置QR二維碼的糾錯級別——這裏選擇最高H級別(暫時未涉及此部分內容,不設置也行,出於後續優化考慮,放在這裏)
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//設置編碼方式,此工具類默認採用utf-8(後續升級可以考慮支持多種編碼)
hints.put(EncodeHintType.CHARACTER_SET, CHARTSET);
//告訴系統二維碼掃描後的內容,以及採用的編碼形式,生成圖片的大小;
//參數順序分別爲:編碼內容,編碼類型,生成圖片寬度,生成圖片高度,設置參數
BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
BarcodeFormat.QR_CODE, width, height, hints);
return bitMatrix;
}
/**
* 生成默認大小的二維碼編碼,字符集默認採用utf-8
* @param content 二維碼內容(可以是url,也可以是文本)
*/
public BitMatrix encode(String content) throws WriterException {
return encode(content, QRCODE_SIZE, QRCODE_SIZE);
}
/**
* <p>創建文件<p>
* 如果存儲路徑不存在則會創建文件
* @param storePath 存儲路徑
* @param fileName 文件名 (如果文件名包含該文件格式後綴會去重)
* @param format 文件格式
* @version 1.0.0
*/
public File mkdirs(String storePath, String fileName, String format) {
File file = new File(storePath);
if(!file.exists() && !file.isDirectory()) {
file.mkdirs();
}
if(fileName.contains("." + format)) {
return new File(storePath + File.separator + fileName);
}
return new File(storePath + File.separator + fileName
+ "." + format.toLowerCase());
}
/**
* 將生成的二維碼轉換成RBG類型的圖片
* @param bitMatrix 二維碼編碼
* @param fillColor 填充部分的RGB顏色編碼
* @param blankColor 空白部分的RBG顏色編碼
*/
public BufferedImage toBufferedImage(BitMatrix bitMatrix, int fillColor,
int blankColor) {
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? fillColor : blankColor);
}
}
return image;
}
/**
* 生成默認顏色樣式的二維碼(RBG黑白)
* @param bitMatrix 二維碼編碼
*/
public BufferedImage toBufferedImage(BitMatrix bitMatrix) {
return toBufferedImage(bitMatrix, BLANK, WHITE);
}
/**
* 將二維碼圖片數據寫入文件(輸出)
* @param image 二維碼圖片數據
* @param format 圖片格式
* @param file 將要寫入的文件
* @throws IOException
*/
public void writeToFile(BufferedImage image, String format, File file)
throws IOException {
if (!ImageIO.write(image, format, file)) {
throw new IOException("Could not write an image of format "
+ format + " to " + file);
}
}
/**
* 將二維碼圖片數據寫入文件(輸出)
* @param image 二維碼圖片數據
* @param format 圖片格式
* @param stream 輸出流
* @throws IOException
*/
public void writeToStream(BufferedImage image, String format,
OutputStream stream) throws IOException {
if (!ImageIO.write(image, format, stream)) {
throw new IOException("Could not write an image of format "
+ format);
}
}
/**
* 類型一:創建二維碼,可以設定二維碼的尺寸,顏色,格式,命名,存儲路徑
*/
public void createQRcode(String content, String format, int width, int height,
String storePath, String fileName, int fillColor, int blankColor)
throws WriterException, IOException {
writeToFile(toBufferedImage(encode(content, width, height),
fillColor, blankColor), format, mkdirs(storePath, fileName, format));
}
/**
* 類型二:創建二維碼,可以設定二維碼的尺寸,格式,命名,存儲路徑(顏色默認RGB黑白)
*/
public void createQRcode(String content, String format, int width, int height,
String storePath, String fileName)
throws WriterException, IOException {
createQRcode(content, format, width, height, storePath, fileName, BLANK, WHITE);
}
/**
* 類型三:創建二維碼,可以設定二維碼的格式,長度(長和寬等值),命名,存儲路徑(顏色默認RGB黑白)
*/
public void createQRcode(String content, String format, int length,
String storePath, String fileName) throws WriterException, IOException {
createQRcode(content, format, length, length, storePath, fileName);
}
/**
* 類型四:創建二維碼,可以設定二維碼的格式,命名,存儲路徑(顏色默認RGB黑白,尺寸默認300*300)
*/
public void createQRcode(String content, String format,String storePath, String fileName)
throws WriterException, IOException {
createQRcode(content, format, QRCODE_SIZE, storePath, fileName);
}
/**
* 類型五:創建二維碼,可以設定二維碼的命名,存儲路徑(顏色默認RGB黑白,尺寸默認300*300,格式爲jpg)
*/
public void createQRcode(String content,String storePath, String fileName)
throws WriterException, IOException {
createQRcode(content, JPG, storePath, fileName);
}
/**
* PNG類型一:創建二維碼,可以設定二維碼的尺寸,顏色,格式,命名,存儲路徑
*/
public void createPngQRcode(String content, int width, int height,
String storePath, String fileName, int fillColor, int blankColor)
throws WriterException, IOException {
createQRcode(content, PNG, width, height, storePath, fileName, fillColor, blankColor);
}
/**
* PNG類型二:創建二維碼,可以設定二維碼的尺寸,格式,命名,存儲路徑(顏色默認RGB黑白)
*/
public void createPngQRcode(String content, int width, int height,
String storePath, String fileName)
throws WriterException, IOException {
createPngQRcode(content, width, height, storePath, fileName, BLANK, WHITE);
}
/**
* PNG類型三:創建二維碼,可以設定二維碼的格式,長度(長和寬等值),命名,存儲路徑(顏色默認RGB黑白)
*/
public void createPngQRcode(String content, int length,
String storePath, String fileName) throws WriterException, IOException {
createPngQRcode(content, length, length, storePath, fileName);
}
/**
* PNG類型四:創建二維碼,可以設定二維碼的格式,命名,存儲路徑(顏色默認RGB黑白,尺寸默認300*300)
*/
public void createPngQRcode(String content,String storePath, String fileName)
throws WriterException, IOException {
createPngQRcode(content, QRCODE_SIZE, storePath, fileName);
}
/**
* JPG類型一:創建二維碼,可以設定二維碼的尺寸,顏色,格式,命名,存儲路徑
*/
public void createJpgQRcode(String content, int width, int height,
String storePath, String fileName, int fillColor, int blankColor)
throws WriterException, IOException {
createQRcode(content, JPG, width, height, storePath, fileName, fillColor, blankColor);
}
/**
* JPG類型二:創建二維碼,可以設定二維碼的尺寸,格式,命名,存儲路徑(顏色默認RGB黑白)
*/
public void createJpgQRcode(String content, int width, int height,
String storePath, String fileName)
throws WriterException, IOException {
createJpgQRcode(content, width, height, storePath, fileName, BLANK, WHITE);
}
/**
* JPG類型三:創建二維碼,可以設定二維碼的格式,長度(長和寬等值),命名,存儲路徑(顏色默認RGB黑白)
*/
public void createJpgQRcode(String content, int length,
String storePath, String fileName) throws WriterException, IOException {
createJpgQRcode(content, length, length, storePath, fileName);
}
/**
* JPG類型四:創建二維碼,可以設定二維碼的格式,命名,存儲路徑(顏色默認RGB黑白,尺寸默認300*300)
*/
public void createJpgQRcode(String content, String storePath, String fileName)
throws WriterException, IOException {
createJpgQRcode(content, QRCODE_SIZE, storePath, fileName);
}
/**
* JPEG類型一:創建二維碼,可以設定二維碼的尺寸,顏色,格式,命名,存儲路徑
*/
public void createJpegQRcode(String content, int width, int height,
String storePath, String fileName, int fillColor, int blankColor)
throws WriterException, IOException {
createQRcode(content, JPEG, width, height, storePath, fileName, fillColor, blankColor);
}
/**
* JPEG類型二:創建二維碼,可以設定二維碼的尺寸,格式,命名,存儲路徑(顏色默認RGB黑白)
*/
public void createJpegQRcode(String content, int width, int height,
String storePath, String fileName)
throws WriterException, IOException {
createJpegQRcode(content, width, height, storePath, fileName, BLANK, WHITE);
}
/**
* JPEG類型三:創建二維碼,可以設定二維碼的格式,長度(長和寬等值),命名,存儲路徑(顏色默認RGB黑白)
*/
public void createJpegQRcode(String content, int length,
String storePath, String fileName) throws WriterException, IOException {
createJpegQRcode(content, length, length, storePath, fileName);
}
/**
* JPEG類型四:創建二維碼,可以設定二維碼的格式,命名,存儲路徑(顏色默認RGB黑白,尺寸默認300*300)
*/
public void createJpegQRcode(String content,String storePath, String fileName)
throws WriterException, IOException {
createJpegQRcode(content, QRCODE_SIZE, storePath, fileName);
}
/**
* GIF類型一:創建二維碼,可以設定二維碼的尺寸,顏色,格式,命名,存儲路徑
*/
public void createGifQRcode(String content, int width, int height,
String storePath, String fileName, int fillColor, int blankColor)
throws WriterException, IOException {
createQRcode(content, GIF, width, height, storePath, fileName, fillColor, blankColor);
}
/**
* GIF類型二:創建二維碼,可以設定二維碼的尺寸,格式,命名,存儲路徑(顏色默認RGB黑白)
*/
public void createGifQRcode(String content, int width, int height,
String storePath, String fileName)
throws WriterException, IOException {
createGifQRcode(content, width, height, storePath, fileName, BLANK, WHITE);
}
/**
* GIF類型三:創建二維碼,可以設定二維碼的格式,長度(長和寬等值),命名,存儲路徑(顏色默認RGB黑白)
*/
public void createGifQRcode(String content, int length,
String storePath, String fileName) throws WriterException, IOException {
createGifQRcode(content, length, length, storePath, fileName);
}
/**
* GIF類型四:創建二維碼,可以設定二維碼的格式,命名,存儲路徑(顏色默認RGB黑白,尺寸默認300*300)
*/
public void createGifQRcode(String content, String storePath, String fileName)
throws WriterException, IOException {
createGifQRcode(content, QRCODE_SIZE, storePath, fileName);
}
/**
* BMP類型一:創建二維碼,可以設定二維碼的尺寸,顏色,格式,命名,存儲路徑
*/
public void createBmpQRcode(String content, int width, int height,
String storePath, String fileName, int fillColor, int blankColor)
throws WriterException, IOException {
createQRcode(content, BMP, width, height, storePath, fileName, fillColor, blankColor);
}
/**
* BMP類型二:創建二維碼,可以設定二維碼的尺寸,格式,命名,存儲路徑(顏色默認RGB黑白)
*/
public void createBmpQRcode(String content, int width, int height,
String storePath, String fileName)
throws WriterException, IOException {
createBmpQRcode(content, width, height, storePath, fileName, BLANK, WHITE);
}
/**
* BMP類型三:創建二維碼,可以設定二維碼的格式,長度(長和寬等值),命名,存儲路徑(顏色默認RGB黑白)
*/
public void createBmpQRcode(String content, int length,
String storePath, String fileName) throws WriterException, IOException {
createBmpQRcode(content, length, length, storePath, fileName);
}
/**
* BMP類型四:創建二維碼,可以設定二維碼的格式,命名,存儲路徑(顏色默認RGB黑白,尺寸默認300*300)
*/
public void createBmpQRcode(String content, String storePath, String fileName)
throws WriterException, IOException {
createBmpQRcode(content, QRCODE_SIZE, storePath, fileName);
}
/**
* 向二維碼圖片中插入logo圖片
* @param source 二維碼圖片流
* @param imgPath logo圖片路徑
* @param needCompress 是否需要壓縮
*/
public BufferedImage insertImage(BufferedImage source, String imgPath,
boolean needCompress) throws IOException {
File file = new File(imgPath);
if(!file.exists()) {
throw new FileNotFoundException("Could not find the file or the "
+ "file does not exist : " + imgPath);
}
Image image = ImageIO.read(file);
int width = image.getWidth(null);
int height = image.getHeight(null);
if(needCompress) {//壓縮(這裏是固定大小壓縮,可以修改成可選大小)
width = LOGO_SIZE;
height = LOGO_SIZE;
Image img = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
BufferedImage target = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = target.getGraphics();
g.drawImage(img, 0, 0, null);
image = img;
}
Graphics2D g2D = source.createGraphics();
int x = (source.getWidth() - width) / 2;
int y = (source.getHeight() - width) / 2;
g2D.drawImage(image, x, y, width, height, null);
Shape shape = new RoundRectangle2D.Float(x, y, width, height, 6, 6);
g2D.setStroke(new BasicStroke(3f));
g2D.draw(shape);
g2D.dispose();
return source;
}
public void createLogoQRcode(String content, String format, int width, int height,
String storePath, String fileName, int fillColor, int blankColor, String logoPath)
throws WriterException, IOException {
writeToFile(insertImage(toBufferedImage(encode(content, width, height),
fillColor, blankColor), logoPath, true), format, mkdirs(storePath, fileName, format));
}
public void createLogoQRcode(String content, String format,String storePath,
String fileName, int fillColor, int blankColor, String logoPath)
throws WriterException, IOException {
createLogoQRcode(content, format, QRCODE_SIZE, QRCODE_SIZE, storePath,
fileName, fillColor, blankColor, logoPath);
}
public void createLogoQRcode(String content, String format,String storePath, int length,
String fileName, int fillColor, int blankColor, String logoPath)
throws WriterException, IOException {
createLogoQRcode(content, format, length, length, storePath,
fileName, fillColor, blankColor, logoPath);
}
public void createLogoQRcode(String content, String format,String storePath,
String fileName, String logoPath)throws WriterException, IOException {
createLogoQRcode(content, format, storePath, fileName, BLANK, WHITE, logoPath);
}
public void createLogoQRcode(String content, String storePath,
String fileName, String logoPath)throws WriterException, IOException {
createLogoQRcode(content, JPG, storePath, fileName, BLANK, WHITE, logoPath);
}
/**
* 通過二維碼文件流解析二維碼
*/
public String analyticalQRCode(BufferedImage image) throws NotFoundException{
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Result result;
Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
//解碼設置編碼方式:utf-8
hints.put(DecodeHintType.CHARACTER_SET, CHARTSET);
result = new MultiFormatReader().decode(bitmap, hints);
return result.getText();
}
/**
* 通過二維碼文件解析二維碼
* @param file 二維碼文件
*/
public String analyticalQRCode(File file) throws IOException, NotFoundException {
BufferedImage image = ImageIO.read(file);
if (image == null) {
throw new FileNotFoundException("can't found file or it's null");
}
return analyticalQRCode(image);
}
/**
* 通過二維碼路徑解析二維碼
* @param path 二維碼路徑
*/
public String analyticalQRCode(String path) throws IOException, NotFoundException {
File file = new File(path);
if(!file.exists()) {
throw new FileNotFoundException("Could not find the file or the "
+ "file does not exist : " + path);
}
return analyticalQRCode(file);
}
public static void main(String[] args) {
int grey = 0xFFBEBEBE;
String logo = "E:/360downloads/wpcache/360wallpaper.jpg";
try {
new QRCodeUtil().createQRcode("https://www.baidu.com", JPG, 300, 300, "E:", "code", BLANK, WHITE);
new QRCodeUtil().createJpgQRcode("https://www.baidu.com", "E:/", "code1");
new QRCodeUtil().createLogoQRcode("https://www.baidu.com", JPG, 300, 300, "E:", "code2", BLANK, grey, logo);
System.out.println(new QRCodeUtil().analyticalQRCode(new File("E:/code.jpg")));
} catch (WriterException | IOException e) {
e.printStackTrace();
} catch (NotFoundException e) {
e.printStackTrace();
}
}
}
其中引入的BufferedImageLuminanceSource的代碼如下:
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import com.google.zxing.LuminanceSource;
/**
* LuminanceSource實現類
*
*/
public class BufferedImageLuminanceSource extends LuminanceSource {
/**
* BufferedImage是Image的一個子類,BufferedImage生成的圖片在內存裏有一個圖像緩衝區,
* 利用這個緩衝區我們可以很方便的操作這個圖片,通常用來做圖片修改操作如大小變換、圖片變灰、設置圖片透明或不透明等。
*/
private final BufferedImage image;
private final int left;
private final int top;
/**
* 構造方法
*
* @param image
*/
public BufferedImageLuminanceSource(BufferedImage image) {
this(image, 0, 0, image.getWidth(), image.getHeight());
}
/**
* 重載的構造方法
*
* @param image
* @param left
* @param top
* @param width
* @param height
*/
public BufferedImageLuminanceSource(BufferedImage image, int left, int top,
int width, int height) {
super(width, height);
/**
* 取出當前圖片的寬度和高度
*/
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
if (left + width > sourceWidth || top + height > sourceHeight) {
throw new IllegalArgumentException(
"Crop rectangle does not fit within image data.");
}
for (int y = top; y < top + height; y++) {
for (int x = left; x < left + width; x++) {
if ((image.getRGB(x, y) & 0xFF000000) == 0) {
image.setRGB(x, y, 0xFFFFFFFF); // = white
}
}
}
this.image = new BufferedImage(sourceWidth, sourceHeight,
BufferedImage.TYPE_BYTE_GRAY);
this.image.getGraphics().drawImage(image, 0, 0, null);
this.left = left;
this.top = top;
}
@Override
public byte[] getRow(int y, byte[] row) {
if (y < 0 || y >= getHeight()) {
throw new IllegalArgumentException(
"Requested row is outside the image: " + y);
}
int width = getWidth();
if (row == null || row.length < width) {
row = new byte[width];
}
image.getRaster().getDataElements(left, top + y, width, 1, row);
return row;
}
@Override
public byte[] getMatrix() {
int width = getWidth();
int height = getHeight();
int area = width * height;
byte[] matrix = new byte[area];
image.getRaster().getDataElements(left, top, width, height, matrix);
return matrix;
}
@Override
public boolean isCropSupported() {
return true;
}
@Override
public LuminanceSource crop(int left, int top, int width, int height) {
return new BufferedImageLuminanceSource(image, this.left + left,
this.top + top, width, height);
}
@Override
public boolean isRotateSupported() {
return true;
}
@Override
public LuminanceSource rotateCounterClockwise() {
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0,
0.0, sourceWidth);
BufferedImage rotatedImage = new BufferedImage(sourceHeight,
sourceWidth, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g = rotatedImage.createGraphics();
g.drawImage(image, transform, null);
g.dispose();
int width = getWidth();
return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth
- (left + width), getHeight(), width);
}
}
如果你的導入你的項目中出現警告時,那說明你的項目沒有權限訪問JDK中的一些類,這個時候你需要先remove path中的JDK,然後在添加JDK,雖然沒有意義的操作但是你可以獲得JDK的全部訪問權限