194 lines
7.1 KiB
Java
194 lines
7.1 KiB
Java
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();
|
|
}
|
|
}
|
|
} |