介绍

Aspose.PDF FOSS for Java 是一个基于 MIT 许可证的 Java 库,用于创建和编辑 PDF 文档。它的类组织在 org.aspose.pdf 包及其子包(org.aspose.pdf.annotations、org.aspose.pdf.forms、org.aspose.pdf.facades 等)中,Document 是大多数工作流的入口点。该库没有第三方运行时依赖;其 Maven 构建中唯一的依赖是测试范围的 JUnit。

已经有 library announcement、facades post 和 page-editing post 涵盖了文档创建、表单字段、用于提取、加密和盖章的外观类以及使用 PdfFileEditor 的页面操作。本文将介绍同一 API 的另外五个方面,这些方面在上述文章中未展示:文本标记注释、自由文本标注、文档级别操作、流解码的大小保护以及诊断日志。

每个领域都是一个小型、独立的 API。下面的各节展示了调用方式、默认值以及库自身测试所确定的边缘情况。


关键特性

文本标记注释

HighlightAnnotation、UnderlineAnnotation、StrikeOutAnnotation 和 SquigglyAnnotation 都接受一个 Page 和一个 Rectangle。构造函数会从矩形中推导注释的四点坐标,因此 getQuadPoints() 在无需手动计算的情况下返回八个值。对于矩形 (100, 200, 300, 250),结果为 [100, 250, 300, 250, 100, 200, 300, 200]:左上、右上、左下,然后右下。setQuadPoints() 用你自己的八值数组替换推导出的值,而从现有字典重建的注释则保留其中已经存储的四点坐标。getSubtype() 返回 PDF 子类型名称:Highlight、Underline、StrikeOut 或 Squiggly。

构造注释并不会将其附加到页面。请使用 page.getAnnotations().add(...) 将其添加。

try (Document doc = new Document()) {
    Page page = doc.getPages().add();

    HighlightAnnotation highlight = new HighlightAnnotation(page, new Rectangle(100, 200, 300, 250));
    double[] quadPoints = highlight.getQuadPoints();

    UnderlineAnnotation underline = new UnderlineAnnotation(page, new Rectangle(50, 100, 200, 120));
    StrikeOutAnnotation strikeOut = new StrikeOutAnnotation(page, new Rectangle(50, 140, 200, 160));
    SquigglyAnnotation squiggly = new SquigglyAnnotation(page, new Rectangle(50, 180, 200, 200));

    page.getAnnotations().add(highlight);
    page.getAnnotations().add(underline);
    page.getAnnotations().add(strikeOut);
    page.getAnnotations().add(squiggly);
    doc.save("markup.pdf");
}

自由文本标注

FreeTextAnnotation 将文本直接放置在页面上。它的三参数构造函数接受一个 DefaultAppearance,其中包含字体名称、字体大小和文本颜色。三个属性决定标注的形状:

  • setIntent() 接受一个 FreeTextIntent:FreeText、FreeTextCallout 或 FreeTextTypeWriter。新建的注释会报告 Undefined,传入 null 则将其恢复到该状态。
  • setCallout() 将标注线作为由两个或三个 {x, y} 点组成的数组。任何其他长度的数组都会被忽略,现有的标注保持不变;null 会移除标注。
  • setEndingStyle() 接受一个 LineEnding 值,例如 OpenArrow 或 Diamond。新建的注释会报告 LineEnding.None。
try (Document doc = new Document()) {
    Page page = doc.getPages().add();
    DefaultAppearance da = new DefaultAppearance("Helv", 10, Color.BLACK);
    FreeTextAnnotation note = new FreeTextAnnotation(page, new Rectangle(50, 50, 200, 100), da);

    note.setContents("Check this value");
    note.setIntent(FreeTextIntent.FreeTextCallout);
    note.setCallout(new double[][] {{10, 10}, {50, 50}, {100, 100}});
    note.setEndingStyle(LineEnding.OpenArrow);

    page.getAnnotations().add(note);
    doc.save("callout.pdf");
}

已保存的注释字典将这些值存储为 /IT、/CL 和 /LE。

文档级操作

Document.getActions() 返回文档目录的 DocumentActions 视图。setOpenAction() 将一个操作存储在目录的 /OpenAction 条目中。进一步的五个触发器,setBeforeClosing()、setBeforeSaving()、setAfterSaving()、setBeforePrinting() 和 setAfterPrinting(),独立存储在目录的 /AA additional-actions 字典中。

每个 getter 在其触发器被设置之前返回 null。将 null 传递给 setter 会移除该条目,删除最后一个触发器还会移除 /AA 字典。Actions 是 PdfAction 实例;GoToURIAction 是 UriAction 的别名,其 getType() 返回 URI。DocumentActions 对象是实时视图,因此对 getActions() 的后续调用会看到通过前一次调用所做的更改,并且在再次打开已保存的文件时会读取这些触发器。

try (Document doc = new Document()) {
    doc.getPages().add();
    DocumentActions actions = doc.getActions();

    actions.setOpenAction(new GoToURIAction("https://example.com"));
    actions.setBeforeSaving(new GoToURIAction("https://example.com/saving"));

    PdfAction open = doc.getActions().getOpenAction();
    if (open instanceof UriAction) {
        System.out.println(((UriAction) open).getUri());
    }

    actions.setBeforeSaving(null);   // removes /WS; /AA is removed once it is empty
    doc.save("actions.pdf");
}

流过滤器的解码限制

PDF 流以编码形式存储,损坏或恶意的流可能会膨胀到远远超过其存储大小。DecodeLimits 是由 FlateDecode、LZWDecode 和 RunLengthDecode 过滤器共享的保护。当流的解码输出超过上限时,过滤器会抛出 DecodeSizeLimitException(IOException 的子类),而不是一直解码直至堆内存耗尽。

默认上限是每个解码流 256MB(DecodeLimits.DEFAULT_MAX_DECODED_BYTES)。要更改它,请将由 DecodeLimits.PROPERTY 命名的系统属性(即 aspose.pdf.maxDecodedStreamBytes)设置为字节数;当值为 0 或更小时,保护将被禁用。该属性在每次解码时读取,因此可以在运行时进行更改。

static byte[] decodeFlate(byte[] encoded) {
    // Lower the cap to 16 MB (16777216 bytes) for this process
    System.setProperty(DecodeLimits.PROPERTY, "16777216");
    try {
        return new FlateFilter().decode(encoded, null);
    } catch (IOException e) {
        // "FlateDecode: decoded output exceeds 16777216 bytes - likely a corrupt stream
        //  or decompression bomb (override with -Daspose.pdf.maxDecodedStreamBytes)"
        return null;
    }
}

低于上限的流会正常解码。当输出保持在限制以内时,FlateFilter 和 RunLengthFilter 都会通过 encode() 和 decode() 完成数据的往返。

诊断日志记录

库通过 java.util.logging 在 org.aspose.pdf 记录器下进行日志记录,默认情况下保持沉默:日志级别为 OFF。AsposePdfLogging 打开日志记录。

  • setLevel(Level) 从代码设置级别;null 将库恢复到 OFF。getLevel() 读取它。
  • 系统属性 aspose.pdf.log(也可以使用 AsposePdfLogging.LOG_PROPERTY)从命令行进行设置。configureFromSystemProperty() 应用该属性,并且在类加载时也会运行。值 on 和 warning 选择 WARNING,verbose 选择 FINE,debug 选择 ALL,任何 java.util.logging.Level 名称,例如 SEVERE,都被接受,未识别的值将回退到 OFF。

WARNING 让引擎的警告通过;FINE,即 verbose 设置,也让解析器的恢复细节通过。AsposePdfLogging 只更改 org.aspose.pdf 日志记录器子树。它不会更改根日志记录器的级别,库日志记录器也不会将记录传递给根日志记录器的处理器。如果启用了日志且库日志记录器没有附加处理器,则会安装一个控制台处理器。

// Equivalent to starting the JVM with -Daspose.pdf.log=warning
AsposePdfLogging.setLevel(Level.WARNING);

System.setProperty(AsposePdfLogging.LOG_PROPERTY, "verbose");
AsposePdfLogging.configureFromSystemProperty();
System.out.println(AsposePdfLogging.getLevel());   // FINE

快速入门

将依赖添加到你的构建中:

<dependency>
  <groupId>org.aspose</groupId>
  <artifactId>aspose-pdf-foss</artifactId>
  <version>26.8.0</version>
</dependency>

以下示例创建一个页面,添加高亮和自由文本标注,并保存文档:

import org.aspose.pdf.*;
import org.aspose.pdf.annotations.*;

try (Document doc = new Document()) {
    Page page = doc.getPages().add();

    page.getAnnotations().add(new HighlightAnnotation(page, new Rectangle(100, 200, 300, 250)));

    FreeTextAnnotation note = new FreeTextAnnotation(page, new Rectangle(50, 50, 200, 100),
            new DefaultAppearance("Helv", 10, Color.BLACK));
    note.setContents("Check this value");
    note.setIntent(FreeTextIntent.FreeTextCallout);
    note.setCallout(new double[][] {{10, 10}, {50, 50}, {100, 100}});
    page.getAnnotations().add(note);

    doc.save("core-features.pdf");
}

支持的格式

格式支持已通过库的加载和保存选项以及渲染设备确认:

格式扩展名读取写入
PDFpdf✓✓
HTMLhtml✓✓
DOCXdocx✓✓
DOCdoc✓✓
XFDFxfdf✓✓
BMPbmp—✓
GIFgif—✓
JPEGjpeg—✓
TIFFtiff—✓
Texttxt—✓

开源与许可

Aspose.PDF FOSS 用于 Java 在 MIT 许可证下发布,该许可证允许商业使用、修改和再分发。源代码和问题跟踪器位于 github.com/aspose-pdf-foss/Aspose.PDF-FOSS-for-Java。该库目标为 Java 11 或更高版本。


快速入门

相关资源