Об аннотациях в целом и аннотациях Callout в частности
Я немного разбирался в этом, и я боюсь, что вы не можете детально манипулировать произвольными входами, используя методы высокого уровня. Причина в том, что существует множество альтернативных способов задать вид аннотации Callout, и PDF Clown поддерживает только менее приоритетные способы с явными высокоуровневыми методами. От высокого приоритета вниз
Явное появление в потоке AP . Если он задан, он используется, игнорируя, выглядит ли этот внешний вид как аннотация Callout, не говоря уже о том, что он определен другими свойствами Callout.
PDF Clown пока не создает внешний вид для аннотаций выноски из других значений, не говоря уже об обновлении существующих представлений для отслеживания изменений определенного атрибута (например, Color
). Для поддержки ISO 32000-2 PDF Clown здесь должен будет улучшиться, так как потоки внешнего вида стали обязательными.
Если он существует, вы можете получить внешний вид, используя getAppearance()
, но вы получите только FormXObject
с его инструкциями по рисованию низкого уровня, без указания выноски.
Одна вещь, которой вы можете довольно легко манипулировать с помощью FormXObject
, тем не менее, вы можете довольно легко вращать или наклонять внешний вид, устанавливая Matrix соответственно, например,
annotation.getAppearance().getNormal().get(null).setMatrix(AffineTransform.getRotateInstance(100, 10));
Текстовая строка в строке или потоке RC . Если внешний вид не задан, текст в текстовом поле «Выноска» генерируется из этого элемента расширенного текста (форматированный текст здесь использует для форматирования подмножество XHTML 1.0).
PDF Clown еще не создает расширенное текстовое представление текста выноски, не говоря уже об обновлении существующих для отслеживания изменений определенного атрибута (например, Color
).
Если он существует, вы можете получить расширенный текст с помощью низкоуровневого доступа, используя getBaseDataObject().get(PdfName.RC)
, изменить эту строку или поток и установить его снова, используя getBaseDataObject().put(PdfName.RC, ...)
. Точно так же вы можете извлекать, обрабатывать и устанавливать строку стиля по умолчанию для расширенного текста, используя вместо этого ее имя PdfName.DS
.
Ряд различных настроек для отдельных аспектов, используемых для построения выноски из-за отсутствия потока появления и (в отношении текстового содержимого) строки расширенного текста.
PDF Clown поддерживает (многие из) эти атрибуты, в частности, если вы приведете клонированную аннотацию к StaticNote
, например, непрозрачность CA с использованием get/set/withAlpha
, граница Граница / BS с использованием get/set/withBorder
, цвет фона C с использованием get/set/withColor
, ...
Кстати, есть ошибка в стиле окончания строки. LE Поддержка: Очевидно, что код для Line аннотации LE был скопирован без проверки; к сожалению, этот атрибут имеет другой синтаксис ...
Ваши задачи
Относительно атрибутов, которые вы указали, вы хотите изменить, поэтому
Поворот : В аннотации Callout отсутствует атрибут поворота как таковой (кроме флага, следовать ли за поворотом страницы). Таким образом, вы не можете установить поворот как простой атрибут аннотации. Если исходная аннотация имеет поток внешнего вида, вы можете манипулировать ее Matrix , чтобы повернуть ее внутри прямоугольника аннотации, см. Выше.
Цвет границы и шрифт : если у вашего выноски есть поток внешнего вида, вы можете попытаться проанализировать его содержимое с помощью ContentScanner
и управлять операциями настройки цвета и шрифта , В противном случае, если задана информация форматированного текста, для шрифта вы можете попытаться проанализировать форматированный текст с помощью некоторого анализатора XML и манипулировать атрибутами стиля шрифта. В противном случае вы можете выполнить синтаксический анализ строки по умолчанию DA и управлять инструкциями по настройке шрифта и цвета.
Пример кода
Я создал файл с примером аннотации Callout, используя Adobe Acrobat: Callout-Yellow.pdf . Он содержит поток внешнего вида, форматированный текст и простые атрибуты, поэтому этот файл можно использовать, например, для манипуляций на разных уровнях.
Я применил этот код к нему с различными значениями для keepAppearanceStream
и keepRichText
(вы не упомянули, использовали ли вы PDF Clown для Java или .Net; поэтому я выбрал Java; порт для .Net должен быть тривиально, хотя ...):
boolean keepAppearanceStream = ...;
boolean keepRichText = ...;
try ( InputStream sourceResource = GET_STREAM_FOR("Callout-Yellow.pdf");
InputStream targetResource = GET_STREAM_FOR("test123.pdf");
org.pdfclown.files.File sourceFile = new org.pdfclown.files.File(sourceResource);
org.pdfclown.files.File targetFile = new org.pdfclown.files.File(targetResource); ) {
Document sourceDoc = sourceFile.getDocument();
Page sourcePage = sourceDoc.getPages().get(0);
Annotation<?> sourceAnnotation = sourcePage.getAnnotations().get(0);
Document targetDoc = targetFile.getDocument();
Page targetPage = targetDoc.getPages().get(0);
StaticNote targetAnnotation = (StaticNote) sourceAnnotation.clone(targetDoc);
if (keepAppearanceStream) {
// changing properties of an appearance
// rotating the appearance in the appearance rectangle
targetAnnotation.getAppearance().getNormal().get(null).setMatrix(AffineTransform.getRotateInstance(100, 10));
} else {
// removing the appearance to allow lower level properties changes
targetAnnotation.setAppearance(null);
}
// changing text background color
targetAnnotation.setColor(new DeviceRGBColor(0, 0, 1));
if (keepRichText) {
// changing rich text properties
PdfString richText = (PdfString) targetAnnotation.getBaseDataObject().get(PdfName.RC);
String richTextString = richText.getStringValue();
// replacing the font family
richTextString = richTextString.replaceAll("font-family:Helvetica", "font-family:Courier");
richText = new PdfString(richTextString);
targetAnnotation.getBaseDataObject().put(PdfName.RC, richText);
} else {
targetAnnotation.getBaseDataObject().remove(PdfName.RC);
targetAnnotation.getBaseDataObject().remove(PdfName.DS);
}
// changing default appearance properties
PdfString defaultAppearance = (PdfString) targetAnnotation.getBaseDataObject().get(PdfName.DA);
String defaultAppearanceString = defaultAppearance.getStringValue();
// replacing the font
defaultAppearanceString = defaultAppearanceString.replaceFirst("Helv", "HeBo");
// replacing the text and line color
defaultAppearanceString = defaultAppearanceString.replaceFirst(". . . rg", ".5 g");
defaultAppearance = new PdfString(defaultAppearanceString);
targetAnnotation.getBaseDataObject().put(PdfName.DA, defaultAppearance);
// changing the text value
PdfString contents = (PdfString) targetAnnotation.getBaseDataObject().get(PdfName.Contents);
String contentsString = contents.getStringValue();
contentsString = contentsString.replaceFirst("text", "text line");
contents = new PdfString(contentsString);
targetAnnotation.getBaseDataObject().put(PdfName.Contents, contents);
// change the line width and style
targetAnnotation.setBorder(new Border(0, new LineDash(new double[] {3, 2})));
targetPage.getAnnotations().add(targetAnnotation);
targetFile.save(new File(RESULT_FOLDER, "test123-withCalloutCopy.pdf"), SerializationModeEnum.Standard);
}
( CopyCallOut тест testCopyCallout
)
Осторожно, код имеет только проверочное качество: для произвольных PDF-файлов нельзя просто ожидать замены строки «font-family: Helvetica» на «font-family: Courier» или «Helv» на «HeBo» или ".... rg" на ".5 g" для выполнения работы: шрифты могут быть заданы с использованием разных атрибутов или имен стилей, и могут использоваться разные инструкции по окраске.
Скриншоты в Adobe
Оригинальный файл:
keepAppearanceStream = true
keepAppearanceStream = false
и keepRichText = true
:
keepAppearanceStream = false
и keepRichText = false
: