PDFClown Скопируйте аннотации и затем управляйте ими - PullRequest
0 голосов
/ 29 апреля 2018

Мне нужно скопировать аннотации из одного файла PDF в другой. Я использовал превосходную библиотеку PDFClown, но не смог управлять такими вещами, как цвет, вращение и т. Д. Возможно ли это? Я могу видеть информацию о базовом объекте, но также не знаю, как манипулировать этим напрямую.

Я могу скопировать внешний вид с помощью клонирования, но не могу «отредактировать» его.

Спасибо заранее. Alex

P.S. Если Стефано написан автором, проект мертв?

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

В качестве комментария Mkl Ваш замечательный совет действительно полезен при создании новых аннотаций. Я применил следующее в качестве метода «копирования» существующей аннотации, где примечание - это «клонированная» аннотация, база объявлений.Аннотация

 foreach (PdfName t in baseAnnotation.BaseDataObject.Keys)
  {
                if (t.Equals(PdfName.DA) || t.Equals(PdfName.DS) || t.Equals(PdfName.RC) || t.Equals(PdfName.Rotate))
                {
                    note.BaseDataObject[t] = baseAnnotation.BaseDataObject[t];
                }
            }

Еще раз спасибо

0 голосов
/ 14 мая 2018

Об аннотациях в целом и аннотациях 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

  • Оригинальный файл:

    Original annotation

  • keepAppearanceStream = true

    with appearance stream kept but rotated

  • keepAppearanceStream = false и keepRichText = true:

    with appearance stream dropped and rich text kept but manipulated

  • keepAppearanceStream = false и keepRichText = false:

    with appearance stream and rich text dropped and simple attributes manipulated

...