Как изменить текст редактирования примечания редактирования, созданного в Adobe Acrobat

Обновление: 15.01.2021 - добавлена ​​награда

Я пытаюсь изменить аннотацию редактирования, чтобы изменить базовый текст, который записывается в PDF-файл, когда вы применяете исправления. В Acrobat вы можете настроить набор кодов редактирования, которые можно использовать для определения того, почему вы помечаете что-то как отредактированное. Моя цель - перезаписать то, что было выбрано пользователем, с системным значением. Код будет запущен до того, как будут применены исправления.

В своих попытках я обнаружил, что предварительный просмотр, доступный в продуктах Acrobat при наведении курсора на поле редактирования, является уникальным для Acrobat, и большинство других средств просмотра не будут отображать предварительный просмотр. Также кажется, что предварительный просмотр поддерживается отдельно от применяемого фактического редактирования. Мне не нужно изменять текст, отображаемый в предварительном просмотре, только то, что отображается после применения исправлений.

Я добавил награду в размере 150 репутации, так как не думаю, что смогу найти решение самостоятельно. В моем исходном вопросе был указан iText7, так как это была библиотека, которая ближе всего ко мне в моих собственных попытках. Хотя я бы предпочел использовать iText7, я также рассмотрю решения с использованием других библиотек, к которым у меня есть разумный доступ (у меня есть небольшой бюджет, который я мог бы использовать для покупки другой библиотеки, если мне нужно).

Я сохранил свой первоначальный вопрос и последующие, которые я лично пробовал, ниже. Я ценю любую предложенную помощь.

Если вам нужен образец для тестирования, в этой папке DropBox есть файл с именем 01 - Original.pdf, который можно использовать в качестве исходного документа. Желаемый результат - иметь возможность изменять текст, который появляется при применении исправлений из исходного оверлейного текста к любому другому значению, например новому тексту.

Исходный вопрос:

Я пытаюсь изменить текст, содержащийся в каждой аннотации редактирования в PDF-файле, используя iText7. У объекта PdfRedactAnnotation есть метод SetOverlayText(), который, похоже, должен делать то, что я хочу. Итак, я написал метод, который открывает PDF-файл, просматривает страницы, затем просматривает аннотации на каждой странице и проверяет, является ли аннотация PdfRedactAnnotation. Если это так, он вызывает SetOverlayText().

При отладке и просмотре свойств аннотации я вижу, что OverlayText определенно изменился. Однако когда я открываю файл и проверяю наложенный текст, наведя курсор мыши на отметку редактирования, исходный текст наложения все еще присутствует.

введите описание изображения здесь

Кроме того, если я применю исправления, исходный текст наложения будет записан на странице.

Однако, когда я щелкаю аннотацию правой кнопкой мыши (перед применением исправлений), текст наложения немедленно обновляется до нового текста:

введите описание изображения здесь

На этом этапе, когда я применяю исправления, в PDF-файл записывается новый текст.

Есть ли способ, которым я могу запустить обновление аннотации Redaction программно, без необходимости открывать и щелкать правой кнопкой мыши каждое из них? Я включил свой код ниже. Спасибо за любой совет, который может дать кто-нибудь.

PdfDocument pdfDoc = new PdfDocument(new PdfReader(@"C:\temp\Test - Original.pdf"), new PdfWriter(@"C:\temp\Test - Output.pdf"));
Document doc = new Document(pdfDoc);
int pageCount = pdfDoc.GetNumberOfPages();
for (int i = 1; i <= pageCount; i++)
{
    var annotations = pdfDoc.GetPage(i).GetAnnotations();
    foreach(var annotation in annotations)
    {
        if (annotation is PdfRedactAnnotation)
        {
            PdfRedactAnnotation redact = (PdfRedactAnnotation)annotation;
            redact.SetOverlayText(new PdfString("New Text"));
        }
    }
}
doc.Close();

Обновление: данные по состоянию на 07.01.2021

Как указывает ответ @mkl, спецификация PDF Redact Annotation Specification разъясняет основные записи DOM аннотации редактирования. OverlayText - это лишь часть уравнения. Если вы используете OverlayText, тогда должен быть определен элемент DA (DA - это строка, которая предоставляет информацию о форматировании для OverlayText). Наконец, если задан RO, он заменяет почти все другие независимые записи отображения.

Мой тестовый документ был создан с использованием Acrobat DC Pro путем ручного редактирования в Acrobat. В результате появится аннотация Redact со всеми указанными выше записями. Копии моих тестовых документов можно найти в этой папке DropBox.

(Боковое примечание: в моем исходном вопросе я упоминаю наведение курсора на красный прямоугольник редактирования, чтобы предварительно просмотреть, как будет выглядеть примененное редактирование ... После тестирования в нескольких браузерах и других средствах просмотра PDF, таких как Foxit Reader, это выглядит как функция предварительного просмотра того, как будет выглядеть редакция при наведении указателя мыши на красный контур, поддерживается только в продуктах Acrobat. Все другие протестированные средства просмотра будут отображать только красную рамку, при наведении курсора на нее ничего не происходит. . Черные прямоугольники, показанные выше, можно просмотреть в других программах только после внесения исправлений.

Дополнительное тестирование показало, что предварительный просмотр при наведении курсора поддерживается отдельно от самих деталей редактирования, при этом Acrobat пытается синхронизировать детали при наведении курсора с основной аннотацией. Лучше игнорировать предварительный просмотр при наведении курсора при тестировании и обращаться к результатам после внесения исправлений.)

Рекомендация @mkl удалить запись RO, чтобы попытаться позволить OverlayText иметь приоритет, была хорошей идеей, но, к сожалению, не сработала. Никаких заметных отличий от моих первоначальных результатов не было.

Покопавшись в PdfRedactAnnotation iText7, я обнаружил, что все следующие методы приводят к ссылке на запись RO объекта Redact:

PdfRedactAnnotation redact = (PdfRedactAnnotation)annotation;
redact.GetRolloverAppearanceObject();
redact.GetRedactionRolloverAppearance();
redact.GetPdfObject().Get(PdfName.RO);
redact.GetAppearanceDictionary().Get(PdfName.R);

(Я подтвердил, что на самом деле это одна и та же ссылка, проверив компаратор равенства. Как ссылочные типы, все они вернули true при тестировании с использованием ==).

При дальнейшем тестировании я пришел к выводу, что свойство RO должно иметь копию того же OverlayText, хранящуюся внутри. Если у вас есть две редакции с разными исходными значениями, вы можете скопировать элемент RO из одной редакции в другую:

PdfObject ro = firstRedact.GetPdfObject().Get(PdfName.RO);
secondRedact.GetPdfObject().Put(PdfName.RO, ro);

Если вы сделаете это и примените исправления, наложенный текст из первого исправления заменит наложенный текст во втором. Другие значения элемента RO также копируются (например, BBox, который определяет размеры черного прямоугольника) ... но, по крайней мере, эти элементы можно настраивать.

Проблема остается в том, что у iText7 PdfObject RO есть 7 субэлементов, и ни один из них или их дочерние элементы, похоже, не раскрывают текст, который я пытаюсь изменить.

Мой последний тест заключался в том, могу ли я скопировать элементы RO из одного PDF-файла в другой (чтобы я мог использовать второй исходный PDF-файл с аннотацией с уже настроенным желаемым наложенным текстом RO), но похоже, что косвенным объектам не нравится быть. Поместите () в другие документы.

Итак, теперь мне остается попытаться либо найти способ получить доступ / изменить текст, хранящийся в RO, либо клонировать предварительно сконфигурированный RO из другого документа.


person Chronicide    schedule 21.12.2020    source источник


Ответы (2)


Что говорится в спецификации?

Запись примечаний редактирования OverlayText указывается как

Key Type Value
OverlayText text string (Optional) A text string specifying the overlay text that should be drawn over the redacted region after the affected content has been removed. This entry is ignored if the RO entry is present.

(ISO 32000-2, Таблица 195 - Дополнительные записи, относящиеся к аннотации редактирования)

Возможно, в исходном PDF-файле у примечания редактирования есть приоритет RO.

Кроме того, эта таблица говорит о записи DA:

Key Type Value
DA byte string (Required if OverlayText is present, ignored otherwise) The appearance string that shall be used in formatting the overlay text when it is drawn after the affected content has been removed (see 12.7.4.3, "Variable text"). This entry is ignored if the RO entry is present.

Следовательно, если вы используете OverlayText, вам также необходимо убедиться, что задана строка внешнего вида DA по умолчанию. А ты?


Запись RO в той же таблице указана как

Key Type Value
RO stream (Optional) A form XObject specifying the overlay appearance for this redaction annotation. After this redaction is applied and the affected content has been removed, the overlay appearance should be drawn such that its origin lines up with the lower-left corner of the annotation rectangle. This form XObject is not necessarily related to other annotation appearances, and may or may not be present in the AP dictionary. This entry takes precedence over the IC, OverlayText, DA, and Q entries.

Так что же теперь делать?

Согласно информации, опубликованной выше, одним из очевидных вариантов продолжения является создание наложения XObject (RO) для измененных аннотаций редактирования. Вы можете сделать это, заменив свой

if (annotation is PdfRedactAnnotation)
{
    PdfRedactAnnotation redact = (PdfRedactAnnotation)annotation;
    redact.SetOverlayText(new PdfString("New Text"));
}

by

if (annotation is PdfRedactAnnotation)
{
    PdfRedactAnnotation redact = (PdfRedactAnnotation)annotation;
    redact.SetOverlayText(new PdfString("New Text"));
    Rectangle rectangle = redact.GetRectangle().ToRectangle();
    PdfStream stream = redact.GetRedactRolloverAppearance();
    if (stream != null)
    {
        rectangle = stream.GetAsArray(PdfName.BBox).ToRectangle();
    }
    PdfFormXObject redactionOverlay = new PdfFormXObject(rectangle);
    redactionOverlay.GetPdfObject().Put(PdfName.Matrix, new PdfArray(new double[] { 1, 0, 0, 1, -rectangle.GetX(), -rectangle.GetY() }));
    using (Canvas canvas = new Canvas(redactionOverlay, pdfDocument))
    {
        PdfCanvas pdfCanvas = canvas.GetPdfCanvas();
        pdfCanvas.SetFillColorGray(0);
        pdfCanvas.Rectangle(rectangle);
        pdfCanvas.Fill();
        pdfCanvas.SetFillColorGray(1);
        canvas.Add(new Paragraph("New Text"));
    }

    stream = redactionOverlay.GetPdfObject();
    redact.SetRolloverAppearance(stream);
    redact.SetDownAppearance(stream);
    redact.SetRedactRolloverAppearance(stream);
}

Результат после редактирования в Acrobat:

скриншот

Адаптируя используемые цвета заливки и стиль абзаца, вы можете сделать внешний вид более близким к внешнему виду, созданному Adobe Acrobat (или вы, альтернативно, можете создать внешний вид полностью самостоятельно дизайн).

Осторожно! У меня доступна только довольно старая версия Adobe Acrobat v9.5, поэтому, вероятно, текущие версии не принимают внешний вид редактирования, созданный выше, или, по крайней мере, не применяют его иначе.

person mkl    schedule 06.01.2021
comment
Спасибо за справочную информацию, она была очень информативной. Хотя эти конкретные свойства не смогли решить проблему, я смог найти документацию в формате PDF, чтобы иметь возможность продолжить эксперименты и найти обходной путь. Вскоре я отправлю ответ, в котором описывается, как я заставил его работать. - person Chronicide; 06.01.2021
comment
Обновление: похоже, что копия исходного OverlayText хранится где-то в записи ролловера в AppearanceDictionary. Первоначально я думал, что удаление AppearanceDictionary решило мою проблему. Однако это привело к множеству сбоев. Поэтому я думаю, что мне нужно обновить ApearanceDictionary, возвращаемый .GetRolloverAppearance (), чтобы обновить и OverlayText, но iText не предоставляет все свойства внешнего вида редактирования, необходимые для его изменения для моих нужд. Может мне не повезло ... - person Chronicide; 07.01.2021
comment
Вы пробовали просто удалить этот RolloverAppearance? (На самом деле я предполагаю, что это неправильно названный получатель. Он относится к записи RO, описанной в моем ответе, которая не имеет ничего общего с ролловером, но, скорее всего, является сокращением от наложение редактирования.) - person mkl; 07.01.2021
comment
Я все же пробовал удалить его. GetRolloverAppearanceObject (), GetRedactionRolloverAppearance (), GetPdfObject (). Get (PdfName.RO) и GetAppearanceDictionary (). Get (PdfName.R) все возвращают один и тот же элемент: либо PdfStream, либо PdfDicitonary оверлея редактирования. Удаление (PdfName.RO) дает тот же эффект, что и в моем исходном вопросе. GetPdfObject (). GetAsDictionary (PdfName.AP) .Remove (PdfName.R) вообще не приводит к эффекту опрокидывания. Удаление (PdfName.AP) казалось, работало при открытии в Acrobat, но для исправления он вводил словарь AppearanceDictionary по умолчанию. У других зрителей ничего не было - person Chronicide; 07.01.2021
comment
Можете ли вы поделиться своим тестовым PDF-файлом, чтобы воспроизвести проблему? При этом XObject OverlayText и RO не должны отображаться немедленно; как вы можете прочитать выше, они будут отображаться после выполнения фактического процесса редактирования, а не сразу. Похоже, вы ожидаете увидеть их немедленно. - person mkl; 07.01.2021
comment
Я не знаю, где бы я мог его разместить, но это был просто PDF-файл с редактированием, добавленным через Acrobat. При добавлении редактирования в Acrobat он добавляет прямоугольник с красной рамкой и прозрачной заливкой вокруг выбранной области. Когда вы наводите курсор на прямоугольник, он показывает «предварительный просмотр» того, как он будет выглядеть после применения исправлений (черный прямоугольник с красным текстом, как показано на изображениях выше). Все, что видно при наведении курсора на красную рамку для предварительного просмотра редактирования, это то, что «отрисовывается» вместо основного содержимого при применении редакций. - person Chronicide; 07.01.2021
comment
«Предварительный просмотр», кажется, является элементом RO. В моем вопросе выше OverlayText в предварительном просмотре не обновлялся, пока я вручную не щелкнул правой кнопкой мыши прямоугольник редактирования, что вызвало обновление OverlayText в элементе RO. Когда я применил исправления без предварительного щелчка правой кнопкой мыши, будет использоваться исходный текст исправления. Если я щелкну его правой кнопкой мыши, чтобы принудительно обновить, а затем применил исправления, будет использован обновленный текст. Таким образом, хотя элемент RO - это то, что отрисовывается при применении исправлений (как описано в определении RO), я также могу видеть его сразу при наведении на него курсора. - person Chronicide; 07.01.2021
comment
У меня нет текущей версии Adobe Acrobat. Я не знаю, где я могу разместить его - Вы можете создать общедоступный ресурс на Google Диске или в Dropbox. - person mkl; 07.01.2021
comment
Я добавил в свой вопрос всю информацию, собранную во время тестирования. Я также создал DropBox Folder для размещения некоторых образцов. Спасибо за время, которое вы посвятили этому до сих пор. - person Chronicide; 07.01.2021
comment
Спасибо, ваш код работал как есть, и он помог мне лучше понять новые способы работы с iText7. Я ценю все время и усилия, которые вы вложили, чтобы помочь мне! - person Chronicide; 21.01.2021

Мне удалось изменить текст наложения аннотации редактирования и после редактирования правильно отобразить этот текст поверх отредактированного блока. Я использовал библиотеку SyncFusion Essential PDF, которая входит в состав SyncFusion File Форматы. (Я не являюсь аффилированным лицом SyncFusion, хотя у меня есть платная лицензия на их библиотеки форматов файлов через моего работодателя.) Я тестировал Adobe Acrobat Pro DC.

Когда я впервые попытался заменить текст наложения при редактировании, я столкнулся с аналогичной проблемой с SyncFusion, как и OP с iText 7: наложение будет отображаться так, как изменилось после запуска моего кода, но при редактировании вернется ранее замененный текст наложения. Поскольку не было возможности изменить как отображаемый текст, так и текст наложения, доступный для процесса редактирования, я решил эту проблему, написав код, который вносит желаемые изменения, экспортирует аннотации PDF в файл JSON, удаляет аннотации PDF, а затем импортирует файл JSON обратно в PDF. Это создает новые аннотации, которые имеют одинаковое текстовое значение как для наложения текста, так и для процесса редактирования (я полагаю, что текст наложения процесса редактирования создается в результате создания аннотации PDF). Это код, использующий SyncFusion Essential PDF:

using System.Drawing;
using Syncfusion.Pdf.Graphics;
using Syncfusion.Pdf.Interactive;
using Syncfusion.Pdf.Parsing;
using Syncfusion.Pdf;

PdfLoadedDocument loadedDocument = new PdfLoadedDocument(@"C:\Users\Joe\Desktop\Redact\MarkedOriginal.pdf");
PdfLoadedPage page = loadedDocument.Pages[0] as PdfLoadedPage;
foreach (PdfLoadedRedactionAnnotation redactionAnnotation in loadedDocument.Pages[0].Annotations)
{
    PdfStandardFont font = new PdfStandardFont(PdfFontFamily.Helvetica, 10);
    redactionAnnotation.Font = font;
    redactionAnnotation.TextColor = Color.White;
    redactionAnnotation.BorderColor = Color.Black; //See note in SO answer about this
    redactionAnnotation.OverlayText = "New Text";
}

//Export, delete, and then import annotations to create a redaction annotation with the same preview and final redaction
loadedDocument.ExportAnnotations(@"C:\Users\Joe\Desktop\Redact\Output.json", AnnotationDataFormat.Json);

for (int i = 1; i <= loadedDocument.Pages[0].Annotations.Count; i++)
{
    loadedDocument.Pages[0].Annotations.RemoveAt(i);
}
loadedDocument.ImportAnnotations(@"C:\Users\Joe\Desktop\Redact\Output.json", AnnotationDataFormat.Json);
loadedDocument.Save();
loadedDocument.Close(true);

Если OP требует, чтобы граница пометок редактирования была другого цвета, а не черного, необходимо будет написать еще немного кода. Я обнаружил, что когда я использовал redactionAnnotation.BorderColor = Color.Black;, поле отметки редактирования выглядело так, как ожидалось. Однако, когда я использовал Color.Red или другие цвета, граница сохраняла черный цвет, при этом новый цвет также граничил с первым редактированием, и только черный граничил со вторым редактированием в файле, предоставленном OP. Я подозреваю, что при дальнейших исследованиях это можно исправить с помощью SyncFusion, iText 7 или, возможно, путем редактирования строки аннотации defaultappearance файла JSON перед импортом файла обратно в PDF. Это строка defaultappearance, сгенерированная, когда я запустил свой код:

"defaultappearance": "1 1 1 RG 0 g 0 Tc 0 Tw 100 Tz 0 TL 0 Ts 0 Tr /Helv 10 Tf"

Стоит отметить, что у SyncFusion есть бесплатные и платные уровни для лицензирования своего программного обеспечения. Лицензия сообщества SyncFusion на SyncFusion бесплатна для компаний и частных лиц с доходом менее 1 миллиона долларов США. годовой валовой выручки и 5 или меньше разработчиков. Форматы файлов SyncFusion Лицензия разработчика распространяется на всех остальных.

person joeschwa    schedule 19.01.2021