基于java的图片水印添加方法(以右下角添加时间水印为例)-(可供rouyi框架上传minio调用)

基于java的图片水印添加方法

效果图:

添加水印前

添加时间水印后

一、应用场景

  水印添加可以保留部分实时信息,如位置、时间等,也可作为图片防盗使用等。有时候由于手机型号等问题在前端添加水印不成功或图片失真,此时可通过Java后端绘图添加。

二、文字水印添加处理

在文件上传到minio之前做处理,主要用到两个类:FileImageWatermarkUtils (水印添加处理)、MultipartFileDto (辅助实体类)

1、水印添加处理类FileImageWatermarkUtils

package com.inspur.common.utils.file;

import com.inspur.common.utils.file.MultipartFileDto;

import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;

import java.awt.AlphaComposite;

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics2D;

import java.awt.RenderingHints;

import java.awt.image.BufferedImage;

import java.io.*;

/**

 * @author inspur

 * 定义文字加水印

 */

public class FileImageWatermarkUtils {

    /**

     * 水印字体

     */

    private static final Font FONT = new Font("微软雅黑", Font.PLAIN, 40);

    /**

     * 透明度

     */

    private static final AlphaComposite COMPOSITE = AlphaComposite

            .getInstance(AlphaComposite.SRC_OVER, 0.9f);

    /**

     * 水印之间的间隔

     */

    private static final int X_MOVE = 150;

    /**

     * 水印之间的间隔

     */

    private static final int Y_MOVE = 200;

    /**

     * 打水印(文字)

     *

     * @param file       MultipartFile

     * @return MultipartFile

     */

    public static MultipartFile markWithContent(MultipartFile file,String keyword) {

        FileOutputStream fos = null;

        try {

            BufferedImage srcImg = ImageIO.read(file.getInputStream());

            // 图片宽、高

            int imgWidth = srcImg.getWidth();

            int imgHeight = srcImg.getHeight();

            // 图片缓存

            BufferedImage bufImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);

            // 创建绘图工具

            Graphics2D graphics = bufImg.createGraphics();

            // 画入原始图像

            graphics.drawImage(srcImg, 0, 0, imgWidth, imgHeight, null);

            // 设置水印颜色

            graphics.setColor(Color.WHITE);

            // 设置水印透明度

            graphics.setComposite(COMPOSITE);

            // 设置倾斜角度

/*            graphics.rotate(Math.toRadians(-35), (double) bufImg.getWidth() / 2,

                    (double) bufImg.getHeight() / 2);*/

            // 设置水印字体

            graphics.setFont(FONT);

            // 消除java.awt.Font字体的锯齿

//            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            int xCoordinate , yCoordinate;

            String mark = "ls65535";

            // 字体长度

            int markWidth = FONT.getSize() * getTextLength(keyword);

            // 字体高度

            int markHeight = FONT.getSize();

            //位置控制 水印位于图片 下方右下角

            xCoordinate = (int)((imgWidth-getWatermarkLength(keyword,graphics)  )*0.9);

            yCoordinate = (int)(imgHeight * 0.93 );

            graphics.drawString(keyword, xCoordinate, yCoordinate);

            InputStream inputStream = buffToInputStream(bufImg);

            // 释放画图工具

            graphics.dispose();

            return new MultipartFileDto(file.getName(),file.getOriginalFilename(),file.getContentType(),inputStream);

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            if (fos != null) {

                try {

                    fos.flush();

                    fos.close();

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }

        }

        return null;

    }

    /**

     * 计算水印文本长度

     * 1、中文长度即文本长度 2、英文长度为文本长度二分之一

     * @param text

     * @return

     */

    public static int getTextLength(String text) {

        //水印文字长度

        int length = text.length();

        for (int i = 0; i < text.length(); i++) {

            String s = String.valueOf(text.charAt(i));

            if (s.getBytes().length > 1) {

                length++;

            }

        }

        length = length % 2 == 0 ? length / 2 : length / 2 + 1;

        return length;

    }

    public static InputStream buffToInputStream(BufferedImage buffer) throws IOException {

        ByteArrayOutputStream os = new ByteArrayOutputStream();

        ImageIO.write(buffer, "png", os);

        return new ByteArrayInputStream(os.toByteArray());

    }

    public static int getWatermarkLength(String waterMarkContent, Graphics2D g) {

        return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());

    }

}

2、实体类MultipartFileDto

package com.inspur.common.utils.file;

import org.springframework.util.FileCopyUtils;

import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;

import java.io.File;

import java.io.IOException;

import java.io.InputStream;

/**

 * @author

 * file转MultipartFile的时候会用到MockMultipartFile

 * 当你导入spring-test依赖的时候 会跟某些依赖冲突(暂未找到具体是哪个冲突)

 * 解决方法 重写一个类去实现MultipartFile接口

 * 直接用MockMultipartFile的源码

 *

 */

public class MultipartFileDto implements MultipartFile {

    private final String name;

    private String originalFilename;

    private String contentType;

    private final byte[] content;

    /**

     * Create a new MultipartFileDto with the given content.

     * @param name the name of the file

     * @param content the content of the file

     */

    public MultipartFileDto(String name, byte[] content) {

        this(name, "", null, content);

    }

    /**

     * Create a new MultipartFileDto with the given content.

     * @param name the name of the file

     * @param contentStream the content of the file as stream

     * @throws IOException if reading from the stream failed

     */

    public MultipartFileDto(String name, InputStream contentStream) throws IOException {

        this(name, "", null, FileCopyUtils.copyToByteArray(contentStream));

    }

    /**

     * Create a new MultipartFileDto with the given content.

     * @param name the name of the file

     * @param originalFilename the original filename (as on the client's machine)

     * @param contentType the content type (if known)

     * @param content the content of the file

     */

    public MultipartFileDto(String name, String originalFilename, String contentType, byte[] content) {

        this.name = name;

        this.originalFilename = (originalFilename != null ? originalFilename : "");

        this.contentType = contentType;

        this.content = (content != null ? content : new byte[0]);

    }

    /**

     * Create a new MultipartFileDto with the given content.

     * @param name the name of the file

     * @param originalFilename the original filename (as on the client's machine)

     * @param contentType the content type (if known)

     * @param contentStream the content of the file as stream

     * @throws IOException if reading from the stream failed

     */

    public MultipartFileDto(String name, String originalFilename, String contentType, InputStream contentStream)

            throws IOException {

        this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));

    }

    @Override

    public String getName() {

        return this.name;

    }

    @Override

    public String getOriginalFilename() {

        return this.originalFilename;

    }

    @Override

    public String getContentType() {

        return this.contentType;

    }

    @Override

    public boolean isEmpty() {

        return (this.content.length == 0);

    }

    @Override

    public long getSize() {

        return this.content.length;

    }

    @Override

    public byte[] getBytes() throws IOException {

        return this.content;

    }

    @Override

    public InputStream getInputStream() throws IOException {

        return new ByteArrayInputStream(this.content);

    }

    @Override

    public void transferTo(File dest) throws IOException, IllegalStateException {

        FileCopyUtils.copy(this.content, dest);

    }

}

三、调用方法

1、文件上传

    /**

     * 文件上传(使用附件表进行管理)

     *

     * @param file

     * @return

     * @throws Exception

     */

    @RequestMapping("/uploadWithManage")

    public Map<String, Object> uploadWithManage(MultipartFile file,@RequestParam(required = false,defaultValue = "default") String bucket) throws Exception {

        String mimeType = FileUploadUtils.getMimeType(file);

        logger.debug(mimeType);

        // 对文件ContenType校验

        if (!FileUploadUtils.checkContenType(mimeType)) {

            return AjaxResult.error("文件格式不支持");

        }

        /** 时间水印添加 */

        // 获取当前时间

        LocalDateTime date = LocalDateTime.now();

        // 设置日期格式

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 通过format调用转换的方法

        String dateWatermark =  formatter.format(date);

        MultipartFile watermarkFile = FileImageWatermarkUtils.markWithContent(file,dateWatermark);

        String url = fileService.uploadFile(watermarkFile,bucket);

        if (StringUtils.isBlank(url)) {

            return AjaxResult.error("文件上传失败");

        }

        String oriName = FileUtils.getOriName(file);

        url = AESUtil.encrypt(url);

        // 存储到fastdfs文件管理表中

        SysFastdfsFile sysFastdfsFile = new SysFastdfsFile();

        if (StringUtils.isNotEmpty(url)) {

            // 上传成功之后会生成路径信息

            String userName = SecurityUtils.getUsername();

            sysFastdfsFile.setCreateBy(userName);

            sysFastdfsFile.setAppendixPath(url);

            sysFastdfsFile.setAppendixName(oriName);

            sysFastdfsFile.setImageThumb(SysFastdfsConstant.NOT_IMAGE_THUMB);

            fastdfsFileService.insertSysFastdfsFile(sysFastdfsFile);

        }

        AjaxResult result = AjaxResult.success("文件上传成功");

        result.put("url", url);

        result.put("fileId", sysFastdfsFile.getId());

        result.put("appendix", sysFastdfsFile);

        return result;

}

2、储存到minio

    @Override

    public String uploadFile(MultipartFile file, String bucket) throws IOException {

        this.createBucket(bucket);

        String fileName = IdUtils.fastUUID() + "." + FileTypeUtils.getExtension(file);

        PutObjectArgs args = PutObjectArgs.builder()

                .bucket(bucket)

                .object(fileName)

                .stream(file.getInputStream(), file.getSize(), -1)

                .contentType(file.getContentType())

                .build();

        try {

            ObjectWriteResponse objectWriteResponse = minioClient.putObject(args);

            return objectWriteResponse.bucket() + "/" + objectWriteResponse.object();

        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {

            logger.error("minio上传文件异常",e);

            throw new RuntimeException(e.getMessage());

        }

    }

3、其他子方法

    private void createBucket(String bucketName)  {

        try {

            // 检查文件夹是否已经存在

            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());

            if (!isExist) {

                // 创建的文件夹

                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());

            }

        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {

            logger.error("minio创建bucket异常",e);

            throw new RuntimeException(e.getMessage());

        }

    }

四、效果

添加水印前

添加水印后

附:

主要参考:

java 加文字水印MultipartFile方式_multipartfile 添加水印-CSDN博客

本文基于此 主要优化了水印位置和水印文字样式hui

  • 31
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
迷你图片批量处理工具,她能够帮您迅速大批量处理您的图片。您只需要将一张或多张图片甚至一个文件夹拖放到添加窗口,即可完成图片添加,方便好用。 功能概述:批量更改大小、批量图片压缩、批量添加水印、批量更改格式、批量增特效等。 修订概述: 新增水印图片旋转功能。 新增图片旋转、灰色、反色、模糊、锐化、棕色、红色、绿色、蓝色、青色、品红、黄色等特效处理。 新增图片色相、饱和度、亮度、对比度、阀值等调整功能。 新增以文件名、拍摄时间、当前时间水印文字的设置。 新增水印文字与水印图片的同时支持。 新增图片裁剪的自定义裁剪位置。 新增添加水印时对小尺寸图片的过滤功能。 新增设置保存功能。 新增水印图片输入框拖拽功能,您可以直接将水印图片拖拽至水印图片文本框。 修正了多文件夹拖拽到添加图片窗体后出现的程序崩溃问题。 修订了图片修改后EXIF信息丢失的问题。 新增图片列表Delete快捷键移除图片功能。 提示:如果您不能正常使用该软件,请安装.NET Framework 2.0, 下载地址:http://www.microsoft.com/downloads/details.aspx?familyid=0856EACB-4362-4B0D-8EDD-AAB15C5E04F5&displaylang=zh-cn 迷你软件系列工具: 迷你图片批量处理工具 迷你文件校验工具 迷你定时提醒工具 迷你词典(MiniDict) Excel数据导出工具 迷你网站检测工具 迷你批量更改文件编码工具 ... 、

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值