如何通过编程将Word文件转换为PDF?

235

我已经找到了几个开源/免费软件,可以将.doc文件转换为.pdf文件,但它们都是应用程序/打印机驱动程序类型,没有SDK附加。

我发现一些有SDK的程序可以进行.doc文件转换为.pdf文件,但它们都是专有类型,每个许可证大约需要$2000。

有人知道任何干净、廉价(最好是免费)的编程解决方案来解决我的问题,使用C#或VB.NET?

谢谢!


2
检查Pandoc是否有你喜欢的编程语言绑定。命令行界面也非常简单,只需输入pandoc manual.docx -o manual.pdf即可。 - Colonel Panic
另外,可以查看GemBox.Document SDK。它有免费版本和廉价版本。它不使用打印机驱动程序或MS Office将Word文件转换为PDF。 - hertzogth
你可以使用docx2pdf进行转换:https://github.com/AlJohri/docx2pdf - Al Johri
对于寻找解决方案的人来说,使用LibreOffice要容易得多。如果您已经安装了docker,那么只需运行一个简单的命令:docker "run" "--rm" "--entrypoint" "soffice" "-v" "$(pwd):/usr/src/project" "linuxserver/libreoffice:latest" "--headless" "--convert-to" "pdf" "--outdir" "/usr/src/project" "/usr/src/project/foo.docx" - nicojs
8个回答

215

使用foreach循环代替for循环 - 这解决了我的问题。

int j = 0;
foreach (Microsoft.Office.Interop.Word.Page p in pane.Pages)
{
    var bits = p.EnhMetaFileBits;
    var target = path1 +j.ToString()+  "_image.doc";
    try
    {
        using (var ms = new MemoryStream((byte[])(bits)))
        {
            var image = System.Drawing.Image.FromStream(ms);
            var pngTarget = Path.ChangeExtension(target, "png");
            image.Save(pngTarget, System.Drawing.Imaging.ImageFormat.Png);
        }
    }
    catch (System.Exception ex)
    {
        MessageBox.Show(ex.Message);  
    }
    j++;
}

这是我使用的一个程序修改版。它使用安装了Save As PDF add-in的Word 2007。它在目录中搜索.doc文件,打开它们并将它们保存为PDF格式。请注意,您需要将Microsoft.Office.Interop.Word添加到解决方案的引用中。
using Microsoft.Office.Interop.Word;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

...

// Create a new Microsoft Word application object
Microsoft.Office.Interop.Word.Application word = new Microsoft.Office.Interop.Word.Application();

// C# doesn't have optional arguments so we'll need a dummy value
object oMissing = System.Reflection.Missing.Value;

// Get list of Word files in specified directory
DirectoryInfo dirInfo = new DirectoryInfo(@"\\server\folder");
FileInfo[] wordFiles = dirInfo.GetFiles("*.doc");

word.Visible = false;
word.ScreenUpdating = false;

foreach (FileInfo wordFile in wordFiles)
{
    // Cast as Object for word Open method
    Object filename = (Object)wordFile.FullName;

    // Use the dummy value as a placeholder for optional arguments
    Document doc = word.Documents.Open(ref filename, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing, ref oMissing);
    doc.Activate();

    object outputFileName = wordFile.FullName.Replace(".doc", ".pdf");
    object fileFormat = WdSaveFormat.wdFormatPDF;

    // Save document into PDF Format
    doc.SaveAs(ref outputFileName,
        ref fileFormat, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing, ref oMissing);

    // Close the Word document, but leave the Word application open.
    // doc has to be cast to type _Document so that it will find the
    // correct Close method.                
    object saveChanges = WdSaveOptions.wdDoNotSaveChanges;
    ((_Document)doc).Close(ref saveChanges, ref oMissing, ref oMissing);
    doc = null;
}

// word has to be cast to type _Application so that it will find
// the correct Quit method.
((_Application)word).Quit(ref oMissing, ref oMissing, ref oMissing);
word = null;

3
谢谢!如果Aspose比Word自动化更快,我可能会选择它。但是如果我可以容忍一点慢速,我可能会选择您的解决方案。再次感谢! - Shaul Behr
4
是的,它不是最快的,但难以击败价格。 :-) 很高兴我能帮忙。 - Eric Ness
11
使用Office 2007 SP2后,您将不再需要下载“另存为PDF”的插件。我还成功地在Excel和Powerpoint中使用了这种技术。 - RichardOD
6
你是否在一个带有Web应用程序的服务器上使用过这种方法?我遇到了很多问题,而且微软也不推荐使用。http://support.microsoft.com/zh-cn/default.aspx?scid=kb;EN-US;q257757#kb2我听说Aspose非常好,但价格有点贵。 - Prabu
6
如果未安装 Word,我认为打包互操作程序集将是你最不用担心的事情。这段代码需要安装 Word 才能运行。 - BrainSlugs83
显示剩余5条评论

39

总结一下,对于vb.net用户来说,免费选项(必须安装office):

Microsoft office程序集下载:

VB.NET示例:

        Dim word As Application = New Application()
        Dim doc As Document = word.Documents.Open("c:\document.docx")
        doc.Activate()
        doc.SaveAs2("c:\document.pdf", WdSaveFormat.wdFormatPDF)
        doc.Close()

3
2015年仍然适用。使用Office 2013,您无需单独下载PIA。 - Adam Anderson
4
如果它打开一个消息框并询问某些事情——例如在 Web 应用程序中……或者同时处理两个文档…… - Stefan Steiger
一个免费的选择(通过nodejs和edge.js,或者Javascript.NET)是https://www.npmjs.com/package/@nativedocuments/docx-wasm(不需要Word) - JasonPlutext

15

只是想补充一下,我使用了Microsoft.Interop库,特别是ExportAsFixedFormat函数,这个函数在这个帖子中没有被使用到。

using Microsoft.Office.Interop.Word;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Office.Core;

Application app;

public string CreatePDF(string path, string exportDir)
{
    Application app = new Application();
    app.DisplayAlerts = WdAlertLevel.wdAlertsNone;
    app.Visible = true;

    var objPresSet = app.Documents;
    var objPres = objPresSet.Open(path, MsoTriState.msoTrue, MsoTriState.msoTrue, MsoTriState.msoFalse);

    var pdfFileName = Path.ChangeExtension(path, ".pdf");
    var pdfPath = Path.Combine(exportDir, pdfFileName);

    try
    {
        objPres.ExportAsFixedFormat(
            pdfPath,
            WdExportFormat.wdExportFormatPDF,
            false,
            WdExportOptimizeFor.wdExportOptimizeForPrint,
            WdExportRange.wdExportAllDocument
        );
    }
    catch
    {
        pdfPath = null;
    }
    finally
    {
        objPres.Close();
    }
    return pdfPath;
}

9
对于那些不知道需要在计算机上安装Office才能使用Microsoft Interop库的人,这里提醒一下。 - Sam Rueby
2
不错!我建议在 finally 块中设置 app.Visible = false; 并添加调用 app.Quit(); - Dan Korn

13

PDFCreator拥有一个COM组件,可以从.NET或VBScript中调用(下载包含示例)。

但是,我认为你只需要打印机-然后将其与Word的自动化混合使用,就可以开始了。


这个COM组件在哪里?“mik”是什么意思?那是不是应该是“mix”? - Shaul Behr
COM组件已经包含在下载中,同时也提供了示例。是的,那应该是“mix”。 - Mark Brackett
5
请注意 - 如果您选择这种方式,PDFCreator安装程序将捆绑恶意软件。自2009年以来,这一问题一直存在于PDFCreator中。 - Phil Gorley
2
@PhilGorley 恶意软件?而且这个答案得到了+8的赞... - Lzh
@Mzn - FWIW,注意不勾选插件安装对我总是有效的。我认为这与 Oracle 在 Java 安装程序中捆绑垃圾软件没有任何区别;尽管很烦人,但我并不认为这个问题值得放弃该软件(是的,好吧,PdfCreator 的广告软件可能比 Oracle 推送的任何东西都没用且更具侵入性……但我仍然不想要其中任何一个)。 - Mark Brackett
啊,所以你可以选择不安装它?我一直以为它会以隐蔽的方式安装!但是一个库并不需要被安装,最好将其提供为一堆库或易于构建的源代码。 - Lzh

6

有一次,有人让我将10000个Word文件转换为PDF,我经历了Word转PDF的痛苦。后来我用C#和Word互操作性完成了它,但速度很慢,而且如果我尝试使用电脑,它会崩溃...非常令人沮丧。

这使我发现可以摆脱互操作性及其缓慢的问题.....对于Excel,我使用(EPPLUS),然后我发现你可以获得一个免费的工具叫做Spire,它允许转换为PDF...但有限制!

http://www.e-iceblue.com/Introduce/free-doc-component.html#.VtAg4PmLRhE


谢谢你提供这个很好的解决方案,而且没有使用Interop。为什么这么难找到一个免费的docx转PDF转换器呢? - mbdavis
我对此充满希望,但免费版本只能输出3页PDF。如果您需要无限部署,则完整版非常昂贵。 - grinder22
grinder22 GemBox.Document还有一个带有大小限制的免费版本和一个付费版本。但是,它包括无版税部署,因此您可以构建和发布无限数量的项目而不需要额外费用。 - hertzogth

5

使用Microsoft.Office.Interop.Word轻松将WORD转换为PDF的代码和解决方案

using Word = Microsoft.Office.Interop.Word;

private void convertDOCtoPDF()
{

  object misValue = System.Reflection.Missing.Value;
  String  PATH_APP_PDF = @"c:\..\MY_WORD_DOCUMENT.pdf"

  var WORD = new Word.Application();

  Word.Document doc   = WORD.Documents.Open(@"c:\..\MY_WORD_DOCUMENT.docx");
  doc.Activate();

  doc.SaveAs2(@PATH_APP_PDF, Word.WdSaveFormat.wdFormatPDF, misValue, misValue, misValue, 
  misValue, misValue, misValue, misValue, misValue, misValue, misValue);

  doc.Close();
  WORD.Quit();


  releaseObject(doc);
  releaseObject(WORD);

}

添加以下步骤以释放内存:

private void releaseObject(object obj)
{
  try
  {
      System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
      obj = null;
  }
  catch (Exception ex)
  {
      //TODO
  }
  finally
  {
     GC.Collect();
  }
}

需要调用GC.Collect吗?难道没有其他方法只标记与下一个自动GC相关的内存部分以释放它们吗? - Preza8

2

这里似乎有一些相关信息:

在ASP.NET中将MS Word文档转换为PDF

此外,由于Office 2007具有发布为PDF功能,您可以使用Office自动化打开Word 2007中的*.DOC文件并另存为PDF。虽然我不太喜欢Office自动化,因为它速度较慢且容易挂起,但这只是一个建议...


2
Aspose可能可行,但价格过高。 - Shaul Behr

1

微软的Word PDF插件似乎是目前最好的解决方案,但需要考虑到它并不能将所有Word文档正确转换为PDF,在某些情况下,您会看到Word和输出PDF之间存在巨大差异。不幸的是,我找不到任何可以完全正确转换所有Word文档的API。

我找到的唯一解决方案是通过打印机驱动程序转换文档以确保转换100%正确。缺点是文档会排队并逐个转换,但您可以确信生成的PDF与Word文档布局完全相同。

我个人更喜欢使用UDC(通用文档转换器),并在服务器上安装了Foxit Reader(免费版本),然后通过启动“进程”并将其动词属性设置为“打印”来打印文档。您还可以使用FileSystemWatcher设置信号,以便在转换完成时发出通知。


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