springboot如何给上传的图片加水印,java工具类分享

文章描述了如何在摄影网站中使用SpringMVC框架实现图片文件上传,同时防止用户窃取图片,通过MD5检查和Redis缓存配合,确保图片唯一性,并利用加水印工具对上传的图片进行处理,保护版权。
摘要由CSDN通过智能技术生成

我写了一个摄影网站,但是不太希望其他用户窃取别人的图片,需要业务中有一个加水印的功能

   /**
     * 图片文件上传
     */
    @Autowired
    private StringRedisTemplate redisTemplate;
    @PostMapping(value = "/imageUpload", name = "图片文件上传")
    public R imageUpload(MultipartFile file) {
        if (file.isEmpty()) {
            return R.error("上传异常");
        }

        try {
            // 计算上传图片的MD5值
            String md5 = calculateMD5(file);

            // 检查Redis中是否存在该MD5值
            Boolean exist = redisTemplate.opsForValue().setIfAbsent(md5, "1");
            if (exist != null && exist) {
                // 说明MD5值不存在,可以上传
                return R.ok(campusFileService.fileUploadImage(file));
            } else {
                return R.error("图片已存在,不能重复上传");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("上传异常");
        }
    }
    private String calculateMD5(MultipartFile file) throws IOException {
        byte[] bytes = file.getBytes();
        return DigestUtil.md5Hex(bytes);
    }
  @Override
    public CampusFileEntity fileUploadImage(MultipartFile file) {
        assertAllowed();
        if (file.getSize() > IMAGE_MAX_SIZE) {
            throw new FileSizeLimitExceededException(IMAGE_MAX_SIZE / 1024 / 1024);
        }
        try {
            String path = FileUploadUtils.upload(CAMPUS_FILE_PATH, file, MimeTypeUtils.IMAGE_EXTENSION);
            return saveDB(path);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }

    }
  /**
     * 文件上传
     *
     * @param baseDir          相对应用的基目录
     * @param file             上传的文件
     * @param allowedExtension 上传文件类型
     * @return 返回上传成功的文件名
     * @throws FileSizeLimitExceededException       如果超出最大大小
     * @throws FileNameLengthLimitExceededException 文件名太长
     * @throws IOException                          比如读写文件出错时
     * @throws InvalidExtensionException            文件校验异常
     */
    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
            InvalidExtensionException {
        int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }

        assertAllowed(file, allowedExtension);

        String fileName = extractFilename(file);

        String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
        file.transferTo(Paths.get(absPath));

        // 调用加水印方法
        ImgWatermarkUtil.imgWatermarkLocal(absPath, absPath,"plog");

        return getPathFileName(baseDir, fileName);
    }

加水印工具类

package com.oddfar.campus.framework.api.file;

import cn.hutool.core.io.IoUtil;
import com.oddfar.campus.common.utils.DateUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Random;
import java.util.stream.IntStream;

/**
 * @program: 工具箱
 * @description 水印
 * @date 2023/6/6
 */
public class ImgWatermarkUtil {
    public static void main(String[] args) throws Exception {
        //imgWatermarkLocal(""D:\\公司文件\\图片.png","D:\\公司文件\\图片1.png","这是水印");
        InputStream inputStream = new FileInputStream("D:\\公司文件\\图片1.png");
        InputStream inputStreamFile = imgWatermarkInt(inputStream, "yph", "这是水印BXCVVBADSSF","png");
        saveFile(inputStreamFile,"D:\\公司文件\\图片" + DateUtils.dateTimeNow() + ".png");

    }

    public static void testFile(InputStream inputStream) throws Exception {
        InputStream inputStreamFile = imgWatermarkInt(inputStream, "这是水印", "png");
        saveFile(inputStreamFile,"D:\\公司文件\\图片" + DateUtils.dateTimeNow() + ".png");
    }

    /**
     * 保存本地
     * @param inputStream 输入流
     * @param filePath 保存地址
     * @throws IOException
     */
    public static void saveFile(InputStream inputStream, String filePath) throws IOException {
        try (OutputStream outputStream = new FileOutputStream(filePath)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
    }


    /**
     * 给图片添加水印
     *
     * @param inputFile     原文件路径+名称
     * @param outputFile    添加水印后输出文件保存的路径+名称
     * @param waterMarkName 添加水印的内容
     */
    public static void imgWatermarkLocal(String inputFile, String outputFile, String waterMarkName) {
        try {
            BufferedImage img = ImageIO.read(new File(inputFile));
            int width = img.getWidth();
            int height = img.getHeight();

            int fontSize = (width + height) / 80;

            Graphics2D g = img.createGraphics();
            g.setFont(new Font("黑体", Font.PLAIN, fontSize));
            g.setColor(new Color(0, 0, 0, 30));
            g.rotate(0.2);

            // 间隔
            int split = fontSize * 2;
            // 文字占用的宽度
            int xWidth = getStrWidth(waterMarkName, fontSize);
            // x,y可以绘制的数量,多加一个补充空白
            int xCanNum = width / xWidth + 1;
            int yCanNum = height / fontSize + 1;
            for (int i = 1; i <= yCanNum; i++) {
                int y = fontSize * i + split * i;
                for (int j = 0; j < xCanNum; j++) {
                    int x = xWidth * j + split * j;
                    g.drawString(waterMarkName, x, y - (fontSize + split) * j);
                }
            }
            g.dispose();
            ImageIO.write(img, "png", new File(outputFile));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 图片加水印
     *
     * @param inputStream   输入流
     * @param waterMarkName 添加水印的内容
     * @return OutputStream 输出流
     */
    public static OutputStream imgWatermarkOut(InputStream inputStream, String waterMarkName) {
        try {
            BufferedImage img = ImageIO.read(inputStream);

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

            int fontSize = (width + height) / 80;

            Graphics2D g = img.createGraphics();
            g.setFont(new Font("黑体", Font.PLAIN, fontSize));
            g.setColor(new Color(0, 0, 0, 30));
            g.rotate(0.2);

            // 间隔
            int split = fontSize * 2;
            // 文字占用的宽度
            int xWidth = getStrWidth(waterMarkName, fontSize);
            // x,y可以绘制的数量,多加一个补充空白
            int xCanNum = width / xWidth + 1;
            int yCanNum = height / fontSize + 1;
            for (int i = 1; i <= yCanNum; i++) {
                int y = fontSize * i + split * i;
                for (int j = 0; j < xCanNum; j++) {
                    int x = xWidth * j + split * j;
                    g.drawString(waterMarkName, x, y - (fontSize + split) * j);
                }
            }
            g.dispose();
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ImageIO.write(img, "png", outputStream);
            return outputStream;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 图片加水印
     *
     * @param inputStream   输入流
     * @param waterMarkName 添加水印的内容
     * @param fileSuffix    扩展名
     * @return InputStream 新的输入流
     */
    public static InputStream imgWatermarkInt(InputStream inputStream, String waterMarkName, String fileSuffix) {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            BufferedImage originalImage = ImageIO.read(inputStream);
            int width = originalImage.getWidth();
            int height = originalImage.getHeight();

            if (width <= 0 || height <= 0) {
                throw new IllegalArgumentException("Invalid image size.");
            }

            if (waterMarkName == null || waterMarkName.trim().isEmpty()) {
                throw new IllegalArgumentException("Watermark name cannot be empty.");
            }

            // 创建新的BufferedImage对象,并复制原始图像
            BufferedImage newImage = new BufferedImage(width, height, originalImage.getType());
            Graphics2D g = newImage.createGraphics();
            g.drawImage(originalImage, 0, 0, null);

            int fontSize = (width + height) / 80;
            g.setFont(new Font("黑体", Font.PLAIN, fontSize));
            g.setColor(new Color(0, 0, 0, 30));
            g.rotate(0.2);

            // 间隔
            int split = fontSize * 2;
            // 文字占用的宽度
            int xWidth = getStrWidth(waterMarkName, fontSize);
            // x,y可以绘制的数量,多加一个补充空白
            int xCanNum = width / xWidth + 1;
            int yCanNum = height / fontSize + 1;
            for (int i = 1; i <= yCanNum; i++) {
                int y = fontSize * i + split * i;
                for (int j = 0; j < xCanNum; j++) {
                    int x = xWidth * j + split * j;
                    g.drawString(waterMarkName, x, y - (fontSize + split) * j);
                }
            }
            g.dispose();

            // 将新的BufferedImage对象写入ByteArrayOutputStream中
            ImageIO.write(newImage, fileSuffix, outputStream);

            // 返回新的InputStream对象
            return new ByteArrayInputStream(outputStream.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 图片加水印
     *
     * @param inputStream      输入流
     * @param waterMarkNameOne 添加水印的内容
     * @param waterMarkNameTwo 添加水印的内容
     * @param fileSuffix       扩展名
     * @return InputStream 输入流
     */
    public static InputStream imgWatermarkInt(InputStream inputStream, String waterMarkNameOne, String waterMarkNameTwo, String fileSuffix) {
        try {

            BufferedImage img = ImageIO.read(inputStream);

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

            int fontSize = (width + height) / 80;


            // 间隔
            int split = fontSize * 2;
            // 文字占用的宽度
            int xWidth1 = getStrWidth(waterMarkNameOne, fontSize);
            int xWidth2 = getStrWidth(waterMarkNameTwo, fontSize);
            int xWidth = Math.max(xWidth1,xWidth2);
            // x,y可以绘制的数量,多加一个补充空白
            int xCanNum = width / xWidth + 1;
            int yCanNum = height / fontSize + 1;
            for (int i = 1; i <= yCanNum; i++) {
                int y = fontSize * i + split * i;
                String waterMarkName = "";
                for (int j = 0; j < xCanNum; j++) {
                    Graphics2D g = img.createGraphics();
                    g.setFont(new Font("黑体", Font.PLAIN, fontSize));
                    g.setColor(new Color(0, 0, 0, 30));
                    g.rotate(0.2);
                    int x = xWidth * j + split * j;
                    //随机水印
                    if (j % 2 == 0) {
                        waterMarkName = waterMarkNameOne;
                    } else {
                        waterMarkName = waterMarkNameTwo;
                    }
                    g.drawString(waterMarkName, x, y - (fontSize + split) * j);
                    g.dispose();
                }
            }


            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ImageIO.write(img, fileSuffix, outputStream);

            return new ByteArrayInputStream(outputStream.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 获取字符串占用的宽度
     * <br>
     *
     * @param str      字符串
     * @param fontSize 文字大小
     * @return 字符串占用的宽度
     */
    public static int getStrWidth(String str, int fontSize) {
        char[] chars = str.toCharArray();
        int fontSize2 = fontSize / 2;

        int width = 0;

        for (char c : chars) {
            int len = String.valueOf(c).getBytes().length;
            // 汉字为3,其余1
            // 可能还有一些特殊字符占用2等等,统统计为汉字
            if (len != 1) {
                width += fontSize;
            } else {
                width += fontSize2;
            }
        }
        return width == 0 ? 1 : width;
    }

    /**
     * 图片加水印
     *
     * @param inputStream   输入流
     * @param waterMarkName 添加水印的内容
     * @param fileSuffix    扩展名
     * @return InputStream 新的输入流
     */
    public static InputStream imgWatermarkInt2(InputStream inputStream, String waterMarkName, String fileSuffix) {
        try (InputStream in = inputStream; ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            BufferedImage originalImage = ImageIO.read(in);
            int width = originalImage.getWidth();
            int height = originalImage.getHeight();

            if(width <= 0 || height <= 0){
                throw new IllegalArgumentException("Invalid image size.");
            }

            if(waterMarkName == null || waterMarkName.trim().isEmpty()){
                throw new IllegalArgumentException("Watermark name cannot be empty.");
            }

            // 创建新的BufferedImage对象,并复制原始图像
            BufferedImage newImage = new BufferedImage(width, height, originalImage.getType());
            Graphics2D g = newImage.createGraphics();
            g.drawImage(originalImage, 0, 0, null);

            int fontSize = (width + height) / 80;
            g.setFont(new Font("黑体", Font.PLAIN, fontSize));
            g.setColor(new Color(0, 0, 0, 30));
            g.rotate(0.2);

            // 间隔
            int split = fontSize * 2;
            // 文字占用的宽度
            int xWidth = getStrWidth(waterMarkName, fontSize);
            // x,y可以绘制的数量,多加一个补充空白
            int xCanNum = width / xWidth + 1;
            int yCanNum = height / fontSize + 1;

            // 使用流式API进行操作
            IntStream.range(1, yCanNum + 1)
                    .forEach(i -> {
                        int y = fontSize * i + split * i;
                        IntStream.range(0, xCanNum)
                                .forEach(j -> {
                                    int x = xWidth * j + split * j;
                                    g.drawString(waterMarkName, x, y - (fontSize + split) * j);
                                });
                    });

            g.dispose();

            // 将新的BufferedImage对象写入ByteArrayOutputStream中
            ImageIO.write(newImage, fileSuffix, out);

            // 返回新的InputStream对象
            return new ByteArrayInputStream(out.toByteArray());

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值