1. 程式人生 > >PDF技術(一)-Java實現Office系列檔案轉PDF檔案

PDF技術(一)-Java實現Office系列檔案轉PDF檔案

最近,公司要求做個檔案轉pdf的調研報告,於是在網上找了一些實現方法,現在將這些方法做個對比,並記錄下來,以後或許有用呢,哈哈。

首先說一下需求,產品要求不能使用第三方軟體實現,因為這種實現方式效率不高,所以需要使用“純Java程式碼”實現。同時也對跨平臺有要求,系統需要執行在linux系統上。綜合現階段發現的方案,決定採用基於Aspose的方式進行實現。

好了,現在先看一下對比的結果:

各實現對比表

於Windows平臺進行測試:

測試檔案:

Word:大小380k、頁數225頁。內含圖片(排版),文字(不同顏色、字型、不同語言)、表格(含樣式)

Excel:大小297k。內含插入圖形、長表格。

PPT:大小539k、內含圖片、自定義圖形、文字(不同顏色、字型、不同語言)、表格(含樣式)

 

基於Openoffice

基於libreOffice

基於Office

基於Pio+Itext

基於Aspose

跨平臺性

跨平臺

跨平臺

僅Windows

跨平臺

跨平臺

是否安裝軟體

需安裝Openoffice

需安裝libreOffice

需安裝Microsoft Office

是否收費

免費

免費

軟體收費

(可破解)

免費

Jar包收費

(可破解)

轉換Word

效率

未測

首次開啟14s。

平均8s

平均10s

平均10s

平均4.2s

效果

未測

支援不同字型、不同文字、支援表格樣式。

插入圖形走樣

轉換後頁數相當

(225-227)

大小相當

(380k-360k)

完全一致

轉換後大小上升

(380k-1.24M)

字型、表格樣式、插入圖形失真。(嚴重失真)

轉換後頁數下降

(225-105)

大小飆升

(380k-1.74M)

字型樣式或無法轉換。

轉換後頁數相當(225-224)

大小上升

(380k-721k)

轉換Excel

效率

未測

首次開啟10s

平均4.5s

異常(Office2016)

平均5.8s

平均2.6s

效果

未測

支援文字顏色。

不支援插入圖形

文字會發生走樣

轉換後大小相當

(297k-140k)

提示異常

(Office 2016)

樣式失真。

excel頁面大小過長導致PDF頁面被截斷,無法顯示完整

不支援插入圖片轉換

轉換後大小減小

(297k-196k)

轉換PPT

效率

未測

平均5.3s

平均4s

平均15s

平均15.5s

效果

未測

幾乎完全一致

能完美支援表格、自定義圖形、圖片、文字等

大小減小

(539k-255k)

轉換成功,無法開啟(Office 2016)

樣式嚴重失真。甚至錯誤。

轉換後大小上升

(539K-1.3M)

頁數

(225-105)

幾乎完全一致

轉換後大小減小

(539k-398k)

優點

跨平臺

文件轉換失真小。

跨平臺

轉化相對快。對於Office能很好保證少失真,特別是Word文件

跨平臺

轉換速度快。

支援跨平臺。

不需要安裝軟體。

失真情況較小

缺點

需要安裝額外軟體

需要安裝額外軟體、效率較低

不跨平臺

需安裝Office

Office收費

Office版本不同效果不同(不穩定性)

對JDK有汙染

樣式失真特別嚴重、效率極低。

技術複雜

收費(但是可以破解)、即使付費,也不提供原始碼(官網)

評價

未知

穩定

極差

結論

使用Aspose效果最好。

各種技術實現起來,綜合來說Aspose是比較好的方案,唯一的弊端就是收費。

下面介紹各種方案的具體實現,以及其優缺點,效果圖。

 

1)基於openoffice(跨平臺、需安裝openoffice、複雜格式有錯位)

原理:

通過第三方工具openoffice,將word、excel、ppt、txt等檔案轉換為pdf檔案

先安裝openoffice軟體(Windows或Linux有提供軟體)

使用JODConverter的Java的OpenDocument 檔案轉換器API操作Office系列檔案轉換為PDF檔案

 

優點:

轉換效果比較好。是比較主流的做法

缺點:

伺服器需要安裝openoffice,比較負重

具體實現:

1.下載安裝軟體

1)Openoffice:Apache下的一個開放免費的文書處理軟體

下載地址:http://www.openoffice.org/zh-cn/download/

2)JODConverter一個Java的OpenDocument 檔案轉換器,只用到它的jar包

下載地址:https://sourceforge.net/projects/jodconverter/files/JODConverter/

 

2.啟動服務:

開啟dos視窗,進入openoffice安裝碟符,輸入以下程式碼來啟動服務:

soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard

 

3.Java實現操作轉化:

Pom.xml依賴

<!-- https://mvnrepository.com/artifact/com.artofsolving/jodconverter-maven-plugin -->
<dependency>
    <groupId>com.artofsolving</groupId>
    <artifactId>jodconverter-maven-plugin</artifactId>
    <version>2.2.1</version></dependency>
</dependency>

轉換工具:

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 java.net.ConnectException;
import java.text.SimpleDateFormat;
import java.util.Date; 
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;
/**
 * 利用jodconverter(基於OpenOffice服務)將檔案(*.doc、*.docx、*.xls、*.ppt)轉化為html格式或者pdf格式,
 * 使用前請檢查OpenOffice服務是否已經開啟, OpenOffice程序名稱:soffice.exe | soffice.bin
 */
public class Doc2HtmlUtil {
    private static Doc2HtmlUtil doc2HtmlUtil;
    /** * 獲取Doc2HtmlUtil例項 */
    public static synchronized Doc2HtmlUtil getDoc2HtmlUtilInstance() {
        if (doc2HtmlUtil == null) {
            doc2HtmlUtil = new Doc2HtmlUtil();
        }
        return doc2HtmlUtil;
    }
    /*** 轉換檔案成pdf */
    public String file2pdf(InputStream fromFileInputStream, String toFilePath,String type) throws IOException {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String timesuffix = sdf.format(date);
        String docFileName = null;
        String htmFileName = null;
        if(".doc".equals(type)){
            docFileName = "doc_" + timesuffix + ".doc";
            htmFileName = "doc_" + timesuffix + ".pdf";
        }else if(".docx".equals(type)){
            docFileName = "docx_" + timesuffix + ".docx";
            htmFileName = "docx_" + timesuffix + ".pdf";
        }else if(".xls".equals(type)){
            docFileName = "xls_" + timesuffix + ".xls";
            htmFileName = "xls_" + timesuffix + ".pdf";
        }else if(".ppt".equals(type)){
            docFileName = "ppt_" + timesuffix + ".ppt";
            htmFileName = "ppt_" + timesuffix + ".pdf";
        }else{
            return null;
        } 
        File htmlOutputFile = new File(toFilePath + File.separatorChar + htmFileName);
        File docInputFile = new File(toFilePath + File.separatorChar + docFileName);
        if (htmlOutputFile.exists())
            htmlOutputFile.delete();
        htmlOutputFile.createNewFile();
        if (docInputFile.exists())
            docInputFile.delete();
        docInputFile.createNewFile();
        /*** 由fromFileInputStream構建輸入檔案  */
        try {
            OutputStream os = new FileOutputStream(docInputFile);
            int bytesRead = 0;
            byte[] buffer = new byte[1024 * 8];
            while ((bytesRead = fromFileInputStream.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            } 
            os.close();
            fromFileInputStream.close();
        } catch (IOException e) {
        } 
        // 連線服務
        OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
        try {
            connection.connect();
        } catch (ConnectException e) {
            System.err.println("檔案轉換出錯,請檢查OpenOffice服務是否啟動。");
        }
        // convert 轉換
        DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
        converter.convert(docInputFile, htmlOutputFile);
        connection.disconnect();
        // 轉換完之後刪除word檔案
        docInputFile.delete();                                                                
        return htmFileName;
    } 
    public static void main(String[] args) throws IOException {
        Doc2HtmlUtil coc2HtmlUtil = getDoc2HtmlUtilInstance ();
        File file = null;
        FileInputStream fileInputStream = null;
        file = new File("C:/Users/MACHENIKE/Desktop/xxx.doc");
        fileInputStream = new FileInputStream(file);
        coc2HtmlUtil.file2pdf(fileInputStream, "E:/360","doc");
    }
}

簡易實現:

public void createPdf(String docFileName) throws IOException{ 
        String path =  this.getSession().getServletContext().getRealPath("/")+"attachment/";
        File inputFile = new File(path+"/doc/"+ docFileName + ".doc");
        File outputFile = new File(path+"/pdf/"+docFileName + ".pdf");
         
        // connect to an OpenOffice.org instance running on port 8100
        OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
        connection.connect();
         
        // convert
        DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
        converter.convert(inputFile, outputFile);
         
        // close the connection
        connection.disconnect();
    }

 

效果:(略)

 

 

2)基於libreoffice(跨平臺、需安裝libreoffice)

原理:

通過第三方工具libreoffice,將word、excel、ppt、txt等檔案轉換為pdf檔案

先安裝libreoffice軟體(Windows或Linux有提供軟體)

使用JODConverter的Java的OpenDocument 檔案轉換器API操作Office系列檔案轉換為PDF檔案

優點:

轉換效果比較好。是比較主流的做法

缺點:

伺服器需要安裝libreoffice,比較負重。啟動服務時效率不是很高

具體實現:

1.下載安裝軟體

1)Openoffice:Apache下的一個開放免費的文書處理軟體

下載地址:http://www.openoffice.org/zh-cn/download/

2)JODConverter一個Java的OpenDocument 檔案轉換器,只用到它的jar包

下載地址:https://sourceforge.net/projects/jodconverter/files/JODConverter/

2.Java實現

依賴:

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-pdfa</artifactId>
            <version>5.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.5.0</version>
        </dependency>


        <dependency>
            <groupId>org.jodconverter</groupId>
            <artifactId>jodconverter-local</artifactId>
            <version>4.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.0.7</version>
        </dependency>

轉換

public class LibreOfficeAndJodconverter {
    private static OfficeManager officeManager = null;
    private static final String dirPath = "F:/pdf/";
    private static final String LibreOfficeDirPath = "D:/LibreOffice6.1.1.2/LibreOffice";
    public static void init() {
        try {
            System.out.println("嘗試連線已啟動的服務...");
            ExternalOfficeManagerConfiguration externalProcessOfficeManager = new ExternalOfficeManagerConfiguration();
            externalProcessOfficeManager.setConnectOnStart(true);
            externalProcessOfficeManager.setPortNumber(8100);
            officeManager = externalProcessOfficeManager.buildOfficeManager();
            officeManager.start();
            System.out.println("轉換服務啟動成功!");
        } catch (Exception e) {
            //命令方式:soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard
            System.out.println("啟動新服務!");
            String libreOfficePath = LibreOfficeDirPath;
            // 此類在jodconverter-core中3版本中存在,在2.2.2版本中不存在
            DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
            // libreOffice的安裝目錄
            configuration.setOfficeHome(new File(libreOfficePath));
            // 設定埠號
            configuration.setPortNumber(8100);
            // 設定任務執行超時為5分鐘
            configuration.setTaskExecutionTimeout(1000 * 60 * 5L);
            // 設定任務佇列超時為24小時
            configuration.setTaskQueueTimeout(1000 * 60 * 60 * 24L);

            // 開啟轉換服務
            officeManager = configuration.buildOfficeManager();
            officeManager.start();
            System.out.println("服務啟動成功!");
        }
    }
    public static void desory() {
        if (officeManager != null) {
            officeManager.stop();
        }
    }
    /** * 合併多個PDF,注意,源pdf中不能含有目的pdf,否則將合併失敗*/
    public static boolean mergePdfFiles(String[] files, String newfile) {
        boolean retValue = false;
        Document document = null;
        try {
            document = new Document(new PdfReader(files[0]).getPageSize(1));
            PdfCopy copy = new PdfCopy(document, new FileOutputStream(newfile));
            document.open();
            for (int i = 0; i < files.length; i++) {
                PdfReader reader = new PdfReader(files[i]);
                int n = reader.getNumberOfPages();
                for (int j = 1; j <= n; j++) {
                    document.newPage();
                    PdfImportedPage page = copy.getImportedPage(reader, j);
                    copy.addPage(page);
                }
            }
            retValue = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            document.close();
        }
        return retValue;
    }
    /**
     * 開啟服務時耗時,需要安裝
     * 並不是看到什麼,就轉化為什麼樣的。有偏移
     *
     * @param args
     */
    public static void main(String[] args) {
        init();
        task();
        desory();
    }
    public static void task() {
        String outputname = "output.pdf";
        doDocToFdpLibre("test.docx", outputname);
        doDocToFdpLibre("ppt.pptx", outputname);
        doDocToFdpLibre("放棄.xlsx", outputname);
        doDocToFdpLibre("1.txt", outputname);
        doDocToFdpLibre("不老夢.jpg", outputname);
    }
    public static String doDocToFdpLibre(String inputFileName, String outputFileName) {
        File inputFile = new File("F:/pdf/" + inputFileName);
        System.out.println("libreOffice開始轉換..............................");
        Long startTime = System.currentTimeMillis();
        OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager);

        File outputFile = new File(dirPath + outputFileName);
        if (outputFile.exists()) {
            String uuid1 = UUID.randomUUID().toString();
            File temp1 = new File(dirPath + uuid1 + ".pdf");
            outputFile.renameTo(temp1);

            String uuid = UUID.randomUUID().toString();
            File temp2 = new File(dirPath + uuid + ".pdf");
            converter.convert(inputFile, temp2);

            String[] files = {dirPath + uuid1 + ".pdf", dirPath + uuid + ".pdf"};
            String savepath = dirPath + outputFileName;

            if (mergePdfFiles(files, savepath)) {
                temp1.delete();
                temp2.delete();
            }
        } else {
            converter.convert(inputFile, outputFile);
        }
        // 轉換結束
        System.out.println("轉換結束。。。。。");
        //轉換時間
        long endTime = System.currentTimeMillis();
        long time = endTime - startTime;
        System.out.println("libreOffice轉換所用時間為:" + time);
        return outputFile.getPath();
    }
}

效果:

Word文件

除去剛開啟,平均8s

libreOffice轉換所用時間為:14044ms

libreOffice轉換所用時間為:7147ms

libreOffice轉換所用時間為:6886ms

libreOffice轉換所用時間為:7176ms

libreOffice轉換所用時間為:7001ms

libreOffice轉換所用時間為:8397ms

libreOffice轉換所用時間為:8141ms

 

Excel

libreOffice轉換所用時間為:10584ms

libreOffice轉換所用時間為:4534ms

libreOffice轉換所用時間為:4453ms

libreOffice轉換所用時間為:4369ms

ppt轉換

libreOffice轉換所用時間為:59257ms

libreOffice轉換所用時間為:52320ms

libreOffice轉換所用時間為:52571ms

 

3)基於Microsofe Office(僅Windows、需安裝Microsoft Office)

原理:

類似於Microsoft Office的“另存為”操作。用Jacob實現對Office系列檔案的轉換(用jacob(Java COM Bridge)操作office的方式

需要在Windows下安裝Microsoft Office,使用jacob操作Office檔案,

並把jacob-x.xx-x64.dll放到java/bin(與java.exe相同)目錄下

 

優點:

能很好的轉換,失真小(完美保持原doc格式)

缺點:

1需要安裝Microsoft Office。

2需要把jacob-x.xx-x64.dll放到java/bin(與java.exe相同)目錄下,對JDK目錄有汙染。

3不支援跨平臺

4. Microsoft Office版本不同可能影響轉換是否成功

具體實現

1.下載jacob包並加入到環境中:

Pom:

        <!-- https://mvnrepository.com/artifact/com.hynnet/jacob -->
        <dependency>
            <groupId>com.hynnet</groupId>
            <artifactId>jacob</artifactId>
            <version>1.18</version>
        </dependency>

2.將jacob包的dll匯入到jdk/jre/bin下

(不放會報錯:java.lang.NoClassDefFoundError: Could not initialize class com.jacob.com.Dispatch)

或指定路徑:System.getProperty("java.library.path");

3.轉換方法:

public class Jacob {
	/** 轉PDF格式值 */
	static final int WORD_FORMAT_PDF = 17;
	static final int EXCEL_FORMAT_PDF = 0;
	static final int PPT_FORMAT_PDF = 32;
	/*** @Description:根據檔案型別轉換為pdf */
	public static void convert2PDF(String inputFile, String pdfFile) {
		String suffix = getFileSufix(inputFile);
		if (suffix.equals("doc") || suffix.equals("docx") || suffix.equals("txt")) {
	        word2PDF(inputFile, pdfFile);
	    } else if (suffix.equals("xls") || suffix.equals("xlsx")) {
	    	excel2PDF(inputFile, pdfFile);
	    } else if (suffix.equals("ppt") || suffix.equals("pptx")) {
	        ppt2PDF(inputFile, pdfFile);
	    } else {
	        System.out.println("檔案格式不支援轉換!");
	    }
	}
	/** * @Description:word轉pdf  */
	private static void word2PDF(String inputFile, String pdfFile) {    
        System.out.println("啟動Word...");      
        long start = System.currentTimeMillis();      
        ActiveXComponent app = null;  
        Dispatch doc = null;  
        try {      
        	// 建立一個word物件
            app = new ActiveXComponent("Word.Application");      
            // 不可見開啟word (但預設是不可見的)
            app.setProperty("Visible", new Variant(false));  
            // 獲取文擋屬性
            // 呼叫Documents物件中Open方法開啟文件,並返回開啟的文件物件Document 
Dispatch docs = app.getProperty("Documents").toDispatch(); 
            doc = Dispatch.call(docs, "Open", inputFile).toDispatch();  
            System.out.println("開啟文件..." + inputFile);  
            System.out.println("轉換文件到PDF..." + pdfFile);      
            File tofile = new File(pdfFile);      
            if(tofile.exists()) {      
                tofile.delete();      
            }      
            // word儲存為pdf格式巨集,值為17
            Dispatch.call(doc, "SaveAs", pdfFile, WORD_FORMAT_PDF);      
            long end = System.currentTimeMillis();      
            System.out.println("轉換完成..用時:" + (end - start) + "ms.");  
        } catch (Exception e) {      
            System.out.println("========Error:文件轉換失敗:" + e.getMessage());      
        } finally {  
            Dispatch.call(doc, "Close", false);  
            System.out.println("關閉文件");  
            if (app != null)      
                app.invoke("Quit", new Variant[] {});      
            }  
          //如果沒有這句話,winword.exe程序將不會關閉  
           ComThread.Release();
    }
	/** * @Description:excel轉pdf  */
	private static void excel2PDF(String inputFile, String pdfFile) {    
        System.out.println("啟動Excel...");      
        long start = System.currentTimeMillis();      
        ActiveXComponent app = null;  
        Dispatch excel = null;  
        try {      
        	// 建立一個excel物件
            app = new ActiveXComponent("Excel.Application");      
            // 不可見開啟excel
            app.setProperty("Visible", new Variant(false));  
            // 獲取文擋屬性
            Dispatch excels = app.getProperty("Workbooks").toDispatch();    
            // 呼叫Documents物件中Open方法開啟文件,並返回開啟的文件物件Document
            excel = Dispatch.call(excels, "Open", inputFile).toDispatch();  
            System.out.println("開啟文件..." + inputFile);  
            System.out.println("轉換文件到PDF..." + pdfFile);      
            File tofile = new File(pdfFile);      
            if(tofile.exists()) {      
                tofile.delete();      
            }      
            // Excel不能呼叫SaveAs方法
            Dispatch.call(excel, "ExportAsFixedFormat", EXCEL_FORMAT_PDF, pdfFile);
            long end = System.currentTimeMillis();      
            System.out.println("轉換完成..用時:" + (end - start) + "ms.");  
        } catch (Exception e) {      
            System.out.println("========Error:文件轉換失敗:" + e.getMessage());      
        } finally {  
            Dispatch.call(excel, "Close", false);  
            System.out.println("關閉文件");  
            if (app != null)      
                app.invoke("Quit", new Variant[] {});      
            }  
          //如果沒有這句話,winword.exe程序將不會關閉  
           ComThread.Release();
    }
	/*** @Description:ppt轉pdf  */
	private static void ppt2PDF(String inputFile, String pdfFile) {    
        System.out.println("啟動PPT...");      
        long start = System.currentTimeMillis();      
        ActiveXComponent app = null;  
        Dispatch ppt = null;  
        try {      
        	// 建立一個ppt物件
            app = new ActiveXComponent("PowerPoint.Application");      
            // 不可見開啟(PPT轉換不執行隱藏,所以這裡要註釋掉)
            // app.setProperty("Visible", new Variant(false));  
            // 獲取文擋屬性
            Dispatch ppts = app.getProperty("Presentations").toDispatch();    
            // 呼叫Documents物件中Open方法開啟文件,並返回開啟的文件物件Document
            ppt = Dispatch.call(ppts, "Open", inputFile, true, true, false).toDispatch();  
            System.out.println("開啟文件..." + inputFile);  
            System.out.println("轉換文件到PDF..." + pdfFile);      
            File tofile = new File(pdfFile);      
            if(tofile.exists()) {      
                tofile.delete();      
            }      
            Dispatch.call(ppt, "SaveAs", pdfFile, PPT_FORMAT_PDF); 
            long end = System.currentTimeMillis();      
            System.out.println("轉換完成..用時:" + (end - start) + "ms.");  
        } catch (Exception e) {      
            System.out.println("========Error:文件轉換失敗:" + e.getMessage());      
        } finally {  
            Dispatch.call(ppt, "Close");  
            System.out.println("關閉文件");  
            if (app != null)      
                app.invoke("Quit", new Variant[] {});      
            }  
          //如果沒有這句話,winword.exe程序將不會關閉  
           ComThread.Release();
    }
	/*** @Description:獲取檔案字尾*/
	private static String getFileSufix(String fileName) {
	    int splitIndex = fileName.lastIndexOf(".");
	    return fileName.substring(splitIndex + 1);
	}
}

效果:

word文件

成功:用時10821ms

成功:用時9865ms

成功:用時9867ms

成功:用時10481ms

 

excel:

ppt

成功:用時5265ms

成功:用時3885ms

成功:用時3788ms

成功:用時3817ms

 

原因探究

報錯的原因主要是:office版本問題。開發的時候使用的office2013,PPT不能轉pdf。在伺服器上安裝的office2007,出現了PPT可以轉成PDF,excel不能轉pdf。解除安裝了office2007安裝office2010後出現了excel能轉PDF,PPT不能轉PDF。office的版本問題中,world文件不管什麼版本都可以成功的轉pdf。最後解決的辦法:安裝2007的excel,2010的PPT,world就能成功的轉pdf。注意:office2007不能轉pdf,需要安裝一個外掛。

 

4)POI+IText方式(跨平臺、效果差、效率低)

原理:

用 poi 將word轉換成 html

用IText 將html轉換成pdf(要求html中所有標籤都必須要閉合,所以這裡用jsoup對html進行轉換)

優點:

不需要安裝軟體、跨平臺

缺點:

  1. 失真問題比較大。(格式相容差)
  2. 涉及到中文編碼問題。
  3. 效率比較低

具體實現

    public static String officeToHtml(String sourcePath,String targetPath){
        String ext = FileUtils.getFileExt(sourcePath).toLowerCase();
        String result = null;
        switch (ext){
            case Consts.OFFICE.DOC:
            case Consts.OFFICE.DOCX:
                result = POIWordToHtml.wordToHtml(sourcePath, wordImagePath, targetPath);
                break; 
            case Consts.OFFICE.XLS:
            case Consts.OFFICE.XLSX:
                result = POIExcelToHtml.excelToHtml(sourcePath,targetPath, true);
                break; 
            case Consts.OFFICE.PPT:
            case Consts.OFFICE.PPTX:
                POIPptToHtml.pptToHtml(sourcePath,targetPath);
                break;
            default:
        }
        return result;
}
具體工具類暫略
 

具體工具類暫略

注意事項:

注意:IText 根據html生成檔案的是否會驗證html檔案是否標準,例如通過poi轉換的出來的html檔案的一些標籤會缺少標籤閉合 ,

如果用這種html進行轉換是沒有辦法通過itext 的校驗的。會出現以下異常 

錯誤: “The element type "meta" must be terminated by the matching end-tag "</meta>".”
org.xhtmlrenderer.util.XRRuntimeException: Can't load the XML resource (using TRaX transformer). org.xml.sax.SAXParseException: The element type "meta" must be terminated by the matching end-tag "</meta>".  。

html不規範可採用第三方 jar 包  Jsoup,  直接呼叫parse方法讓html標準

 

相關部落格:

java 實現word 轉PDF (採用第三方技術 IText、Poi、Jsoup)

 

效果(很差):

Word:

耗時大概平均10s左右

耗時:10832ms

耗時:8788ms

耗時:9035ms

耗時:8827ms

Ppt:

平均大概15s左右

耗時:15932ms

耗時:14835ms

耗時:14884ms

耗時:14889ms

Excel:

平均5.8s

耗時:6263ms

耗時:5858ms

耗時:5698ms

耗時:5546ms

 

5)Aspose實現(跨平臺、付費)

優點:

比較完美,低失真。

缺點:

不跨平臺、不免費

具體實現:

下載相應jar包。(若不是付費版,將出現水印,限制頁數等情況)

Word:

    public static boolean getLicense() {
        boolean result = false;
        try {
            InputStream is = new FileInputStream(new File("E:\\IDEA2017\\something2pdf-demo\\src\\main\\resources\\license.xml")); //  license.xml應放在..\WebRoot\WEB-INF\classes路徑下
            License aposeLic = new License();
            aposeLic.setLicense(is);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    public static void doc2pdf(String Address) {
        if (!getLicense()) {          // 驗證License 若不驗證則轉化出的pdf文件會有水印產生
            return;
        }
        try {
            long old = System.currentTimeMillis();
            File file = new File("F:\\pdf/pdf1.pdf");  //新建一個空白pdf文件
            FileOutputStream os = new FileOutputStream(file);
            Document doc = new Document(Address);                    //Address是將要被轉化的word文件
            doc.save(os, SaveFormat.PDF);//全面支援DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互轉換
            long now = System.currentTimeMillis();
            System.out.println("共耗時:" + ((now - old) / 1000.0) + "秒");  //轉化用時
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Excel

    public static boolean getLicense() {
        boolean result = false;
        try {
            InputStream is = Excel2Pdf.class.getClassLoader().getResourceAsStream("xlsxlicense.xml"); //  license.xml應放在..\WebRoot\WEB-INF\classes路徑下
            License aposeLic = new License();
            aposeLic.setLicense(is);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    public static void excel2pdf(String Address) {
        if (!getLicense()) {          // 驗證License 若不驗證則轉化出的pdf文件會有水印產生
            return;
        }
        try {
            long old = System.currentTimeMillis();
            File file = new File("F:\\pdf/pdf2.pdf");// 輸出路徑
            Workbook wb = new Workbook(Address);// 原始excel路徑
            FileOutputStream fileOS = new FileOutputStream(file);
            wb.save(fileOS, SaveFormat.PDF);
            fileOS.close();
            long now = System.currentTimeMillis();
            System.out.println("共耗時:" + ((now - old) / 1000.0) + "秒\n\n" + "檔案儲存在:" + file.getPath()); //轉化過程耗時
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Ppt

    public static boolean getLicense() {
        boolean result = false;
        try {
            license = Ppt2Pdf.class.getClassLoader().getResourceAsStream("pptlicense.xml");// license路徑
            License aposeLic = new License();
            aposeLic.setLicense(license);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    public static void ppt2pdf(String Address) {
        // 驗證License
        if (!getLicense()) {
            return;
        }
        try {
            long old = System.currentTimeMillis();
            File file = new File("F:\\pdf/pdf3.pdf");// 輸出pdf路徑
            Presentation pres = new Presentation(Address);//輸入pdf路徑
            FileOutputStream fileOS = new FileOutputStream(file);
            pres.save(fileOS, SaveFormat.Pdf);
            fileOS.close();
            long now = System.currentTimeMillis();
            System.out.println("共耗時:" + ((now - old) / 1000.0) + "秒\n\n" + "檔案儲存在:" + file.getPath()); //轉化過程耗時
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Linux下編譯執行:

javac -cp /usr/local/temp/aspose-words-15.8.0-jdk16.jar Doc2Pdf.java

java -cp /usr/local/temp/aspose-words-15.8.0-jdk16.jar:/usr/local/temp Doc2Pdf

 

效果:

轉換文件:

平均4.2s。

共耗時:4.213秒

共耗時:4.2秒

共耗時:4.361秒

共耗時:3.959秒

共耗時:4.235秒

 

轉換ppt:

平均15.5s

共耗時:15.979秒

共耗時:15.212秒

共耗時:14.663秒

轉換excel:

平均2.6s

共耗時:2.67秒

共耗時:2.524秒

共耗時:2.741秒

共耗時:2.7秒

 

暫時就發現這些實現Office轉PDF的方法,以後還有其他方法的話,歡迎大家評論共討,同時本部落格也會繼續更新下去。