package com.ruoyi.common.utils; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.InputStream; import java.util.Random; import javax.imageio.ImageIO; public class CoverGenerator { private static final Color[][] COLOR_SCHEMES = { // 绿色系 {new Color(0, 128, 0)}, // 绿色 {new Color(46, 139, 87)}, // 海洋绿 {new Color(60, 179, 113)}, // 中海洋绿 {new Color(32, 178, 170)}, // 浅海洋绿 {new Color(0, 106, 78)}, // 深森林绿 {new Color(0, 139, 69)}, // 春绿 {new Color(34, 139, 34)}, // 森林绿 {new Color(50, 205, 50)}, // 酸橙绿 {new Color(0, 128, 128)}, // 水鸭绿 // 蓝色系 {new Color(70, 130, 180)}, // 钢青色 {new Color(95, 158, 160)}, // 暗青色 {new Color(100, 149, 237)}, // 矢车菊蓝 {new Color(25, 25, 112)}, // 午夜蓝 {new Color(0, 0, 139)}, // 深蓝色 {new Color(30, 144, 255)}, // 道奇蓝 {new Color(65, 105, 225)}, // 皇家蓝 {new Color(0, 191, 255)}, // 深天蓝 // 紫色系 {new Color(106, 90, 205)}, // 石板蓝 {new Color(123, 104, 238)}, // 中紫色 {new Color(72, 61, 139)}, // 暗紫色 {new Color(138, 43, 226)}, // 紫罗兰 {new Color(148, 0, 211)}, // 暗紫罗兰 {new Color(153, 50, 204)}, // 深兰花紫 // 青色系 {new Color(0, 139, 139)}, // 深青色 {new Color(0, 206, 209)}, // 深绿松石 {new Color(72, 209, 204)}, // 中绿松石 {new Color(64, 224, 208)}, // 绿松石 // 灰色系 {new Color(47, 79, 79)}, // 暗岩灰 {new Color(105, 105, 105)}, // 暗灰 {new Color(112, 128, 144)}, // 石板灰 {new Color(119, 136, 153)}, // 浅石板灰 // 褐色系 {new Color(139, 69, 19)}, // 马鞍棕色 {new Color(160, 82, 45)}, // 赭色 {new Color(165, 42, 42)}, // 褐色 {new Color(128, 0, 0)}, // 栗色 // 其他优雅配色 {new Color(85, 107, 47)}, // 暗橄榄绿 {new Color(107, 142, 35)}, // 橄榄土褐色 {new Color(143, 188, 143)}, // 暗海绿 {new Color(176, 196, 222)}, // 浅钢蓝 {new Color(176, 224, 230)} // 粉蓝色 }; private static Color getRandomColor() { Random random = new Random(); return COLOR_SCHEMES[random.nextInt(COLOR_SCHEMES.length)][0]; } private static void addSubtleShadow(Graphics2D g2d, String text, int x, int y, Font font, Color shadowColor) { int offset = 2; // 第一层阴影,较淡 g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.12f)); g2d.setColor(shadowColor); g2d.drawString(text, x + offset, y + offset); // 第二层阴影,稍深 g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f)); g2d.drawString(text, x + offset - 1, y + offset - 1); // 重置透明度 g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); } // 添加字体加载逻辑 private static Font loadFont(int size) { try { // 优先尝试加载项目内部的字体文件 InputStream is = CoverGenerator.class.getResourceAsStream("/fonts/SimHei.ttf"); if (is != null) { Font font = Font.createFont(Font.TRUETYPE_FONT, is); return font.deriveFont(Font.BOLD, size); } } catch (Exception e) { // 记录日志但继续执行 System.out.println("Failed to load custom font: " + e.getMessage()); } // fallback到系统字体 return new Font("Dialog.plain", Font.BOLD, size); } public static BufferedImage createCover(String text1, String text2, String tagText, int titleSize) { int width = 1200; int height = 675; // 创建图片 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = image.createGraphics(); // 设置背景色 Color bgColor = getRandomColor(); g2d.setColor(bgColor); g2d.fillRect(0, 0, width, height); // 启用抗锯齿 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // 修改字体设置部分 Font titleFont = loadFont(60); Font subtitleFont = loadFont(titleSize); Font tagFont = loadFont(35); // 计算文字位置 FontMetrics titleMetrics = g2d.getFontMetrics(titleFont); int titleWidth = titleMetrics.stringWidth(text1); int titleX = (width - titleWidth) / 2; int titleY = height / 6 + titleMetrics.getAscent(); FontMetrics subtitleMetrics = g2d.getFontMetrics(subtitleFont); int subtitleWidth = subtitleMetrics.stringWidth(text2); int subtitleX = (width - subtitleWidth) / 2; int subtitleY = height / 2 - 60 + subtitleMetrics.getAscent(); // 绘制主标题 g2d.setFont(titleFont); addSubtleShadow(g2d, text1, titleX, titleY, titleFont, Color.BLACK); g2d.setColor(Color.WHITE); g2d.drawString(text1, titleX, titleY); // 绘制副标题 g2d.setFont(subtitleFont); addSubtleShadow(g2d, text2, subtitleX, subtitleY, subtitleFont, Color.BLACK); g2d.setColor(new Color(255, 223, 128)); g2d.drawString(text2, subtitleX, subtitleY); // 绘制标签 g2d.setFont(tagFont); FontMetrics tagMetrics = g2d.getFontMetrics(tagFont); int tagWidth = tagMetrics.stringWidth(tagText); int tagHeight = tagMetrics.getHeight(); int tagX = (width - tagWidth) / 2; int tagY = height * 3 / 4 + tagMetrics.getAscent(); // 绘制标签背景 int paddingX = 30; int paddingY = 15; g2d.setColor(new Color(255, 223, 128)); g2d.fillRoundRect( tagX - paddingX, tagY - tagMetrics.getAscent() - paddingY, tagWidth + paddingX * 2, tagHeight + paddingY * 2, 20, 20 ); // 绘制标签文字 g2d.setColor(Color.BLACK); g2d.drawString(tagText, tagX, tagY); g2d.dispose(); return image; } public static void main(String[] args) { try { String title = "SpringBoot + Vue2"; String subtitle = "二手手机管理系统"; String tagText = "源码 + 数据库 + 论文"; int titleSize = 120; BufferedImage cover = createCover(title, subtitle, tagText, titleSize); ImageIO.write(cover, "PNG", new File("cover.png")); System.out.println("Cover image generated successfully!"); } catch (Exception e) { e.printStackTrace(); } } }