采用Java实现下载图片、pdf加水印

需求:点击下载---》弹窗加入水印(可加可不加,加上就有水印,没有不加水印),点击之后下载文件

处理思路及流程

前端:

用户点击下载 → 收集水印参数 → 调用后端API → 处理响应为Blob → 触发文件下载

后端:

接收请求 → 验证权限 → 从Minio获取文件 → 判断文件类型 → 添加水印 → 返回处理后的文件流

前端




Java

加jar包


  
    org.apache.pdfbox
    pdfbox
    2.0.24
  
import io.minio.MinioClient;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

@RestController
public class FileDownloadController {

    @Autowired
    private MinioClient minioClient;

    @GetMapping("/api/download")
    public byte[] downloadFileWithWatermark(@RequestParam String fileUrl, @RequestParam String watermarkText) throws Exception {
        // 解析 MinIO 存储桶和对象名称
        String[] parts = fileUrl.split("/");
        String bucketName = parts[parts.length - 2];
        String objectName = parts[parts.length - 1];

        // 获取字节
        InputStream inputStream = minioClient.getObject(GetObjectArgs.builder()
                                                        .bucket(bucketName)
                                                        .object(objectName)
                                                        .build());
        byte[] content = inputStreamToByteArray(inputStream);
        inputStream.close();

        byte[] fileBytes;
        if (objectName.toLowerCase().endsWith(".pdf")) {
            fileBytes = addWatermarkToPdf(content, watermarkText);
        } else if (objectName.toLowerCase().endsWith(".jpg") || objectName.toLowerCase().endsWith(".png")) {
            fileBytes = addWatermarkToImage(content, watermarkText);
        } else {
            throw new IllegalArgumentException("不支持的文件类型");
        }

        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", URLEncoder.encode(objectName, StandardCharsets.UTF_8));

        return fileBytes
    }

    private byte[] inputStreamToByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int nRead;
        byte[] data = new byte[16384];
        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }
        buffer.flush();
        return buffer.toByteArray();
    }

    private byte[] addWatermarkToPdf(byte[] content, String watermarkText) throws IOException {
        try (PDDocument document = PDDocument.load(content)) {
            for (PDPage page : document.getPages()) {
                try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
                    contentStream.setFont(PDType1Font.HELVETICA_BOLD, 20);
                    contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
                    contentStream.beginText();
                    contentStream.newLineAtOffset(100, 100);
                    contentStream.showText(watermarkText);
                    contentStream.endText();
                }
            }
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            document.save(outputStream);
            return outputStream.toByteArray();
        }
    }

    private byte[] addWatermarkToImage(byte[] content, String watermarkText) throws IOException {
        java.io.ByteArrayInputStream bis = new java.io.ByteArrayInputStream(content);
        BufferedImage image = ImageIO.read(bis);

        Graphics2D g2d = image.createGraphics();
        g2d.setColor(Color.LIGHT_GRAY);
        g2d.setFont(new Font("Arial", Font.BOLD, 20));
        g2d.drawString(watermarkText, 100, 100);
        g2d.dispose();

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ImageIO.write(image, "png", bos);
        return bos.toByteArray();
    }
}

修改pdf加水印,因为没有对应的字体没输入文字水印之后pdf文件会打不开

所以现在改进方法:

从网站下载对应字体的ttf,我是从c:/windows/fonts/ 下找到对应的 “simhei.ttf”文件复制在“ssrc/main/resources/fonts”文件夹下;

修改对应加水印的代码,如下:

private byte[] addWatermarkToPdf(byte[] content, String watermarkText) throws IOException {
    try (PDDocument document = PDDocument.load(content)) {
        // 使用try-with-resources确保字体流关闭
        try (InputStream fontStream = getClass().getResourceAsStream("/fonts/simhei.ttf")) {
            //PDTrueTypeFont font = PDTrueTypeFont.loadTTF(document, fontStream);注意这是个大坑!
            PDTType0Font font = PDTType0Font.load(document, fontStream);

            for (PDPage page : document.getPages()) {
                try (PDPageContentStream contentStream = new PDPageContentStream(
                        document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
                    contentStream.setFont(font, 20);
                    contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
                    contentStream.beginText();
                    contentStream.newLineAtOffset(100, 100);
                    contentStream.showText(watermarkText);
                    contentStream.endText();
                }
            }
        }
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        document.save(outputStream);
        return outputStream.toByteArray();
    }
}

这样就基本都可以出来了,样式什么的需要后续自己调节。

你可能感兴趣的:(pdf,java)