背景图和二维码合成
需求: 類似于做一個碼牌, UI提供背景圖模板, 后端將二維碼合成到背景圖模板中
背景圖模板????????????????????????????????????????? ? ? ? 最終效果圖
開擼
package cc.sunni;import cn.hutool.core.util.StrUtil; import cn.hutool.extra.qrcode.QrCodeUtil; import cn.hutool.extra.qrcode.QrConfig; import org.springframework.core.io.ClassPathResource; import sun.misc.BASE64Encoder;import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream;/*** 碼牌: 將二維碼合成到背景圖片中** @author 江黎* @since 2022-07-21*/ public class QrCodeCard {/*** 二維碼的寬度*/private static final int QR_CODE_WIDTH = 640;/*** 二維碼的高度*/private static final int QR_CODE_HEIGHT = 640;/*** title字體*/private static final Font TITLE_FONT = new Font("宋體", Font.BOLD, 30);/*** desc字體*/private static final Font DESC_FONT = new Font("宋體", Font.PLAIN, 25);/*** bottom字體*/private static final Font BOTTOM_FONT = new Font("宋體", Font.ITALIC, 24);private static final String FORMAT_NAME = "PNG";/*** @param title 標題* @param desc 描述* @param content 二維碼內容* @param bottom 底部文字* @param imgLogo 二維碼中間圖片地址* @param backgroundImage 背景圖片地址* @param imageY 二維碼在背景圖片的Y軸位置, X軸是居中的* @return 返回BufferedImage方便后續處理是生成圖片還是生成base64字符串*/public static BufferedImage createQrCode(String title, String desc, String content, String bottom, String imgLogo, String backgroundImage, int imageY) throws IOException {// 創建主模板圖片int maxWidth = getMaxWidth(title, desc, bottom);int maxHeight = getMaxHeight();BufferedImage image = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_RGB);Graphics2D graphics = image.createGraphics();if (StrUtil.isNotBlank(backgroundImage)) {// 設置圖片的背景色為透明, 需要合成到背景圖片就設置為透明image = graphics.getDeviceConfiguration().createCompatibleImage(maxWidth, maxHeight, Transparency.TRANSLUCENT);} else {// 設置圖片的背景色為白色graphics.setColor(Color.white);}graphics.fillRect(0, 0, maxWidth, maxHeight);// 動態高度int height = 0;// *********************** title ***********************if (StrUtil.isNotBlank(title)) {graphics = image.createGraphics();// 設置字體顏色 black黑 white白graphics.setColor(Color.black);// 設置字體graphics.setFont(TITLE_FONT);graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);// 居中 x開始的位置:(圖片寬度-字體大小*字的個數)/2int x = (maxWidth - (TITLE_FONT.getSize() * title.length())) / 2;int strHeight = getStringHeight(graphics);graphics.drawString(title, x, strHeight);height += strHeight;}// ********************** desc **********************if (StrUtil.isNotBlank(desc)) {graphics = image.createGraphics();// 設置字體顏色,先設置顏色,再填充內容graphics.setColor(Color.black);// 設置字體graphics.setFont(DESC_FONT);graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);// 獲取字符高度int strHeight = getStringHeight(graphics);// 按行居中顯示String[] info = desc.split("\\$"); // 多行文字以 $ 分隔for (int i = 0; i < info.length; i++) {String s = info[i];// x開始的位置:(圖片寬度-字體大小*字的個數)/2int strWidth = graphics.getFontMetrics().stringWidth(s);// 總長度減去文字長度的一半 (居中顯示)int startX = (maxWidth - strWidth) / 2;height += strHeight * (i + 1);graphics.drawString(s, startX, height);}}// ********************** 插入二維碼圖片 **********************Graphics codePic = image.getGraphics();BufferedImage codeImg;QrConfig config = new QrConfig();config.setMargin(2);config.setWidth(QR_CODE_WIDTH);config.setHeight(QR_CODE_HEIGHT);if (StrUtil.isNotBlank(imgLogo)) {config.setImg(imgLogo);}codeImg = QrCodeUtil.generate(content, config);// 繪制二維碼codePic.drawImage(codeImg, (maxWidth - QR_CODE_WIDTH) / 2, height, QR_CODE_WIDTH, QR_CODE_HEIGHT, null);codePic.dispose();// ********************** bottom **********************if (StrUtil.isNotBlank(bottom)) {graphics = image.createGraphics();// 設置字體顏色graphics.setColor(Color.black);// 設置字體graphics.setFont(BOTTOM_FONT);graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);// x開始的位置:(圖片寬度-字體大小*字的個數)/2int startX = (maxWidth - (BOTTOM_FONT.getSize() * bottom.length())) / 2;// 獲取字符高度int footerStrHeight = getStringHeight(graphics);height += QR_CODE_HEIGHT + footerStrHeight;graphics.drawString(bottom, startX, height);}if (StrUtil.isNotBlank(backgroundImage)) {// 加載背景模板ClassPathResource resource = new ClassPathResource(backgroundImage);InputStream inputStream = resource.getInputStream();BufferedImage templateImage = ImageIO.read(inputStream);Graphics graphicsTemplate = templateImage.getGraphics();// 根據模板寬度 - 二維碼寬度 進行居中算出X坐標int widthX = (templateImage.getWidth() - image.getWidth()) / 2;// 添加二維碼graphicsTemplate.drawImage(image, widthX, imageY, null);graphicsTemplate.dispose();return templateImage;} else {return image;}}// 生成圖片文件public static void createImage(BufferedImage image, String fileLocation) {if (image != null) {try {ImageIO.write(image, "png", new File(fileLocation));} catch (IOException e) {e.printStackTrace();}}}// 獲取圖片base64數據public static String base64ImageString(BufferedImage image) throws IOException {ByteArrayOutputStream bos = new ByteArrayOutputStream();//io流ImageIO.write(image, FORMAT_NAME, bos);//寫入流中byte[] bytes = bos.toByteArray();//轉換成字節BASE64Encoder encoder = new BASE64Encoder();String jpgBase64 = encoder.encodeBuffer(bytes).trim();//轉換成base64串jpgBase64 = jpgBase64.replaceAll("\n", "").replaceAll("\r", "");//刪除 \r\nreturn "data:image/jpg;base64," + jpgBase64;}// 字符串總寬度private static int getStringLength(Graphics g, String str) {char[] chars = str.toCharArray();return g.getFontMetrics().charsWidth(chars, 0, str.length());}// 字符高度private static int getStringHeight(Graphics g) {return g.getFontMetrics().getHeight();}// 每一行字符的個數private static int getRowStrNum(int strNum, int rowWidth, int strWidth) {return (rowWidth * strNum) / strWidth;}// 字符行數private static int getRows(int strWidth, int rowWidth) {int rows;if (strWidth % rowWidth > 0) {rows = strWidth / rowWidth + 1;} else {rows = strWidth / rowWidth;}return rows;}// 計算二維碼圖片最大寬度private static int getMaxWidth(String title, String desc, String bottom) {int width = 0;BufferedImage image = new BufferedImage(QR_CODE_WIDTH, QR_CODE_HEIGHT, BufferedImage.TYPE_INT_RGB);Graphics2D graphics = image.createGraphics();if (StrUtil.isNotBlank(title)) {width = Math.max(getStringLength(graphics, title), width);}if (StrUtil.isNotBlank(desc)) {width = Math.max(getStringLength(graphics, desc), width);}if (StrUtil.isNotBlank(bottom)) {width = Math.max(getStringLength(graphics, bottom), width);}return Math.max(QR_CODE_WIDTH, width);}// 計算二維碼圖片最大高度private static int getMaxHeight() {int height = QR_CODE_HEIGHT;BufferedImage image = new BufferedImage(QR_CODE_WIDTH, QR_CODE_HEIGHT, BufferedImage.TYPE_INT_RGB);Graphics2D graphics = image.createGraphics();graphics.setFont(TITLE_FONT);height += getStringHeight(graphics);graphics.setFont(DESC_FONT);height += getStringHeight(graphics);graphics.setFont(BOTTOM_FONT);height += getStringHeight(graphics);return height;}public static void main(String[] args) throws IOException {String title = "碼牌";String desc = "知名互聯網公司CEO";String content = "https://www.baidu.com";String logo = "templates/logo@2x.png";String bottom = "國家認證";String backgroundImage = "templates/announcer.png"; // BufferedImage bufferedImage = createQrCode(null, null, content, logo, null, backgroundImage, 290);BufferedImage bufferedImage = createQrCode(title, desc, content, logo, bottom, backgroundImage, 290);createImage(bufferedImage, "D:/test.png");} }?附上下載的方法
????
總結
- 上一篇: centos 宝塔面板 mongodb
- 下一篇: 博客园的编辑器毛病真多.....