Java实现PDF添加水印

根据文件id获取文件流,通过动态水印配置,添加动态水印


/**
 * 水印下载业务操作实现
 *
 * @Author yong.li_1
 **/
@Service
@Slf4j
public class DownloadExistWatermarkBusinessServiceImpl implements DownloadExistWatermarkBusinessService {

    @Autowired
    private FileFeignService fileFeignService;

    @Autowired
    private PimWatermarkBusinessService pimWatermarkBusinessService;

    /**
     * 替换为支持中文字符的字体文件路径
     */
    @Value("${font.fontPath:/usr/share/fonts/windows/simkai.ttf}")
    private String fontPath;


    /**
     * 处理文件水印
     *
     * @param request   请求信息
     * @param response  响应信息
     * @param fileInfo  文件信息
     * @param waterMark 水印信息
     */
    @Override
    public void dealWithWatermark(HttpServletRequest request, HttpServletResponse response, Map<String, Object> fileInfo, PimWatermarkModel waterMark) {
        Response stream = getStream(fileInfo);

        log.info("替换为支持中文字符的字体文件路径:{}", fontPath);

        try (ServletOutputStream sos = response.getOutputStream(); InputStream is = stream.body().asInputStream()) {

            PDDocument document = PDDocument.load(is);

            for (PDPage page : document.getPages()) {
                PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true);

                contentStream.setFont(PDType0Font.load(document, new File(fontPath)), Float.parseFloat(waterMark.getFontSize()));

                this.setOpacity(contentStream, waterMark);

                this.setColor(contentStream, waterMark);

                this.setHorizontalAndVertical(contentStream, waterMark, page, document);

                contentStream.close();
            }

            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setContentType("application/octet-stream; charset=UTF-8");
            String userAgent = request.getHeader("User-Agent");
            String fileName = fileInfo.get("fileName").toString();
            fileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf";
            byte[] bytes = (userAgent.contains("MSIE") || userAgent.contains("Trident")) ? fileName.getBytes() : fileName.getBytes(StandardCharsets.UTF_8);
            fileName = new String(bytes, StandardCharsets.ISO_8859_1);
            response.addHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", fileName));
            document.save(sos);
            document.close();
            sos.flush();

        } catch (IOException e) {
            log.error("水印添加失败:{}", e.getMessage());
            DocToolUtil.responseResult(response, false, "水印添加失败:" + e.getMessage());
        }
    }

    /**
     * 获取水印信息
     *
     * @return 水印信息
     */
    @Override
    public PimWatermarkModel getWaterMark() {
        PlatformUserModel currentUser = UserManager.getCurrentUser();
        PimWatermarkModel watermarkModel = null;
        if (currentUser == null) {
            return watermarkModel;
        }
        ObjectQuery query = ObjectQuery.from(PimWatermarkModel.META_ID);
        PimWatermarkModel[] models = pimWatermarkBusinessService.query(query);
        if (models.length > 0) {
            watermarkModel = models[0];
            String addName = watermarkModel.getIsAddName();
            if ("username".equals(addName)) {
                watermarkModel.setAttribute(PimWatermarkModel.TXTVAL, watermarkModel.getTxtVal() + "-" + currentUser.getUsername());
            } else if ("nickname".equals(addName)) {
                watermarkModel.setAttribute(PimWatermarkModel.TXTVAL, watermarkModel.getTxtVal() + "-" + currentUser.getNickname());
            }
            return watermarkModel;
        }
        return watermarkModel;
    }

    private static float calculateTextWidth(String text, PDType0Font font, float fontSize) throws IOException {
        return font.getStringWidth(text) / 1000f * fontSize;
    }

    private static float calculateTextHeight(PDType0Font font, float fontSize) {
        return font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000f * fontSize;
    }

    /**
     * 获取文件流
     *
     * @param fileInfo 文件信息
     * @return 文件流
     */
    private Response getStream(Map<String, Object> fileInfo) {
        String fileSuffix = String.valueOf(fileInfo.get("fileSuffix"));
        Long id = Long.valueOf(fileInfo.get("id").toString());
        Response stream;
        //调用文件服务获取文件流
        if (".pdf".equals(fileSuffix) || "pdf".equals(fileSuffix)) {
            stream = fileFeignService.stream(id);
        } else {
            stream = fileFeignService.preview(id);
        }
        return stream;
    }

    /**
     * 设置透明度
     *
     * @param contentStream 页面流
     * @param waterMark     水印信息
     * @throws IOException 异常信息
     */
    private void setOpacity(PDPageContentStream contentStream, PimWatermarkModel waterMark) throws IOException {
        float opacity = Float.parseFloat(waterMark.getOpacity());
        PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
        graphicsState.setNonStrokingAlphaConstant(opacity);
        contentStream.setGraphicsStateParameters(graphicsState);
    }

    /**
     * 设置填充颜色
     *
     * @param contentStream 页面流
     * @param waterMark     水印信息
     * @throws IOException 异常信息
     */
    private void setColor(PDPageContentStream contentStream, PimWatermarkModel waterMark) throws IOException {
        String fontColor = waterMark.getFontColor();
        Color color = hex2Rgb(fontColor);
        contentStream.setNonStrokingColor(color);
    }

    /**
     * 设置横纵水印
     *
     * @param contentStream 页面流
     * @param waterMark     水印信息
     * @param page          页面信息
     * @param document      文档信息
     * @throws IOException 异常
     */
    private void setHorizontalAndVertical(PDPageContentStream contentStream, PimWatermarkModel waterMark, PDPage page, PDDocument document) throws IOException {
        String count = waterMark.getCount();
        // 去除方括号 "[" 和 "]"
        count = count.replace("[", "").replace("]", "");
        // 拆分字符串并转换为整数数组
        String[] watermarkCount = count.split(",");
        int horizontalWatermarkCount = Integer.parseInt(watermarkCount[0]); // 横向水印个数
        int verticalWatermarkCount = Integer.parseInt(watermarkCount[1]); // 纵向水印个数

        float pageWidth = page.getMediaBox().getWidth();
        float pageHeight = page.getMediaBox().getHeight();

        BigDecimal watermarkWidth = BigDecimal.valueOf(calculateTextWidth(waterMark.getTxtVal(), PDType0Font.load(document, new File(fontPath)), Float.parseFloat(waterMark.getFontSize())));
        BigDecimal watermarkHeight = BigDecimal.valueOf(calculateTextHeight(PDType0Font.load(document, new File(fontPath)), Float.parseFloat(waterMark.getFontSize())));

        BigDecimal horizontalSpacing = calculateSpacing(pageWidth, horizontalWatermarkCount, watermarkWidth);
        BigDecimal verticalSpacing = calculateSpacing(pageWidth, verticalWatermarkCount, watermarkHeight);

        // 循环写水印
        for (int i = 0; i < horizontalWatermarkCount; i++) {
            for (int j = 0; j < verticalWatermarkCount; j++) {
                BigDecimal x = horizontalSpacing.multiply(BigDecimal.valueOf(i + 1L)).add(watermarkWidth.multiply(BigDecimal.valueOf(i)));
                BigDecimal y = verticalSpacing.multiply(BigDecimal.valueOf(j + 1L)).add(watermarkHeight.multiply(BigDecimal.valueOf(j)));
                float width = x.add(watermarkWidth).floatValue();
                float height = y.add(watermarkHeight).floatValue();
                float xfloat = x.floatValue();
                if (xfloat < 0 || width > pageWidth || height > pageHeight) {
                    continue;
                }
                contentStream.beginText();
                // 倾斜角度
                double angle = Double.parseDouble(waterMark.getAngle());
                AffineTransform transform = AffineTransform.getRotateInstance(Math.toRadians(angle), xfloat, y.floatValue());
                contentStream.setTextMatrix(transform);
                contentStream.newLineAtOffset(xfloat, y.floatValue());
                contentStream.showText(waterMark.getTxtVal()); // 水印文本内容
                contentStream.endText();
            }
        }
    }

    
    private static BigDecimal calculateSpacing(float pageNum, int watermarkCount, BigDecimal watermarkSize) {
        BigDecimal bdpageNum = BigDecimal.valueOf(pageNum);
        BigDecimal bdWatermarkCount = BigDecimal.valueOf(watermarkCount);
        BigDecimal one = BigDecimal.ONE;

        BigDecimal numerator = bdpageNum.subtract(bdWatermarkCount.multiply(watermarkSize));
        BigDecimal denominator = bdWatermarkCount.add(one);

        return numerator.divide(denominator, RoundingMode.HALF_UP);
    }


    /**
     * 16进制转RGB
     * @param colorStr e.g. "#FFFFFF"
     * @return
     */
    private Color hex2Rgb(String colorStr) {
        return new Color(
                Integer.valueOf(colorStr.substring(1, 3), 16),
                Integer.valueOf(colorStr.substring(3, 5), 16),
                Integer.valueOf(colorStr.substring(5, 7), 16));
    }


}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在Java中导出PDF添加水印,可以使用iText库。您需要导入iText的依赖包,并使用iText的API来实现。首先,您需要创建一个PdfReader对象来读取现有的PDF文件,然后创建一个PdfStamper对象来修改该PDF文件。使用PdfContentByte对象可以添加文本或图像作为水印。最后,通过关闭PdfStamper对象并保存修改后的PDF文件来完成操作。以下是一个简单的示例代码: ```java import com.itextpdf.text.DocumentException; import com.itextpdf.text.pdf.*; import java.io.FileOutputStream; import java.io.IOException; public class PdfWatermarkExample { public static void main(String[] args) { String inputFile = "input.pdf"; // 输入的PDF文件路径 String outputFile = "output.pdf"; // 输出的PDF文件路径 String watermarkText = "Watermark"; // 水印文本 try { PdfReader reader = new PdfReader(inputFile); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile)); int pageCount = reader.getNumberOfPages(); PdfContentByte content; // 在每页添加文字水印 for (int i = 1; i <= pageCount; i++) { content = stamper.getUnderContent(i); content.beginText(); content.setFontAndSize(BaseFont.createFont(), 48); // 设置字体和字号 content.showTextAligned(Element.ALIGN_CENTER, watermarkText, 300, 400, 45); // 设置水印位置和角度 content.endText(); } stamper.close(); reader.close(); System.out.println("水印添加成功!"); } catch (IOException | DocumentException e) { e.printStackTrace(); } } } ``` 您可以根据需要自定义水印的文本、位置、字体和大小。此代码示例仅添加了文字水印,如果您需要添加图像水印,则可以使用`content.addImage()`方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值