将 MemoryStream 用于 iTextSharp 的 PdfWriter 输出时未填充流

Stream is not filled when using a MemoryStream for PdfWriter output from iTextSharp

我有以下问题。

这段代码工作正常

private void ModifyAndSavePDF(Stream sourceFile, string text)
{
    using (var pdfWriterStream = new FileStream(@"d:/temp/test.pdf", FileMode.Create))
    {
        var reader = new PdfReader(sourceFile);
        var document = new Document(reader.GetPageSizeWithRotation(1));
        var writer = PdfWriter.GetInstance(document, pdfWriterStream);
        document.Open();
        for (var i = 1; i <= reader.NumberOfPages; i++)
        {
            document.NewPage();
            var importedPage = writer.GetImportedPage(reader, i);
            var contentByte = writer.DirectContent;
            //some more PDF editing stuff here. Not relevant.
        }
        document.Close();
        writer.Close();
        reader.Close();
    }
}

这很好用。 sourceFile 流包含大约 200Kb,保存的 pdf 看起来完全符合我的预期。我注意到的一件事是,在 document.Close() 之前,pdfWriterStream 流的长度只有大约 800 字节。

我的问题是我不想将其保存到磁盘上的文件中,而是希望将输出作为 MemoryStream。但是,我无法按预期工作。我的第一次尝试是这样的:

private Stream ModifyAndSavePDF(Stream sourceFile, string text)
{
    using (var pdfWriterStream = new MemoryStream())
    {
        var reader = new PdfReader(sourceFile);
        var document = new Document(reader.GetPageSizeWithRotation(1));
        var writer = PdfWriter.GetInstance(document, pdfWriterStream);
        document.Open();
        for (var i = 1; i <= reader.NumberOfPages; i++)
        {
            document.NewPage();
            var importedPage = writer.GetImportedPage(reader, i);
            var contentByte = writer.DirectContent;
            //some more PDF editing stuff here. Not relevant.
        }
        document.Close();
        writer.Close();
        reader.Close();
    }
    return pdfWriterStream;
}

这当然行不通,因为当我调用 document.Close() 时,pdfWriterStream 也被释放,我无法读取流的内容。

第二次尝试:

private Stream ModifyAndSavePDF(Stream sourceFile, string text)
{
    var result = new MemoryStream();
    using (var pdfWriterStream = new MemoryStream())
    {
        var reader = new PdfReader(sourceFile);
        var document = new Document(reader.GetPageSizeWithRotation(1));
        var writer = PdfWriter.GetInstance(document, pdfWriterStream);
        document.Open();
        for (var i = 1; i <= reader.NumberOfPages; i++)
        {
            document.NewPage();
            var importedPage = writer.GetImportedPage(reader, i);
            var contentByte = writer.DirectContent;
            //some more PDF editing stuff here. Not relevant.
        }
        pdfWriterStream.Position = 0;
        pdfWriterStream.CopyTo(result);
        document.Close();
        writer.Close();
        reader.Close();
    }
    return result;
}

这让我遇到了第一个列出的代码的问题。 pdfWriterStream 此时只包含大约 800 个字节,当复制到 result 时也只得到这 800 个字节而不是整个文件。

所以看起来 document.Close() 将文件刷新到缓冲区,然后处理它。所以我想在将 pdfWriterStream 复制到 result 之前我需要做一些操作,但我不知道是什么。

首先,如果你想return一个MemoryStream方法中的对象,不要把它放到using 那个方法中的子句:当离开那个 using 块时,流对象被释放,所以你的方法的调用者得到一个他不会高兴的关闭流。

其次,如果您不想在关联的 Document 关闭时关闭 PdfWriter 写入的流,只需设置 PdfWriter 属性 CloseStreamfalse.

因此:

private Stream ModifyAndSavePDF(Stream sourceFile, string text)
{
    var pdfWriterStream = new MemoryStream();
    var reader = new PdfReader(sourceFile);
    var document = new Document(reader.GetPageSizeWithRotation(1));
    var writer = PdfWriter.GetInstance(document, pdfWriterStream);
    writer.CloseStream = false;
    document.Open();
    for (var i = 1; i <= reader.NumberOfPages; i++)
    {
        document.NewPage();
        var importedPage = writer.GetImportedPage(reader, i);
        var contentByte = writer.DirectContent;
        //some more PDF editing stuff here. Not relevant.
    }
    document.Close();
    reader.Close();

    return pdfWriterStream;
}

顺便说一句,您不需要关闭 PdfWriter,当关联的 Document 关闭时它会隐式关闭。

另外,乍一看您的方法就像是复制了一些原始 PDF 并对其进行了一些更改。通常(取决于您要应用的确切更改,也就是说)应该使用 PdfStamper 而不是普通的 PdfWriter.