Java基于Graphics2D實(shí)現(xiàn)海報制作
效果
海報一

海報二

代碼
參數(shù)實(shí)體類
package com.ly.cloud.dto;
import lombok.Data;
/**
* @Author
* @Date Created in 2024/4/24 下午2:16
* @DESCRIPTION: 海報頁面所需的參數(shù) 實(shí)體類
* @Version V1.0
*/
@Data
public class PosterTemplateDto {
/**
* 用來判斷是不是 需要把數(shù)據(jù)寫死 0 寫死的對象,1 自己傳的
*/
private String id;
{
id = "0";
}
/**
* 海報編號 0: 橫向海報 1: 豎向海報
*/
private String posterId;
/**
* 海報顏色 0: 綠色 1: 藍(lán)色 2: 紅色
*/
private String posterColor;
/**
* 海報背景圖片名稱
*/
private String posterBackImage;
/**
* 海報logo
*/
private String posterLogo;
/**
* 海報主題 xxxx 第 x 期
*/
private String posterTopic;
/**
* 海報標(biāo)題
*/
private String posterTitle;
/**
* 海報年份
*/
private String posterYear;
/**
* 海報具體時間 幾月幾號
*/
private String posterMonth;
/**
* 海報具體時間 14:30 ~ 15:30(周四)
*/
private String posterDay;
/**
* 講座就行校區(qū)
*/
private String posterSchool;
/**
* 講座的具體地址
*/
private String posterAddress;
/**
* 講座主講人
*/
private String posterMainSpeaker;
/**
* 主講人個人詳細(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)建臨時文件
File tempFile = File.createTempFile("temp", null);
// 將MultipartFile的數(shù)據(jù)寫入臨時文件
try (FileOutputStream fos = new FileOutputStream(tempFile)) {
fos.write(multipartFile.getBytes());
}
// 將臨時文件轉(zhuǎn)換為FileInputStream
FileInputStream fileInputStream = new FileInputStream(tempFile);
// 刪除臨時文件
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目錄下的一個示例子目錄,你可以根據(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ò)大 海報背景圖和 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: 海報工具類
* @Version V1.0
*/
public class PosterUtil {
/**
* 從新設(shè)置海報圖片的寬和高
* @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 海報橫向文字寫字換行算法
* @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)計字符串寬度 并與 預(yù)設(shè)好的寬度 作比較
if (width <= wordsWidth) {
width += metrics.charWidth(words.charAt(i)); // 獲取每個字符的寬度
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));
}
}
}
/**
* 將上傳的個人頭像裁剪成對應(yīng)的海報比例的頭像,并裁剪成圓形
* @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;
}
/**
* 部分文字 垂直排序時,不滿多列,最后一列居中顯示
* @param textGraphics Graphics 對象
* @param text 要傳入的海報描述
*/
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);
// 計算每列的寬度
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);
// 計算當(dāng)前位置
int cx = x - columnIndex * columnWidth;
int cy = y + rowIndex * fontHeight + rowIndex * verticalSpacing; // 加入垂直偏移量
// 計算當(dāng)前位置
// int cx = x - columnIndex * columnWidth;
// int cy = y + rowIndex * fontHeight + rowIndex * verticalSpacing + columnIndex ;
// 如果是最后一列并且不滿 7 個字符,則需要將剩余字符居中
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();
// 計算每列的寬度
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);
// 計算當(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);
// 計算第一行文字的起始x坐標(biāo),使其水平居中
int oneX = 50;
// 計算第二行文字的起始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;
// 計算每列的寬度
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);
// 計算總列數(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);
// 計算當(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();
// 計算每列的寬度
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);
// 計算當(dāng)前位置
int cx = x - (i / columnSize) * columnWidth;
int cy = y + (i % columnSize) * fontHeight;
textGraphics.drawString(String.valueOf(ch), cx, cy);
}
}
}業(yè)務(wù)代碼
首先新建3個目錄用來存放一下固定的背景圖片和 臨時的文件

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())) {
// 橫向海報
// 讀取海報背景圖片 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);
// 填充整個圖片區(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);
// 計算貼圖位置
// 在背景圖片上貼上第一張圖片
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è)置第一行字體和顏色:添加海報主題文字
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 添加海報的文字日期 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)建一個 AffineTransform 對象,并將其設(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 {
// 豎向 排版海報
// 讀取背景圖片 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);
// 填充整個圖片區(qū)域
g2d.fillRect(0, 0, 450, 230);
// 設(shè)置背景色
Graphics2D g3d = backgroundImage.createGraphics();
// 設(shè)置最下面的背景色
g3d.setColor(color);
// 填充整個圖片區(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);
// 計算貼圖位置 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 時間 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 時間 月份 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 具體時間 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();
// 刪除臨時文件
file.delete();
return fileMap;
}
/**
* 修改圖片尺寸
*
* @return 新的海報地址
*/
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)建臨時文件(如果需要)
File tempFile = File.createTempFile("temp", ".tmp");
// 將 ByteArrayInputStream 中的數(shù)據(jù)寫入臨時文件
IOUtils.copy(byteArrayInputStream, Files.newOutputStream(tempFile.toPath()));
// 使用臨時文件創(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)閉流和刪除臨時文件
fileInputStream.close();
tempFile.delete();
return path + fileName;
}
//寫死兩個模板所需要的參數(shù)
public PosterTemplateDto createPosterTemplate(PosterTemplateDto oldDto) {
if ("0".equals(oldDto.getPosterId())){
oldDto.setPosterTopic("物理與天文學(xué)院學(xué)術(shù)報告 第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("時空相分離調(diào)控的職務(wù)細(xì)胞信號轉(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)海報制作的文章就介紹到這了,更多相關(guān)Java Graphics2D海報內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Jmeter正則表達(dá)式提取器實(shí)現(xiàn)過程圖解
這篇文章主要介紹了Jmeter正則表達(dá)式提取器實(shí)現(xiàn)過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08
SpringAI流式輸出的底層實(shí)現(xiàn)原理解析
在 Spring AI 中,流式輸出(Streaming Output)是一種逐步返回 AI 模型生成結(jié)果的技術(shù),允許服務(wù)器將響應(yīng)內(nèi)容分批次實(shí)時傳輸給客戶端,而不是等待全部內(nèi)容生成完畢后再一次性返回,這篇文章主要介紹了SpringAI流式輸出的底層實(shí)現(xiàn),需要的朋友可以參考下2025-04-04
java 中多線程生產(chǎn)者消費(fèi)者問題詳細(xì)介紹
這篇文章主要介紹了java 中多線程生產(chǎn)者消費(fèi)者問題詳細(xì)介紹的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-09-09
Java實(shí)現(xiàn)數(shù)據(jù)庫圖片上傳功能詳解
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)數(shù)據(jù)庫圖片上傳功能,包含從數(shù)據(jù)庫拿圖片傳遞前端渲染,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-03-03
Java?中很好用的數(shù)據(jù)結(jié)構(gòu)EnumSet
這篇文章主要介紹了Java?中很好用的數(shù)據(jù)結(jié)構(gòu)EnumSet,EnumMap即屬于一個Map,下文圍繞主題展開詳細(xì)內(nèi)容,需要的小伙伴可以參考參考一下2022-05-05
詳解Mybatis攔截器安全加解密MySQL數(shù)據(jù)實(shí)戰(zhàn)
本文主要介紹了Mybatis攔截器安全加解密MySQL數(shù)據(jù)實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01

