Java基于Graphics2D實(shí)現(xiàn)海報(bào)制作
效果
海報(bào)一
海報(bào)二
代碼
參數(shù)實(shí)體類
package com.ly.cloud.dto; import lombok.Data; /** * @Author * @Date Created in 2024/4/24 下午2:16 * @DESCRIPTION: 海報(bào)頁面所需的參數(shù) 實(shí)體類 * @Version V1.0 */ @Data public class PosterTemplateDto { /** * 用來判斷是不是 需要把數(shù)據(jù)寫死 0 寫死的對象,1 自己傳的 */ private String id; { id = "0"; } /** * 海報(bào)編號(hào) 0: 橫向海報(bào) 1: 豎向海報(bào) */ private String posterId; /** * 海報(bào)顏色 0: 綠色 1: 藍(lán)色 2: 紅色 */ private String posterColor; /** * 海報(bào)背景圖片名稱 */ private String posterBackImage; /** * 海報(bào)logo */ private String posterLogo; /** * 海報(bào)主題 xxxx 第 x 期 */ private String posterTopic; /** * 海報(bào)標(biāo)題 */ private String posterTitle; /** * 海報(bào)年份 */ private String posterYear; /** * 海報(bào)具體時(shí)間 幾月幾號(hào) */ private String posterMonth; /** * 海報(bào)具體時(shí)間 14:30 ~ 15:30(周四) */ private String posterDay; /** * 講座就行校區(qū) */ private String posterSchool; /** * 講座的具體地址 */ private String posterAddress; /** * 講座主講人 */ private String posterMainSpeaker; /** * 主講人個(gè)人詳細(xì)信息介紹 */ private String posterPeopleDetail; /** * 主持人 */ private String mainPeople; }
工具類
FileUtil.java
package com.ly.cloud.util; import com.alibaba.druid.support.logging.Log; import com.alibaba.druid.support.logging.LogFactory; import org.springframework.web.multipart.MultipartFile; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.nio.file.Files; /** * @Author * @Date Created in 2024/4/11 上午11:13 * @DESCRIPTION: 將 multipartFile --> file * @Version V1.0 */ public class FileUtil { private final static Log logger = LogFactory.getLog(FileUtil.class); /** * 將 multipartFile --> fileInputStream */ public static FileInputStream convertMultipartFileToInputStream(MultipartFile multipartFile) throws IOException { // 創(chuàng)建臨時(shí)文件 File tempFile = File.createTempFile("temp", null); // 將MultipartFile的數(shù)據(jù)寫入臨時(shí)文件 try (FileOutputStream fos = new FileOutputStream(tempFile)) { fos.write(multipartFile.getBytes()); } // 將臨時(shí)文件轉(zhuǎn)換為FileInputStream FileInputStream fileInputStream = new FileInputStream(tempFile); // 刪除臨時(shí)文件 tempFile.delete(); return fileInputStream; } /** * 將上傳的 logo圖片保存在本地; */ public static File convertInputStreamToFile(InputStream inputStream,String fileName) throws IOException { // 創(chuàng)建圖片文件 String resourcesPath = new File("src/main/resources/").getAbsolutePath(); // 拼接images目錄的路徑 String imagesPath = resourcesPath + "/static/imagesLogo/"; // 這里的static是resources目錄下的一個(gè)示例子目錄,你可以根據(jù)實(shí)際情況修改 logger.info("我的路徑是:{}"+imagesPath); File directory = new File(imagesPath); // 如果目標(biāo)文件夾不存在,則創(chuàng)建它 if (!directory.exists()) { directory.mkdirs(); } File file = new File(directory, fileName); try (OutputStream outputStream = Files.newOutputStream(file.toPath())) { byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, length); } } // deleteImage(imagesPath,fileName); return file; } /** * 刪除圖片 */ public static void deleteImage(String directoryPath, String imageName) { File directory = new File(directoryPath); if (!directory.exists() || !directory.isDirectory()) { return; } File imageFile = new File(directory, imageName); if (imageFile.exists() && imageFile.isFile()) { if (imageFile.delete()) { logger.info("刪除圖片成功!"); } else { logger.error("刪除圖片失?。?); } } else { System.out.println("Image file " + imageName + " does not exist."); } } /** * 修改圖片的寬高 等比例擴(kuò)大 海報(bào)背景圖和 logo */ public static byte[] resizeImage(byte[] imageData, int width, int height) throws IOException { ByteArrayInputStream bis = new ByteArrayInputStream(imageData); BufferedImage image = ImageIO.read(bis); Image resizedImage = image.getScaledInstance(width, height, Image.SCALE_SMOOTH); BufferedImage bufferedResizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); bufferedResizedImage.getGraphics().drawImage(resizedImage, 0, 0, null); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ImageIO.write(bufferedResizedImage, "jpg", bos); byte[] resizedImageData = bos.toByteArray(); bis.close(); bos.close(); return resizedImageData; } // public static void main(String[] args) throws IOException { // String resourcesPath = new File("src/main/resources/").getAbsolutePath(); // // 拼接images目錄的路徑 // String imagesPath = resourcesPath + "/static/images/"; // 這里的static // // // 讀取背景圖片 // BufferedImage backgroundImage = ImageIO.read(new File(imagesPath + "/" + "4c9a599ae920240424112637.png")); // ImageIO.write(backgroundImage, "PNG", new File("D:\\test1\\image.png")); // // } }
PosterUtil.java
package com.ly.cloud.util; import sun.font.FontDesignMetrics; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; /** * @Author * @Date Created in 2024/4/24 下午2:45 * @DESCRIPTION: 海報(bào)工具類 * @Version V1.0 */ public class PosterUtil { /** * 從新設(shè)置海報(bào)圖片的寬和高 * @param originalImage 原始圖片 * @param targetWidth 寬 * @param targetHeight 高 * @return BufferedImage */ public static BufferedImage scaleImage(BufferedImage originalImage, int targetWidth, int targetHeight) { int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType(); BufferedImage scaledImage = new BufferedImage(targetWidth, targetHeight, type); Graphics2D g = scaledImage.createGraphics(); // Calculate the ratio between the original and scaled image size double scaleX = (double) targetWidth / originalImage.getWidth(); double scaleY = (double) targetHeight / originalImage.getHeight(); double scale = Math.min(scaleX, scaleY); // Now we perform the actual scaling int newWidth = (int) (originalImage.getWidth() * scale); int newHeight = (int) (originalImage.getHeight() * scale); int x = (targetWidth - newWidth) / 2; int y = (targetHeight - newHeight) / 2; g.drawImage(originalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH), x, y, null); g.dispose(); return scaledImage; } /** * @Author * @Description 海報(bào)橫向文字寫字換行算法 * @Date 18:08 2024/4/24 * @Param 參數(shù) Graphics2D 對象 、font 字體設(shè)置 、 文字、 x軸左邊、 y軸坐標(biāo) 、每行字體的換行寬度 **/ public static void drawWordAndLineFeed(Graphics2D g2d, Font font, String words, int wordsX, int wordsY, int wordsWidth) { FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font); // 獲取字符的最高的高度 int height = metrics.getHeight(); int width = 0; int count = 0; int total = words.length(); String subWords = words; int b = 0; for (int i = 0; i < total; i++) { // 統(tǒng)計(jì)字符串寬度 并與 預(yù)設(shè)好的寬度 作比較 if (width <= wordsWidth) { width += metrics.charWidth(words.charAt(i)); // 獲取每個(gè)字符的寬度 count++; } else { // 畫 除了最后一行的前幾行 String substring = subWords.substring(0, count); g2d.drawString(substring, wordsX, wordsY + (b * height)); subWords = subWords.substring(count); b++; width = 0; count = 0; } // 畫 最后一行字符串 if (i == total - 1) { g2d.drawString(subWords, wordsX, wordsY + (b * height)); } } } /** * 將上傳的個(gè)人頭像裁剪成對應(yīng)的海報(bào)比例的頭像,并裁剪成圓形 * @param image 讀取的頭像找 * @param size 寬高大小像素 * @return BufferedImage */ public static BufferedImage resizeAndClipToCircle(BufferedImage image, int size) { // 縮小圖片 BufferedImage resizedImage = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = resizedImage.createGraphics(); g2d.drawImage(image, 0, 0, size, size, null); g2d.dispose(); // 裁剪成圓形 BufferedImage circularImage = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d2 = circularImage.createGraphics(); Ellipse2D.Double ellipse = new Ellipse2D.Double(0, 0, size, size); g2d2.setClip(ellipse); g2d2.drawImage(resizedImage, 0, 0, size, size, null); g2d2.dispose(); return circularImage; } /** * 部分文字 垂直排序時(shí),不滿多列,最后一列居中顯示 * @param textGraphics Graphics 對象 * @param text 要傳入的海報(bào)描述 */ public static void drawMyString(Graphics textGraphics, String text,Color color) { // 每列顯示的漢字?jǐn)?shù)量 int columnSize = 7; // 文字之間的垂直間距 int verticalSpacing = 75; // 獲取字體渲染上下文 FontMetrics fm = textGraphics.getFontMetrics(); // 獲取字體的高度 int fontHeight = fm.getHeight(); System.out.println(fontHeight); // 計(jì)算每列的寬度 int columnWidth = fontHeight + verticalSpacing; // 設(shè)置初始位置 int x = 280; int y = 450; Font fontFour = new Font(" Source Han Sans CN", Font.BOLD, 100); textGraphics.setFont(fontFour); textGraphics.setColor(color); // 繪制文字 int charCount = 0; int totalColumns = (int)Math.ceil((double)text.length() / columnSize); // 總列數(shù) int totalRows = Math.min(columnSize, text.length()); // 總行數(shù) int remainingChars = text.length() % columnSize; // 最后一列剩余字符數(shù) for (int columnIndex = 0; columnIndex < totalColumns; columnIndex++) { for (int rowIndex = 0; rowIndex < totalRows; rowIndex++) { if (charCount >= text.length()) break; char ch = text.charAt(charCount); // 計(jì)算當(dāng)前位置 int cx = x - columnIndex * columnWidth; int cy = y + rowIndex * fontHeight + rowIndex * verticalSpacing; // 加入垂直偏移量 // 計(jì)算當(dāng)前位置 // int cx = x - columnIndex * columnWidth; // int cy = y + rowIndex * fontHeight + rowIndex * verticalSpacing + columnIndex ; // 如果是最后一列并且不滿 7 個(gè)字符,則需要將剩余字符居中 if (columnIndex == totalColumns - 1 && remainingChars > 0) { int extraVerticalSpace = (columnSize - remainingChars) * (fontHeight + verticalSpacing) / 2; cy += extraVerticalSpace; } // 繪制文字 textGraphics.drawString(String.valueOf(ch), cx, cy); charCount++; } } } /** * 橫向顯示 垂直文字 * @param textGraphics Graphics 對象 * @param text 顯示的 內(nèi)容 * @param number 沒列顯示漢字?jǐn)?shù)量 */ public static void drawString(Graphics textGraphics,String text,int number){ // 每列顯示的漢字?jǐn)?shù)量 int columnSize = number; // 文字之間的垂直間距 int verticalSpacing = 50; // 獲取字體渲染上下文 FontMetrics fm = textGraphics.getFontMetrics(); // 獲取字體的高度 int fontHeight = fm.getHeight(); // 計(jì)算每列的寬度 int columnWidth = fontHeight + verticalSpacing; // 設(shè)置初始位置 int x = 0; int y = 0; switch (number) { case 3: x = 1250; y = 790; break; case 10: x = 1150; y = 800; break; // 可以添加更多的條件分支 default: // 默認(rèn)情況下的坐標(biāo)設(shè)置 break; } if (number == 10) { Font fontFour = new Font(text, Font.BOLD, 60); textGraphics.setFont(fontFour); textGraphics.setColor(Color.WHITE); } // 繪制文字 for (int i = 0; i < text.length(); i++) { char ch = text.charAt(i); // 計(jì)算當(dāng)前位置 int cx = x - (i / columnSize) * columnWidth; int cy = y + (i % columnSize) * fontHeight; // 繪制文字 textGraphics.drawString(String.valueOf(ch), cx, cy); } } public static void drawCenteredText(Graphics graphics, String text, int oneY, int twoY) { // 設(shè)置字體和顏色 Font font = new Font("宋體", Font.BOLD, 50); graphics.setFont(font); graphics.setColor(Color.WHITE); // 獲取字體渲染上下文 FontMetrics fm = graphics.getFontMetrics(font); // 截取第二行文字的部分 String textTwo = text.substring(text.indexOf("第")); // 獲取第一行文字的寬度 String textOne = text.substring(0, text.indexOf("第")); // 獲取第二行文字的寬度 int textTwoWidth = fm.stringWidth(textTwo); // 計(jì)算第一行文字的起始x坐標(biāo),使其水平居中 int oneX = 50; // 計(jì)算第二行文字的起始x坐標(biāo),使其水平居中 int twoX = (450 - textTwoWidth) / 2; // 繪制第一行文字 graphics.drawString(textOne, oneX, oneY); // 繪制第二行文字 graphics.drawString(textTwo, twoX, twoY); } /** * 在Graphics2D對象上繪制豎排文字 * * @param textGraphics Graphics2D對象 * @param text 要繪制的文字 */ public static void drawMyLectureString(Graphics textGraphics, String text) { // 每列顯示的漢字?jǐn)?shù)量 int columnSize = 25; // 文字之間的垂直間距 int verticalSpacing = 1; // 獲取字體渲染上下文 FontMetrics fm = textGraphics.getFontMetrics(); // 獲取字體的高度 int fontHeight = fm.getHeight() - 30; // 計(jì)算每列的寬度 int columnWidth = fontHeight + verticalSpacing; // 設(shè)置初始位置 int x = 800; int y = 190; Font fontFour = new Font("宋體", Font.BOLD, 40); textGraphics.setFont(fontFour); textGraphics.setColor(Color.WHITE); // 計(jì)算總列數(shù) int totalColumns = (int) Math.ceil((double) text.length() / columnSize); // 總列數(shù) // 繪制文字 int charCount = 0; for (int rowIndex = 0; rowIndex < columnSize; rowIndex++) { for (int columnIndex = 0; columnIndex < totalColumns; columnIndex++) { int charIndex = rowIndex * totalColumns + columnIndex; if (charIndex >= text.length()) break; char ch = text.charAt(charIndex); // 計(jì)算當(dāng)前位置 int cx = x - columnIndex * columnWidth; int cy = y + rowIndex * fontHeight + rowIndex * verticalSpacing; // 加入垂直偏移量 // 繪制文字 textGraphics.drawString(String.valueOf(ch), cx, cy); } } } /** * 字體傾斜 */ public static void qinxie(Font fontMonth,Graphics2D graphics){ // 創(chuàng)建 AffineTransform 對象 AffineTransform month = new AffineTransform(); // 設(shè)置水平傾斜 month.shear(-0.2, 0); // + 向左 - 向右傾斜 // 應(yīng)用變換到字體 fontMonth = fontMonth.deriveFont(month); graphics.setFont(fontMonth); } /** * 文字垂直 */ public static void drawSecondString(Graphics textGraphics, String text, int number) { // 每列顯示的漢字?jǐn)?shù)量 int columnSize = number; // 文字之間的垂直間距 int verticalSpacing = columnSize == 15 ? -500 : 50; // 獲取字體渲染上下文 FontMetrics fm = textGraphics.getFontMetrics(); // 獲取字體的高度 int fontHeight = fm.getHeight(); // 計(jì)算每列的寬度 int columnWidth = columnSize == 15 ? 60 : fontHeight + verticalSpacing; // 設(shè)置初始位置 int x = 0; int y = 0; switch (number) { case 3: x = 1100; y = 200; break; case 10: x = 1000; y = 210; break; case 15: x = 800; y = 210; break; // 可以添加更多的條件分支 default: // 默認(rèn)情況下的坐標(biāo)設(shè)置 break; } if (number == 10) { Font fontFour = new Font(text, Font.BOLD, 60); textGraphics.setFont(fontFour); textGraphics.setColor(Color.WHITE); } else if (number == 15) { Font fontFour = new Font(text, Font.BOLD, 40); textGraphics.setFont(fontFour); textGraphics.setColor(Color.WHITE); } // 繪制文字 for (int i = 0; i < text.length(); i++) { char ch = text.charAt(i); // 計(jì)算當(dāng)前位置 int cx = x - (i / columnSize) * columnWidth; int cy = y + (i % columnSize) * fontHeight; textGraphics.drawString(String.valueOf(ch), cx, cy); } } }
業(yè)務(wù)代碼
首先新建3個(gè)目錄用來存放一下固定的背景圖片和 臨時(shí)的文件
generatePosterTemplate.java
@Override public Map<String, Object> generatePosterTemplate(PosterTemplateDto template) throws IOException { // 首先讀取文件的路徑 String imagesPath = new File("src/main/resources/").getAbsolutePath() + "/static/imagesFirst/"; String imagesPathSecond = new File("src/main/resources/").getAbsolutePath() + "/static/imagesSecond/"; String imagesPathLogo = new File("src/main/resources/").getAbsolutePath() + "/static/imagesLogo/"; String temp = new File("src/main/resources/").getAbsolutePath() + "/static/temp/"; // 創(chuàng)建顏色并設(shè)置透明度 Map<String, Color> map = new HashMap<>(); map.put("0", new Color(0, 88, 38)); map.put("1", new Color(40, 50, 112)); map.put("2", new Color(129, 2, 3)); Color color = map.getOrDefault(template.getPosterColor(), new Color(0, 88, 38)); Map<String, Object> fileMap = new HashMap<>(); String fileName = IdUtil.simpleUUID().substring(0, 10) + DateTimeUtils.stringTime(); PosterTemplateDto posterTemplate = "0".equals(template.getId()) ? createPosterTemplate(template) : template; try { // 讀取背景圖片 if ("0".equals(template.getPosterId())) { // 橫向海報(bào) // 讀取海報(bào)背景圖片 BufferedImage backgroundImage = ImageIO.read(new File("D:\\test1\\backImage.png")); File originalBackFile = new File(StrUtil.isNotBlank(template.getPosterBackImage()) ? getUpdatePhotoPath(imagesPathLogo, template.getPosterBackImage(), 1372, 1978) : imagesPath + "backImage.png"); BufferedImage backgroundImage = ImageIO.read(originalBackFile); if (StrUtil.isNotBlank(template.getPosterBackImage())) { // 將保存到本地的圖片名稱返回給我 fileMap.put("backImage", template.getPosterBackImage()); } int alpha = 180; // 透明度(取值范圍:0 - 255) // 創(chuàng)建 Graphics2D 對象 Graphics2D g2d = backgroundImage.createGraphics(); // 設(shè)置透明度 AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) alpha / 255); g2d.setComposite(alphaComposite); // 設(shè)置背景色 g2d.setColor(color); // 填充整個(gè)圖片區(qū)域 g2d.fillRect(0, 0, backgroundImage.getWidth(), backgroundImage.getHeight()); // 讀取要貼的第一張小圖片 "D:\\test1\\schoolLogo.png" File originalFile = new File(imagesPath + "schoolLogo.png"); BufferedImage image = ImageIO.read(originalFile); // 調(diào)用 resizeImageOne 方法進(jìn)行放大 BufferedImage overlayImage1 = PosterUtil.scaleImage(image, 200, 90); // 讀取要貼的第二張小圖片 BufferedImage overlayImage2 = ImageIO.read(new File(StrUtil.isNotBlank(template.getPosterLogo()) ? getUpdatePhotoPath(imagesPathLogo, template.getPosterLogo(), 670, 66) : imagesPath + "collegeLogo.png")); if (StrUtil.isNotBlank(template.getPosterLogo())) { // 將保存到本地的圖片名稱返回給我 fileMap.put("logo", template.getPosterLogo()); } // 讀取要貼的第三張小圖片 BufferedImage overlayImage3 = ImageIO.read(new File(imagesPath + "erweima.png")); // 讀取頭像圖片 BufferedImage avatarImage = ImageIO.read(new File(imagesPath + "touxiang.png")); // 縮小第五張圖片并裁剪成圓形 BufferedImage scaledCircularAvatar = PosterUtil.resizeAndClipToCircle(avatarImage, 400); // 計(jì)算貼圖位置 // 在背景圖片上貼上第一張圖片 createImage(backgroundImage, overlayImage1, 50, 60); // 在背景圖片上貼上第二張圖片 createImage(backgroundImage, overlayImage2, 280, 70); // 在背景圖片上貼上第三張圖片 createImage(backgroundImage, overlayImage3, 50, 1200); // 在背景圖片上貼上縮小并且裁剪成圓形后的頭像圖片 createImage(backgroundImage, scaledCircularAvatar, 790, 800); // 在圖片上寫字 // TODO 創(chuàng)建Graphics對象 Graphics2D graphics = backgroundImage.createGraphics(); // 設(shè)置第一行字體和顏色:添加海報(bào)主題文字 Font font = new Font("", Font.BOLD, 50); graphics.setFont(font); graphics.setColor(Color.WHITE); graphics.drawString(posterTemplate.getPosterTopic(), 50, 280); // 設(shè)置第二行的字體和顏色 // TODO 添加第二行文字 Font fontTwo = new Font("", Font.BOLD, 140); graphics.setFont(fontTwo); graphics.setColor(Color.WHITE); PosterUtil.drawWordAndLineFeed(graphics, fontTwo, posterTemplate.getPosterTitle(), 45, 480, 1200); // TODO 添加第三行文字 具體地址文字 Font fontThree = new Font("", Font.BOLD, 65); graphics.setFont(fontThree); graphics.setColor(Color.WHITE); graphics.drawString(posterTemplate.getPosterAddress(), 43, 1800); // TODO 添加第四行文字 校區(qū) 地址文字 Font fontFour = new Font("", Font.BOLD, 45); graphics.setFont(fontFour); graphics.setColor(Color.WHITE); graphics.drawString(posterTemplate.getPosterSchool(), 48, 1870); //主講人 PosterUtil.drawString(graphics, "主講人", 3); PosterUtil.drawString(graphics, posterTemplate.getPosterMainSpeaker(), 10); // TODO 1.18 日期 Font fontDate = new Font("", Font.BOLD, posterTemplate.getPosterMonth().length() == 4 ? 150 : 120); graphics.setFont(fontDate); graphics.setColor(Color.WHITE); graphics.drawString(posterTemplate.getPosterMonth(), 135, 900); // TODO 14:30 ~ 15:30 (周四) Font fontMinutes = new Font("", Font.BOLD, 60); graphics.setFont(fontMinutes); graphics.setColor(Color.WHITE); PosterUtil.drawWordAndLineFeed(graphics, fontMinutes, posterTemplate.getPosterDay(), 50, 970, 350); // TODO 添加海報(bào)的文字日期 2024 年份 int yearX = 55; // 文字起始位置 x 坐標(biāo) int yearY = 930; // 文字起始位置 y 坐標(biāo) Font yearFont = new Font("", Font.BOLD, 50); // 設(shè)置渲染提示以獲得更好的質(zhì)量 graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 創(chuàng)建一個(gè) AffineTransform 對象,并將其設(shè)置為順時(shí)針旋轉(zhuǎn)90度 AffineTransform at = new AffineTransform(); at.setToRotation(Math.PI / 2.0, yearX, yearY); // 應(yīng)用 AffineTransform 對象 graphics.setTransform(at); // 獲取字體渲染上下文 FontRenderContext frc = graphics.getFontRenderContext(); // 獲取文本寬度 int textWidth = (int) graphics.getFont().getStringBounds(posterTemplate.getPosterYear(), frc).getWidth(); // 調(diào)整起始位置,以確保文本在旋轉(zhuǎn)后完全可見 yearX -= textWidth; graphics.setFont(yearFont); // 繪制文字 graphics.drawString(posterTemplate.getPosterYear(), yearX, yearY); // 釋放Graphics對象 graphics.dispose(); InsertMinio(temp, backgroundImage, fileName, fileMap); } else { // 豎向 排版海報(bào) // 讀取背景圖片 getUpdatePhotoPath(imagesPathLogo, template.getPosterLogo(), 670, 66) File originalBackFile = new File(StrUtil.isNotBlank(template.getPosterBackImage()) ? getUpdatePhotoPath(imagesPathLogo, template.getPosterBackImage(), 1472, 2102) : imagesPathSecond + "backImageSecondTwo.png"); if (StrUtil.isNotBlank(template.getPosterBackImage())) { // 將保存到本地的圖片名稱返回給我 fileMap.put("backImage", template.getPosterBackImage()); } BufferedImage backgroundImage = ImageIO.read(originalBackFile); // 創(chuàng)建顏色并設(shè)置透明度 int alpha = 240; // 透明度(取值范圍:0 - 255) // 創(chuàng)建 Graphics2D 對象 Graphics2D g2d = backgroundImage.createGraphics(); // 設(shè)置透明度 AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) alpha / 255); g2d.setComposite(alphaComposite); // 設(shè)置左上角背景色 g2d.setColor(color); // 填充整個(gè)圖片區(qū)域 g2d.fillRect(0, 0, 450, 230); // 設(shè)置背景色 Graphics2D g3d = backgroundImage.createGraphics(); // 設(shè)置最下面的背景色 g3d.setColor(color); // 填充整個(gè)圖片區(qū)域 g3d.fillRect(0, 1980, backgroundImage.getWidth(), 230); // 讀取要貼的第一張小圖片 File originalFile = new File(imagesPathSecond + "schoolImageLogo.png"); BufferedImage image = ImageIO.read(originalFile); // 調(diào)用 resizeImageOne 方法進(jìn)行放大 int width = 280; int height = 230; BufferedImage overlayImage1 = PosterUtil.scaleImage(image, width, height); // 讀取要貼的第二張小圖片 BufferedImage overlayImage2 = ImageIO.read(new File(imagesPathSecond + "back2.png")); // 讀取要貼的第三張小圖片 Map<String, Object> hashMap = new HashMap<>(); hashMap.put("0", "green.png"); hashMap.put("1", "blue.png"); hashMap.put("2", "red.png"); BufferedImage overlayImage3 = ImageIO.read(new File(imagesPathSecond + hashMap.getOrDefault(template.getPosterColor(), "green.png"))); BufferedImage overlayImage4 = ImageIO.read(new File(imagesPathSecond + hashMap.getOrDefault(template.getPosterColor(), "green.png"))); // 讀取頭像圖片 BufferedImage avatarImage = ImageIO.read(new File(imagesPathSecond + "touxiang.png")); // 讀取二維碼 File erweima = new File(imagesPathSecond + "erweima.png"); BufferedImage erweimalogo = ImageIO.read(erweima); BufferedImage erweimaLogo = PosterUtil.scaleImage(erweimalogo, 200, 200); // 縮小第六張圖片并裁剪成圓形 BufferedImage scaledCircularAvatar = PosterUtil.resizeAndClipToCircle(avatarImage, 400); // 讀取學(xué)校logo File schoolLogo = new File(imagesPathSecond + "schoolLogo.png"); BufferedImage logo = ImageIO.read(schoolLogo); // 調(diào)用 resizeImageOne 方法進(jìn)行放大 BufferedImage imageLogo = PosterUtil.scaleImage(logo, 200, 100); // 讀取學(xué)院logo getUpdatePhotoPath(imagesPathSecond, template.getPosterLogo(), 1472, 2102) 440 118 // 讀取學(xué)院logo BufferedImage images; if (StrUtil.isNotBlank(template.getPosterLogo())) { File collegeLogo = new File(getUpdatePhotoPath(imagesPathLogo, template.getPosterLogo(), 200, 100)); if (StrUtil.isNotBlank(template.getPosterLogo())) { // 將保存到本地的圖片名稱返回給我 fileMap.put("logo", template.getPosterLogo()); } images = ImageIO.read(collegeLogo); } else { File collegeLogos = new File(imagesPathSecond + "collegelogos.png"); BufferedImage collegeImage = ImageIO.read(collegeLogos); // 調(diào)用 resizeImageOne 方法進(jìn)行放大 images = PosterUtil.scaleImage(collegeImage, 200, 100); } // 讀取白色圓圈 File yuan = new File(imagesPathSecond + "yuan.png"); BufferedImage yuanImage = ImageIO.read(yuan); // 調(diào)用 resizeImageOne 方法進(jìn)行放大 BufferedImage imagesYuan = PosterUtil.scaleImage(yuanImage, 450, 450); // 計(jì)算貼圖位置 X,Y // 在背景圖片上貼上第一張圖片 createImage(backgroundImage, overlayImage1, -5, 5); // 在背景圖片上貼上第二張圖片 createImage(backgroundImage, overlayImage2, 0, 230); // 在背景圖片上貼上第三張圖片 createImage(backgroundImage, overlayImage3, 50, 1400); //在背景圖片上貼上第四張圖片 createImage(backgroundImage, overlayImage4, 50, 1580); // 在背景圖片上貼上縮小并且裁剪成圓形后的頭像圖片 createImage(backgroundImage, scaledCircularAvatar, 950, 370); //在背景圖片上貼上第六張圖片 createImage(backgroundImage, erweimaLogo, 50, 1750); //在背景圖片上貼上第7張圖片 createImage(backgroundImage, imageLogo, 900, 1990); //在背景圖片上貼上第8張圖片 createImage(backgroundImage, images, 1200, 1990); //在背景圖片上貼上第9張圖片 createImage(backgroundImage, imagesYuan, 925, 345); // 保存合成后的背景圖片 // TODO 標(biāo)題 Graphics2D graphics = backgroundImage.createGraphics(); // TODO 添加第二行文字 Font fontTwo = new Font("", Font.BOLD, 50); graphics.setFont(fontTwo); graphics.setColor(Color.WHITE); String posterTopic = posterTemplate.getPosterTopic(); // drawWordAndLineFeed(graphics, fontTwo, textTwo, twoX, twoY, 320); PosterUtil.drawCenteredText(graphics, posterTopic, 100, 180); // TODO 主講人信息 PosterUtil.drawSecondString(graphics, "主講人", 3); PosterUtil.drawSecondString(graphics, posterTemplate.getPosterMainSpeaker(), 10); // TODO 主講人詳細(xì)介紹信息 PosterUtil.drawMyLectureString(graphics, posterTemplate.getPosterPeopleDetail()); // 設(shè)置字體和顏色 Font font = new Font("宋體", Font.PLAIN, 50); g2d.setFont(font); g2d.setColor(Color.BLACK); // 繪制豎排文字 // TODO 講座名稱 PosterUtil.drawMyString(graphics, posterTemplate.getPosterTitle(), color); //TODO 時(shí)間 2024 Font fontYear = new Font("Source Han Sans CN", Font.PLAIN, 40); graphics.setColor(Color.BLACK); PosterUtil.qinxie(fontYear, graphics); //字體傾斜 graphics.drawString(posterTemplate.getPosterYear(), 50, 1480); //TODO 時(shí)間 月份 10.23 1.23 Font fontMonth = new Font("Source Han Sans CN", Font.BOLD, 75); graphics.setColor(Color.BLACK); PosterUtil.qinxie(fontMonth, graphics); String posterMonth = posterTemplate.getPosterMonth(); graphics.drawString(posterMonth, posterMonth.length() == 5 ? 210 : 250, 1480); //TODO 具體時(shí)間 20:12 ~ 11:00 周五 Font fontDate = new Font("Source Han Sans CN", Font.PLAIN, 40); graphics.setColor(Color.BLACK); PosterUtil.qinxie(fontDate, graphics); graphics.drawString(posterTemplate.getPosterDay(), 50, 1550); // TODO 具體舉辦地點(diǎn) Font fontDd = new Font("", Font.BOLD, 35); graphics.setFont(fontDd); graphics.setColor(Color.BLACK); PosterUtil.qinxie(fontDd, graphics); PosterUtil.drawWordAndLineFeed(graphics, fontDd, posterTemplate.getPosterAddress(), 50, 1630, 330); // TODO 主持人 Font zcr = new Font(" Source Han Sans CN", Font.PLAIN, 40); graphics.setColor(Color.white); graphics.setFont(zcr); String zcrName = "主持人: " + posterTemplate.getMainPeople(); graphics.drawString(zcrName, 50, 2060); // 設(shè)置抗鋸齒 graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graphics.dispose(); return InsertMinio(temp, backgroundImage, fileName, fileMap); } } catch (Exception e) { throw new BusinessException(e.getMessage()); } return fileMap; } public void createImage(BufferedImage backgroundImage, BufferedImage imagesYuan, int x, int y) { Graphics2D graphics9 = backgroundImage.createGraphics(); graphics9.drawImage(imagesYuan, x, y, null); graphics9.dispose(); } public Map<String, Object> InsertMinio(String temp, BufferedImage backgroundImage, String fileName, Map<String, Object> fileMap) throws Exception { File file = new File(temp); ImageIO.write(backgroundImage, "PNG", file); // 創(chuàng)建 FileInputStream 流 FileInputStream inputStream = new FileInputStream(file); // 現(xiàn)在你可以使用 inputStream 進(jìn)行操作 minioUtil.uploadInputStream("mpbucket", "sjs/wdjz/hbgl" + SLASH_SUFFIX + fileName + ".png", inputStream); InputStream download = minioUtil.download("mpbucket", "sjs/wdjz/hbgl" + SLASH_SUFFIX + fileName + ".png"); // 將刪除的圖片文件保存到本地 String name = fileName + ".png"; byte[] bytes = IOUtils.toByteArray(download); String encoded = Base64.getEncoder().encodeToString(bytes); fileMap.put("posterTemplate", name); fileMap.put("code", BASE_64 + encoded); // 記得關(guān)閉流 inputStream.close(); // 刪除臨時(shí)文件 file.delete(); return fileMap; } /** * 修改圖片尺寸 * * @return 新的海報(bào)地址 */ public String getUpdatePhotoPath(String path, String fileName, int width, int height) throws Exception { File originalFile = new File(path + fileName); byte[] originalImageData = Files.readAllBytes(originalFile.toPath()); byte[] resizedImageData = FileUtil.resizeImage(originalImageData, width, height); // 將 byte[] 轉(zhuǎn)換為 ByteArrayInputStream ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(resizedImageData); // 創(chuàng)建臨時(shí)文件(如果需要) File tempFile = File.createTempFile("temp", ".tmp"); // 將 ByteArrayInputStream 中的數(shù)據(jù)寫入臨時(shí)文件 IOUtils.copy(byteArrayInputStream, Files.newOutputStream(tempFile.toPath())); // 使用臨時(shí)文件創(chuàng)建 FileInputStream FileInputStream fileInputStream = new FileInputStream(tempFile); // 現(xiàn)在你可以使用 fileInputStream 對象進(jìn)行操作 minioUtil.uploadInputStream("mpbucket", "sjs/wdjz/hbgl" + SLASH_SUFFIX + fileName, fileInputStream); InputStream download = minioUtil.download("mpbucket", "sjs/wdjz/hbgl" + SLASH_SUFFIX + fileName); // 將保存的logo 圖片文件保存到本地 FileUtil.convertInputStreamToFile(download, fileName); // 刪除 minio中的圖片 minioUtil.deleteFile("mpbucket", fileName); // 關(guān)閉流和刪除臨時(shí)文件 fileInputStream.close(); tempFile.delete(); return path + fileName; } //寫死兩個(gè)模板所需要的參數(shù) public PosterTemplateDto createPosterTemplate(PosterTemplateDto oldDto) { if ("0".equals(oldDto.getPosterId())){ oldDto.setPosterTopic("物理與天文學(xué)院學(xué)術(shù)報(bào)告 第359期"); oldDto.setPosterTitle("MIMO天線及其空口測試技術(shù)"); oldDto.setPosterYear("2024"); oldDto.setPosterMonth("10.18"); oldDto.setPosterDay("14:30 ~ 15:30(周四)"); oldDto.setPosterAddress("電信樓101講學(xué)廳"); oldDto.setPosterSchool("中山大學(xué)(東校園)"); oldDto.setPosterMainSpeaker("歐陽上官"); } else { oldDto.setPosterTopic("逸仙生命講壇人第五十九講"); oldDto.setPosterTitle("時(shí)空相分離調(diào)控的職務(wù)細(xì)胞信號(hào)轉(zhuǎn)導(dǎo)"); oldDto.setPosterYear("2024"); oldDto.setPosterMonth("1.23"); oldDto.setPosterDay("20:12 ~ 11:00 周五"); oldDto.setPosterAddress("中山大學(xué)(東校園)-電信樓101講學(xué)廳"); oldDto.setPosterMainSpeaker("歐陽上官"); oldDto.setPosterPeopleDetail("我啥事打卡機(jī)大街上的情況為其較為氣溫氣溫其味無窮我的撒登記卡水電氣網(wǎng)紅,誒打算近期我后端數(shù)據(jù)啊按地區(qū)為背景墻網(wǎng)格袋安山東劃算的揮灑的企鵝企鵝群。"); oldDto.setMainPeople("李劍鋒"); } return oldDto; }
到此這篇關(guān)于Java基于Graphics2D實(shí)現(xiàn)海報(bào)制作的文章就介紹到這了,更多相關(guān)Java Graphics2D海報(bào)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Jmeter正則表達(dá)式提取器實(shí)現(xiàn)過程圖解
這篇文章主要介紹了Jmeter正則表達(dá)式提取器實(shí)現(xiàn)過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08mybatis的大于小于號(hào)轉(zhuǎn)義符號(hào)一覽
這篇文章主要介紹了mybatis的大于小于號(hào)轉(zhuǎn)義符號(hào)一覽,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08SpringAI流式輸出的底層實(shí)現(xiàn)原理解析
在 Spring AI 中,流式輸出(Streaming Output)是一種逐步返回 AI 模型生成結(jié)果的技術(shù),允許服務(wù)器將響應(yīng)內(nèi)容分批次實(shí)時(shí)傳輸給客戶端,而不是等待全部內(nèi)容生成完畢后再一次性返回,這篇文章主要介紹了SpringAI流式輸出的底層實(shí)現(xiàn),需要的朋友可以參考下2025-04-04java 中多線程生產(chǎn)者消費(fèi)者問題詳細(xì)介紹
這篇文章主要介紹了java 中多線程生產(chǎn)者消費(fèi)者問題詳細(xì)介紹的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-09-09Java實(shí)現(xiàn)數(shù)據(jù)庫圖片上傳功能詳解
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)數(shù)據(jù)庫圖片上傳功能,包含從數(shù)據(jù)庫拿圖片傳遞前端渲染,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-03-03Java?中很好用的數(shù)據(jù)結(jié)構(gòu)EnumSet
這篇文章主要介紹了Java?中很好用的數(shù)據(jù)結(jié)構(gòu)EnumSet,EnumMap即屬于一個(gè)Map,下文圍繞主題展開詳細(xì)內(nèi)容,需要的小伙伴可以參考參考一下2022-05-05詳解Mybatis攔截器安全加解密MySQL數(shù)據(jù)實(shí)戰(zhàn)
本文主要介紹了Mybatis攔截器安全加解密MySQL數(shù)據(jù)實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01