package com.swft.util;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
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.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;
/**
* @ClassName: QRcodeObject
* @description:
* @author: JTJ
* @Date: 2019年2月17日 下午1:52:32
*/
public class QRcodeObject {
public static int width = 600;
public static int height = 600;
public static String format = "png";
public static String contents = "默認內容";
public static String defaultFilePath = "";
public static String[] checkList = new String[] {"png","jpg","gif","jepg"};
/**
* @Title: createLogoAndCode
* @Desc: 創建二維碼
* @param logo contents path
* @return
*/
public static String createLogoAndCode(File logo, String contents, String path) {
String result = "success";
if (!$.stringObj.isEmpty(contents)) {
QRcodeObject.contents = contents;
}
if(!checkFormat(logo)) {
return "logo文件出錯!";
}
// 生成二維碼
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height,
setCodeParams());
if(!$.stringObj.isEmpty(path)) {
//生成文件路徑
Path filePath = new File(savePalce(path)).toPath();
MatrixToImageWriter.writeToPath(bitMatrix, format, filePath);
}
MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
/* 添加logo圖片
* 問題:生成二維碼正常,生成帶logo的二維碼logo變成黑白
* 原因:MatrixToImageConfig默認黑白,需要設置BLACK、WHITE
* 解決:https://ququjioulai.iteye.com/blog/2254382
*/
//判斷是否需要logo
if(logo!=null) {
BufferedImage bufferedImage = groupImage(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig),logo);
//生成圖片文件
ImageIO.write(bufferedImage, format, new File(defaultFilePath));
}else {
ImageIO.write(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig), format, new File(defaultFilePath));
}
} catch (Exception e) {
result = "生成二維碼出錯!"+e.toString();
}
return result;
}
/**
* 繪製logo圖片
* @param matrixImage
* @param logoFile
* @return
* @throws IOException
*/
public static BufferedImage groupImage(BufferedImage matrixImage, File logoFile) throws IOException {
//先讀取二維碼圖片
Graphics2D g = matrixImage.createGraphics();
//再讀取logo圖片
BufferedImage logoImage = ImageIO.read(logoFile);
//設置logo大小,太大,會覆蓋二維碼,此處20%
int logoWidth = logoImage.getWidth() > matrixImage.getWidth()*2 /10 ? (matrixImage.getWidth()*2 /10) : logoImage.getWidth();
int logoHeight = logoImage.getHeight() > matrixImage.getHeight()*2 /10 ? (matrixImage.getHeight()*2 /10) : logoImage.getHeight();
//設置logo圖片放置位置 放在中心
int x = (matrixImage.getWidth() - logoWidth) / 2;
int y = (matrixImage.getHeight() - logoHeight) / 2;
//開始合併繪製圖片
g.drawImage(logoImage, x, y, logoWidth, logoHeight, null);
g.drawRoundRect(x, y, logoWidth, logoHeight, 15 ,15);
//線條設置
BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
g.setStroke(stroke);
//logo邊框顏色
g.setColor(Color.WHITE);
g.drawRect(x, y, logoWidth, logoHeight);
//釋放對象
g.dispose();
logoImage.flush();
matrixImage.flush();
return matrixImage;
}
/**
* @Title: setCodeParams
* @Desc: 設置二維碼參數
* @param
* @return
*/
public static HashMap<EncodeHintType, Object> setCodeParams() {
// 封裝二維碼的參數
HashMap<EncodeHintType, Object> hashMap = new HashMap<>();
hashMap.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 字符集
hashMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); // 糾錯等級
hashMap.put(EncodeHintType.MARGIN, 2); // 邊距
return hashMap;
}
/**
* @Title: savePalce
* @Desc: 二維碼保存地址
* @param
* @return
*/
public static String savePalce(String path) {
String codeName = UUID.randomUUID().toString() + $.dateObj.Format("YYYY-MM-DD",new Date()).replace("-", "s");
defaultFilePath = path + codeName.trim() + "." + format;
return defaultFilePath;
}
/**
* @Title: readCode
* @Desc: 讀取二維碼信息
* @param file
* @return
*/
public static String readCode(File file) {
String result = "";
try {
MultiFormatReader formatReader = new MultiFormatReader();
BufferedImage image = ImageIO.read(file);
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(image)));
Map<DecodeHintType, Object> hints = new HashMap<>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8");// 字符集
Result decodeResult = formatReader.decode(binaryBitmap, hints);
result = "解析之後的結果:" + decodeResult.toString() + "\n" + "二維碼格式類型:" + decodeResult.getBarcodeFormat() + "\n"
+ "二維碼文本內容:" + decodeResult.getText() + "!";
} catch (Exception e) {
result = "解析錯誤";
return result;
}
return result;
}
/**
* @Title: checkFormat
* @Desc: 驗證文件後綴格式
* @param logoFile
* @return
*/
public static boolean checkFormat(File logoFile) {
//文件是否爲空
if(null==logoFile) {
System.out.println("logo文件爲空!");
return true;
}
String fileName = logoFile.getName();
String suffix = fileName.substring(fileName.lastIndexOf(".")+1);
for(String s : checkList) {
if(s.equalsIgnoreCase(suffix)) {
return true;
}
}
return false;
}
}