1

我正在努力在多页 PDF 上插入图像。为了创建几个页面,我使用了 PdfConcatenate,它可以工作。我可以完美地添加我的模板页面。当我尝试添加图像时,问题就开始了。它只是不加载它们。

这是用于添加图像的代码:

        string pdfTemplate = @"Tools\template.pdf";
        string targetPdfPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), fileName + ".pdf");

        FileStream output = new FileStream(targetPdfPath, FileMode.Create);
        PdfConcatenate pdfConcatenate = new PdfConcatenate(output);

        PdfReader pdfReader = new PdfReader(pdfTemplate);
        MemoryStream memoryStream = getMemoryStream(output);
        PdfStamper pdfStamper = new PdfStamper(pdfReader, output);

        int cardIndex = 1;

        foreach (Registry reg in registries)
        {
            setFields(reg, pdfStamper, cardIndex);

            if (cardIndex == 4)
            {
                pdfConcatenate.AddPages(pdfReader);
                pdfReader = new PdfReader(pdfTemplate);
                pdfStamper = new PdfStamper(pdfReader, output);

                cardIndex = 1;
            }
            else
            {
                cardIndex++;
            }
        }

        //if (cardIndex != 1)
        //    pdfConcatenate.AddPages(pdfReader);

        //make the form no longer editable
        pdfStamper.FormFlattening = true;

        pdfStamper.Close();
        pdfReader.Close();
        //pdfConcatenate.Close();

如果对 PdfStamper 使用 MemoryStream 并取消注释这些行:

//if (cardIndex != 1)
//    pdfConcatenate.AddPages(pdfReader);
//pdfConcatenate.Close();

我得到它来添加页面,但没有图像。

知道出了什么问题吗?

解决方案:(感谢@mkl)

        string pdfTemplate = @"Tools\template.pdf";
        string targetPdfPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), fileName + ".pdf");

        FileStream output = new FileStream(targetPdfPath, FileMode.Create);
        PdfConcatenate pdfConcatenate = new PdfConcatenate(output);

        PdfReader pdfReader = new PdfReader(pdfTemplate);
        MemoryStream memoryStream = new MemoryStream();
        PdfStamper pdfStamper = new PdfStamper(pdfReader, memoryStream);

        int cardIndex = 1;

        foreach (Registry reg in registries)
        {
            setFields(reg, pdfStamper, cardIndex);

            if (cardIndex == 4)
            {
                pdfStamper.FormFlattening = true;
                pdfStamper.Close();
                PdfReader tempReader = new PdfReader(memoryStream.ToArray());

                pdfConcatenate.AddPages(tempReader);

                memoryStream = new MemoryStream();
                pdfReader = new PdfReader(pdfTemplate);
                pdfStamper = new PdfStamper(pdfReader, memoryStream);

                cardIndex = 1;
            }
            else
            {
                cardIndex++;
            }
        }

        if (cardIndex != 1)
        {
            pdfStamper.FormFlattening = true;
            pdfStamper.Close();
            PdfReader tempReader = new PdfReader(memoryStream.ToArray());

            pdfConcatenate.AddPages(tempReader);

            tempReader.Close();
        }

        pdfStamper.Close();
        pdfReader.Close();
        pdfConcatenate.Close();
4

1 回答 1

2

问题很可能是对如何PdfStamper工作的一些误解。您似乎认为它以某种方式操纵了PdfReaderit 标记中的数据,以及事先从该阅读器导出的页面。情况并非如此,aPdfStamper根据阅读器中的数据生成一个新的 PDF 文件(在其输出流中),但阅读器本身的内容并未更新以反映所有更改(PdfReader在此过程中可能会触摸对象, 但是,之后不可重复使用)。所以...

正如评论中已经提到的,您有PdfConcatenate和未知数量的PdfStamper实例都在编写相同的“FileStream”输出。由于这些对象中的每一个都创建了一个独立的 PDF,因此如果其中一个获胜,您将很幸运,因为这样您至少会得到一个正确的 PDF 作为输出。否则,您要么得到一些异常,要么得到由多个混合 PDF 组成的垃圾。因此,仅使 PdfConcatenate 以您的输出文件为目标。

如果您的实际意图是每次重复填写模板字段中 4 张卡片的内容并合并结果,则不PdfReader应将模板中的页面添加到PdfConcatenate--- 该阅读器中的页面未填写!--- 而是将 PdfStamper 输出到 a MemoryStream,填充其字段,展平其表单,关闭它,在新的 中打开其输出PdfReader,并将该阅读器中的所有页面添加到 PdfConcatenate。

我不敢将其放入代码中,因为我主要使用 Java 并且写下未经测试的 C# 代码很可能会包含多个错误... ;)

PS:目前您指望PdfReader您打开的所有实例都在某处隐式关闭。虽然目前确实如此,但 iText SVN 存储库中的最近签入似乎表明这些隐式关闭调用已从代码中删除。因此,也请开始明确关闭PdfReader不再使用的实例。否则,由于读者关闭得太晚,您很快将不得不处理内存泄漏。

于 2012-11-15T09:22:11.097 回答