Введение

Aspose.PDF FOSS для Java — это библиотека Java под лицензией MIT для создания и редактирования PDF-документов. Ее классы организованы в пакете org.aspose.pdf и его подпакетах (org.aspose.pdf.annotations, org.aspose.pdf.forms, org.aspose.pdf.facades и др.), а Document служит точкой входа для большинства рабочих процессов. Библиотека не имеет сторонних зависимостей во время выполнения; единственной зависимостью в её сборке Maven является JUnit с областью тестов.

объявление библиотеки, пост о фасадах и пост о редактировании страниц уже охватывают создание документов, поля форм, классы-фасады для извлечения, шифрования и штамповки, а также операции со страницами с 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 каталога.

Каждый getter возвращает null, пока его триггер не установлен. Передача null в setter удаляет эту запись, а удаление последнего триггера также удаляет словарь /AA. Действия являются экземплярами 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, вместо того чтобы продолжать декодировать до исчерпания кучи.

Лимит по умолчанию составляет 256МБ на декодированный поток (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 или новее.


Начало работы

Связанные ресурсы