java 中的生成二維碼工具類 圖片中並帶圖片


package com.property.common.utils.qrcode;

import com.google.common.collect.Maps;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.property.common.utils.DESUtil;
import com.property.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.util.Map;

/**
* @author Administrator
*/
@Slf4j
public class QrCodeUtils {

/**
* 字體大小
*/

private static final int FONT_STYLE = 1;
/**
* 圖片的寬度
*/
private static final int IMAGE_WIDTH = 350;
/**
* 圖片的高度(需按實際內容高度進行調整)
*/
private static final int IMAGE_HEIGHT = 350;
/**
* 二維碼的寬度
*/
private static final int QR_CODE_WIDTH = 220;
/**
* 二維碼的寬度
*/
private static final int QR_CODE_HEIGHT = 220;


/**
* 字體大小
*/
private static final int FONT_SIZE = 15;

/**
* 生成二維碼的格式
*/
private static final String FORMAT = "jpg";


/**
* 根據內容生成二維碼數據
*
* @param content 二維碼文字內容[為了信息安全性,一般都要先進行數據加密]
* @param imgWidth 二維碼圖片寬度
* @param imgLength 二維碼圖片高度
*/
private static BitMatrix createQrcodeMatrix(String content, int imgWidth, int imgLength) {
Map<EncodeHintType, Object> hints = Maps.newEnumMap(EncodeHintType.class);
// 設置字符編碼
hints.put(EncodeHintType.CHARACTER_SET, Charsets.UTF_8.name());
// 指定糾錯等級
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//設置二維碼四周白色區域的大小
hints.put(EncodeHintType.MARGIN, 1);
try {
String encrypt = DESUtil.encrypt(content);
return new MultiFormatWriter().encode(StringUtils.isNotBlank(encrypt) ? encrypt : "很抱歉,二維碼生成失敗!", BarcodeFormat.QR_CODE, imgWidth == 0 ? IMAGE_WIDTH : imgWidth, imgLength == 0 ? IMAGE_HEIGHT : imgLength, hints);
} catch (Exception e) {
return null;
}

}

/**
* 根據指定邊長創建生成的二維碼,允許配置logo屬性
*
* @param content 二維碼內容
* @param logoFile logo 文件對象,可以為空
* @param logoConfig logo配置,可設置logo展示長寬,邊框顏色
* @param imgWidth 二維碼寬度
* @param imgLength 二維碼長度
* @return 二維碼圖片的字節數組
*/
public static byte[] createQrcode(String content, File logoFile, LogoConfig logoConfig, int imgWidth, int imgLength) {
if (logoFile != null && !logoFile.exists()) {
throw new IllegalArgumentException("請提供正確的logo文件!");
}
BitMatrix qrCodeMatrix = createQrcodeMatrix(content, imgWidth, imgLength);
if (qrCodeMatrix == null) {
return null;
}
try {
File file = Files.createTempFile("qrcode_log", "." + FORMAT).toFile();

MatrixToImageWriter.writeToFile(qrCodeMatrix, FORMAT, file);
if (logoFile != null) {
// 添加logo圖片, 此處一定需要重新進行讀取,而不能直接使用二維碼的BufferedImage 對象
BufferedImage img = ImageIO.read(file);
overlapImage(img, FORMAT, file.getAbsolutePath(), logoFile, logoConfig);
}
return toByteArray(file);
} catch (Exception e) {
return null;
}
}

/**
* 根據指定邊長創建生成的二維碼,
*
* @param content 二維碼內容
* @param imgWidth 二維碼寬度
* @param imgLength 二維碼長度
* @return BufferedImage
*/
public static BufferedImage bufferedImage(String content, int imgWidth, int imgLength) {
BitMatrix qrCodeMatrix = createQrcodeMatrix(content, imgWidth, imgLength);
if (qrCodeMatrix == null) {
return null;
}
try {
return MatrixToImageWriter.toBufferedImage(qrCodeMatrix);
} catch (Exception e) {
return null;
}
}

/**
* 把生成的圖片寫到本地磁盤
*
* @param qrCodeContent 二維碼內容
* @param headText 頭部文字內容
* @param pressText 增加的文字
* @throws Exception
*/
public static InputStream generateQrCode(String qrCodeContent, String headText, String pressText) {
// 頭部文字區域高度
int titleHeight = 50;
// 創建主模板圖片
BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D main = image.createGraphics();
// 設置圖片的背景色
//白色
main.setColor(Color.white);
main.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
// BufferedImage image = bufferedImage(qrCodeContent, IMAGE_WIDTH, IMAGE_HEIGHT);
ByteArrayOutputStream byteArrayOutputStream = null;
try {
// String path = Thread.currentThread().getContextClassLoader().getResource("static/simsun.ttc").getPath();
// 動態高度
int height = 0;
//***********************頁面頭部 文字****************
Graphics2D titleRight = image.createGraphics();
// 設置字體顏色 black黑 white白
titleRight.setColor(Color.black);
// 設置字體
Font titleFont = new Font("NSimSun", Font.BOLD, 25);
// Font titleFont = SystemLoadFont.styleFont(path, Font.BOLD, 25);
titleRight.setFont(titleFont);
titleRight.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
// 居中 x開始的位置:(圖片寬度-字體大小*字的個數)/2
int x = (IMAGE_WIDTH - (titleFont.getSize() * headText.length())) / 2;
titleRight.drawString(headText, x, (titleHeight) / 2 + 10);
height += titleHeight;


//**********************中間文字部分*********
Graphics2D centerWord = image.createGraphics();
// 設置字體顏色,先設置顏色,再填充內容
centerWord.setColor(Color.black);
// 設置字體
// Font wordFont = SystemLoadFont.styleFont(path, Font.PLAIN, 15);
Font wordFont = new Font("NSimSun", Font.PLAIN, 15);
centerWord.setFont(wordFont);
centerWord.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
String[] info = pressText.split("&");
for (String s : info) {
// x開始的位置:(圖片寬度-字體大小*字的個數)/2
int strWidth = centerWord.getFontMetrics().stringWidth(s);
// 總長度減去文字長度的一半 (居中顯示)
int startX = (IMAGE_WIDTH - strWidth) / 2;
height += 20;
centerWord.drawString(s, startX, height);
}

//***************插入二維碼圖片***********************************************
Graphics codePic = image.getGraphics();
BufferedImage codeImg;

codeImg = bufferedImage(qrCodeContent, QR_CODE_WIDTH, QR_CODE_HEIGHT);
// 繪制二維碼
codePic.drawImage(codeImg, (IMAGE_WIDTH - QR_CODE_WIDTH) / 2, (height + 5), QR_CODE_WIDTH, QR_CODE_HEIGHT, null);
codePic.dispose();


//**********************底部公司名字*********
Graphics2D g2 = (Graphics2D) image.getGraphics();
//開啟文字抗鋸齒
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
Font font = new Font("NSimSun", Font.PLAIN, 15);
// Font font = SystemLoadFont.styleFont(path, Font.PLAIN, 15);
g2.setFont(font);
pressText = "公司名字";
//x開始的位置:(圖片寬度-字體大小*字的個數)/2
int startX = (IMAGE_WIDTH - (font.getSize() * pressText.length())) / 2;
// //y開始的位置:圖片高度-(圖片高度-圖片寬度)/2
// height += QR_CODE_HEIGHT;
// 獲取字符高度
int footerStrHeight = getStringHeight(g2);
height += QR_CODE_HEIGHT + footerStrHeight;
// 設置字體顏色
g2.setColor(Color.black);
g2.drawString(pressText, startX, height);
g2.dispose();
image.flush();
byteArrayOutputStream = new ByteArrayOutputStream();
ImageOutputStream imageOutput = ImageIO.createImageOutputStream(byteArrayOutputStream);
ImageIO.write(image, "jpg", imageOutput);
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
// 圖片文件輸入輸出流必須記得關閉
IOUtils.closeQuietly(byteArrayOutputStream);
}
}

// 字符高度
private static int getStringHeight(Graphics g) {
return g.getFontMetrics().getHeight();
}

// 字符串總寬度
private static int getStringLength(Graphics g, String str) {
char[] chars = str.toCharArray();
return g.getFontMetrics().charsWidth(chars, 0, str.length());
}

/**
* 將文件轉換為字節數組,
* 使用MappedByteBuffer,可以在處理大文件時,提升性能
*
* @param file 文件
* @return 二維碼圖片的字節數組
*/
private static byte[] toByteArray(File file) {
try (FileChannel fc = new RandomAccessFile(file, "r").getChannel();) {
MappedByteBuffer byteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load();
byte[] result = new byte[(int) fc.size()];
if (byteBuffer.remaining() > 0) {
byteBuffer.get(result, 0, byteBuffer.remaining());
}
return result;
} catch (Exception e) {
return null;
}
}

/**
* 將logo添加到二維碼中間
*
* @param image 生成的二維碼圖片對象
* @param imagePath 圖片保存路徑
* @param logoFile logo文件對象
* @param format 圖片格式
*/
private static void overlapImage(BufferedImage image, String format, String imagePath, File logoFile,
LogoConfig logoConfig) throws IOException {
try {
BufferedImage logo = ImageIO.read(logoFile);
Graphics2D g = image.createGraphics();
// 考慮到logo圖片貼到二維碼中,建議大小不要超過二維碼的1/5;
int width = image.getWidth() / logoConfig.getLogoPart();
int height = image.getHeight() / logoConfig.getLogoPart();
// logo起始位置,此目的是為logo居中顯示
int x = (image.getWidth() - width) / 2;
int y = (image.getHeight() - height) / 2;
// 繪制圖
g.drawImage(logo, x, y, width, height, null);
// 給logo畫邊框
// 構造一個具有指定線條寬度以及 cap 和 join 風格的默認值的實心 BasicStroke
g.setStroke(new BasicStroke(logoConfig.getBorder()));
g.setColor(logoConfig.getBorderColor());
g.drawRect(x, y, width, height);
g.dispose();
// 寫入logo圖片到二維碼
ImageIO.write(image, format, new File(imagePath));
} catch (Exception e) {
throw new IOException("二維碼添加logo時發生異常!", e);
}
}

}






生成的樣圖:
用到的字體是 新宋體





package com.property.common.utils.qrcode;

import com.google.zxing.common.BitMatrix;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

/**
* @Description 二維碼生成類
* @Author wangliangzhi
* @Date 日期:2021/11/3 時間:17:41
**/
public final class MatrixToImageWriter {
private static final int BLACK = 0xFF000000;
private static final int WHITE = 0xFFFFFFFF;

private MatrixToImageWriter() {
}


public static BufferedImage toBufferedImage(BitMatrix matrix) {
int width = matrix.getWidth();
int height = matrix.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, matrix.get(x, y) ? BLACK : WHITE);
}
}
return image;
}


public static void writeToFile(BitMatrix matrix, String format, File file)
throws IOException {
BufferedImage image = toBufferedImage(matrix);
if (!ImageIO.write(image, format, file)) {
throw new IOException("Could not write an image of format " + format + " to " + file);
}
}


public static void writeToStream(BitMatrix matrix, String format, OutputStream stream)
throws IOException {
BufferedImage image = toBufferedImage(matrix);
if (!ImageIO.write(image, format, stream)) {
throw new IOException("Could not write an image of format " + format);
}
}
}




圖片中的文字換行 是根據
String[] info = pressText.split("&");

這行代碼實現的

 

 





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM