Пишите в файл PDF с полями несколько раз, используя iTextSharp - PullRequest
3 голосов
/ 06 июня 2019

У меня есть PDF-документ с 3 полями txt_FirstName, txt_MiddleName и txt_LastName, в который я пишу, используя iTextSharp .

У меня есть цикл, который создает выходной файл, записывает в него и закрывает файл.

В первый раз в цикле файл записывает имя и отчество.

Во второй раз в цикле файл должен иметь имя, отчество и написать фамилию.

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

Цель: Главное, что я хочу сделать, - это записывать в одни и те же документы PDF несколько раз

Скачать шаблон PDF: https://www.scribd.com/document/412586469/Testing-Doc

    public static string templatePath = "C:\\temp\\template.pdf";
    public static string OutputPath = "C:\\Output\\";

    private static void Fill_PDF()
    {
        string outputFile = "output.pdf";
        int counter = 1;

        for (int i = 0; i < 2; i++)
        {
            PdfStamper pdfStamper;
            PdfReader reader;

            reader = new PdfReader(File.ReadAllBytes(templatePath));
            PdfReader.unethicalreading = true;

            if (File.Exists(OutputPath + outputFile))
            {
                pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                                        FileMode.Append, FileAccess.Write));
            }
            else
            {
                pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                                        FileMode.Create));
            }
            AcroFields pdfFormFields = pdfStamper.AcroFields;

            if (counter == 1)
            {
                pdfFormFields.SetField("txt_FirstName", "Scooby");
                pdfFormFields.SetField("txt_MiddleName", "Dooby");
                counter++;
            }
            else if (counter == 2)
            {
                pdfFormFields.SetField("txt_LastName", "Doo");
            }
            pdfStamper.Close();
        }
    }

Ответы [ 3 ]

5 голосов
/ 12 июня 2019

Это похоже на прямую ошибку.При первом запуске цикла вы загружаете пустой шаблон и пишете имя и отчество.Во второй раз в цикле вы загружаете пустой шаблон снова и пишете только последнюю фамилию , затем сохраняете в то же имя файла, перезаписывая его.Если во второй раз в цикле вы хотите загрузить файл, который уже содержит имя и отчество, вам нужно загрузить выходной файл , который вы написали в первый раз около , а не пустой шаблонснова.Или, если вы хотите снова загрузить пустой шаблон, внутри вашего предложения if (counter == 2), вам нужно будет написать все 3 имени, а не только фамилию.

Я воспроизвел вашу ошибку и получил ееза работой.Вот код первого решения, которое я описал (незначительная модификация вашего кода):

    public static string templatePath = "C:\\temp\\template.pdf";
    public static string OutputPath = "C:\\temp\\output\\";

    private static void Fill_PDF()
    {
        string outputFile = "output.pdf";
        int counter = 1;

        for (int i = 0; i < 2; i++)
        {
            PdfStamper pdfStamper;
            PdfReader reader = null;

            /********** here's the changed part */
            if (counter == 1)
            {
                reader = new PdfReader(File.ReadAllBytes(templatePath));
            } else if (counter == 2)
            {
                reader = new PdfReader(File.ReadAllBytes(OutputPath + outputFile));
            }
            /************ end changed part */

            PdfReader.unethicalreading = true;

            if (File.Exists(OutputPath + outputFile))
            {
                pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                    FileMode.Append, FileAccess.Write));
            }
            else
            {
                pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                    FileMode.Create));
            }
            AcroFields pdfFormFields = pdfStamper.AcroFields;

            if (counter == 1)
            {
                pdfFormFields.SetField("txt_FirstName", "Scooby");
                pdfFormFields.SetField("txt_MiddleName", "Dooby");
                counter++;
            }
            else if (counter == 2)
            {
                pdfFormFields.SetField("txt_LastName", "Doo");
            }
            pdfStamper.Close();
        }
    }
1 голос
/ 12 июня 2019

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

Второй номер находится здесь:

if (File.Exists(OutputPath + outputFile))
{
    pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                            FileMode.Append, FileAccess.Write));
}
else
{
    pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                            FileMode.Create));
}

Если выходной файл уже существует, вы добавляете к нему вывод вашего PdfStamper . Это не верно! Выходные данные PdfStamper уже содержат содержимое исходного PDF (из PdfReader), поскольку оно не изменяется. Таким образом, ваш код эффективно создает конкатенацию полного выходного PDF первого прохода и полного выходного PDF второго прохода.

PDF - это двоичный формат, для которого объединение подобных файлов не приводит к действительному PDF-файлу. Таким образом, программа просмотра PDF, загружающая ваш конечный результат, пытается восстановить этот двойной PDF, предполагая, что он является единственным. Результат может или не может выглядеть так, как вы хотите.

Чтобы устранить вторую проблему, просто замените if{...}else{...} выше содержимым только ветки else:

pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                        FileMode.Create));

(FileMode.Create определяется как

Указывает, что операционная система должна создать новый файл. Если файл уже существует, он будет перезаписан. Это требует разрешения Write. FileMode.Create эквивалентно запросу, что если файл не существует, используйте CreateNew; в противном случае используйте Truncate. Если файл уже существует, но является скрытым, выдается исключение UnauthorizedAccessException.

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

Вы можете распознать проблемы кода с Append, запустив его несколько раз и наблюдая, как выходной файл растет и растет по мере необходимости. Кроме того, если вы откроете этот файл в Adobe Reader и закроете снова, Adobe Reader предложит сохранить изменения; изменения - ремонтные работы.


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

iText содержит конструктор PdfStamper с 4 параметрами, включая последний логический параметр append. Использование этого конструктора и установка append в true заставляет iText создавать инкрементные обновления. Но даже здесь вы не используете FileMode.Append ...

0 голосов
/ 17 июня 2019

Проблема заключается в повторном использовании файла шаблона для второй итерации.

Первая итерация: работает нормально, как и ожидалось!

Вторая итерация: вы читаете тот же файл и пишете только фамилию. Наконец, выходной файл, созданный в первой итерации, заменяется.

Исправление: Узнав, существует ли выходной файл в этом месте, выберите источник файла для чтения, как показано ниже. Это должно решить проблему. Проверено лично и все заработало!

if (File.Exists(OutputPath + outputFile))
{
    reader = new PdfReader(File.ReadAllBytes(OutputPath + outputFile));
    pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                                            FileMode.Append, FileAccess.Write));
}
else
{
    reader = new PdfReader(File.ReadAllBytes(templatePath));
    pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
                                                            FileMode.Create));
}
...