为了账号安全,请及时绑定邮箱和手机立即绑定

无法使用 MemoryStream 合并 2 个 PDF

无法使用 MemoryStream 合并 2 个 PDF

C#
月关宝盒 2023-09-16 20:10:47
我有一个 c# 类,它接受 HTML 并使用 wkhtmltopdf 将其转换为 PDF。正如您将在下面看到的,我生成了 3 个 PDF - 横向、纵向以及两者的组合。该properties对象包含字符串形式的 html 以及横向/纵向的参数。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();}PDF“abc_landscape.pdf”和“abc_portrait.pdf”按预期正确生成,但当我尝试将两者合并到第三个 pdf (abc_combined.pdf) 中时,操作失败。我用来MemoryStream执行合并,在调试时,我可以看到finalStream.length等于前两个 PDF 的总和。但当我尝试打开 PDF 时,我只看到两个 PDF 中的 1 个的内容。下图也可以看到同样的情况:此外,当我尝试关闭“abc_combined.pdf”时,系统会提示我保存它,而其他 2 个 PDF 则不会出现这种情况。以下是我已经尝试过的一些方法,但没有效果:将 CopyTo() 更改为 WriteTo()将相同的 PDF(横向或纵向)与其自身合并如果需要,下面是该GetPdfStream()方法的详细说明。var htmlStream = new MemoryStream();var writer = new StreamWriter(htmlStream);writer.Write(htmlString);writer.Flush();htmlStream.Position = 0;return htmlStream;Process process = Process.Start(psi);process.EnableRaisingEvents = true;
查看完整描述

4 回答

?
函数式编程

TA贡献1807条经验 获得超9个赞

如果不使用第 3 方库,用 C# 或任何其他语言合并 pdf 并不简单。

我假设您不使用库的要求是大多数免费库、nuget 包都有限制或/并且商业用途需要花钱。

我做了研究,找到了一个名为PdfClown的开源库,带有nuget包,它也适用于 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);

    }

}

测试一下


var srcPath = @"C:\temp\pdf\input";

var destFile = @"c:\temp\pdf\output\merged.pdf";

MergePdf(srcPath, destFile);

输入示例

PDF 文档 A 和 PDF 文档 B

https://img1.sycdn.imooc.com/65059bab0001ed5a06360362.jpg

输出示例


https://img3.sycdn.imooc.com/65059bb70001dfb603910635.jpg

查看完整回答
反对 回复 2023-09-16
?
千巷猫影

TA贡献1829条经验 获得超7个赞

这个答案有用:


      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]);

            }

        }


查看完整回答
反对 回复 2023-09-16
?
噜噜哒

TA贡献1784条经验 获得超7个赞

PDF 的工作原理并不完全是这样。PDF 是特定格式的结构化文件。您不能只是将一个字节附加到另一个字节并期望结果是有效的文档。

您将必须使用一个能够理解格式并可以为您执行操作的库,或者开发您自己的解决方案。


查看完整回答
反对 回复 2023-09-16
?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

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

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

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

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

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

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

查看完整回答
反对 回复 2023-09-16
  • 4 回答
  • 0 关注
  • 80 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信