办公文档转PDF

8
我看到了一些关于此事的讨论,但是在我的搜索中并没有得到非常明确的答案。我有一个 Web 应用程序,需要接收 doc、docx、xls 和 xlsx 文件,并将它们转换为 PDF。目前我们使用 Microsoft.Office.Interop.Word 库来打开文档,将其打印成 PS 文件,然后使用 GPL GhostScript 将 PS 文件转换为 PDF。
这个过程还算可以,但总体来说其中有几个步骤,在多年前开发时更难找到 PDF 打印驱动程序和接口。为了更新,我正在寻找可能更好的处理方式。主要原因是,在我们的应用程序中,我们使用 Web 服务调用来执行转换过程的提升操作。在较新版本的 Windows Server 中,特别是在 Windows 7 上进行开发时,即使使用模拟身份也无法打开文件,这会导致 Interop 库出现问题。
我相信所有这些都可以解决和改善,但我想知道是否有更新的、更好的方法来处理这个问题。我已经研究了 PDF995,但没有找到一个很好的编程方式直接将文件打印为 PDF。他们提供的代码是用 C++ 编写的,我没有找到如何在 C# 中模仿这些调用。

3
你不应从ASP.NET应用程序或任何其他服务器应用程序调用Office互操作性。请参阅考虑在服务器端自动化Office时需要注意的事项 - John Saunders
有趣的文章。谢谢你指出来。现在还是很难实现这种功能吗?像Aspose这样的东西并不是不可能,但我认为可能存在一些不需要如此昂贵的购买的方法。 - Justin Rassier
Office Interop 代码以及它所连接的 Office 应用程序是为单用户、交互式环境设计的。在多线程、多用户环境中,这种设计根本无法正常工作。相信我,我已经吃过苦头,你不想走这条路。使用 Interop 并假装它可以工作会让你付出更多代价,需要一遍又一遍地“修复”它…… - John Saunders
明白了,这是很有用的信息,谢谢。但我仍然有一个问题,就是完成这个任务的选项。如果没有Interop,我知道我们可以使用Aspose。但是否还有其他选择呢?是否有其他方法可以在不先使用Interop库的情况下仍然使用PDF驱动程序?非常感谢您的帮助。 - Justin Rassier
可以在服务器上运行,只需一个后台进程来监视需要转换的文档数据。直接从ASP页面运行的问题在于多个请求可能同时尝试调用COM对象。 - FlavorScape
我运行自动化控制台应用程序时没有遇到任何问题,该应用程序调用 Web API 获取状态为“未转换”的文档,然后将其标记为已转换,以便客户端知道现在可以加载缩略图等... 这确保它每次只处理一个文档/幻灯片。 - FlavorScape
3个回答

7
如果你正在寻找一个“免费”的解决方案,我认为你可能只有唯一可行的选择,但像John所说,服务器端互操作通常不是一个好主意。我们已经成功地使用了.NET Aspose 组件。这是一个纯托管的解决方案,不需要任何互操作或办公室。

我们也很擅长使用Aspose。仍然难以置信微软在这方面没有提供任何东西。 - gsharp
iTextSharp是另一个选择。它是免费的,但据我所知,他们的文档很糟糕。 - DJ Quimby
1
iTextSharp仅适用于开源项目,其他用途需要购买许可证。 - Bobrovsky

4

编辑:鉴于John Saunders提供的Office服务器端自动化考虑因素文章,下面的代码不应用于服务器端开发目的。

以下是使用Interop将Docx转换为PDF的代码。希望您可以以此为起点,弄清如何处理其他文档。

private void DocxToPdf(String sourcePath, String destPath) {

        //Change the path of the .docx file and filename to your file name.

        object paramSourceDocPath = sourcePath;
        object paramMissing = Type.Missing;
        var wordApplication = new Microsoft.Office.Interop.Word.Application();
        Document wordDocument = null;

        //Change the path of the .pdf file and filename to your file name.

        string paramExportFilePath = destPath;
        WdExportFormat paramExportFormat = WdExportFormat.wdExportFormatPDF;
        bool paramOpenAfterExport = false;
        WdExportOptimizeFor paramExportOptimizeFor =
            WdExportOptimizeFor.wdExportOptimizeForPrint;
        WdExportRange paramExportRange = WdExportRange.wdExportAllDocument;
        int paramStartPage = 0;
        int paramEndPage = 0;
        WdExportItem paramExportItem = WdExportItem.wdExportDocumentContent;
        bool paramIncludeDocProps = true;
        bool paramKeepIRM = true;
        WdExportCreateBookmarks paramCreateBookmarks =
            WdExportCreateBookmarks.wdExportCreateWordBookmarks;
        bool paramDocStructureTags = true;
        bool paramBitmapMissingFonts = true;
        bool paramUseISO19005_1 = false;

        try {
            // Open the source document.
            wordDocument = wordApplication.Documents.Open(
                ref paramSourceDocPath, ref paramMissing, ref paramMissing,
                ref paramMissing, ref paramMissing, ref paramMissing,
                ref paramMissing, ref paramMissing, ref paramMissing,
                ref paramMissing, ref paramMissing, ref paramMissing,
                ref paramMissing, ref paramMissing, ref paramMissing,
                ref paramMissing);

            // Export it in the specified format.
            if (wordDocument != null)
                wordDocument.ExportAsFixedFormat(paramExportFilePath,
                    paramExportFormat, paramOpenAfterExport,
                    paramExportOptimizeFor, paramExportRange, paramStartPage,
                    paramEndPage, paramExportItem, paramIncludeDocProps,
                    paramKeepIRM, paramCreateBookmarks, paramDocStructureTags,
                    paramBitmapMissingFonts, paramUseISO19005_1,
                    ref paramMissing);
        }
        catch (Exception ex) {
            // Respond to the error
            System.Windows.Forms.MessageBox.Show(ex.Message);
        }
        finally {
            // Close and release the Document object.
            if (wordDocument != null) {
                wordDocument.Close(ref paramMissing, ref paramMissing,
                    ref paramMissing);
                wordDocument = null;
            }

            // Quit Word and release the ApplicationClass object.
            if (wordApplication != null) {
                wordApplication.Quit(ref paramMissing, ref paramMissing,
                    ref paramMissing);
                wordApplication = null;
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }

2
-1 表示建议他实现许多难以找到的错误。不要在服务器应用程序中使用 Office Interop。 - John Saunders
1
@JohnSaunders 我并没有建议他做或不做任何事情。我碰巧有一些代码可以完成他想要做的部分,所以我发布了它。你们可以在自己的评论中告诉他不应该做什么。 - DJ Quimby
2
@DarinDimitrov 很好,我相信几年前我也是这样发现这个问题的。不过,像那样的负面评论很容易被更好的解释所取代,我们都可以从中学习。我们并不处于同样的经验水平,记住这一点非常重要。 - DJ Quimby
2
我必须说我很欣赏@DJ Quimby并且他发布了一些东西。我知道这可能不是一个非常安全的解决方案,但我自己刚学习了所有潜在的陷阱。我很高兴他提供了一个技术上符合我的要求的解决方案。我也很高兴社区中还有其他人来教育和解释为什么这可能不是一个好的解决方案。 - Justin Rassier
1
我认为最好保留这个答案和警告,这样其他人在找到这段代码时就能被警告其危险性。保留答案以及反对使用它的论点,让人们自行判断是否使用。 - Ivy
显示剩余7条评论

2

Syncfusion Essential PDF可以用于将办公文档转换为PDF格式。该库可从Windows Forms、WPF、ASP.NET Webforms 和 ASP.NET MVC应用程序中使用。

如果您符合条件,整套控件可以通过社区许可计划免费获得(商业应用也一样)。社区许可是完整的产品,没有限制或水印。

注意:我在Syncfusion工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接