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

news2024/11/16 0:02:00

效果:

海报一:

海报二:

代码:

参数实体类:

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个目录用来存放一下固定的背景图片和 临时的文件

 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;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1630763.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

防火墙对要保护的服务器做端口映射的好处是几个

防火墙对要保护的服务器进行端口映射具有多重好处&#xff0c;这些好处主要围绕网络安全性、灵活性和可管理性展开。以下是对这些好处的专业分析&#xff1a; 1. 增强网络安全性&#xff1a;端口映射允许防火墙对进入服务器的流量进行精确控制。通过映射特定端口&#xff0c;防…

volatile的相关知识点

volatitle这个关键字&#xff0c;不管是在Java还是在C中都有使用到&#xff0c;但是在两种语言中&#xff0c;由于编译器的原因&#xff0c;他们存在一点点区别。 C中的volatile关键字 在C中volatile主要用于告诉编译器&#xff0c;这个变量的值可能会意外改变 ,例如被硬件或者…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之七 简单进行人脸检测并添加面具特效实现

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之七 简单进行人脸检测并添加面具特效实现 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之七 简单进行人脸检测并添加面具特效实现 一、简单介绍 二、简单进行…

ChatGPT记忆功能终于上线了, OpenAI 官方:用得越久越聪明!

原文 ChatGPT记忆功能终于上线了, OpenAI 官方&#xff1a;用得越久越聪明&#xff01; Aitrainee | 公众号&#xff1a;AI进修生 &#x1f31f; 记得今年2月份OpenAI发布过ChatGPT上线记忆功能的消息&#xff0c;我记得当时还弹出过这个窗口给我&#xff0c;但是仅仅体验了几…

centos7 openresty lua 自适应webp和缩放图片

目录 背景效果图准备安装cwebp等命令&#xff0c;转换文件格式安装ImageMagick&#xff0c;压缩文件下载Lua API 操控ImageMagick的依赖包 代码参考 背景 缩小图片体积&#xff0c;提升加载速度&#xff0c;节省流量。 效果图 参数格式 &#xff1a; ?image_processformat,…

C语言之详细讲解文件操作

什么是文件 与普通文件载体不同&#xff0c;文件是以硬盘为载体存储在计算机上的信息集合&#xff0c;文件可以是文本文档、图片、程序等等。文件通常具有点三个字母的文件扩展名&#xff0c;用于指示文件类型&#xff08;例如&#xff0c;图片文件常常以KPEG格式保存并且文件…

idea创建完项目如何隐藏不重要的文件

如果您不打算直接使用这些脚本&#xff0c;而是更倾向于通过IDEA的内置工具来运行Maven命令&#xff0c;那么您可以选择隐藏这些文件。但是&#xff0c;隐藏这些文件并不会影响它们的功能&#xff0c;只是在项目视图中不再显示它们。 1.转到 File > Settings&#xff08;Wi…

信息系统项目管理师——第7章项目立项管理

本章考选择题2-3分&#xff0c;案例和论文均有可能作为领域考试。 项目建议与立项申请♥♥♥♥♥ 立项申请的概念 立项申请又称为项目建议书&#xff0c;是项目建设单位向上级主管部门提交项目申请时所必须的文 件&#xff0c;是该项目建设筹建单位根据国民经济的发展、国家…

Spark高可用模式和Spark分布式Yarn环境安装

Spark分布式HA环境安装 图-12 高可用模式原理 因为在目前情况下&#xff0c;集群中只有一个Master&#xff0c;如果master挂掉&#xff0c;便无法对外提供新的服务&#xff0c;显然有单点故障问题&#xff0c;解决方法就是master的ha。 有两种方式解决单点故障&#xff0c;一…

无脑入单向无头链表的实现| ArrayList和LinkedList的区别

1. ArrayList的缺陷 上节课已经熟悉了ArrayList的使用&#xff0c;并且进行了简单模拟实现。通过源码知道&#xff0c;ArrayList底层使用数组来存储元素。 由于其底层是一段连续空间&#xff0c;当 在 ArrayList 任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往…

如何使用docker部署前端项目

账号&#xff1a;root 密码&#xff1a;*** 主机&#xff1a;ip地址 登录后&#xff1a; 初级名词&#xff1a; sudo 是Linux和类Unix操作系统中的一个命令&#xff0c;全称为“super user do”&#xff0c;用于允许普通用户以超级用户(root)的身份执行某些或全部命令 需要下…

【python】简单实现遍历文件夹和子文件夹重命名

个人简介 &#x1f468;&#x1f3fb;‍&#x1f4bb;个人主页&#xff1a;九黎aj &#x1f3c3;&#x1f3fb;‍♂️幸福源自奋斗,平凡造就不凡 &#x1f31f;如果文章对你有用&#xff0c;麻烦关注点赞收藏走一波&#xff0c;感谢支持&#xff01; &#x1f331;欢迎订阅我的…

sql注入漏洞及其sqlmap工具的使用

一、sql注入的原理 sql注入概念&#xff1a; sql注入主要是将sql语句&#xff0c;插入到web表单提交或者输入域名或者页面请求的查询字符串&#xff0c;最 终 达到一个欺骗服务器执行sql语句的效果。 sql注入的原理&#xff1a;主要分为平台层注入和代码层注入两种原因 …

TechTool Pro for mac中文激活版:硬件监测和系统维护工具

TechTool Pro mac帮助用户实现系统硬件监测&#xff08;CPU、内存、硬盘、网络、USB等&#xff09;、内存测试、S.M.A.R.T检测、磁盘宗卷扫描、宗卷重建和优化、数据恢复和粉碎等等&#xff0c;定期使用&#xff0c;可以确保您的Mac保持优化和无故障。 TechTool Pro for mac v1…

(学习日记)2024.04.19:UCOSIII第四十七节:各文件夹功能介绍

之前的章节都是针对某个或某些知识点进行的专项讲解&#xff0c;重点在功能和代码解释。 回到最初开始学μC/OS-III系统时&#xff0c;当时就定下了一个目标&#xff0c;不仅要读懂&#xff0c;还要读透&#xff0c;改造成更适合中国宝宝体质的使用方式。在学完野火的教程后&a…

JavaScript操作DOM实现页面元素更改

DOM是什么 DOM&#xff08;文档对象模型&#xff09;是一种用于表示和操作HTML、XML文档的标准编程接口。它将文档中的每个元素、属性、文本和事件都表示为对象&#xff0c;从而可以使用JavaScript等脚本语言来操作和修改文档的结构、样式和内容。 DOM 将文档表示为一个树状结…

AI绘画的算法原理:从生成模型到Diffusion

近年来&#xff0c;AI绘画技术引起了广泛关注&#xff0c;让我们深入探讨其背后的技术原理和发展历程。本文将以通俗易懂的方式&#xff0c;介绍AI绘画的核心算法&#xff0c;从生成模型到Diffusion。 1. 计算机如何生成图画&#xff1f; AI绘画的核心在于生成模型&#xff08…

【平台开发】MTK6833 实现lk下CQE接口移植 - cmdq request

1.函数调用图 对应协议上结构为&#xff1a; 2.函数拆解 cmdq_request: 1)配置task_desc和tran_desc参数 2)EN_CQHCI_IRQ 3)write CQTDBR cmdq_prep_task_desc: 设置task_desc参数 cmdq_set_tran_desc: 设置tran_desc参数

Elasticsearch下载

1 最新版下载地址 Download Elasticsearch | Elastic https://www.elastic.co/cn/downloads/elasticsearch 2 其他版本下载地址 https://www.elastic.co/cn/downloads/past-releases#elasticsearch 7.9.2:https://artifacts.elastic.co/downloads/elasticsearch/elasticsear…

github two-factor authentication是个啥?

最近在逛github时&#xff0c;总是时不时会弹出一下界面&#xff0c;很烦 看到红框里的文字&#xff0c;这明显是强制要求做这个认证&#xff0c;如果不认证4天后账号将不可访问&#xff0c;所以今天花点时间看看怎么做这个认证&#xff0c;点“Enable 2FA now”进入这个界面&a…