Введение
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");
}
Поддерживаемые форматы
Поддержка форматов, подтверждённая параметрами загрузки и сохранения библиотеки и устройствами рендеринга:
| Формат | Расширение | Чтение | Запись |
|---|---|---|---|
| ✓ | ✓ | ||
| HTML | html | ✓ | ✓ |
| DOCX | docx | ✓ | ✓ |
| DOC | doc | ✓ | ✓ |
| XFDF | xfdf | ✓ | ✓ |
| BMP | bmp | — | ✓ |
| GIF | gif | — | ✓ |
| JPEG | jpeg | — | ✓ |
| TIFF | tiff | — | ✓ |
| Text | txt | — | ✓ |
Открытый исходный код и лицензирование
Aspose.PDF FOSS для Java выпущен под лицензией MIT, которая разрешает коммерческое использование, модификацию и перераспространение. Исходный код и система отслеживания проблем находятся по адресу github.com/aspose-pdf-foss/Aspose.PDF-FOSS-for-Java. Библиотека нацелена на Java 11 или новее.