首页 > 解决方案 > itextsharp 5 writer.DirectContent 创建的文件比 PDFStamper 小 50%

问题描述

我真的很想使用使用 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();
            }
        }
    }
}

标签: c#itextpdfstamper

解决方案


您的盖章副本(“较新方法”的输出)包含一个结构树,我假设它来自原始文档。它在“旧方法”的输出中丢失了。

结构树描述了文档的逻辑结构。它增加了文档的可访问性,并且它的存在成为越来越多的国家和环境中的法律要求。因此,一般来说丢弃结构树是一个坏主意。

结构树本身由非常多的小型间接对象组成,如果您的 PDF 有 1000 多个间接对象,总大小约为 90KB。此外,每个间接对象都需要一个 20 字节的交叉引用条目,在您的情况下总计将近 20KB。这几乎解释了两个输出之间 111KB 的大小差异。

如果使用对象流和交叉引用流,通常可以很好地压缩结构树。因此,我建议您在 iText 中激活完全压缩,使其使用对象流和交叉引用流:

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

通过PdfReader/PdfStamper使用这些设置简单地处理您的大型 PDF,无需任何其他操作,我将您的文件大小从 234KB 减少到 133KB。


顺便说一句,您将使用PdfWriter页面导入的方法称为“旧方法”,将方法PdfStamper称为“新方法”。实际上PdfStamper,至少自 2003 年以来,该类就存在于 iText 中!所以它并不是真正的......


推荐阅读