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

Java 實現傾斜水印鋪滿全圖:完整工具類與調用指南

     編輯:Java 相關知識

效果預覽

將水印圖片按指定角度旋轉,以網格狀鋪滿整張目標圖片,支援透明度、間距、角度配置。

核心工具類:ImageMarkUtil

public class ImageMarkUtil {
    /** 水印透明度 0.0-1.0 */
    private static float alpha = 0.5f;
    /** 水印旋轉角度 */
    private static double degree = 30.0;
    /** 水印間距 (像素) */
    private static int interval = 50;

    /** 統一配置入口 */
    public static void setImageMarkOptions(float alpha, int degree, int interval) {
        if (alpha > 0) ImageMarkUtil.alpha = alpha;
        if (degree != 0) ImageMarkUtil.degree = degree;
        if (interval > 0) ImageMarkUtil.interval = interval;
    }

    /** 主入口:給圖片添加水印
     * @param waterImgPath 水印圖片路徑 (建議 PNG/GIF 支援透明)
     * @param srcImgPath 源圖片路徑
     * @param targetPath 輸出路徑 (可覆蓋原圖)
     */
    public static void waterMarkByImg(String waterImgPath, String srcImgPath, String targetPath) 
            throws Exception {
        waterMarkByImg(waterImgPath, srcImgPath, targetPath, degree);
    }

    /** 完整參數版本 */
    public static void waterMarkByImg(String waterImgPath, String srcImgPath, 
            String targetPath, double degree) throws Exception {
        
        OutputStream os = null;
        try {
            // 1. 讀取源圖
            Image srcImg = ImageIO.read(new File(srcImgPath));
            BufferedImage buffImg = new BufferedImage(
                srcImg.getWidth(null), srcImg.getHeight(null), 
                BufferedImage.TYPE_INT_RGB);
            
            // 2. 繪圖上下文
            Graphics2D g = buffImg.createGraphics();
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.drawImage(srcImg.getScaledInstance(
                srcImg.getWidth(null), srcImg.getHeight(null), 
                Image.SCALE_SMOOTH), 0, 0, null);
            
            // 3. 旋轉變換 (以圖片中心為原點)
            if (degree != 0) {
                g.rotate(Math.toRadians(degree), 
                    buffImg.getWidth() / 2.0, buffImg.getHeight() / 2.0);
            }
            
            // 4. 載入水印圖片
            ImageIcon imgIcon = new ImageIcon(waterImgPath);
            Image waterImg = imgIcon.getImage();
            int wWidth = imgIcon.getIconWidth();
            int wHeight = imgIcon.getIconHeight();
            
            // 5. 設定透明度合成規則
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            
            // 6. 網格鋪滿繪製
            for (int y = interval + wHeight; y < buffImg.getHeight(); 
                 y += interval + wHeight) {
                for (int x = interval + wWidth; x < buffImg.getWidth(); 
                     x += interval + wWidth) {
                    g.drawImage(waterImg, x - wWidth, y - wHeight, null);
                }
            }
            
            // 7. 恢復合成模式並釋放
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
            g.dispose();
            
            // 8. 輸出文件
            os = new FileOutputStream(targetPath);
            ImageIO.write(buffImg, "JPG", os);
            System.out.println("水印添加完成: " + targetPath);
            
        } finally {
            if (os != null) try { os.close(); } catch (IOException ignored) {}
        }
    }
}

調用示例

基本調用 (使用預設參數)

String watermarkPath = "/path/to/watermark.png";
String uploadPath = "/path/to/uploaded/photo.jpg";
ImageMarkUtil.waterMarkByImg(watermarkPath, uploadPath); // 覆蓋原圖

自定義參數調用

// 透明度 0.3、角度 45°、間距 30px
ImageMarkUtil.setImageMarkOptions(0.3f, 45, 30);
ImageMarkUtil.waterMarkByImg(watermarkPath, uploadPath, uploadPath);

在文件上傳成功後自動加水印

@PostMapping("/upload")
public Result upload(@RequestParam("file") MultipartFile file) {
    String savePath = saveFile(file); // 你的保存邏輯
    // 異步添加水印,不阻塞響應
    CompletableFuture.runAsync(() -> {
        try {
            ImageMarkUtil.setImageMarkOptions(0.4f, 30, 40);
            ImageMarkUtil.waterMarkByImg(
                "/static/watermark/logo.png", savePath, savePath);
        } catch (Exception e) {
            log.error("水印添加失敗", e);
        }
    });
    return Result.ok(savePath);
}

關鍵技術點解析

技術點實現細節
旋轉中心g.rotate(angle, width/2, height/2) 以圖片中心旋轉,避免邊緣截斷
透明度合成AlphaComposite.SRC_ATOP 只在目標像素非透明處顯示水印,配合 alpha 參數
網格計算雙層迴圈步長 = 水印尺寸 + interval,確保均勻分佈
圖片類型源圖用 TYPE_INT_RGB,水印建議 PNG 保留 Alpha 通道
資源釋放Graphics2D.dispose() + 流關閉,防止記憶體洩漏

常見問題與優化

  • 水印不顯示:檢查水印路徑、格式是否支援透明、alpha 是否為 0
  • 旋轉後邊緣留白:旋轉會導致邊角超出畫布,可考慮先建立更大畫布繪製再裁剪
  • 大圖 OOM:大圖片建議使用 ImageIO.read 時配合 ImageReader 分塊處理,或縮放後再加水印
  • 效能優化:水印圖片可預先載入緩存 BufferedImage,避免重複 ImageIO.read
  • 併發安全:工具類為無狀態靜態方法,線程安全;但 setImageMarkOptions 修改靜態變數,高併發建議改為參數傳遞

擴展建議

  • 支援文字水印:g.drawString() + 字體/顏色/斜體設置
  • 支援九宮格/對角線/隨機分佈等多種鋪滿模式
  • 整合 Spring Boot Starter,提供 @EnableWatermark 自動配置
  • 增加水印防刪除:隱寫術/盲水印技術
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved