效果:

海报一:

Java 基于Graphics2D 实现海报(支持自定义颜色,背景,logo,贴图)-LMLPHP

海报二:

Java 基于Graphics2D 实现海报(支持自定义颜色,背景,logo,贴图)-LMLPHP

代码:

参数实体类:

package com.ly.cloud.dto;

import lombok.Data;

/**
 * @Author  
 * @Date  Created in  2024/4/24 下午2:16
 * @DESCRIPTION:   海报页面所需的参数 实体类
 * @Version  V1.0
 */
@Data
public class PosterTemplateDto {
    /**
     * 用来判断是不是 需要把数据写死 0 写死的对象,1 自己传的
     */
    private String id;
    {
        id = "0";
    }
    /**
     * 海报编号  0: 横向海报   1: 竖向海报
     */
    private String posterId;

    /**
     * 海报颜色 0: 绿色  1: 蓝色  2: 红色
     */
    private String posterColor;
    /**
     * 海报背景图片名称
     */
    private String posterBackImage;

    /**
     * 海报logo
     */
    private String posterLogo;
    /**
     * 海报主题  xxxx 第 x 期
     */
    private String posterTopic;

    /**
     * 海报标题
     */
    private String posterTitle;

    /**
     * 海报年份
     */
    private String posterYear;

    /**
     * 海报具体时间  几月几号
     */
    private String posterMonth;

    /**
     * 海报具体时间 14:30 ~ 15:30(周四)
     */
    private String posterDay;

    /**
     * 讲座就行校区
     */
    private String posterSchool;
    /**
     * 讲座的具体地址
     */
    private String posterAddress;

    /**
     * 讲座主讲人
     */
    private String posterMainSpeaker;

    /**
     * 主讲人个人详细信息介绍
     */
    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 {
        // 创建临时文件
        File tempFile = File.createTempFile("temp", null);

        // 将MultipartFile的数据写入临时文件
        try (FileOutputStream fos = new FileOutputStream(tempFile)) {
            fos.write(multipartFile.getBytes());
        }

        // 将临时文件转换为FileInputStream
        FileInputStream fileInputStream = new FileInputStream(tempFile);

        // 删除临时文件
        tempFile.delete();

        return fileInputStream;
    }

    /**
     * 将上传的 logo图片保存在本地;
     */
    public static File convertInputStreamToFile(InputStream inputStream,String fileName) throws IOException {
        // 创建图片文件
        String resourcesPath = new File("src/main/resources/").getAbsolutePath();
        // 拼接images目录的路径
        String imagesPath = resourcesPath + "/static/imagesLogo/"; // 这里的static是resources目录下的一个示例子目录,你可以根据实际情况修改
        logger.info("我的路径是:{}"+imagesPath);
        File directory = new File(imagesPath);
        // 如果目标文件夹不存在,则创建它
        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.");
        }
    }

    /**
     * 修改图片的宽高 等比例扩大 海报背景图和 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 {

    /**
     * 从新设置海报图片的宽和高
     * @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 参数 Graphics2D 对象 、font 字体设置 、 文字、 x轴左边、 y轴坐标 、每行字体的换行宽度
     **/
    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++) {
            // 统计字符串宽度 并与 预设好的宽度 作比较
            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));
            }
        }
    }

    /**
     * 将上传的个人头像裁剪成对应的海报比例的头像,并裁剪成圆形
     * @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) {

        // 每列显示的汉字数量
        int columnSize = 7;
        // 文字之间的垂直间距
        int verticalSpacing = 75;

        // 获取字体渲染上下文
        FontMetrics fm = textGraphics.getFontMetrics();
        // 获取字体的高度
        int fontHeight = fm.getHeight();
        System.out.println(fontHeight);
        // 计算每列的宽度
        int columnWidth = fontHeight + verticalSpacing;

        // 设置初始位置
        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); // 总列数
        int totalRows = Math.min(columnSize, text.length()); // 总行数
        int remainingChars = text.length() % columnSize; // 最后一列剩余字符数

        for (int columnIndex = 0; columnIndex < totalColumns; columnIndex++) {
            for (int rowIndex = 0; rowIndex < totalRows; rowIndex++) {
                if (charCount >= text.length()) break;
                char ch = text.charAt(charCount);
                 // 计算当前位置
                int cx = x - columnIndex * columnWidth;
                int cy = y + rowIndex * fontHeight + rowIndex * verticalSpacing; // 加入垂直偏移量
                 // 计算当前位置
//                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   显示的 内容
     * @param number 没列显示汉字数量
     */
    public static void drawString(Graphics textGraphics,String text,int number){

        // 每列显示的汉字数量
        int columnSize = number;
        // 文字之间的垂直间距
        int verticalSpacing = 50;

        // 获取字体渲染上下文
        FontMetrics fm = textGraphics.getFontMetrics();
        // 获取字体的高度
        int fontHeight = fm.getHeight();

        // 计算每列的宽度
        int columnWidth = fontHeight + verticalSpacing;

        // 设置初始位置
        int x = 0;
        int y = 0;
        switch (number) {
            case 3:
                x = 1250;
                y = 790;
                break;
            case 10:
                x = 1150;
                y = 800;
                break;
            // 可以添加更多的条件分支
            default:
                // 默认情况下的坐标设置
                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);
            // 计算当前位置
            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) {
        // 设置字体和颜色
        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坐标,使其水平居中
        int oneX = 50;
        // 计算第二行文字的起始x坐标,使其水平居中
        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) {

        // 每列显示的汉字数量
        int columnSize = 25;
        // 文字之间的垂直间距
        int verticalSpacing = 1;

        // 获取字体渲染上下文
        FontMetrics fm = textGraphics.getFontMetrics();
        // 获取字体的高度
        int fontHeight = fm.getHeight() - 30;

        // 计算每列的宽度
        int columnWidth = fontHeight + verticalSpacing;

        // 设置初始位置
        int x = 800;
        int y = 190;
        Font fontFour = new Font("宋体", Font.BOLD, 40);
        textGraphics.setFont(fontFour);
        textGraphics.setColor(Color.WHITE);

        // 计算总列数
        int totalColumns = (int) Math.ceil((double) text.length() / columnSize); // 总列数

        // 绘制文字
        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);
                // 计算当前位置
                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){
        // 创建 AffineTransform 对象
        AffineTransform month = new AffineTransform();
        // 设置水平倾斜
        month.shear(-0.2, 0); // + 向左  -  向右倾斜
        // 应用变换到字体
        fontMonth = fontMonth.deriveFont(month);
        graphics.setFont(fontMonth);
    }

    /**
     * 文字垂直
     */
    public static void drawSecondString(Graphics textGraphics, String text, int number) {

        // 每列显示的汉字数量
        int columnSize = number;
        // 文字之间的垂直间距
        int verticalSpacing = columnSize == 15 ? -500 : 50;
        // 获取字体渲染上下文
        FontMetrics fm = textGraphics.getFontMetrics();
        // 获取字体的高度
        int fontHeight = fm.getHeight();

        // 计算每列的宽度
        int columnWidth = columnSize == 15 ? 60 : fontHeight + verticalSpacing;

        // 设置初始位置
        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:
                // 默认情况下的坐标设置
                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);
            // 计算当前位置
            int cx = x - (i / columnSize) * columnWidth;
            int cy = y + (i % columnSize) * fontHeight;

            textGraphics.drawString(String.valueOf(ch), cx, cy);
        }
    }

}

业务代码:

首先新建3个目录用来存放一下固定的背景图片和 临时的文件

Java 基于Graphics2D 实现海报(支持自定义颜色,背景,logo,贴图)-LMLPHP

 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/";

        // 创建颜色并设置透明度
        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)

                // 创建 Graphics2D 对象
                Graphics2D g2d = backgroundImage.createGraphics();

                // 设置透明度
                AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) alpha / 255);
                g2d.setComposite(alphaComposite);

                // 设置背景色
                g2d.setColor(color);

                // 填充整个图片区域
                g2d.fillRect(0, 0, backgroundImage.getWidth(), backgroundImage.getHeight());

                // 读取要贴的第一张小图片 "D:\\test1\\schoolLogo.png"
                File originalFile = new File(imagesPath + "schoolLogo.png");
                BufferedImage image = ImageIO.read(originalFile);
                // 调用 resizeImageOne 方法进行放大
                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 创建Graphics对象
                Graphics2D graphics = backgroundImage.createGraphics();

                // 设置第一行字体和颜色:添加海报主题文字
                Font font = new Font("", Font.BOLD, 50);
                graphics.setFont(font);
                graphics.setColor(Color.WHITE);
                graphics.drawString(posterTemplate.getPosterTopic(), 50, 280);

                // 设置第二行的字体和颜色
                // 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 添加第四行文字 校区 地址文字
                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 坐标
                int yearY = 930; // 文字起始位置 y 坐标
                Font yearFont = new Font("", Font.BOLD, 50);
                // 设置渲染提示以获得更好的质量
                graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

                // 创建一个 AffineTransform 对象,并将其设置为顺时针旋转90度
                AffineTransform at = new AffineTransform();
                at.setToRotation(Math.PI / 2.0, yearX, yearY);

                // 应用 AffineTransform 对象
                graphics.setTransform(at);

                // 获取字体渲染上下文
                FontRenderContext frc = graphics.getFontRenderContext();
                // 获取文本宽度
                int textWidth = (int) graphics.getFont().getStringBounds(posterTemplate.getPosterYear(), frc).getWidth();

                // 调整起始位置,以确保文本在旋转后完全可见
                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);
                // 创建颜色并设置透明度
                int alpha = 240; // 透明度(取值范围:0 - 255)
                // 创建 Graphics2D 对象
                Graphics2D g2d = backgroundImage.createGraphics();

                // 设置透明度
                AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) alpha / 255);
                g2d.setComposite(alphaComposite);
                // 设置左上角背景色
                g2d.setColor(color);
                // 填充整个图片区域
                g2d.fillRect(0, 0, 450, 230);
                // 设置背景色
                Graphics2D g3d = backgroundImage.createGraphics();
                // 设置最下面的背景色
                g3d.setColor(color);
                // 填充整个图片区域
                g3d.fillRect(0, 1980, backgroundImage.getWidth(), 230);
                // 读取要贴的第一张小图片
                File originalFile = new File(imagesPathSecond + "schoolImageLogo.png");
                BufferedImage image = ImageIO.read(originalFile);
                // 调用 resizeImageOne 方法进行放大
                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);

                // 读取学校logo
                File schoolLogo = new File(imagesPathSecond + "schoolLogo.png");
                BufferedImage logo = ImageIO.read(schoolLogo);
                // 调用 resizeImageOne 方法进行放大
                BufferedImage imageLogo = PosterUtil.scaleImage(logo, 200, 100);

                // 读取学院logo getUpdatePhotoPath(imagesPathSecond, template.getPosterLogo(), 1472, 2102) 440 118

                // 读取学院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);
                    // 调用 resizeImageOne 方法进行放大
                    images = PosterUtil.scaleImage(collegeImage, 200, 100);
                }

                // 读取白色圆圈
                File yuan = new File(imagesPathSecond + "yuan.png");
                BufferedImage yuanImage = ImageIO.read(yuan);
                // 调用 resizeImageOne 方法进行放大
                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 标题
                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 主讲人详细介绍信息
                PosterUtil.drawMyLectureString(graphics, posterTemplate.getPosterPeopleDetail());
                // 设置字体和颜色
                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 具体举办地点
                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);

                // 设置抗锯齿
                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);
        // 创建 FileInputStream 流
        FileInputStream inputStream = new FileInputStream(file);

        // 现在你可以使用 inputStream 进行操作
        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);
        // 记得关闭流
        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[] 转换为 ByteArrayInputStream
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(resizedImageData);
        // 创建临时文件(如果需要)
        File tempFile = File.createTempFile("temp", ".tmp");
        // 将 ByteArrayInputStream 中的数据写入临时文件
        IOUtils.copy(byteArrayInputStream, Files.newOutputStream(tempFile.toPath()));
        // 使用临时文件创建 FileInputStream
        FileInputStream fileInputStream = new FileInputStream(tempFile);
        // 现在你可以使用 fileInputStream 对象进行操作
        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);
        // 关闭流和删除临时文件
        fileInputStream.close();
        tempFile.delete();
        return path + fileName;
    }
    //写死两个模板所需要的参数
    public PosterTemplateDto createPosterTemplate(PosterTemplateDto oldDto) {
        if ("0".equals(oldDto.getPosterId())){
            oldDto.setPosterTopic("物理与天文学院学术报告 第359期");
            oldDto.setPosterTitle("MIMO天线及其空口测试技术");
            oldDto.setPosterYear("2024");
            oldDto.setPosterMonth("10.18");
            oldDto.setPosterDay("14:30 ~ 15:30(周四)");
            oldDto.setPosterAddress("电信楼101讲学厅");
            oldDto.setPosterSchool("中山大学(东校园)");
            oldDto.setPosterMainSpeaker("欧阳上官");
        } else {
            oldDto.setPosterTopic("逸仙生命讲坛人第五十九讲");
            oldDto.setPosterTitle("时空相分离调控的职务细胞信号转导");
            oldDto.setPosterYear("2024");
            oldDto.setPosterMonth("1.23");
            oldDto.setPosterDay("20:12 ~ 11:00  周五");
            oldDto.setPosterAddress("中山大学(东校园)-电信楼101讲学厅");
            oldDto.setPosterMainSpeaker("欧阳上官");
            oldDto.setPosterPeopleDetail("我啥事打卡机大街上的情况为其较为气温气温其味无穷我的撒登记卡水电气网红,诶打算近期我后端数据啊按地区为背景墙网格袋安山东划算的挥洒的企鹅企鹅群。");
            oldDto.setMainPeople("李剑锋");
        }
        return oldDto;
    }
04-29 19:26