From a8601548c620249d3332de5711456a810fa13d71 Mon Sep 17 00:00:00 2001
From: Jerry Yan <792602257@qq.com>
Date: Wed, 19 Mar 2025 17:56:18 +0800
Subject: [PATCH] =?UTF-8?q?=E5=9B=BE=E7=89=87=E5=8F=AF=E6=8C=87=E5=AE=9A?=
 =?UTF-8?q?=E6=A0=BC=E5=BC=8F=EF=BC=8C=E5=8F=AF=E6=8E=A8=E8=8D=90=E6=A0=BC?=
 =?UTF-8?q?=E5=BC=8F=EF=BC=8C=E5=8E=8B=E7=BC=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../enums/ImageWatermarkOperatorEnum.java     | 10 +++---
 .../DefaultImageWatermarkOperator.java        | 34 +++++++++++++++++--
 .../operator/LeicaWatermarkOperator.java      | 34 +++++++++++++++++--
 .../operator/NormalWatermarkOperator.java     | 34 +++++++++++++++++--
 .../service/impl/mobile/GoodsServiceImpl.java |  4 +--
 5 files changed, 104 insertions(+), 12 deletions(-)

diff --git a/src/main/java/com/ycwl/basic/image/watermark/enums/ImageWatermarkOperatorEnum.java b/src/main/java/com/ycwl/basic/image/watermark/enums/ImageWatermarkOperatorEnum.java
index eea6983..7759356 100644
--- a/src/main/java/com/ycwl/basic/image/watermark/enums/ImageWatermarkOperatorEnum.java
+++ b/src/main/java/com/ycwl/basic/image/watermark/enums/ImageWatermarkOperatorEnum.java
@@ -4,14 +4,16 @@ import lombok.Getter;
 
 @Getter
 public enum ImageWatermarkOperatorEnum {
-    WATERMARK("defW"),
-    LEICA("leica"),
-    NORMAL("normal");
+    WATERMARK("defW", "jpg"),
+    LEICA("leica", "png"),
+    NORMAL("normal", "png");
 
     private final String type;
+    private final String preferFileType;
 
-    ImageWatermarkOperatorEnum(String type) {
+    ImageWatermarkOperatorEnum(String type, String preferFileType) {
         this.type = type;
+        this.preferFileType = preferFileType;
     }
 
     public static ImageWatermarkOperatorEnum getByCode(String type) {
diff --git a/src/main/java/com/ycwl/basic/image/watermark/operator/DefaultImageWatermarkOperator.java b/src/main/java/com/ycwl/basic/image/watermark/operator/DefaultImageWatermarkOperator.java
index 3a1e3a6..8d1e807 100644
--- a/src/main/java/com/ycwl/basic/image/watermark/operator/DefaultImageWatermarkOperator.java
+++ b/src/main/java/com/ycwl/basic/image/watermark/operator/DefaultImageWatermarkOperator.java
@@ -5,6 +5,9 @@ import com.ycwl.basic.image.watermark.exception.ImageWatermarkException;
 import lombok.extern.slf4j.Slf4j;
 
 import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.stream.ImageOutputStream;
 import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.File;
@@ -34,12 +37,39 @@ public class DefaultImageWatermarkOperator implements IOperator {
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
         g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f));
         g2d.drawImage(watermarkImage, 0, 0,  baseImage.getWidth(), baseImage.getHeight(), null);
+        String fileName = info.getWatermarkedFile().getName();
+        String formatName = "jpg"; // 默认格式为 jpg
+        if (fileName.endsWith(".png")) {
+            formatName = "png";
+        } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
+            formatName = "jpg";
+        }
+        ImageWriter writer = ImageIO.getImageWritersByFormatName(formatName).next();
+        ImageOutputStream ios;
         try {
-            ImageIO.write(newImage, "jpg", info.getWatermarkedFile());
+            ios = ImageIO.createImageOutputStream(info.getWatermarkedFile());
+        } catch (IOException e) {
+            throw new ImageWatermarkException("图片保存失败,目标文件无法写入");
+        }
+        writer.setOutput(ios);
+        try {
+            // 使用 ImageWriter 设置写入质量
+            ImageWriteParam writeParam = writer.getDefaultWriteParam();
+            if (writeParam.canWriteCompressed()) {
+                writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+                writeParam.setCompressionQuality(0.8f); // 设置写入质量为 80%
+            }
+            writer.write(null, new javax.imageio.IIOImage(newImage, null, null), writeParam);
         } catch (IOException e) {
             throw new ImageWatermarkException("图片保存失败");
-        } finally {
+        }
+        finally {
             g2d.dispose();
+            try {
+                ios.close();
+            } catch (IOException ignore) {
+            }
+            writer.dispose();
         }
         return info.getWatermarkedFile();
     }
diff --git a/src/main/java/com/ycwl/basic/image/watermark/operator/LeicaWatermarkOperator.java b/src/main/java/com/ycwl/basic/image/watermark/operator/LeicaWatermarkOperator.java
index 869d345..3857bed 100644
--- a/src/main/java/com/ycwl/basic/image/watermark/operator/LeicaWatermarkOperator.java
+++ b/src/main/java/com/ycwl/basic/image/watermark/operator/LeicaWatermarkOperator.java
@@ -5,6 +5,9 @@ import com.ycwl.basic.image.watermark.exception.ImageWatermarkException;
 import lombok.extern.slf4j.Slf4j;
 
 import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.stream.ImageOutputStream;
 import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.File;
@@ -110,12 +113,39 @@ public class LeicaWatermarkOperator implements IOperator {
         g2d.setFont(datetimeFont);
         g2d.setColor(datetimeColor);
         g2d.drawString(info.getDatetimeLine(), newImage.getWidth() + EXTRA_BORDER_PX - OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth), EXTRA_BORDER_PX + baseImage.getHeight() +  + OFFSET_Y + scenicLineHeight + dtLineHeight + dtLineHeight * FONT_GLOBAL_OFFSET_PERCENT);
+        String fileName = info.getWatermarkedFile().getName();
+        String formatName = "jpg"; // 默认格式为 jpg
+        if (fileName.endsWith(".png")) {
+            formatName = "png";
+        } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
+            formatName = "jpg";
+        }
+        ImageWriter writer = ImageIO.getImageWritersByFormatName(formatName).next();
+        ImageOutputStream ios;
         try {
-            ImageIO.write(newImage, "png", info.getWatermarkedFile());
+            ios = ImageIO.createImageOutputStream(info.getWatermarkedFile());
+        } catch (IOException e) {
+            throw new ImageWatermarkException("图片保存失败,目标文件无法写入");
+        }
+        writer.setOutput(ios);
+        try {
+            // 使用 ImageWriter 设置写入质量
+            ImageWriteParam writeParam = writer.getDefaultWriteParam();
+            if (writeParam.canWriteCompressed()) {
+                writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+                writeParam.setCompressionQuality(0.95f); // 设置写入质量为 95%
+            }
+            writer.write(null, new javax.imageio.IIOImage(newImage, null, null), writeParam);
         } catch (IOException e) {
             throw new ImageWatermarkException("图片保存失败");
-        } finally {
+        }
+        finally {
             g2d.dispose();
+            try {
+                ios.close();
+            } catch (IOException ignore) {
+            }
+            writer.dispose();
         }
         return info.getWatermarkedFile();
     }
diff --git a/src/main/java/com/ycwl/basic/image/watermark/operator/NormalWatermarkOperator.java b/src/main/java/com/ycwl/basic/image/watermark/operator/NormalWatermarkOperator.java
index 36bdf85..ca4bc71 100644
--- a/src/main/java/com/ycwl/basic/image/watermark/operator/NormalWatermarkOperator.java
+++ b/src/main/java/com/ycwl/basic/image/watermark/operator/NormalWatermarkOperator.java
@@ -5,6 +5,9 @@ import com.ycwl.basic.image.watermark.exception.ImageWatermarkException;
 import lombok.extern.slf4j.Slf4j;
 
 import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.stream.ImageOutputStream;
 import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.File;
@@ -86,12 +89,39 @@ public class NormalWatermarkOperator implements IOperator {
         g2d.setFont(datetimeFont);
         g2d.setColor(datetimeColor);
         g2d.drawString(info.getDatetimeLine(), offsetX + newQrcodeWidth + QRCODE_OFFSET_X, offsetY + scenicLineHeight + dtLineHeight + FONT_GLOBAL_OFFSET_PERCENT * dtLineHeight);
+        String fileName = info.getWatermarkedFile().getName();
+        String formatName = "jpg"; // 默认格式为 jpg
+        if (fileName.endsWith(".png")) {
+            formatName = "png";
+        } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
+            formatName = "jpg";
+        }
+        ImageWriter writer = ImageIO.getImageWritersByFormatName(formatName).next();
+        ImageOutputStream ios;
         try {
-            ImageIO.write(newImage, "png", info.getWatermarkedFile());
+            ios = ImageIO.createImageOutputStream(info.getWatermarkedFile());
+        } catch (IOException e) {
+            throw new ImageWatermarkException("图片保存失败,目标文件无法写入");
+        }
+        writer.setOutput(ios);
+        try {
+            // 使用 ImageWriter 设置写入质量
+            ImageWriteParam writeParam = writer.getDefaultWriteParam();
+            if (writeParam.canWriteCompressed()) {
+                writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+                writeParam.setCompressionQuality(0.95f); // 设置写入质量为 95%
+            }
+            writer.write(null, new javax.imageio.IIOImage(newImage, null, null), writeParam);
         } catch (IOException e) {
             throw new ImageWatermarkException("图片保存失败");
-        } finally {
+        }
+        finally {
             g2d.dispose();
+            try {
+                ios.close();
+            } catch (IOException ignore) {
+            }
+            writer.dispose();
         }
         return info.getWatermarkedFile();
     }
diff --git a/src/main/java/com/ycwl/basic/service/impl/mobile/GoodsServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/mobile/GoodsServiceImpl.java
index 1d9f6a3..63101f6 100644
--- a/src/main/java/com/ycwl/basic/service/impl/mobile/GoodsServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/impl/mobile/GoodsServiceImpl.java
@@ -505,7 +505,7 @@ public class GoodsServiceImpl implements GoodsService {
                 } else {
                     // 生成
                     File dstFile = new File(item.getGoodsId() + ".jpg");
-                    File watermarkedFile = new File(item.getGoodsId() + "_" + ImageWatermarkOperatorEnum.WATERMARK.getType() + ".png");
+                    File watermarkedFile = new File(item.getGoodsId() + "_" + ImageWatermarkOperatorEnum.WATERMARK.getType() + "." + ImageWatermarkOperatorEnum.WATERMARK.getPreferFileType());
                     try {
                         HttpUtil.downloadFile(item.getUrl().replace("oss.zhentuai.com", "frametour-assets.oss-cn-shanghai-internal.aliyuncs.com"), dstFile);
                     } catch (Exception e) {
@@ -613,7 +613,7 @@ public class GoodsServiceImpl implements GoodsService {
                     } else {
                         // 生成
                         File dstFile = new File(item.getGoodsId() + ".jpg");
-                        File watermarkedFile = new File(item.getGoodsId() + "_" + type.getType() + ".png");
+                        File watermarkedFile = new File(item.getGoodsId() + "_" + type.getType() + "." + type.getPreferFileType());
                         try {
                             HttpUtil.downloadFile(item.getUrl().replace("oss.zhentuai.com", "frametour-assets.oss-cn-shanghai-internal.aliyuncs.com"), dstFile);
                         } catch (Exception e) {