2015-02-10 24 views
2

我想使用wkhtmltopdf将html文件转换为pdf文件。因为我的html文件可以是任何外观和感觉,所以wkhtmltopdf是我最好的选择,因为它使用webkit呈现html文件。现在,问题是我想用Java来做同样的事情,但wkhtmltopdf不提供任何Java API。如何在java中使用wkhtmltopdf

我可以使用Runtime.exec()ProcessBuilder从Java分离出一个新进程,并在该进程中使用wkhtmtopdf创建pdf输出。但是,当我开发一个基于Web的应用程序时,我不允许在服务器中创建这么多的新进程。

是否有其他方法可以使用wkhtmltopdf?我真的很想使用它,因为它给了我确切的输出。

或者,是否有任何其他开源的浏览器引擎提供Java API,可以呈现我的HTML页面,就像wkhtmltopdf

回答

1

wkhtmltopdf有一个C API。然后,您可以使用JNI进行Java到C的通信。

编辑:还有一个Java包装:wkhtmltopdf-wrapper

1

请记住,运行您的Java代码的系统必须安装wkhtmltopdf,以用于我在此说的任何工作......转到www.wkhtmltopdf.org并下载您需要的版本。

我知道这是旧的,现在你已经明白了这一点,但如果你不想使用JNI或JNA来做到这一点,你可以很简单地通过.exec调用你的系统。

这里是一个类,你想要什么呢,而无需使用JNI或JNA大惊小怪:

public class MegaSimplePdfGenerator { 

    public void makeAPdf() throws InterruptedException, IOException { 
     Process wkhtml; // Create uninitialized process 
     String command = "wkhtmltopdf http://www.google.com /Users/Shared/output.pdf"; // Desired command 

     wkhtml = Runtime.getRuntime().exec(command); // Start process 
     IOUtils.copy(wkhtml.getErrorStream(), System.err); // Print output to console 

     wkhtml.waitFor(); // Allow process to run 
    } 
} 

必须以某种方式结合到一个输入流的过程中运行。这可以是inputStream或errorStream。在这种情况下,因为我只是在写一个文件,所以我继续将System.err连接到wkhtml进程的errorStream。

如何只使用流!

如果你想HTML源来自流和/或目标PDF写入到流那么你可以使用一个“ - ”为“URI”,而不是一个普通字符串。

示例:wkhtmltopdf - -wkhtmltopdf /Users/Shared/somefile.html -

然后可以捕获输入和输出流和写入,并根据需要读出。

如果你只连接到一个单一的流,那么你不需要使用线程,你不会得到一个场景,在这个场景中,这些流彼此无休止地等待着。

但是,如果您正在使用HTML源和PDF目的地的流,那么您必须使用线程来完成此过程。

注意:请记住,OutputStream必须刷新并关闭wkhtmltopdf才能开始构建PDF并将结果流式传输!

例子:

public class StreamBasedPdfGenerator { 
    public void makeAPdfWithStreams() throws InterruptedException, IOException { 
     Process wkhtml; // Create uninitialized process 

     // Start by setting up file streams 
     File destinationFile = new File("/Users/Shared/output.pdf"); 
     File sourceFile = new File("/Users/Shared/pdfPrintExample.html"); 

     FileInputStream fis = new FileInputStream(sourceFile); 
     FileOutputStream fos = new FileOutputStream(destinationFile); 

     String command = "wkhtmltopdf - -"; // Desired command 

     wkhtml = Runtime.getRuntime().exec(command); // Start process 

     Thread errThread = new Thread(() -> { 
      try { 
       IOUtils.copy(wkhtml.getErrorStream(), System.err); 
      } catch (IOException e) { 
       throw new RuntimeException(e); 
      } 
     }); 
     Thread htmlReadThread = new Thread(() -> { 
      try { 
       IOUtils.copy(fis, wkhtml.getOutputStream()); 
       wkhtml.getOutputStream().flush(); 
       wkhtml.getOutputStream().close(); 
      } catch (IOException e) { 
       throw new RuntimeException(e); 
      } 
     }); 
     Thread pdfWriteThread = new Thread(() -> { 
      try { 
       IOUtils.copy(wkhtml.getInputStream(), fos); 
      } catch (IOException e) { 
       throw new RuntimeException(e); 
      } 
     }); 

     // Do NOT use Run... it should be clear why, you want them to all be going at the same time. 
     errThread.start(); 
     pdfWriteThread.start(); 
     htmlReadThread.start(); 

     // Connect HTML Source Stream to wkhtmltopdf 
     // Connect PDF Source Stream from wkhtmltopdf to the Destination file steam 

     wkhtml.waitFor(); // Allow process to run 
    } 
} 

流,当你在Web服务器上运行本作是巨大的,要避免创建临时HTML或PDF文件,你可以简单地通过捕捉和写作流回响应到HTTP响应流。

我希望这可以帮助别人!

相关问题