itextsharp 5 Writer.DirectContent создает файл на 50% меньше, чем PDFStamper

Мне бы очень хотелось использовать более новый подход с использованием PDFStamper вместо использования старого подхода (PdfWriter.GetInstance... Writer.DirectContent), но файл PDF, созданный с использованием старого метода, составляет 1/2 размера, чем при использовании более нового подхода . Есть ли что-то, что мне не хватает между двумя подходами?

//Old way using PdfWriter.GetInstance... writer.DirectContent
        public static void AddHeaderTextLayer()
        {
            string HdrLeft = string.Empty;
            string HdrRight = string.Empty;
            string PageHdrName = "XHdr";
            string NoOfPagesPadded = string.Empty;
            string PageNoPadded = string.Empty;
            int xLeft = 30;
            int xRight = 100;
            int xTop = 15;
            string filename = "4_20140909.pdf";

            PdfReader reader = new PdfReader(@"C:\!stuff\Junk\ChemWatchPDF\" + filename); // input file

            using (var fileStream = new FileStream(@"C:\!stuff\Junk\ChemWatchPDF\" + filename.Replace(".pdf", "") + "_withHdrLTp.pdf", FileMode.Create, FileAccess.Write))
            {
                var document = new Document(reader.GetPageSizeWithRotation(1));
                var writer = PdfWriter.GetInstance(document, fileStream);
                document.Open();

                for (var i = 1; i <= reader.NumberOfPages; i++)
                {
                    Rectangle pageRect = reader.GetPageSize(i);
                    document.NewPage();

                    var baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
                    var importedPage = writer.GetImportedPage(reader, i);
                    var contentByte = writer.DirectContent;

                    contentByte.AddTemplate(importedPage, 0, 0);
                    string SDSNo = "12345678";
                    HdrLeft = $"Company MSDS# {SDSNo}";

                    NoOfPagesPadded = (reader.NumberOfPages.ToString());
                    PageNoPadded = i.ToString();
                    HdrRight = $" Page {PageNoPadded} of {NoOfPagesPadded}";

                    contentByte.BeginLayer(new PdfLayer(PageHdrName + i.ToString(), writer));

                    contentByte.BeginText();
                    contentByte.SetFontAndSize(baseFont, 10);
                    contentByte.SetColorFill(LabColor.RED);
                    contentByte.ShowTextAligned(PdfContentByte.ALIGN_LEFT, HdrLeft, pageRect.Left + xLeft, pageRect.Top - xTop, 0);
                    contentByte.EndText();

                    contentByte.BeginText();
                    contentByte.SetFontAndSize(baseFont, 10);
                    contentByte.SetColorFill(LabColor.RED);
                    contentByte.ShowTextAligned(PdfContentByte.ALIGN_LEFT, HdrRight, pageRect.Right - xRight, pageRect.Top - xTop, 0);
                    contentByte.EndText();

                    contentByte.EndLayer();
                }
                document.Close();
                writer.Close();
            }
        }

// New way using PDFStamper
       public void Add()
        {
            BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, Encoding.ASCII.EncodingName, false);
            string outPutFile = string.Empty;
            var SingleLine = string.Empty;
            string HdrLeft = string.Empty;
            string HdrRight = string.Empty;
            string PageHdrName = "xHdr";
            string NoOfPagesPadded = string.Empty;
            string PageNoPadded = string.Empty;
            int xLeft = 30;
            int xRight = 100;
            int xTop = 15;
            string filename = "4_20140909.pdf";
            outPutFile = @"C:\!stuff\Junk\ChemWatchPDF\" + filename.Replace(".pdf", "") + "_withHdrLTStamp.pdf";

            using (var newPDF = new FileStream(outPutFile, FileMode.Create, FileAccess.ReadWrite))
            {
                PdfReader reader = new PdfReader(@"C:\!stuff\Junk\ChemWatchPDF\" + filename); // input file
                PdfStamper pdfStamper = new PdfStamper(reader, newPDF);
                PdfLayer wmLayer = new PdfLayer(PageHdrName, pdfStamper.Writer);
                for (int page = 1; page <= reader.NumberOfPages; page++)
                {
                    PdfContentByte pdfContent = pdfStamper.GetOverContent(page);
                    Rectangle pageRect = reader.GetPageSize(page);
                    string SDSNo = "12345678";
                    HdrLeft = $"Company MSDS# {SDSNo}";
                    NoOfPagesPadded = (reader.NumberOfPages.ToString());
                    PageNoPadded = page.ToString();

                    HdrRight = $"Page {PageNoPadded} of {NoOfPagesPadded}";
                    pdfContent.BeginLayer(wmLayer);

                    pdfContent.BeginText();
                    pdfContent.SetFontAndSize(baseFont, 10);
                    pdfContent.SetColorFill(LabColor.RED);
                    pdfContent.ShowTextAligned(PdfContentByte.ALIGN_LEFT, HdrLeft, pageRect.Left + xLeft, pageRect.Top - xTop, 0);
                    pdfContent.EndText();

                    pdfContent.BeginText();
                    pdfContent.SetFontAndSize(baseFont, 10);
                    pdfContent.SetColorFill(LabColor.RED);
                    pdfContent.ShowTextAligned(PdfContentByte.ALIGN_LEFT, HdrRight, pageRect.Right - xRight, pageRect.Top - xTop, 0);
                    pdfContent.EndText();

                    pdfContent.EndLayer();
                }
                pdfStamper.Close();
            }
        }
    }
}

person Remy    schedule 12.05.2019    source источник
comment
Обычно этого не должно происходить... если в исходном PDF-файле просто больше, чем то, что копируется с помощью PdfWriter.GetImportedPage. Например. может быть дерево структуры или вложение, или шаблоны скрытых страниц, или форма XFA, или, или, или. Таким образом, вы можете поделиться рассматриваемым PDF-файлом для анализа?   -  person mkl    schedule 13.05.2019
comment
mkl - я отправлю вам PDF-файлы по электронной почте. Спасибо!   -  person Remy    schedule 14.05.2019


Ответы (1)


Ваша копия с печатью (результат «более нового подхода») содержит дерево структуры, которое, как я полагаю, взято из исходного документа. Он теряется в выводе «старого подхода».

Дерево структуры описывает логическую структуру документа. Это повышает доступность документа, и его наличие становится юридическим требованием во все большем количестве стран и контекстов. Таким образом, выбрасывать дерево структуры вообще — плохая идея.

Само дерево структуры состоит из очень многих небольших косвенных объектов, в случае вашего PDF-файла более 1000 косвенных объектов размером примерно 90 КБ. Кроме того, для каждого косвенного объекта требуется 20-байтовая перекрестная ссылка, что в вашем случае составляет почти 20 КБ. Это объясняет почти всю разницу в размере 111 КБ между двумя выходами.

Если вы используете потоки объектов и потоки перекрестных ссылок, дерево структуры обычно может быть достаточно хорошо сжато. Таким образом, я предлагаю вам активировать полное сжатие в iText, что заставит его использовать потоки объектов и потоки перекрестных ссылок:

PdfStamper pdfStamper = new PdfStamper(reader, newPDF);
pdfStamper.SetFullCompression();
pdfStamper.Writer.CompressionLevel = 9;

Просто обработав ваш большой PDF парой PdfReader/PdfStamper с этими настройками без каких-либо других манипуляций, я уменьшил размер вашего файла с 234 КБ до 133 КБ.


Кстати, вы называете подход с PdfWriter и импортом страницы "старым способом", а подход с PdfStamper "новым способом". На самом деле класс PdfStamper существует в iText как минимум с 2003 года! Так что на самом деле это не старый и новый...

person mkl    schedule 14.05.2019