package com.ruoyi.common.utils.file; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.StringUtils; import net.coobird.thumbnailator.Thumbnails; import org.apache.poi.util.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.net.URL; import java.net.URLConnection; import java.util.Arrays; /** * 图片处理工具类 * * @author ruoyi */ public class ImageUtils { private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); public static byte[] getImage(String imagePath) { InputStream is = getFile(imagePath); try { return IOUtils.toByteArray(is); } catch (Exception e) { log.error("图片加载异常 {}", e); return null; } finally { IOUtils.closeQuietly(is); } } public static InputStream getFile(String imagePath) { try { byte[] result = readFile(imagePath); result = Arrays.copyOf(result, result.length); return new ByteArrayInputStream(result); } catch (Exception e) { log.error("获取图片异常 {}", e); } return null; } /** * 读取文件为字节数据 * * @param url 地址 * @return 字节数据 */ public static byte[] readFile(String url) { InputStream in = null; try { if (url.startsWith("http")) { // 网络地址 URL urlObj = new URL(url); URLConnection urlConnection = urlObj.openConnection(); urlConnection.setConnectTimeout(30 * 1000); urlConnection.setReadTimeout(60 * 1000); urlConnection.setDoInput(true); in = urlConnection.getInputStream(); } else { // 本机地址 String localPath = RuoYiConfig.getProfile(); String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX); in = new FileInputStream(downloadPath); } return IOUtils.toByteArray(in); } catch (Exception e) { log.error("获取文件路径异常 {}", e); return null; } finally { IOUtils.closeQuietly(in); } } /** * 添加图片水印 * * @param sourceFile 文件源路径 * @param destFile 文件路径 * @param watermarkText1 水印信息上 * @param watermarkText2 水印信息下 * @throws Exception 异常 */ public static void addWatermark(File sourceFile, File destFile, String watermarkText1, String watermarkText2) throws Exception { // 读取图片 BufferedImage image = ImageIO.read(sourceFile); // 获取图片宽高 int width = image.getWidth(); int height = image.getHeight(); // 创建 Graphics2D 对象 Graphics2D g2d = (Graphics2D) image.getGraphics(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 根据图片大小调整字体大小 int fontSize = Math.max(width, height) / 40; // 字体大小为图片较大边长的 1/20 g2d.setFont(new Font("SimHei", Font.BOLD, fontSize)); // g2d.setColor(new Color(255, 255, 255, 128)); // 白色半透明 // 计算水印文本宽高 FontMetrics fontMetrics = g2d.getFontMetrics(); // 第一行水印的宽高 int textWidth1 = fontMetrics.stringWidth(watermarkText1); int textHeight = fontMetrics.getHeight(); // 每行的高度 // 第二行水印的宽度 int textWidth2 = fontMetrics.stringWidth(watermarkText2); // 计算水印的位置(右下角,分两行) int padding = width / 50; // 边距 int x1 = width - textWidth1 - padding; // 第一行水平位置 int x2 = width - textWidth2 - padding; // 第二行水平位置 int y1 = height - textHeight - padding; // 第一行垂直位置 int y2 = height - padding; // 第二行垂直位置 // 分析水印区域的背景颜色(取样水印区域的平均颜色) Color averageColor = getAverageColor(image, x1, y1 - textHeight, textWidth1, textHeight + (y2 - y1)); // 判断背景颜色是否浅色或深色 Color watermarkColor = isLightColor(averageColor) ? new Color(0, 0, 0, 180) : new Color(255, 255, 255, 128); // 设置水印颜色 g2d.setColor(watermarkColor); // 绘制两行水印 g2d.drawString(watermarkText1, x1, y1); g2d.drawString(watermarkText2, x2, y2); g2d.dispose(); // 保存处理后的图片 // ImageIO.write(image, "jpg", destFile); String format = sourceFile.getName().substring(sourceFile.getName().lastIndexOf(".") + 1); ImageIO.write(image, format, destFile); } /** * 判断颜色是否为浅色 * * @param color 颜色 * @return true 表示浅色,false 表示深色 */ private static boolean isLightColor(Color color) { // 使用加权公式计算亮度 double brightness = (color.getRed() * 0.299 + color.getGreen() * 0.587 + color.getBlue() * 0.114); return brightness > 128; // 亮度大于128为浅色 } /** * 获取指定区域的平均颜色 * * @param image 图片 * @param x 起始横坐标 * @param y 起始纵坐标 * @param width 区域宽度 * @param height 区域高度 * @return 平均颜色 */ private static Color getAverageColor(BufferedImage image, int x, int y, int width, int height) { int r = 0, g = 0, b = 0, count = 0; for (int i = x; i < x + width && i < image.getWidth(); i++) { for (int j = y; j < y + height && j < image.getHeight(); j++) { Color pixelColor = new Color(image.getRGB(i, j)); r += pixelColor.getRed(); g += pixelColor.getGreen(); b += pixelColor.getBlue(); count++; } } return new Color(r / count, g / count, b / count); } /** * 生成缩略图并进行压缩 * * @param originalImagePath 原始图片路径 * @param thumbImagePath 缩略图保存路径 * @param width 缩略图宽度 * @param height 缩略图高度 * @param quality 压缩质量,范围0-1,值越低压缩越厉害 * @throws IOException IO异常 */ public static void compressAndGenerateThumbnail(String originalImagePath, String thumbImagePath, int width, int height, float quality) throws IOException { // 压缩图片并生成缩略图 Thumbnails.of(new File(originalImagePath)) .size(width, height) // 设置缩略图的宽高 .outputQuality(quality) // 设置图片压缩质量 .toFile(new File(thumbImagePath)); // 输出文件 } }