Как добавить изображение в файл pdf в режиме APPEND с помощью PdfStamper?

Я использую библиотеку iTextSharp версии 5.5.6.0. Этот файл содержит настраиваемые текстовые поля, и необходимо сохранить поля интерактивной текстовой формы: https://yadi.sk/i/yoUvDI9EmtVhc . Но я не могу добавить изображение в объект PdfTemplate. Код в С# на этом этапе:

    string outpath = @"D:\pdf_\output.pdf";
    string inpath = @"D:\pdf_\input.pdf";
    string stamp = @"D:\pdf_\img.png";

Этот метод не добавляет изображение, но текстовые поля активны.

            public static void onlyInteractive()
            {
                using (MemoryStream os = new MemoryStream())
                using (PdfReader pdfReader = new PdfReader(inpath))

//режим APPEND

                using (PdfStamper stamper = new PdfStamper(pdfReader, os, '\0', true))
                {
                    iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
                    image.SetAbsolutePosition(0, 0);

                    PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
                    template.AddImage(image);

                    stamper.GetOverContent(1).AddTemplate(template, 150, 200, true); 

                    os.WriteTo(new FileStream(outpath, FileMode.Create, FileAccess.ReadWrite));
                }
            }

Поведение этого метода возвращается к первому.

            public static void onlyImage()
            {
                using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
                using (PdfReader reader = new PdfReader(inpath))
                using (var stamper = new PdfStamper(reader, output, '\0', true))
                {
                    iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
                    image.SetAbsolutePosition(0, 0);

                    PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
                    template.AddImage(image);

                    stamper.GetOverContent(1).AddTemplate(template, 150, 200, true); 
                }
            }

person Kseniya Yudina    schedule 13.01.2016    source источник


Ответы (1)


только интерактивный

Проблема с этим кодом заключается в том, что вы получаете выходной PDF-файл до его завершения:

using (PdfStamper stamper = new PdfStamper(pdfReader, os, '\0', true))
{
    [...]
    os.WriteTo(new FileStream(outpath, FileMode.Create, FileAccess.ReadWrite));
}

Когда stamper закрывается (здесь неявно в конце его блока using), записываются некоторые еще не сохраненные объекты PDF, а также записываются внутренние перекрестные ссылки и трейлер файла.

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

только изображение

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

Ваша проблема здесь в том, что сам документ Reader-enabled, т. е. он подписан так называемой подписью прав использования. Такие подписи сообщают Adobe Reader при открытии файла, чтобы сделать доступными дополнительные функции, отображающие редактирование рассматриваемого документа.

Но при проверке подписи на документе с изображением Adobe Reader видит, что документ был изменен способом, несовместимым с правами использования, предоставленными подписью: к содержимому страницы добавлено изображение, которое не является предоставляется подписью. Таким образом, Adobe Reader аннулирует предоставленные функции, в вашем случае редактирование формы.

Удаление подписи прав использования

Одним из вариантов в этой ситуации является удаление этой подписи. В этом случае редактирование формы с помощью этой подписи больше не предоставляется. Но в более новых версиях Adobe Reader (начиная с версии XI, если я правильно помню) редактирование формы было предоставлено всем документам по умолчанию! В вашем случае эта функция удалена из-за недействительной подписи!

Это можно сделать следующим образом:

using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output))
{
    reader.RemoveUsageRights();
    iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
    image.SetAbsolutePosition(0, 0);

    PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
    template.AddImage(image);

    stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}

Теперь вы можете редактировать PDF-файл с изображением в более новых версиях Adobe Readers.

К сожалению, при сохранении документа возникает ошибка. Я не знаю, связаны ли они с тем фактом, что исходный документ частично недействителен (Adobe Preflight жалуется на ряд проблем, в первую очередь на использование неопределенного имени кодировки Win1251Encoding) или что-то иначе сломается.

Удаление подписи прав использования в режиме добавления

Работая в режиме добавления, мы должны вручную удалить подпись прав использования. На самом деле мы удалим весь словарь Perms из Каталога:

using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output, '\0', true))
{
    reader.Catalog.Remove(PdfName.PERMS);
    stamper.MarkUsed(reader.Catalog);
    iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
    image.SetAbsolutePosition(0, 0);

    PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
    template.AddImage(image);

    stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}

Теперь можно отредактировать форму и сохранить файл (по крайней мере я могу в Adobe Reader DC).

PS: правильные координаты

В комментарии ОП поделился другим PDF-файлом и заявил, что он

для другого файла невозможно разместить картинку на странице с альбомной ориентацией.

В коде OP действительно есть проблема:

stamper.GetOverContent(1).AddTemplate(template, 150, 200, true); 

Фиксированные координаты 150, 200 являются признаком того, что OP предполагает, что нижний левый угол страницы является источником 0, 0 системы координат. Хотя это часто имеет место, это не обязательно верно. Всегда нужно принимать во внимание CropBox (по умолчанию это MediaBox), то есть для кода OP:

Rectangle cropBox = reader.GetCropBox(1);
stamper.GetOverContent(1).AddTemplate(template, cropBox.Left + 150, cropBox.Bottom + 200, true);

библиотека принимает вращение не правильно, но дает 0 градусов.

Но это правильно! Ваш образец PDF-файла несколько особенный, поскольку в нем используется прямоугольник без поворота для альбомной ориентации и повернутый прямоугольник для портретной ориентации.

person mkl    schedule 14.01.2016
comment
Большое спасибо, ваше объяснение очень подробное. Для этого файла pdf проблема решена, но для другого файла невозможно разместить картинку на странице с альбомной ориентацией. yadi.sk/i/kfW4LdxAn3ZVu Что можете посоветовать в таком случае? Интересует ваше мнение. - person Kseniya Yudina; 15.01.2016
comment
Что вы подразумеваете под невозможно? Конечно, это возможно, вам могут понадобиться другие координаты и некоторый поворот, но это все. - person mkl; 16.01.2016
comment
Нет, похоже проблема именно в этом файле. Он содержит скриншоты страниц. И библиотека не правильно принимает вращение, а дает 0 градусов. - person Kseniya Yudina; 20.01.2016
comment
Спасибо, мкл! Очень полезно. - person Kseniya Yudina; 26.01.2016