itext pdf设置密码、权限和添加水印功能

文章目录

  • 一、Maven依赖
  • 二、PDF设置密码与编辑权限
    • 1、userPassword
    • 2、ownerPassword
    • 3、permissions
    • 4、encryptionType
  • 三、添加水印
    • 1、读取pdf文件的方式创建水印
    • 2、Document创建pdf的方式添加水印
  • 四、常见异常

一、Maven依赖

<dependencies>
	<dependency>
		<groupId>com.itextpdfgroupId>
        <artifactId>itextpdfartifactId>
        <version>5.5.13.3version>
    dependency>
    <dependency>
        <groupId>org.bouncycastlegroupId>
        <artifactId>bcprov-jdk15onartifactId>
        <version>1.70version>
    dependency>
    <dependency>
        <groupId>com.itextpdfgroupId>
        <artifactId>itext-asianartifactId>
        <version>5.2.0version>
    dependency>
dependencies>

itextpdf是pdf操作的核心,bcprov-jdk15on用于pdf加密,itext-asian是亚洲字体

二、PDF设置密码与编辑权限

如果是读取本地pdf文件则可以用pdfStamper.setEncryption方法

// is为pdf文件输入流,os为要输出的文件流
PdfReader reader = new PdfReader(is);
PdfStamper stamper = new PdfStamper(reader, os);
// 设密码,禁止编辑
stamper.setEncryption("userPassword".getBytes(StandardCharsets.UTF_8), "ownerPassword".getBytes(StandardCharsets.UTF_8), PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_COPY, PdfWriter.ENCRYPTION_AES_128);

如果是创建的pdf则可以用pdfWriter.setEncryption方法

// os为要输出的文件流
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, os);
writer.setEncryption("userPassword".getBytes(StandardCharsets.UTF_8), "ownerPassword".getBytes(StandardCharsets.UTF_8), PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_COPY, PdfWriter.ENCRYPTION_AES_128);

setEncrption有4个参数:userPassword, ownerPassword, permissions, encryptionType

1、userPassword

userPassword为用户密码,当用户打开时输入此密码将被赋予相应权限(见下面),该选项可以填null,表示无密码

2、ownerPassword

ownerPassword为管理员密码,将获得文档全部权限,也可以填null

3、permissions

permissions为用户权限,多个权限以或(|)连接

  • PdfWriter.ALLOW_PRINTING:允许打印
  • PdfWriter.ALLOW_MODIFY_CONTENTS:允许编辑内容
  • PdfWriter.ALLOW_COPY:允许复制
  • PdfWriter.ALLOW_MODIFY_ANNOTATIONS:允许编辑注释
  • PdfWriter.ALLOW_FILL_IN:允许填充表单(128位加密)
  • PdfWriter.ALLOW_SCREENREADERS:允许用户提取文本和图形以供易访问性设备使用(128位加密)
  • PdfWriter.ALLOW_ASSEMBLY:允许用户插入、删除和旋转页面和添加书签(128位加密)
  • PdfWriter.ALLOW_DEGRADED_PRINTING:允许低质量打印(128位加密)

4、encryptionType

encryptionType为加密方式,有4种:
PdfWriter.STANDARD_ENCRYPTION_40
PdfWriter.STANDARD_ENCRYPTION_128
PdfWriter.ENCRYPTION_AES_128
PdfWriter.ENCRYPTION_AES_256

最终效果
itext pdf设置密码、权限和添加水印功能_第1张图片
itext pdf设置密码、权限和添加水印功能_第2张图片

三、添加水印

1、读取pdf文件的方式创建水印

从本地或服务器获取pdf文件输入流,添加水印并输出

// is为文件输入流,os为文件输出流,password为密码,watermark为水印字符串
PdfReader reader = new PdfReader(is);
PdfStamper stamper = new PdfStamper(reader, os);
// 设密码,禁止编辑
stamper.setEncryption(password == null ? null : password.getBytes(StandardCharsets.UTF_8), null, PdfWriter.ALLOW_COPY, PdfWriter.ENCRYPTION_AES_128);
// 水印字体
BaseFont base = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.EMBEDDED);
Rectangle pageRect = null;
PdfGState gs = new PdfGState();
gs.setFillOpacity(0.3f);
gs.setStrokeOpacity(0.4f);
int total = reader.getNumberOfPages() + 1;

JLabel label = new JLabel();
FontMetrics metrics;
int textH = 0;
int textW = 0;
label.setText(watermark);
metrics = label.getFontMetrics(label.getFont());
textH = metrics.getHeight();
textW = metrics.stringWidth(label.getText());

PdfContentByte under;
// pdf每一页加水印
for (int i = 1; i < total; i++) {
	pageRect = reader.getPageSizeWithRotation(i);
	under = stamper.getOverContent(i);
	under.saveState();
	under.setGState(gs);
	under.beginText();
	under.setFontAndSize(base, 20);
	under.setRGBColorFill(145,145,145);

	// 页面填充水印
	for (int height = textH; height < pageRect.getHeight(); height = height + textH * 10) {
		for (int width = textW; width < pageRect.getWidth() + textW; width = width + textW * 3) {
			under.showTextAligned( Element.ALIGN_LEFT,
				watermark, width - textW,
				height - textH, 30); // rotation是水印倾斜角度
		}
	}
	under.endText();
	under.restoreState();
}
stamper.close();
reader.close();

2、Document创建pdf的方式添加水印

通过itext的Document类创建pdf,添加水印并输出。
设置PdfWriter的pageEvent事件,当新页面被创建时会触发事件的onStartPage方法,在这里添加水印即可。

// os为文件输出流,password为密码,watermark为水印字符串
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, os);
writer.setEncryption(password != null ? password.getBytes(StandardCharsets.UTF_8) : null, null, PdfWriter.ALLOW_COPY, PdfWriter.ENCRYPTION_AES_128);
BaseFont base = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.EMBEDDED);
Font font = new Font(base);
// 设置页面事件,在页面被创建的时候添加水印
writer.setPageEvent(new PdfPageEvent() {
    @Override
    public void onOpenDocument(PdfWriter pdfWriter, Document document) {}
    @Override
    public void onStartPage(PdfWriter pdfWriter, Document document) {
        // 新的一页被创建后添加水印
        Rectangle pageRect;
        PdfGState gs = new PdfGState();
        gs.setFillOpacity(0.3f);
        gs.setStrokeOpacity(0.4f);

        JLabel label = new JLabel();
        FontMetrics metrics;
        label.setText(watermark);
        metrics = label.getFontMetrics(label.getFont());
        int textH = metrics.getHeight();
        int textW = metrics.stringWidth(label.getText());

        pageRect = pdfWriter.getPageSize();
        PdfContentByte under = pdfWriter.getDirectContentUnder();
        under.saveState();
        under.setGState(gs);
        under.beginText();
        under.setFontAndSize(base, 20);
        under.setRGBColorFill(145,145,145);

        // 页面填充水印
        for (int height = textH; height < pageRect.getHeight();
             height = height + textH*10) {
            for (int width = textW; width < pageRect.getWidth() + textW; width = width + textW*3) {
                under.showTextAligned( Element.ALIGN_LEFT, watermark, width - textW, height - textH, 30); // rotation是水印倾斜角度
            }
        }
        under.endText();
        under.restoreState();
    }
    @Override
    public void onEndPage(PdfWriter pdfWriter, Document document) { }
    @Override
    public void onCloseDocument(PdfWriter pdfWriter, Document document) { }
    @Override
    public void onParagraph(PdfWriter pdfWriter, Document document, float v) { }
    @Override
    public void onParagraphEnd(PdfWriter pdfWriter, Document document, float v) { }
    @Override
    public void onChapter(PdfWriter pdfWriter, Document document, float v, Paragraph paragraph) { }
    @Override
    public void onChapterEnd(PdfWriter pdfWriter, Document document, float v) { }
    @Override
    public void onSection(PdfWriter pdfWriter, Document document, float v, int i, Paragraph paragraph) { }
    @Override
    public void onSectionEnd(PdfWriter pdfWriter, Document document, float v) { }
    @Override
    public void onGenericTag(PdfWriter pdfWriter, Document document, Rectangle rectangle, String s) { }
});
document.open();
// 添加一些文本测试
for (int i = 0; i < 100; i++) {
    Paragraph paragraph = new Paragraph("测试 test", font);
    document.add(paragraph);
}

document.close();
os.flush();
os.close();
writer.close();

效果
itext pdf设置密码、权限和添加水印功能_第3张图片

四、常见异常

  • NoClassDefFoundError: org/bouncycastle/asn1/ASN1Encodable
    itext pdf设置密码、权限和添加水印功能_第4张图片
    由于使用加密方法但没有加密的依赖导致的,在maven中添加bcprov-jdk15on(见文章开头)即可

  • Font is not recognized
    异常2
    没有引入字体依赖导致的,在maven中添加itext-asian(见文章开头)即可

  • IllegalPdfSyntaxException: Unbalanced save/restore state operators
    itext pdf设置密码、权限和添加水印功能_第5张图片
    使用saveState()后没有调用restoreState()导致的,在结束前调用即可

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