在Java中将docx转换为pdf

34

我正在尝试将一个包含表格和图片的docx文件转换为pdf格式的文件。

我已经到处搜索但没有得到正确的解决方案,请提供正确的解决方案:

这是我尝试过的:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.poi.xwpf.converter.pdf.PdfConverter;
import org.apache.poi.xwpf.converter.pdf.PdfOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

public class TestCon {

    public static void main(String[] args) {
        TestCon cwoWord = new TestCon();
        System.out.println("Start");
        cwoWord.ConvertToPDF("D:\\Test.docx", "D:\\Test1.pdf");
    }

    public void ConvertToPDF(String docPath, String pdfPath) {
        try {
            InputStream doc = new FileInputStream(new File(docPath));
            XWPFDocument document = new XWPFDocument(doc);
            PdfOptions options = PdfOptions.create();
            OutputStream out = new FileOutputStream(new File(pdfPath));
            PdfConverter.getInstance().convert(document, out, options);
            System.out.println("Done");
        } catch (FileNotFoundException ex) {
            System.out.println(ex.getMessage());
        } catch (IOException ex) {

            System.out.println(ex.getMessage());
        }
    }

}

异常:

Exception in thread "main" java.lang.IllegalAccessError: tried to access method org.apache.poi.util.POILogger.log(ILjava/lang/Object;)V from class org.apache.poi.openxml4j.opc.PackageRelationshipCollection
at org.apache.poi.openxml4j.opc.PackageRelationshipCollection.parseRelationshipsPart(PackageRelationshipCollection.java:313)
at org.apache.poi.openxml4j.opc.PackageRelationshipCollection.<init>(PackageRelationshipCollection.java:162)
at org.apache.poi.openxml4j.opc.PackageRelationshipCollection.<init>(PackageRelationshipCollection.java:130)
at org.apache.poi.openxml4j.opc.PackagePart.loadRelationships(PackagePart.java:559)
at org.apache.poi.openxml4j.opc.PackagePart.<init>(PackagePart.java:112)
at org.apache.poi.openxml4j.opc.PackagePart.<init>(PackagePart.java:83)
at org.apache.poi.openxml4j.opc.PackagePart.<init>(PackagePart.java:128)
at org.apache.poi.openxml4j.opc.ZipPackagePart.<init>(ZipPackagePart.java:78)
at org.apache.poi.openxml4j.opc.ZipPackage.getPartsImpl(ZipPackage.java:239)
at org.apache.poi.openxml4j.opc.OPCPackage.getParts(OPCPackage.java:665)
at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:274)
at org.apache.poi.util.PackageHelper.open(PackageHelper.java:39)
at org.apache.poi.xwpf.usermodel.XWPFDocument.<init>(XWPFDocument.java:121)
at test.TestCon.ConvertToPDF(TestCon.java:31)
at test.TestCon.main(TestCon.java:25)

我的要求是创建一个Java代码,将现有的docx文档转换为带有正确格式和对齐方式的pdf。

请提供建议。

使用的Jars:

已更新的Jars


1
如果你坚持使用ApachePOI,这里还有另一个答案:https://dev59.com/PG025IYBdhLWcg3wIyKf - Krzysztof Cichocki
1
Bruno只能帮助你关于iText的问题。但是你的问题不是关于iText,而是关于Apache POI。无论如何,如果你标记了一个没有评论的人,他们将不会收到通知。Stack Overflow这样做是为了防止标签垃圾邮件,这也是你所做的描述。 - Amedee Van Gasse
7
如果你不断改变目标,没有人能够帮助你。在过去的15分钟内,你已经多次编辑帖子并更换了同样多的库。 - VivekRatanSinha
@VivekRatanSinha,我正在尝试不同的可能性,你能帮忙编写将docx转换为带有表格的pdf的代码吗? - user1999397
1
在你的许多编辑中,我可以看到com.lowagie在你的异常中。这意味着你使用的是一个古老的 iText 版本,2.1.7 或更早版本,已经至少有8年历史了。既然你似乎信任 Bruno Lowagie 的专业知识,那么你应该熟悉他对仍在使用如此旧的 iText 版本的人的看法。 - Amedee Van Gasse
显示剩余9条评论
11个回答

31

除了 VivekRatanSinha 的 回答,我还想发布完整的代码和所需的jar文件,以供将来需要的人使用。

代码:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.poi.xwpf.converter.pdf.PdfConverter;
import org.apache.poi.xwpf.converter.pdf.PdfOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

public class WordConvertPDF {
    public static void main(String[] args) {
        WordConvertPDF cwoWord = new WordConvertPDF();
        cwoWord.ConvertToPDF("D:/Test.docx", "D:/Test.pdf");
    }

    public void ConvertToPDF(String docPath, String pdfPath) {
        try {
            InputStream doc = new FileInputStream(new File(docPath));
            XWPFDocument document = new XWPFDocument(doc);
            PdfOptions options = PdfOptions.create();
            OutputStream out = new FileOutputStream(new File(pdfPath));
            PdfConverter.getInstance().convert(document, out, options);
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }
}

和JARS:

所需的JARS

祝您愉快 :)


@user1999397,你能提供完整的示例吗?因为这些库彼此之间存在依赖关系。 - vickyVick
7
请将图片中的jar替换为pom。 - Ulphat
我跟着你的代码和库,出现了错误:未找到有效条目或内容,这不是一个有效的OOXML(Office Open XML)文件。 - superup

18
您缺少一些库。
我添加了以下库后,能够运行您的代码:
    Apache POI 3.15
    org.apache.poi.xwpf.converter.core-1.0.6.jar
    org.apache.poi.xwpf.converter.pdf-1.0.6.jar
    fr.opensagres.xdocreport.itext.extension-2.0.0.jar
    itext-2.1.7.jar
    ooxml-schemas-1.3.jar
我已经成功将一个包含表格、图片和各种格式的6页Word文档(.docx)转换为PDF。

1
请注意,尽管包名相同,但这并不是使用POI进行转换。只有ooxml-schemas-1.3.jar来自Apache POI。其余的来自opensagresitext项目。 - jmarkmurphy
1
我的方法并不是重新发明轮子,只是让需要的代码运行起来。 - VivekRatanSinha
1
你的回答没有问题,只是我不想让任何人误以为 org.apache.poi.xwpf.converter.* 包是 Apache POI 的一部分。 - jmarkmurphy
谢谢您先生,这对我很有帮助。 - user1999397
1
@BakedInhalf 位置在 https://mvnrepository.com/artifact/org.apache.poi/ooxml-schemas/1.3。 - VivekRatanSinha
显示剩余6条评论

16

我将提供3种方法将docx转换为pdf:

  1. 使用itext、opensagres和apache poi

代码:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions;
import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

public class ConvertDocToPdfitext {

  public static void main(String[] args) {
    System.out.println( "Starting conversion!!!" );
    ConvertDocToPdfitext cwoWord = new ConvertDocToPdfitext();
    cwoWord.ConvertToPDF("C:/Users/avijit.shaw/Desktop/testing/docx/Account Opening Prototype Details.docx", "C:/Users/avijit.shaw/Desktop/testing/docx/Test-1.pdf");
    System.out.println( "Ending conversion!!!" );
  }

  public void ConvertToPDF(String docPath, String pdfPath) {
    try {
        InputStream doc = new FileInputStream(new File(docPath));
        XWPFDocument document = new XWPFDocument(doc);
        PdfOptions options = PdfOptions.create();
        OutputStream out = new FileOutputStream(new File(pdfPath));
        PdfConverter.getInstance().convert(document, out, options);
    } catch (IOException ex) {
        System.out.println(ex.getMessage());
    }
  }
}

依赖项: 使用Maven解析依赖项。

最新版本的fr.opensagres.poi.xwpf.converter.core 2.0.2与apache poi 4.0.1和itext 2.17一起运行。您只需要在Maven中添加以下依赖项,然后Maven将自动下载所有相关的依赖项。(更新了您的Maven项目,因此它下载了所有这些库及其所有依赖项)

<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>fr.opensagres.poi.xwpf.converter.pdf</artifactId>
    <version>2.0.2</version>
</dependency>
  1. 使用 Documents4j

注意:您需要在运行此代码的计算机上安装MS Office。

代码:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;

public class Document4jApp {

  public static void main(String[] args) {

      File inputWord = new File("C:/Users/avijit.shaw/Desktop/testing/docx/Account Opening Prototype Details.docx");
      File outputFile = new File("Test_out.pdf");
      try  {
          InputStream docxInputStream = new FileInputStream(inputWord);
          OutputStream outputStream = new FileOutputStream(outputFile);
          IConverter converter = LocalConverter.builder().build();         
          converter.convert(docxInputStream).as(DocumentType.DOCX).to(outputStream).as(DocumentType.PDF).execute();
          outputStream.close();
          System.out.println("success");
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
}

依赖项:使用 Maven 解决依赖关系。

<dependency>
    <groupId>com.documents4j</groupId>
    <artifactId>documents4j-local</artifactId>
    <version>1.0.3</version>
</dependency>
<dependency>
    <groupId>com.documents4j</groupId>
    <artifactId>documents4j-transformer-msoffice-word</artifactId>
    <version>1.0.3</version>
</dependency>
  1. 使用OpenOffice NuOil

注意:您需要在运行此代码的计算机上安装OpenOffice。

代码:

import java.io.File;
import com.sun.star.beans.PropertyValue;
import com.sun.star.comp.helper.BootstrapException;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.frame.XDesktop;
import com.sun.star.frame.XStorable;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.uno.Exception;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;

import ooo.connector.BootstrapSocketConnector;

public class App {
  public static void main(String[] args) throws Exception, BootstrapException {
      System.out.println("Stating conversion!!!");
      // Initialise
      String oooExeFolder = "C:\\Program Files (x86)\\OpenOffice 4\\program"; //Provide path on which OpenOffice is installed
      XComponentContext xContext = BootstrapSocketConnector.bootstrap(oooExeFolder);
      XMultiComponentFactory xMCF = xContext.getServiceManager();
  
      Object oDesktop = xMCF.createInstanceWithContext("com.sun.star.frame.Desktop", xContext);
  
      XDesktop xDesktop = (XDesktop) UnoRuntime.queryInterface(XDesktop.class, oDesktop);
  
      // Load the Document
      String workingDir = "C:/Users/avijit.shaw/Desktop/testing/docx/"; //Provide directory path of docx file to be converted
      String myTemplate = workingDir + "Account Opening Prototype Details.docx"; // Name of docx file to be converted
  
      if (!new File(myTemplate).canRead()) {
        throw new RuntimeException("Cannot load template:" + new File(myTemplate));
      }
  
      XComponentLoader xCompLoader = (XComponentLoader) UnoRuntime
          .queryInterface(com.sun.star.frame.XComponentLoader.class, xDesktop);
  
      String sUrl = "file:///" + myTemplate;
  
      PropertyValue[] propertyValues = new PropertyValue[0];
  
      propertyValues = new PropertyValue[1];
      propertyValues[0] = new PropertyValue();
      propertyValues[0].Name = "Hidden";
  

          propertyValues[0].Value = new Boolean(true);
  
      XComponent xComp = xCompLoader.loadComponentFromURL(sUrl, "_blank", 0, propertyValues);
  
      // save as a PDF
      XStorable xStorable = (XStorable) UnoRuntime.queryInterface(XStorable.class, xComp);
  
      propertyValues = new PropertyValue[2];
      // Setting the flag for overwriting
      propertyValues[0] = new PropertyValue();
      propertyValues[0].Name = "Overwrite";
      propertyValues[0].Value = new Boolean(true);
      // Setting the filter name
      propertyValues[1] = new PropertyValue();
      propertyValues[1].Name = "FilterName";
      propertyValues[1].Value = "writer_pdf_Export";
  
      // Appending the favoured extension to the origin document name
      String myResult = workingDir + "letterOutput.pdf"; // Name of pdf file to be output
      xStorable.storeToURL("file:///" + myResult, propertyValues);
  
      System.out.println("Saved " + myResult);
  
      // shutdown
      xDesktop.terminate();
  }
}

依赖项:使用Maven来解决依赖关系。

<!-- https://mvnrepository.com/artifact/org.openoffice/unoil -->
    <dependency>
        <groupId>org.openoffice</groupId>
        <artifactId>unoil</artifactId>
        <version>3.2.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.openoffice/juh -->
    <dependency>
        <groupId>org.openoffice</groupId>
        <artifactId>juh</artifactId>
        <version>3.2.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.openoffice/bootstrap-connector -->
    <dependency>
        <groupId>org.openoffice</groupId>
        <artifactId>bootstrap-connector</artifactId>
        <version>0.1.1</version>
    </dependency>

当使用Documents4j时,请记得在 execute(); 之后调用 converter.shutDown(); - skyoxZ
在从右到左书写的语言中,Opensagres 的输出效果不佳,但是 Documents4j 可以正常使用。 - Amir Azizkhani

8
如果您的文档非常复杂,且您需要在Linux/Unix上进行转换,则在此线程中建议的三种主要选项中选择任意一种都可能会有点痛苦。
我可以建议一种解决方案,即使用Gotenberg:一个基于Docker的无状态API,用于将HTML、Markdown和Office文档转换为PDF。
  • 启动容器$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:7
  • 向容器发出请求。这里是如何使用curl
$ curl \
    --request POST 'http://localhost:3000/forms/libreoffice/convert' \
    --form 'files=@"/path/to/file.docx"' \
    -o result.pdf

将其部署到您的基础架构中(例如作为单独的微服务),并从您的Java服务发出简单的HTTP请求来触发它。在响应中获取您的PDF文件,然后对其进行任何操作。

已测试并且运行良好!


8

我已经做了很多研究,发现Documents4j是将docx转换为pdf的最佳免费API。在 对齐字体 等方面,Documents4j表现得非常出色。

Maven依赖项:

<dependency>
    <groupId>com.documents4j</groupId>
    <artifactId>documents4j-local</artifactId>
    <version>1.0.3</version>
</dependency>
<dependency>
    <groupId>com.documents4j</groupId>
    <artifactId>documents4j-transformer-msoffice-word</artifactId>
    <version>1.0.3</version>
</dependency>

使用以下代码将docx转换为pdf。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;

public class Document4jApp {

    public static void main(String[] args) {

        File inputWord = new File("Tests.docx");
        File outputFile = new File("Test_out.pdf");
        try  {
            InputStream docxInputStream = new FileInputStream(inputWord);
            OutputStream outputStream = new FileOutputStream(outputFile);
            IConverter converter = LocalConverter.builder().build();
            converter.convert(docxInputStream).as(DocumentType.DOCX).to(outputStream).as(DocumentType.PDF).execute();
            outputStream.close();
            System.out.println("success");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2
documents4j存在问题,需要安装MS组件,因此在Linux上几乎无法使用。https://github.com/documents4j/documents4j/issues/41 - Serhii Povísenko
2
execute();之后记得调用converter.shutDown(); - skyoxZ
@povis,是的,你说得对,documents4j在Linux环境下无法使用。请使用docx4j,它适用于Windows和Linux环境。https://dev59.com/uHA75IYBdhLWcg3w794Y#65403145 - Sathiamoorthy
1
这是唯一一个对我进行docx->pdf转换起作用的Java开源库。我尝试过以下3个库:apache POI、fr.opensagres(使用apache POI进行转换)和docx4j。感谢@Sathia。此代码在Windows机器上测试通过。 - brebDev
请注意,这在基于UNIX的系统中无法工作。不幸的是,这在Windows本地机器上对我非常有效,但在Bamboo中却不行。 - brebDev

2
您需要添加以下Maven依赖项。
  <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>4.0.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>4.0.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-scratchpad</artifactId>
        <version>4.0.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml-schemas</artifactId>
        <version>4.0.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-excelant</artifactId>
        <version>4.0.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-examples</artifactId>
        <version>4.0.1</version>
    </dependency>

    <dependency>
        <groupId>fr.opensagres.xdocreport</groupId>
        <artifactId>org.apache.poi.xwpf.converter.core</artifactId>
        <version>1.0.6</version>
    </dependency>

    <dependency>
        <groupId>fr.opensagres.xdocreport</groupId>
        <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
        <version>1.0.6</version>
    </dependency>

1

我有一个非常复杂的文档,微软 Graph Api 帮助生成了正确的 PDF 文件,并且与输入的 Docx 格式完全一致。

以下链接可帮助完成应用程序注册,设置 API 密钥/密码以访问 Graph Api: https://medium.com/medialesson/convert-files-to-pdf-using-microsoft-graph-azure-functions-20bc84d2adc4

https://devzigma.com/java/upload-files-to-sharepoint-using-java/

上传docx文档后,点击此处即可下载相应的pdf版本:https://learn.microsoft.com/en-us/graph/api/driveitem-get-content-format?view=graph-rest-1.0&tabs=java


1

Docx4j是开源的,也是将Docx转换为PDF的最佳API之一,没有任何对齐或字体问题。

Maven依赖项

<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j-JAXB-Internal</artifactId>
    <version>8.0.0</version>
</dependency>
<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
    <version>8.0.0</version>
</dependency>
<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j-JAXB-MOXy</artifactId>
    <version>8.0.0</version>
</dependency>
<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j-export-fo</artifactId>
    <version>8.0.0</version>
</dependency>

代码:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;

import org.docx4j.Docx4J;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;

public class DocToPDF {

    public static void main(String[] args) {
        
        try {
            InputStream templateInputStream = new FileInputStream("D:\\\\Workspace\\\\New\\\\Sample.docx");
            WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(templateInputStream);
            MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();

            String outputfilepath = "D:\\\\Workspace\\\\New\\\\Sample.pdf";
            FileOutputStream os = new FileOutputStream(outputfilepath);
            Docx4J.toPDF(wordMLPackage,os);
            os.flush();
            os.close();
        } catch (Throwable e) {

            e.printStackTrace();
        } 
    }

}

1

只需手动添加一个依赖项(其他依赖项应自动拉取)。截至目前,最新版本为2.0.2。

Gradle:

dependencies {
    // What you should already have
    implementation "org.apache.poi:poi-ooxml:latest.release"


    // ADD THE BELOW LINE TO DEPENDENCIES BLOCK IN build.gradle
    implementation 'fr.opensagres.xdocreport:fr.opensagres.poi.xwpf.converter.pdf:2.0.2'
}

仅限Maven:
<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>fr.opensagres.poi.xwpf.converter.pdf</artifactId>
    <version>2.0.2</version>
</dependency>

0

我使用这段代码。

private byte[] toPdf(ByteArrayOutputStream docx) {
    InputStream isFromFirstData = new ByteArrayInputStream(docx.toByteArray());

    XWPFDocument document = new XWPFDocument(isFromFirstData);
    PdfOptions options = PdfOptions.create();

    //make new file in c:\temp\
    OutputStream out = new FileOutputStream(new File("c:\\tmp\\HelloWord.pdf"));
    PdfConverter.getInstance().convert(document, out, options);

    //return byte array for return in http request.
    ByteArrayOutputStream pdf = new ByteArrayOutputStream();
    PdfConverter.getInstance().convert(document, pdf, options);

    document.write(pdf);
    document.close();
    return pdf.toByteArray();
}

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