OpenPDF的学习文档(第九章·水印)

@Slf4j
public class WaterMakerUtils {
    private final PdfReader reader;
    private final ByteArrayOutputStream outputStream;
    private final PdfStamper stamp;
    private final String text;
    private final int fontsize;
    private final float opacity;
    private final int textDensity;
    private final BaseFont font = FontUtils.NOTO_FONT;
    private Color color = Color.BLACK;
    private float rotation = 45F;

    /**
     * Watermarker的构造函数
     * @param input PDF的输入流
     * @param text 水印文字
     * @param fontsize 文字大小
     * @param opacity 文字透明度 0到1
     * @param textDensity 水印密度,值越大,密度越高。
     */
    public WaterMakerUtils(byte[] input, String text, int fontsize, float opacity, int textDensity) throws IOException, DocumentException {
        this.reader = new PdfReader(input);
        this.outputStream = new ByteArrayOutputStream();
        // 将额外内容应用于 PDF 文档的页面
        this.stamp = new PdfStamper(reader, outputStream);
        this.text = text;
        this.fontsize = fontsize;
        this.opacity = opacity;
        this.textDensity = textDensity;
    }

    /**
     * 水印文字颜色
     *
     * @param color 默认为黑色
     */
    public void withColor(Color color) {
        this.color = color;
    }


    /**
     * 倾斜角度
     *
     * @param rotation 默认为45度
     */
    public void withRotation(float rotation) {
        this.rotation = rotation;
    }


    public byte[] write() throws IOException, DocumentException {
        final BaseFont bf = (font != null) ? font : FontUtils.NOTO_FONT;
        // 获取文档所有页数
        int pagecount = reader.getNumberOfPages();
        PdfGState gstate  = new PdfGState();
        // 设置当前填充 Alpha 常数,指定要用于透明成像模型中填充作的常量形状或恒定不透明度值
        gstate.setFillOpacity(opacity); // 设置填充透明度
        gstate.setStrokeOpacity(opacity); // 设置描边透明度

        for (int i = 1; i <= pagecount; i++) {
            // 使用OverContent以确保水印在页面内容之上
            PdfContentByte content = stamp.getOverContent(i);

            // 设置水印透明度
            content.saveState();
            content.setGState(gstate);
            // 设置字体和颜色
            content.setFontAndSize(bf, fontsize);
            content.setColorFill(color);


            // 获取页宽
            float width = content.getPdfDocument().getPageSize().getWidth();
            // 获取页高
            float height = content.getPdfDocument().getPageSize().getHeight();
            // 计算文字的密度
            int xStep = (int) (width / Math.sqrt(textDensity));
            int yStep = (int) (height / Math.sqrt(textDensity));

            // 在页面上绘制文字
            for (int x = fontsize; x < width; x += xStep) {
                for (int y = fontsize; y < height; y += yStep) {
                    content.beginText();
                    content.showTextAligned(PdfContentByte.ALIGN_CENTER, text, x, y, rotation); // 45度倾斜
                    content.endText();
                }
            }
            // 恢复状态
            content.restoreState();
        }
        stamp.close();
        reader.close();
        return outputStream.toByteArray();
    }
}
@Test
public void createPDF() throws IOException {
    FileInputStream inputStream = new FileInputStream("C:/TMP/table.pdf");

    WaterMakerUtils waterMaker = new WaterMakerUtils(inputStream.readAllBytes(), "I am Water Maker", 20, 0.5f, 20);
    waterMaker.withColor(Color.RED);
    waterMaker.withRotation(-45f);
    byte[] write = waterMaker.write();
    Files.write(Paths.get("C:/TMP/watermaker.pdf"), write);
    inputStream.close();
    log.info("PDF创建成功!");
}

image

posted @ 2026-07-30 23:07  铁锅炖大鹅ing  阅读(9)  评论(0)    收藏  举报