给图片添加水印接口(文字水印和照片水印)

最近在调试的时候,发现打印出来的卡证上姓名处本来应该是中文名的地方,结果出现了三个方框。初步怀疑是再给图片加水印的时候乱码了(原本服务器是Windows的,后面换成Linux)。经过排查,发现代码中有调用Graphics2D 加水印的方法。网络上借鉴了一下前辈的经验,发现是Linux上没有安装中文字体。随在Linux下安装中文字体,字体安装成功后,问题成功解决。下面列出Linux下安装中文字体的详细步骤。
1. 拷贝本地Windows系统的字体
Windows下字体的存放位置为:C:\Windows\Fonts,里面有很多字体。网上推荐选择自己喜欢的字体进行安装,我选择更为简单粗暴的方式,直接拷贝整个文件夹,打算把所有字体都安装上去。拷贝出来之后,发现也就几百兆,就这么干了。
字体文件夹拷贝出来之后,重命名为WinFronts,直接拷贝出来的文件夹应该是没有相关权限的。我也就没有去给文件夹设置权限什么的,直接通过WinS C P将文件加移动到目标Linux服务器上。将WinFronts文件夹复制到目标Linux服务器/usr/share/fonts下。
2.执行命令,安装字体
下面就是执行一系列的命令安装字体即可。
a: 去向字体文件目录,命令:cd /usr/share/fonts/WinFonts
b: 执行:mkfontscale (如果提示 mkfontscale: command not found,要自己安装,安装命令: yum install mkfontscale,提示安装内容是否正确的话, 敲Y,回车就好),安装完成要重新执行:mkfontscale
c: 执行:mkfontdir
d: 执行:fc-cache -fv (如果提示 fc-cache: command not found,要自己安装,安装命令: yum install fontconfig ,提示安装内容是否正确的话,敲Y,回车就好),安装完成要重新执行:fc-cache -fv
e.可以用:fc-list :lang=zh 命令 查看安装的中文字体,fc-list 命令查看linux的所有字体

`
/**
* oss添加文字水印接口
/
@RequestMapping(value = "/uploadOSSWatermark", method = RequestMethod.POST)
public @ResponseBody
String uploadWatermark(@RequestParam(value = "ossFile") MultipartFile ossFile,@RequestParam("objectName") String objectName) {
return uploadFileOSS(ossFile, objectName,0, TEXT_WATERMARK,null,true,0.25f);
}
/
*
* 上传到服务器 照片水印
*/
@RequestMapping(value = "/uploadOSSWatermarkImg", method = RequestMethod.POST)
public @ResponseBody
String uploadWatermarkImg(HttpServletRequest request,@RequestParam(value = "file") MultipartFile file) throws IOException {
return uploadImgFile(request,file,1,null,IMG_URL,true,1f);
}

/**
 * 保存到云端
 * @param ossFile
 * @param objectName oss路径
 * @param watermarkType 水印类型 (0=文字, 1=图片)
 * @param watermarkText 水印文字
 * @param testWatermark 水印图片存放绝对路径 或 网络路径
 * @param   isWatermarkStatus   是true 加水印 false 不加水印
 * @param  alpha 水印透明度
 * @return
 */
public String uploadFileOSS(MultipartFile ossFile, String objectName,Integer watermarkType,String watermarkText, String testWatermark,Boolean isWatermarkStatus,float alpha) {
    Map<String, String> resMap = new HashMap<>();

    if (ossFile != null) {
        if (ossFile.isEmpty()) {
            resMap.put("status", "EMPTY");
        } else {
            String originFileName = ossFile.getOriginalFilename();
            String prefix = originFileName.substring(originFileName.lastIndexOf(".") + 1);
            String fileName = System.currentTimeMillis() + MyUtils.getAuthCode(6) + "." + prefix;
            try {
                byte[] watermarkedBytes = null;
                if (isWatermarkStatus){
                    // 添加企业微信样式的平铺水印
                    watermarkedBytes = ImageUtil.addTiledWatermark(ossFile.getBytes(), watermarkType, watermarkText, testWatermark,alpha);
                }else {
                    watermarkedBytes = ossFile.getBytes();
                }


                FileUtil.uploadOSS(watermarkedBytes, objectName + "/" + fileName);

                resMap.put("status", "SUCCESS");
                resMap.put("fileName", "https://oss.eohelp.com/" + objectName + "/" + fileName);
            } catch (IOException e) {
                log.error("文件上传失败:{}", e);
                resMap.put("status", "FAIL");
                e.printStackTrace();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    JSONObject jsonObj = JSONObject.fromObject(resMap);

    return jsonObj.toString();
}

/**
 * 保存到服务器
 * @param request
 * @param file
 * @param watermarkType 水印类型 (0=文字, 1=图片)
 * @param watermarkText 水印文字
 * @param testWatermark 水印图片存放绝对路径 或 网络路径
 * @param isWatermarkStatus 是true 加水印 不是true 不加水印
 * @param  alpha 水印透明度
 * @return
 * @throws IOException
 */
public String uploadImgFile(HttpServletRequest request,
                            MultipartFile file,Integer watermarkType,String watermarkText, String testWatermark,Boolean isWatermarkStatus,float alpha) throws IOException {

    if (file == null || file.isEmpty()) {
        throw new IllegalArgumentException("上传文件为空");
    }

    ServletContext application = request.getServletContext();

    // --------- 按日期创建一级文件夹 ---------
    String ymd = new SimpleDateFormat("yyyyMMdd").format(new Date());
    String savePath = application.getRealPath("/") + Constant.UPLOADIMG_PATH + ymd + "/";
    File dir = new File(savePath);
    if (!dir.exists()) dir.mkdirs();

    // --------- 生成唯一文件名 ---------
    String originalName = file.getOriginalFilename();
    String ext = originalName.substring(originalName.lastIndexOf(".") + 1);
    String fileName = System.currentTimeMillis() + "_" + (int) (Math.random() * 10000) + "." + ext;
    byte[] watermarkedBytes = null;
    if (isWatermarkStatus){
        // 添加企业微信样式的平铺水印
        watermarkedBytes = ImageUtil.addTiledWatermark(file.getBytes(), watermarkType, watermarkText, testWatermark,alpha);
    }else {
        watermarkedBytes = file.getBytes();
    }
    // --------- 保存文件 ---------
    String path = savePath + fileName;
    File saveFile = new File(path);
    try (FileOutputStream fos = new FileOutputStream(saveFile)) {
        fos.write(watermarkedBytes);
    }
    PMCtrlParamKey pmCtrlParamKey = new PMCtrlParamKey();
    pmCtrlParamKey.setCtrlparamtype(CtrlParam.CTRL_PARAM_SYS);
    pmCtrlParamKey.setKeystring(CtrlParam.CTRL_PARAM_SYS_HEALTH_MALL_PAGE_URL);
    PMCtrlParam pmCtrlParam = pmCtrlParamService.selectById(pmCtrlParamKey);
    // --------- 返回 URL ---------
    Map<String, String> res = new HashMap<>();
    res.put("status", "SUCCESS");
    res.put("fileUrl", pmCtrlParam.getDefaultvalue() +"/mall"+Constant.UPLOADIMG_PATH + ymd +"/"+ fileName);

    JSONObject jsonObject = JSONObject.fromObject(res);
    return jsonObject.toString();

}


package mall.healthinfo.basic.utils;

import cn.hutool.core.util.ObjectUtil;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;

/**

  • JAVA 画图(生成文字水印)
    */
    public class ImageUtil {

    /**

    • 主方法:根据类型调用不同的水印处理

    • imageBytes 图片的字节数组

    • watermarkType 水印类型(0=文字, 1=图片)

    • watermarkText 水印文字

    • logoPath 水印图片路径

    • alpha 水印透明度
      /
      public static byte[] addTiledWatermark(byte[] imageBytes, int watermarkType, String watermarkText, String logoPath,float alpha) throws IOException {
      switch (watermarkType) {
      case 0:
      if (ObjectUtil.isEmpty(watermarkText)) {
      throw new IllegalArgumentException("无效的水印文字");
      }
      return addTextWatermark(imageBytes, watermarkText,alpha);
      case 1:
      if (ObjectUtil.isEmpty(logoPath)) {
      throw new IllegalArgumentException("无效的水印图片路径");
      }
      return addImageWatermark(imageBytes, logoPath,alpha);
      default:
      throw new IllegalArgumentException("无效的水印类型(0=文字, 1=图片): " + watermarkType);
      }
      }
      /
      *

    • 文字水印处理
      */
      private static byte[] addTextWatermark(byte[] imageBytes, String watermarkText, float alphaParams) throws IOException {
      ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);
      BufferedImage srcImg = ImageIO.read(bais);
      int width = srcImg.getWidth();
      int height = srcImg.getHeight();

      BufferedImage watermarked = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2d = watermarked.createGraphics();

      // 开启抗锯齿
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

      // 绘制原图
      g2d.drawImage(srcImg, 0, 0, width, height, null);

      // 设置透明度
      AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alphaParams);
      g2d.setComposite(alpha);

      // 设置颜色和字体
      g2d.setColor(new Color(50, 50, 50, 180)); // 深灰半透明
      g2d.setFont(new Font("SansSerif", Font.BOLD, width / 18));

      // 倾斜文字
      g2d.rotate(Math.toRadians(-30), width / 2.0, height / 2.0);

      // 计算间距
      int textWidth = g2d.getFontMetrics().stringWidth(watermarkText);
      int textHeight = g2d.getFontMetrics().getHeight();
      int xInterval = textWidth + 180;
      int yInterval = textHeight + 130;

      // 平铺绘制水印
      for (int x = -width; x < width * 2; x += xInterval) {
      for (int y = -height; y < height * 2; y += yInterval) {
      g2d.drawString(watermarkText, x, y);
      }
      }

      g2d.dispose();

      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ImageIO.write(watermarked, "png", baos);
      return baos.toByteArray();
      }

    /**

    • 图片水印处理(右下角单个水印,支持本地或网络路径)
      */
      private static byte[] addImageWatermark(byte[] imageBytes, String logoPath,float alphaParams) throws IOException {
      if (imageBytes == null || imageBytes.length == 0) {
      throw new IllegalArgumentException("原始图片数据不能为空");
      }
      if (logoPath == null || logoPath.trim().isEmpty()) {
      throw new IllegalArgumentException("水印图片路径不能为空");
      }

      // 读取原图
      ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);
      BufferedImage srcImg = ImageIO.read(bais);
      if (srcImg == null) {
      throw new IOException("无法读取原始图片,请检查文件格式");
      }

      int width = srcImg.getWidth();
      int height = srcImg.getHeight();

      // 创建绘图容器
      BufferedImage watermarked = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
      Graphics2D g2d = watermarked.createGraphics();
      g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
      g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g2d.drawImage(srcImg, 0, 0, width, height, null);

      //支持本地文件或网络路径
      BufferedImage watermarkImg;
      if (logoPath.startsWith("http://") || logoPath.startsWith("https://")) {
      URL url = new URL(logoPath);
      watermarkImg = ImageIO.read(url);
      } else {
      watermarkImg = ImageIO.read(new File(logoPath));
      }

      if (watermarkImg == null) {
      throw new IOException("无法读取水印图片: " + logoPath);
      }

      // 自适应缩放(水印宽度 = 原图宽度的 1/6)
      int wmWidth = width / 4;
      int wmHeight = watermarkImg.getHeight() * wmWidth / watermarkImg.getWidth();
      Image scaledLogo = watermarkImg.getScaledInstance(wmWidth, wmHeight, Image.SCALE_SMOOTH);

      // 半透明叠加(不旋转)
      g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alphaParams));

      // 计算右下角位置(留边距 60px)
      int x = width - wmWidth - 60;
      int y = height - wmHeight - 60;

      // 绘制水印
      g2d.drawImage(scaledLogo, x, y, wmWidth, wmHeight, null);

      g2d.dispose();

      // 输出为 JPEG
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ImageIO.write(watermarked, "jpg", baos);
      return baos.toByteArray();
      }

}

`

posted @ 2025-11-05 14:44  Mrl0308  阅读(6)  评论(0)    收藏  举报