摘要:在下一切運(yùn)行正常,但是到下文件的文件名和生成路徑就會(huì)發(fā)生變化,這里的不會(huì)被當(dāng)作路徑分隔符了,而是當(dāng)作文件名的一部分,其實(shí)修改起來也很簡單創(chuàng)建另一個(gè)線程啟動(dòng)服務(wù),老是會(huì)出現(xiàn)無法連接服務(wù)的異常。
php預(yù)覽word文檔的實(shí)現(xiàn) 以及實(shí)現(xiàn)過程中遇到的各種坑
在做軟件工程的課程設(shè)計(jì)的時(shí)候,我們小組選擇做一個(gè)資料分享網(wǎng)站,網(wǎng)站最重要的功能當(dāng)然就是上傳文件和下載文件。但是這中間就需要一個(gè)比較重要的過程:預(yù)覽。
預(yù)覽最終結(jié)果是一張長圖,很長很長的png圖片。大致可以分為下面這幾個(gè)步驟:
將WORD文檔轉(zhuǎn)為PDF
將PDF拆分,畢竟只是預(yù)覽,而不是查看全部,這里我設(shè)置的是預(yù)覽10頁
將PDF按頁轉(zhuǎn)換為PNG圖片
將所有的PNG圖片合并成一張長圖
四個(gè)步驟,分別需要用到不同的工具:
第一步:對于WORD轉(zhuǎn)PDF,在度娘的幫助下,我們決定使用Java語言實(shí)現(xiàn)這一功能。使用開源的openoffice+jodconverter來對WORD進(jìn)行轉(zhuǎn)換。首先我們要考慮php如何調(diào)用Java,很幸運(yùn),有一個(gè)叫做JavaBridge的東西為我們解決了這個(gè)問題,JavaBridge的使用在百度中有大量的博客教程(ps:雖然我對國內(nèi)這些博客互相抄襲,還錯(cuò)誤百出很看不習(xí)慣,但確實(shí)也有好的博客,并且數(shù)量很多);
然后就是要安裝OpenOffice,這個(gè)很簡單,無論是Windows還是Linux都不難(直接百度搜索openoffice安裝即可);
最后下載jodconverter的jar包,編寫程序?qū)ORD轉(zhuǎn)為PDF。
源碼如下
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文檔轉(zhuǎn)換為PDF * @param srcPath WORD文檔路徑 * @param desPath 目標(biāo)PDF保存路徑 * @param pages 轉(zhuǎn)換頁數(shù) * @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(); } // 調(diào)用openoffice服務(wù)線程 // String command = "C:Program Files (x86)OpenOffice 4programsoffice.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服務(wù) OpenOfficeConnection connection = new SocketOpenOfficeConnection( "127.0.0.1", 8100); connection.connect(); // 轉(zhuǎn)換word到pdf DocumentConverter converter = new OpenOfficeDocumentConverter( connection); converter.convert(inputFile, outputFile); // 關(guān)閉連接 connection.disconnect(); // 關(guān)閉進(jìn)程 p.destroy(); System.out.println("轉(zhuǎn)換完成!"); } }
在程序中我們創(chuàng)建一個(gè)線程來打開OpenOffice的服務(wù)Process p = Runtime.getRuntime().exec(command);這條代碼的作用相當(dāng)于在命令行(終端)輸入command字符串,而command字符串就是我們啟動(dòng)openoffice服務(wù)的命令。后面連接openoffice然后利用它提供的接口將WORD轉(zhuǎn)為PDF即可。(注意:注釋起來的command是Windows下的啟動(dòng)命令,因?yàn)閃indows系統(tǒng)和linux系統(tǒng)中openoffice安裝路徑不同,所以需要使用不同的路徑啟動(dòng)服務(wù),所以在安裝OpenOffice時(shí)一定要注意安裝路徑)
第二步:將一個(gè)大的PDF拆分為小的PDF,可能是PHP這方面的支持不夠,也可能是我對Java很有好感,這一步我選擇的是使用Apache的pdfbox結(jié)合Java實(shí)現(xiàn)的。在apache官網(wǎng)中找到pdfbox,下載fontbox-2.0.15.jar、pdfbox-2.0.15.jar、commons-logging-1.2.jar這三個(gè)jar包,但是我在apahce官網(wǎng)上面并沒有找到最后一個(gè)jar包,是在別人分享的百度云盤里面下載的,所以最后我會(huì)把我用到的所有jar包上傳到百度云并提供永久下載鏈接;獲得這三個(gè)jar包后編寫程序;
源碼如下
/** * 將一個(gè)大pdf拆分為小pdf * @param src 大PDF路徑 * @param dest 小PDF保存路徑 * @param pages 拆分頁數(shù) */ public void split(String src, String dest, int pages) { File srcFile = new File(src); if(!srcFile.exists()) { System.out.println("原文件不存在"); return; } // 如果目標(biāo)路徑的父目錄不存在,則創(chuàng)建 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文件總頁數(shù) int pageCount = pdf.getPages().getCount(); // 當(dāng)所需要的頁數(shù)大于總頁數(shù)時(shí),按最大總頁數(shù)進(jìn)行拆分 if(pages > pageCount) { pages = pageCount; } PDDocument newPdf = new PDDocument(); for(int i=0;i 第三步:將PDF轉(zhuǎn)為PNG圖片,很幸運(yùn)在pdfbox中提供了這樣的功能,所以這一步不需要任何工具包
直接就可以編寫代碼/** * 將pdf轉(zhuǎn)為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由于第二步和第三步用到了同樣的外部jar包,所以我把它們放在同一個(gè)項(xiàng)目,下面是完整的項(xiàng)目
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轉(zhuǎn)為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;ipageCount) { pages = pageCount; } PDDocument newPdf = new PDDocument(); for(int i=0;i 最后一個(gè)合并PNG,這個(gè)要求直接使用php即可實(shí)現(xiàn),不過需要GD2擴(kuò)展庫,如果是Windows下這個(gè)擴(kuò)展是自帶的,Linux下需要自己安裝擴(kuò)展$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具體的思想就是先創(chuàng)建一張空的長圖,然后將要合并的圖片一張一張放進(jìn)去(用的是imagecopy()函數(shù)),這里我做了一個(gè)間隔處理,每兩張圖片之間間隔了10像素。到目前為止貌似所有的問題都得到了解決,我們只需要將Java項(xiàng)目打包成jar包,放入JavaBridge所要求的jre環(huán)境的ext目錄中,就能完成所有的功能了。
但是,當(dāng)我將所有東西放入項(xiàng)目中運(yùn)行時(shí),會(huì)發(fā)生各種“意外”(特別是在Windows開發(fā),然后源碼移植到linux上時(shí)問題最為嚴(yán)重)。具體有哪些問題,下面我一一列舉,并且將之與我的項(xiàng)目結(jié)合在一起說明
由于系統(tǒng)不同,所以文件路徑的分隔符也不同,在windows下分隔符為"",而Linux下分隔符為"/",于是在我將PDF轉(zhuǎn)為PNG時(shí),這個(gè)問題出現(xiàn)了,現(xiàn)在回去看PDF轉(zhuǎn)PNG的源碼,會(huì)有這樣一條代碼File file = new File(dest + "" + i + ".png");如果你看懂了我的代碼,就會(huì)知道問題所在。在Windows下一切運(yùn)行正常,但是到Linux下PNG文件的文件名和生成路徑就會(huì)發(fā)生變化,這里的""不會(huì)被當(dāng)作路徑分隔符了,而是當(dāng)作文件名的一部分,其實(shí)修改起來也很簡單:File file = new File(dest + File.separator + i + ".png");
創(chuàng)建另一個(gè)線程啟動(dòng)openoffice服務(wù),老是會(huì)出現(xiàn)無法連接服務(wù)的異常。根據(jù)我的各種調(diào)試,發(fā)現(xiàn)有時(shí)候會(huì)有這樣的情況發(fā)生:在程序運(yùn)行到連接服務(wù)的時(shí)候,服務(wù)并沒有開啟。按理說開啟服務(wù)的代碼寫在連接服務(wù)之前,不應(yīng)該出現(xiàn)這樣的問題。我猜測是由于創(chuàng)建了另一個(gè)線程來啟動(dòng)服務(wù),而主線程并沒有停止,而會(huì)繼續(xù)執(zhí)行,如果主線程先執(zhí)行到連接服務(wù)的代碼,那么就會(huì)出現(xiàn)這個(gè)錯(cuò)誤。雖然是猜測,我覺得八九不離十了,有兩種方式解決這個(gè)問題:
第一種就是線程等待,讓主線程等待,直到另一個(gè)線程執(zhí)行完畢后喚醒主線程;
第二種就是讓openoffice服務(wù)長期開啟,而不需要在程序中啟動(dòng)服務(wù);
由于此時(shí)處于開發(fā)初期,小組選擇先長期開啟服務(wù),等后期再改為線程等待策略。那么代碼也得做相應(yīng)的修改,將啟動(dòng)openoffice服務(wù)的代碼刪除即可,但是要記住需要手動(dòng)啟動(dòng)服務(wù)。如果web網(wǎng)站放在遠(yuǎn)程服務(wù)器上,而且只能用終端進(jìn)行遠(yuǎn)程連接沒有圖形界面時(shí),JavaBridge和openoffice服務(wù)就必須放在后臺(tái)執(zhí)行了,還好Linux有直接提供將進(jìn)程轉(zhuǎn)為后臺(tái)執(zhí)行的命令,這都不是大問題。
第一個(gè)問題和第二個(gè)問題需要不斷的嘗試,才能發(fā)現(xiàn)問題,浪費(fèi)了大部分時(shí)間。最后一個(gè)問題和Java編程經(jīng)驗(yàn)有很大關(guān)系了。前面提到我們需要將Java項(xiàng)目打包成jar包,而且需要將外部jar包也放入其中。而eclipse在打包的時(shí)候不能包含外部jar包(這里打包需要選擇JAR File而不能選擇Runnable Jar File),我們得想辦法將外部jar包塞進(jìn)去。這里我提供三種方法,但是我只測試過其中一種方法。
方法一:將打包好的jar包用rar打開,將外部jar包直接復(fù)制到里面,至于復(fù)制到哪里,根據(jù)程序中import外部jar包張的類所使用的路徑來判斷,實(shí)在判斷不出來就一個(gè)目錄一個(gè)目錄嘗試。方法二:將外部jar包解壓縮成許多class文件,將class文件復(fù)制到目標(biāo)jar包中,這種方式我通過了測試。例如:將jodconverter的jar包解壓縮后,有四個(gè)文件夾(com、drafts、org、META-INT),將這四個(gè)文件夾復(fù)制到目標(biāo)jar包的頂層目錄中。
方法三:如果能找到外部jar包的源代碼,可以將源代碼直接復(fù)制到項(xiàng)目中,跟項(xiàng)目一起打包成jar。這里的源代碼指的是.java文件而不是.class文件,這種方式應(yīng)該百分之百能成,但是一般想要找到源代碼很難。
總結(jié)一下:jar文件相當(dāng)于一個(gè)壓縮包,可以使用winrar這樣的壓縮軟件打開,并且往里面加入其他文件;
編寫程序中如果使用到路徑,不要直接用""或"/",使用編程語言中提供的常量來表示分隔符,例如Java中的File.separator,php中的DIRECTORY_SEPARATOR常量;
排查錯(cuò)誤的時(shí)候,要結(jié)合前端和數(shù)據(jù)庫一起進(jìn)行排查,同時(shí)可以通過輸入日志判斷錯(cuò)誤位置,php中提供了error_log()函數(shù)輸入日志。
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聯(lián)系方式(qq):1518542802
若是覺得這篇博客有地方不明白可以加我的qq問我,在下必然知無不言言無不盡。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/74162.html
摘要:在下一切運(yùn)行正常,但是到下文件的文件名和生成路徑就會(huì)發(fā)生變化,這里的不會(huì)被當(dāng)作路徑分隔符了,而是當(dāng)作文件名的一部分,其實(shí)修改起來也很簡單創(chuàng)建另一個(gè)線程啟動(dòng)服務(wù),老是會(huì)出現(xiàn)無法連接服務(wù)的異常。 php預(yù)覽word文檔的實(shí)現(xiàn) 以及實(shí)現(xiàn)過程中遇到的各種坑 在做軟件工程的課程設(shè)計(jì)的時(shí)候,我們小組選擇做一個(gè)資料分享網(wǎng)站,網(wǎng)站最重要的功能當(dāng)然就是上傳文件和下載文件。但是這中間就需要一個(gè)比較重要的過...
摘要:在下一切運(yùn)行正常,但是到下文件的文件名和生成路徑就會(huì)發(fā)生變化,這里的不會(huì)被當(dāng)作路徑分隔符了,而是當(dāng)作文件名的一部分,其實(shí)修改起來也很簡單創(chuàng)建另一個(gè)線程啟動(dòng)服務(wù),老是會(huì)出現(xiàn)無法連接服務(wù)的異常。 php預(yù)覽word文檔的實(shí)現(xiàn) 以及實(shí)現(xiàn)過程中遇到的各種坑 在做軟件工程的課程設(shè)計(jì)的時(shí)候,我們小組選擇做一個(gè)資料分享網(wǎng)站,網(wǎng)站最重要的功能當(dāng)然就是上傳文件和下載文件。但是這中間就需要一個(gè)比較重要的過...
摘要:概述工欲善其事必先利其器,如果現(xiàn)在要評選數(shù)據(jù)科學(xué)中最好用的編輯器注意一定是可以通過訪問的,和一定是角逐的最大熱門,正確使用編輯器可以很大地提升我們的工作效率。 概述 showImg(https://segmentfault.com/img/bVAdol); 工欲善其事必先利其器,如果現(xiàn)在要評選數(shù)據(jù)科學(xué)中最好用的Web 編輯器(注意一定是可以通過Web訪問的),RStudio和Jupyt...
摘要:模板替換的方式制作簡歷在許多招聘網(wǎng)站都有一個(gè)簡歷下載的功能,如何用實(shí)現(xiàn)呢在里面就有一個(gè)非常簡單的生成一個(gè)文檔,向文檔中插入一些文字。安裝創(chuàng)建控制器及方法用于測試,并建立路由。 PHP操作word有一個(gè)非常好用的輪子,就是phpword,該輪子可以在github上查找到(PHPOffice/PHPWord)。上面有較為詳細(xì)的例子和代碼,其中里面的源碼包含有一些常用的操作例子,包括設(shè)置頁眉...
閱讀 1067·2021-11-23 09:51
閱讀 2412·2021-09-29 09:34
閱讀 3149·2019-08-30 14:20
閱讀 1044·2019-08-29 14:14
閱讀 3182·2019-08-29 13:46
閱讀 1076·2019-08-26 13:54
閱讀 1633·2019-08-26 13:32
閱讀 1426·2019-08-26 12:23