在作軟件工程的課程設計的時候,咱們小組選擇作一個資料分享網站,網站最重要的功能固然就是上傳文件和下載文件。可是這中間就須要一個比較重要的過程:預覽。
預覽最終結果是一張長圖,很長很長的png圖片。大體能夠分爲下面這幾個步驟:php
四個步驟,分別須要用到不一樣的工具:前端
第一步:對於WORD轉PDF,在度孃的幫助下,咱們決定使用Java語言實現這一功能。使用開源的openoffice+jodconverter來對WORD進行轉換。首先咱們要考慮php如何調用Java,很幸運,有一個叫作JavaBridge的東西爲咱們解決了這個問題,JavaBridge的使用在百度中有大量的博客教程(ps:雖然我對國內這些博客互相抄襲,還錯誤百出很看不習慣,但確實也有好的博客,而且數量不少);java
而後就是要安裝OpenOffice,這個很簡單,不管是Windows仍是Linux都不難(直接百度搜索openoffice安裝便可);
最後下載jodconverter的jar包,編寫程序將WORD轉爲PDF。linux
源碼以下web
import java.io.File; import java.io.IOException; import com.artofsolving.jodconverter.DocumentConverter; import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection; import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection; import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter; public class PDFConverter { /** * 將WORD文檔轉換爲PDF * @param srcPath WORD文檔路徑 * @param desPath 目標PDF保存路徑 * @param pages 轉換頁數 * @throws IOException */ public void Word2Pdf(String srcPath, String desPath) throws IOException { // 源文件目錄 File inputFile = new File(srcPath); if (!inputFile.exists()) { System.out.println("源文件不存在!"); System.out.println(srcPath + ", " + desPath); return; } // 輸出文件目錄 File outputFile = new File(desPath); if (!outputFile.getParentFile().exists()) { outputFile.getParentFile().mkdirs(); } // 調用openoffice服務線程 // String command = "C:\\Program Files (x86)\\OpenOffice 4\\program\\soffice.exe -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\""; String command = "/opt/openoffice4/program/soffice -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\" -nofirststartwizard"; Process p = Runtime.getRuntime().exec(command); // 鏈接openoffice服務 OpenOfficeConnection connection = new SocketOpenOfficeConnection( "127.0.0.1", 8100); connection.connect(); // 轉換word到pdf DocumentConverter converter = new OpenOfficeDocumentConverter( connection); converter.convert(inputFile, outputFile); // 關閉鏈接 connection.disconnect(); // 關閉進程 p.destroy(); System.out.println("轉換完成!"); } }
在程序中咱們建立一個線程來打開OpenOffice的服務
Process p = Runtime.getRuntime().exec(command);
這條代碼的做用至關於在命令行(終端)輸入command字符串,而command字符串就是咱們啓動openoffice服務的命令。後面鏈接openoffice而後利用它提供的接口將WORD轉爲PDF便可。(注意:
註釋起來的command是Windows下的啓動命令,由於Windows系統和linux系統中openoffice安裝路徑不一樣,因此須要使用不一樣的路徑啓動服務,因此在安裝OpenOffice時必定要注意安裝路徑)
第二步:將一個大的PDF拆分爲小的PDF,多是PHP這方面的支持不夠,也多是我對Java頗有好感,這一步我選擇的是使用Apache的pdfbox結合Java實現的。在apache官網中找到pdfbox,下載fontbox-2.0.15.jar、pdfbox-2.0.15.jar、commons-logging-1.2.jar這三個jar包,可是我在apahce官網上面並無找到最後一個jar包,是在別人分享的百度雲盤裏面下載的,因此最後我會把我用到的全部jar包上傳到百度雲並提供永久下載連接;得到這三個jar包後編寫程序;數據庫
源碼以下apache
/** * 將一個大pdf拆分爲小pdf * @param src 大PDF路徑 * @param dest 小PDF保存路徑 * @param pages 拆分頁數 */ public void split(String src, String dest, int pages) { File srcFile = new File(src); if(!srcFile.exists()) { System.out.println("原文件不存在"); return; } // 若是目標路徑的父目錄不存在,則建立 File destFile = new File(dest); if(!destFile.getParentFile().exists()) { destFile.getParentFile().mkdirs(); } try { System.out.println("開始拆分"); // 加載原PDF文件 PDDocument pdf = PDDocument.load(srcFile, MemoryUsageSetting.setupTempFileOnly()); // 獲取原PDF文件總頁數 int pageCount = pdf.getPages().getCount(); // 當所須要的頁數大於總頁數時,按最大總頁數進行拆分 if(pages > pageCount) { pages = pageCount; } PDDocument newPdf = new PDDocument(); for(int i=0;i<pages;i++) { newPdf.addPage(pdf.getPage(i)); } newPdf.save(destFile); pdf.close(); newPdf.close(); System.out.println("拆分結束"); } catch (IOException e) { e.printStackTrace(); } }
第三步:將PDF轉爲PNG圖片,很幸運在pdfbox中提供了這樣的功能,因此這一步不須要任何工具包
直接就能夠編寫代碼
/** * 將pdf轉爲png圖片 * @param src 原pdf路徑 * @param dest 圖片的父目錄 */ public void Pdf2Png(String src, String dest) { File srcFile = new File(src); if(!srcFile.exists()) { System.out.println("源文件不存在"); return; } File destFile = new File(dest); if(!destFile.exists()) { destFile.mkdirs(); } try { PDDocument doc = PDDocument.load(srcFile); PDFRenderer renderer = new PDFRenderer(doc); int pageCount = doc.getNumberOfPages(); for(int i=0;i<pageCount;i++){ BufferedImage image = renderer.renderImageWithDPI(i, 300); File file = new File(dest + "\" + i + ".png"); ImageIO.write(image, "PNG", file); } doc.close(); } catch (IOException e) { e.printStackTrace(); } }
因爲第二步和第三步用到了一樣的外部jar包,因此我把它們放在同一個項目,下面是完整的項目編程
import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import org.apache.pdfbox.io.MemoryUsageSetting; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.rendering.PDFRenderer; public class PDFProcess { /** * 將pdf轉爲png圖片 * @param src 原pdf路徑 * @param dest 圖片的父目錄 */ public void Pdf2Png(String src, String dest) { File srcFile = new File(src); if(!srcFile.exists()) { System.out.println("源文件不存在"); return; } File destFile = new File(dest); if(!destFile.exists()) { destFile.mkdirs(); } try { PDDocument doc = PDDocument.load(srcFile); PDFRenderer renderer = new PDFRenderer(doc); int pageCount = doc.getNumberOfPages(); for(int i=0;i<pageCount;i++){ BufferedImage image = renderer.renderImageWithDPI(i, 300); File file = new File(dest + "\" + i + ".png"); ImageIO.write(image, "PNG", file); } doc.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 將一個大pdf拆分爲小pdf * @param src 大PDF路徑 * @param dest 小PDF保存路徑 * @param pages 拆分頁數 */ public void split(String src, String dest, int pages) { File srcFile = new File(src); if(!srcFile.exists()) { System.out.println("原文件不存在"); return; } // 若是目標路徑的父目錄不存在,則建立 File destFile = new File(dest); if(!destFile.getParentFile().exists()) { destFile.getParentFile().mkdirs(); } try { System.out.println("開始拆分"); // 加載原PDF文件 PDDocument pdf = PDDocument.load(srcFile, MemoryUsageSetting.setupTempFileOnly()); // 獲取原PDF文件總頁數 int pageCount = pdf.getPages().getCount(); // 當所須要的頁數大於總頁數時,按最大總頁數進行拆分 if(pages > pageCount) { pages = pageCount; } PDDocument newPdf = new PDDocument(); for(int i=0;i<pages;i++) { newPdf.addPage(pdf.getPage(i)); } newPdf.save(destFile); pdf.close(); newPdf.close(); System.out.println("拆分結束"); } catch (IOException e) { e.printStackTrace(); } } }
最後一個合併PNG,這個要求直接使用php便可實現,不過須要GD2擴展庫,若是是Windows下這個擴展是自帶的,Linux下須要本身安裝擴展
<?php /** * 豎直方向上合併圖片(合併爲png格式),目標圖片的寬度取全部圖片中寬度最大的那張,高度取全部圖片高度之和 * @param array 一組圖片的路徑 * @param String $dest 合併以後的圖片地址 */ public static function merge($source, String $dest) { $width = 0; // 合併後圖片的寬 $height = 0; // 合併後圖片的高 $arr = array(); for($i=0;$i<count($source);$i++) { $info = getimagesize($source[$i]); // 獲取圖片詳細信息(寬、高、類型等) // 獲取圖片類型 $type = image_type_to_extension($info[2], false); $fun = "Imagecreatefrom{$type}"; // 根據圖片類型構造一個符合該類型圖片的讀取函數 $arr[$i]['source'] = $fun($source[$i]); $arr[$i]['size'] = $info; if($arr[$i]['size'][0] > $width) { $width = $arr[$i]['size'][0]; } $height += $arr[$i]['size'][1]; } $merge = imagecreate($width, $height+10*count($source)); $space = imagecreate($width, 10); $dst_x = 0; $dst_y = 0; for($i=0;$i<count($source);$i++) { imagecopy($merge, $arr[$i]['source'], $dst_x, $dst_y, 0, 0, $arr[$i]['size'][0], $arr[$i]['size'][0]); imagecopy($merge, $space, $dst_x, $dst_y, 0, 0, $width, 10); $dst_y += $arr[$i]['size'][1]; } imagepng($merge, $dest); imagedestroy($merge); } ?>
具體的思想就是先建立一張空的長圖,而後將要合併的圖片一張一張放進去(用的是imagecopy()函數),這裏我作了一個間隔處理,每兩張圖片之間間隔了10像素。到目前爲止貌似全部的問題都獲得瞭解決,咱們只須要將Java項目打包成jar包,放入JavaBridge所要求的jre環境的ext目錄中,就能完成全部的功能了。windows
可是,當我將全部東西放入項目中運行時,會發生各類「意外」(特別是在Windows開發,而後源碼移植到linux上時問題最爲嚴重)。具體有哪些問題,下面我一一列舉,而且將之與個人項目結合在一塊兒說明服務器
File file = new File(dest + "\" + i + ".png");
若是你看懂了個人代碼,就會知道問題所在。在Windows下一切運行正常,可是到Linux下PNG文件的文件名和生成路徑就會發生變化,這裏的""不會被看成路徑分隔符了,而是看成文件名的一部分,其實修改起來也很簡單:File file = new File(dest + File.separator + i + ".png");
第一種就是線程等待,讓主線程等待,直到另外一個線程執行完畢後喚醒主線程;
第二種就是讓openoffice服務長期開啓,而不須要在程序中啓動服務;
因爲此時處於開發初期,小組選擇先長期開啓服務,等後期再改成線程等待策略。那麼代碼也得作相應的修改,將啓動openoffice服務的代碼刪除便可,可是要記住須要手動啓動服務。
方法一:將打包好的jar包用rar打開,將外部jar包直接複製到裏面,至於複製到哪裏,根據程序中import外部jar包張的類所使用的路徑來判斷,實在判斷不出來就一個目錄一個目錄嘗試。方法二:將外部jar包解壓縮成許多class文件,將class文件複製到目標jar包中,這種方式我經過了測試。例如:將jodconverter的jar包解壓縮後,有四個文件夾(com、drafts、org、META-INT),將這四個文件夾複製到目標jar包的頂層目錄中。
方法三:若是能找到外部jar包的源代碼,能夠將源代碼直接複製到項目中,跟項目一塊兒打包成jar。這裏的源代碼指的是.java文件而不是.class文件,這種方式應該百分之百能成,可是通常想要找到源代碼很難。
總結一下:
jar包的永久下載連接:
jodconverter:https://pan.baidu.com/s/1XwhiVhmlXxVvkPiiIkYi_Q
提取碼:1dgj
pdfbox:https://pan.baidu.com/s/19bPBsoJhEv-m0l5ZLlMZbg
提取碼:ymnt
JavaBridge:https://pan.baidu.com/s/1XKdC8vSLlmOGIGYRAmSQTA
提取碼:k3lb
聯繫方式(qq):1518542802如果以爲這篇博客有地方不明白能夠加個人qq問我,在下必然知無不言言無不盡。