无法使用MemoryStream合并2个PDF

San*_*ain 12 c# wkhtmltopdf

我有一个ac#类,它接受HTML并使用wkhtmltopdf将其转换为PDF。
正如您将在下面看到的,我正在生成3个PDF-横向,纵向和两者结合。

properties对象包含html作为字符串,以及landscape / portrait的参数。

System.IO.MemoryStream PDF = new WkHtmlToPdfConverter().GetPdfStream(properties);
System.IO.FileStream file = new System.IO.FileStream("abc_landscape.pdf", System.IO.FileMode.Create);
PDF.Position = 0;

properties.IsHorizontalOrientation = false;
System.IO.MemoryStream PDF_portrait = new WkHtmlToPdfConverter().GetPdfStream(properties);
System.IO.FileStream file_portrait = new System.IO.FileStream("abc_portrait.pdf", System.IO.FileMode.Create);
PDF_portrait.Position = 0;

System.IO.MemoryStream finalStream = new System.IO.MemoryStream();
PDF.CopyTo(finalStream);
PDF_portrait.CopyTo(finalStream);
System.IO.FileStream file_combined = new System.IO.FileStream("abc_combined.pdf", System.IO.FileMode.Create);

try
{
    PDF.WriteTo(file);
    PDF.Flush();

    PDF_portrait.WriteTo(file_portrait);
    PDF_portrait.Flush();

    finalStream.WriteTo(file_combined);
    finalStream.Flush();
}
catch (Exception)
{
    throw;
}
finally
{
    PDF.Close();
    file.Close();

    PDF_portrait.Close();
    file_portrait.Close();

    finalStream.Close();
    file_combined.Close();
}
Run Code Online (Sandbox Code Playgroud)

PDF“ abc_landscape.pdf”和“ abc_portrait.pdf”如预期那样正确生成,但是当我尝试将两者合并为第三个pdf(abc_combined.pdf)时,该操作失败。

我正在MemoryStream执行合并,在调试时,我可以看到finalStream.length等于前两个PDF的总和。但是,当我尝试打开PDF时,仅看到两个PDF中的1个的内容。
可以在下面看到相同的内容: PDF尺寸

此外,当我尝试关闭“ abc_combined.pdf”时,系统会提示我保存它,而其他2个PDF则不会。 保存提示

以下是我已经尝试过的一些方法,但无济于事:

  1. 将CopyTo()更改为WriteTo()
  2. 与自己合并同一PDF(横向或纵向)

    如果需要,下面将详细说明该GetPdfStream()方法。
System.IO.MemoryStream PDF = new WkHtmlToPdfConverter().GetPdfStream(properties);
System.IO.FileStream file = new System.IO.FileStream("abc_landscape.pdf", System.IO.FileMode.Create);
PDF.Position = 0;

properties.IsHorizontalOrientation = false;
System.IO.MemoryStream PDF_portrait = new WkHtmlToPdfConverter().GetPdfStream(properties);
System.IO.FileStream file_portrait = new System.IO.FileStream("abc_portrait.pdf", System.IO.FileMode.Create);
PDF_portrait.Position = 0;

System.IO.MemoryStream finalStream = new System.IO.MemoryStream();
PDF.CopyTo(finalStream);
PDF_portrait.CopyTo(finalStream);
System.IO.FileStream file_combined = new System.IO.FileStream("abc_combined.pdf", System.IO.FileMode.Create);

try
{
    PDF.WriteTo(file);
    PDF.Flush();

    PDF_portrait.WriteTo(file_portrait);
    PDF_portrait.Flush();

    finalStream.WriteTo(file_combined);
    finalStream.Flush();
}
catch (Exception)
{
    throw;
}
finally
{
    PDF.Close();
    file.Close();

    PDF_portrait.Close();
    file_portrait.Close();

    finalStream.Close();
    file_combined.Close();
}
Run Code Online (Sandbox Code Playgroud)

may*_*ʎɐɯ 10

使用第3方库无法直接合并C#或任何其他语言的pdf。

我假设您对不使用库的要求是,大多数免费库,nuget软件包都存在限制或/并且要花费商业用途。

我进行了研究,发现一个带有nuget包的名为PdfClown的开源库,它也可用于Java。它是免费的,没有限制(如果愿意,请捐款)。该库具有很多功能。这样一来,您可以将2个或多个文档合并为一个文档。

我提供的示例包含一个包含多个pdf文件的文件夹,将其合并并保存到相同或另一个文件夹中。也可以使用MemoryStream,但在这种情况下我认为没有必要。

代码是自解释的,这里的重点是使用SerializationModeEnum.Incremental

public static void MergePdf(string srcPath, string destFile)
{
    var list = Directory.GetFiles(Path.GetFullPath(srcPath));
    if (string.IsNullOrWhiteSpace(srcPath) || string.IsNullOrWhiteSpace(destFile) || list.Length <= 1)
        return;
    var files = list.Select(File.ReadAllBytes).ToList();
    using (var dest = new org.pdfclown.files.File(new org.pdfclown.bytes.Buffer(files[0])))
    {
        var document = dest.Document;
        var builder = new org.pdfclown.tools.PageManager(document);
        foreach (var file in files.Skip(1))
        {
            using (var src = new org.pdfclown.files.File(new org.pdfclown.bytes.Buffer(file)))
            { builder.Add(src.Document); }
        }

        dest.Save(destFile, SerializationModeEnum.Incremental);
    }
}
Run Code Online (Sandbox Code Playgroud)

测试一下

var srcPath = @"C:\temp\pdf\input";
var destFile = @"c:\temp\pdf\output\merged.pdf";
MergePdf(srcPath, destFile);
Run Code Online (Sandbox Code Playgroud)

输入示例
PDF文档A和PDF文档B

PDF文档A和PDF文档B

输出示例

合并后

链接到我的研究:

免责声明:此答案的一部分来自我的个人网站https://itbackyard.com/merge-multiple-pdf-files-to-one-pdf-file-in-c/,带有源代码到github。


Ale*_*uun 6

安德鲁·伯恩斯Andrew Burns )的 Stack Overflow(合并两个(或多个)PDF)的答案为我工作:

        using (PdfDocument one = PdfReader.Open("pdf 1.pdf", PdfDocumentOpenMode.Import))
        using (PdfDocument two = PdfReader.Open("pdf 2.pdf", PdfDocumentOpenMode.Import))
        using (PdfDocument outPdf = new PdfDocument())
        {
            CopyPages(one, outPdf);
            CopyPages(two, outPdf);

            outPdf.Save("file1and2.pdf");
        }

        void CopyPages(PdfDocument from, PdfDocument to)
        {
            for (int i = 0; i < from.PageCount; i++)
            {
                to.AddPage(from.Pages[i]);
            }
        }
Run Code Online (Sandbox Code Playgroud)

  • @ Sanketh.K.Jain是MemoryStream专有的,还是允许其他技术?(/sf/answers/2255817651/) (2认同)

Mat*_*art 4

PDF 文件不仅仅是文本和图像。在幕后有一个严格的文件格式来描述 PDF 版本、文件中包含的对象以及在哪里可以找到它们等内容

为了合并 2 个 PDF,您需要操作流。

首先,您需要仅保留其中一个文件的标头。这非常简单,因为它只是第一行。

然后你可以写第一页的正文,然后是第二页。

现在最困难的部分,也可能是说服您使用库的部分,是您必须重新构建外部参照表。外部参照表是一个交叉引用表,它描述了文档的内容,更重要的是在哪里可以找到每个元素。您必须计算第二页的字节偏移量,将其外部参照表中的所有元素移动那么多,然后将其外部参照表添加到第一页。您还需要确保在外部参照表中为分页符创建对象。

完成后,您需要重新构建文档预告片,它告诉应用程序文档的各个部分的位置。

请参阅https://resources.infosecinstitute.com/pdf-file-format-basic-struct/

这并不是一件小事,您最终将重写大量已经存在的代码。