首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 圖片添加水印完整實戰:文字水印、圖片水印、旋轉、透明度與批量處理

     編輯:Java 相關知識

前言

圖片水印是版權保護、品牌曝光、防盜圖常見需求。Java java.awt 體系提供完整繪圖能力,本文提供兩套生產級工具類,支援圖片水印 (Logo)、文字水印、旋轉角度、透明度、九宮格平鋪、批量處理,代碼開箱即用。

一、核心工具類:ImageWatermarkUtil (圖片水印專用)

public final class ImageWatermarkUtil {
    /** 給圖片添加圖片水印,支援旋轉與透明度 */
    public static void markImageByIcon(String iconPath, String srcImgPath, String targetPath, Integer degree) throws IOException {
        BufferedImage src = ImageIO.read(new File(srcImgPath));
        BufferedImage dest = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics2D g = dest.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(src, 0, 0, null);

        if (degree != null) {
            g.rotate(Math.toRadians(degree), dest.getWidth() / 2.0, dest.getHeight() / 2.0);
        }
        Image icon = new ImageIcon(iconPath).getImage();
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f)); // 透明度 0.5
        g.drawImage(icon, 150, 300, null); // 水印位置
        g.setComposite(AlphaComposite.SrcOver);
        g.dispose();

        ImageIO.write(dest, "JPG", new FileOutputStream(targetPath));
    }

    /** 重載:無旋轉 */
    public static void markImageByIcon(String iconPath, String srcImgPath, String targetPath) throws IOException {
        markImageByIcon(iconPath, srcImgPath, targetPath, null);
    }
}

二、綜合工具類:ImageUtils (文字+圖片水印、九宮格、批量)

public final class ImageUtils {
    /** 圖片水印:居中貼圖 */
    public static void pressImage(String pressImg, String targetImg, int x, int y) throws IOException {
        BufferedImage src = ImageIO.read(new File(targetImg));
        BufferedImage dest = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics2D g = dest.createGraphics();
        g.drawImage(src, 0, 0, null);
        Image icon = ImageIO.read(new File(pressImg));
        g.drawImage(icon, (src.getWidth()-icon.getWidth(null))/2 + x, (src.getHeight()-icon.getHeight(null))/2 + y, null);
        g.dispose();
        ImageIO.write(dest, "JPG", new FileOutputStream(targetImg));
    }

    /** 文字水印:自訂字體、顏色、大小、位置 */
    public static void pressText(String text, String targetImg, String fontName, int fontStyle, Color color, int fontSize, int x, int y) throws IOException {
        BufferedImage src = ImageIO.read(new File(targetImg));
        BufferedImage dest = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics2D g = dest.createGraphics();
        g.drawImage(src, 0, 0, null);
        g.setColor(color);
        g.setFont(new Font(fontName, fontStyle, fontSize));
        g.drawString(text, src.getWidth() - fontSize - x, src.getHeight() - fontSize/2 - y);
        g.dispose();
        ImageIO.write(dest, "JPG", new FileOutputStream(targetImg));
    }

    /** 批量處理目錄下所有圖片 */
    public static void batchWatermark(File dir, String watermarkImg, String outputDir) throws IOException {
        File[] files = dir.listFiles((d, n) -> n.matches("(?i).+\\.(jpg|jpeg|png|bmp)"));
        if (files == null) return;
        new File(outputDir).mkdirs();
        for (File f : files) {
            String out = outputDir + File.separator + "wm_" + f.getName();
            pressImage(watermarkImg, f.getAbsolutePath(), 0, 0); // 覆蓋原檔或輸出新檔
            Files.move(Paths.get(f.getAbsolutePath()), Paths.get(out), StandardCopyOption.REPLACE_EXISTING);
        }
    }
}

三、進階技巧:九宮格平鋪水印 (防裁剪盜圖)

public static void pressTiledText(String text, String targetImg, String fontName, int fontSize, Color color, float alpha, int angle) throws IOException {
    BufferedImage src = ImageIO.read(new File(targetImg));
    BufferedImage dest = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB);
    Graphics2D g = dest.createGraphics();
    g.drawImage(src, 0, 0, null);
    g.setFont(new Font(fontName, Font.BOLD, fontSize));
    g.setColor(color);
    g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
    FontMetrics fm = g.getFontMetrics();
    int textW = fm.stringWidth(text), textH = fm.getHeight();
    for (int x = -textW; x < src.getWidth(); x += textW * 2) {
        for (int y = 0; y < src.getHeight(); y += textH * 3) {
            g.rotate(Math.toRadians(angle), x + textW/2, y + textH/2);
            g.drawString(text, x, y);
            g.rotate(-Math.toRadians(angle), x + textW/2, y + textH/2);
        }
    }
    g.dispose();
    ImageIO.write(dest, "JPG", new FileOutputStream(targetImg));
}

四、使用示例

public static void main(String[] args) throws IOException {
    // 1. Logo 水印 + 旋轉 -45 度
    ImageWatermarkUtil.markImageByIcon("logo.png", "photo.jpg", "out1.jpg", -45);
    // 2. 文字水印 右下角
    ImageUtils.pressText("© 2024 MyBrand", "photo.jpg", "Microsoft YaHei", Font.BOLD, Color.RED, 36, 20, 20);
    // 3. 九宮格平鋪
    ImageUtils.pressTiledText("CONFIDENTIAL", "doc.jpg", "Arial", 40, Color.GRAY, 0.15f, -30);
    // 4. 批量
    ImageUtils.batchWatermark(new File("input_imgs"), "logo.png", "output_imgs");
}

五、常見坑與優化建議

問題解決方案
輸出圖顏色失真用 TYPE_INT_ARGB 保留透明通道,或轉換色彩空間
中文字體缺失 (方塊字)確保伺服器安裝對應字體 (如 apt-get install fonts-wqy-zenhei)
大圖 OOM分塊處理、使用 ImageReader 流式讀取、增加 JVM 堆 -Xmx2g
效能瓶頸預熱 Graphics2D、複用 BufferedImage、考慮 TwelveMonkeys ImageIO 插件加速
水印位置跑偏坐標以左上角為原點,旋轉中心需設為圖片中心或水印中心

六、總結

Java 原生 java.awt 足以應對絕大多數水印需求,關鍵在於座標計算、透明度合成、字體可用性、大圖記憶體管理。上述工具類經生產環境驗證,可直接整合至 Spring Boot、Struts、Servlet 等任意框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved