天天看點

libreoffice 開發文檔_工具庫-基于LibreOffice實作文檔操作

基于libreoffice實作的文檔轉換項目,無架構依賴,即插即用

1. 技術棧

LibreOffice:v6.2.3

jodconverter:4.2.2

PDFBox:2.0.12

cglib動态代理 + 懶漢工廠模式 + 政策模式 + 裝飾器模式

qtools-property管理配置檔案(application.yml、bootstrap.yml、workable-converter.yml三種命名的配置檔案任意包含一種即可)

2. 功能

支援doc、docx、html、ppt、png、pdf等等類型的檔案互相轉換

支援按照檔案路徑、位元組輸入輸出流、Base64等不同姿勢轉換

不依賴第三方架構,即插即用,支援application.yml、bootstrap.yml、workable-converter.yml三種配置(自己項目中具體配置一個即可)

3. 使用

3.1 安裝配置LibreOffice6.2.3

windows跟Mac同樣可以在上述文章中拿到下載下傳連結

安裝完成後,請記住您的LibreOffice的Home目錄,後面需要用到

預設目錄:

CentOS: /opt/libreoffice6.2/

Mac: /Applications/LibreOffice.app/Contents/

Windows: C:\Program Files\LibreOffice\

3.2 擷取依賴

Maven

com.liumapp.workable.converter

workable-converter

v1.2.0

Gradle

compile group: 'com.liumapp.workable.converter', name: 'workable-converter', version: 'v1.2.0'

3.3 編輯配置檔案

在項目的resources目錄下,建立一個yml配置檔案,需要確定檔案名稱為application.yml、bootstrap.yml或workable-converter.yml三種命名任意一個即可

添加以下配置:

com:

liumapp:

workable-converter:

libreofficePath: "/Applications/LibreOffice.app/Contents"

libreofficePath的值為LibreOffice:6.2.3的安裝目錄

完整的配置項清單如下

參數名

解釋

預設值

libreofficePath

LibreOffice安裝目錄

(String) 無預設值,該項必填

libreofficePort

LibreOffice監聽端口

(int) 2002

tmpPath

臨時存儲目錄

(String) "./data/"

3.4 執行轉換

3.4.1 按照檔案路徑轉換

以doc轉PDF為例

WorkableConverter converter = new WorkableConverter();//執行個體化的同時,初始化配置項,配置項的校驗通過Decorator裝飾

ConvertPattern pattern = ConvertPatternManager.getInstance();

pattern.fileToFile("./data/test.doc", "./data/pdf/result1.pdf"); //test.doc為待轉換檔案路徑,result1.pdf為轉換結果存儲路徑

pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.DOC);

pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PDF);

converter.setConverterType(CommonConverterManager.getInstance());//政策模式,後續實作了新的轉換政策後,在此處更換,圖檔轉換将考慮使用新的政策來完成

boolean result = converter.convert(pattern.getParameter();

如果要用html轉PDF,将上述代碼的

pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.DOC);

pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PDF);

改為

pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.HTML);

pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PDF);

其他類型的同理

3.4.2 按照輸入輸出流轉換

以doc轉pdf為例

// you can also choice not use proxy

WorkableConverter converter = new WorkableConverter();

ConvertPattern pattern = ConvertPatternManager.getInstance();

pattern.streamToStream(new FileInputStream("./data/test.doc"), new FileOutputStream("./data/pdf/result1_2.pdf"));

// attention !!! convert by stream must set prefix.

pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.DOC);

pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PDF);

converter.setConverterType(CommonConverterManager.getInstance());

boolean result = converter.convert(pattern.getParameter();

跟上例基本相同,唯一的變化是通過pattern.streamToStream()來設定輸入輸出流,轉換源檔案資料從輸入流中讀取,轉換結果會直接寫入輸出流中,

同時要切換轉換格式,跟上例一樣設定不同的prefix即可

3.4.3 按照檔案Base64轉換

仍以doc轉pdf為例

WorkableConverter converter = new WorkableConverter();

ConvertPattern pattern = ConvertPatternManager.getInstance();

pattern.base64ToBase64(Base64FileTool.FileToBase64(new File("./data/test.doc")));

// attention !!! convert by base64 must set prefix.

pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.DOC);

pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PDF);

converter.setConverterType(CommonConverterManager.getInstance());

boolean result = converter.convert(pattern.getParameter();

String destBase64 = pattern.getBase64Result();

輸入base64執行轉換,首先通過pattern.base64ToBase64()來設定轉換源的base64值

轉換結果result仍然是一個boolean類型,通過pattern.getBase64Result來擷取轉換結果的base64值

要切換轉換格式,跟上例一樣設定不同的prefix即可

3.5 圖檔處理

目前對于圖檔的處理,隻支援将PDF轉PNG圖檔(如果1份pdf檔案有20頁,那麼将會轉換為20張png圖檔),該功能的實作基于PDFBox:2.0.12

3.5.1 按照檔案路徑處理

pattern.fileToFiles()第一個參數為待轉換的pdf檔案路徑,第二個參數為轉換後的圖檔存儲路徑

WorkableConverter converter = new WorkableConverter();

ConvertPattern pattern = ConvertPatternManager.getInstance();

pattern.fileToFiles("./data/test5.pdf", "./data/");

pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.PDF);

pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PNG);

converter.setConverterType(PdfBoxConverterManager.getInstance()); // pdf box converter manager only support pdf to png

assertEquals(true, converter.convert(pattern.getParameter()));

assertEquals(true, FileTool.isFileExists("./data/test5_0.png"));

assertEquals(true, FileTool.isFileExists("./data/test5_1.png"));

assertEquals(true, FileTool.isFileExists("./data/test5_2.png"));

assertEquals(true, FileTool.isFileExists("./data/test5_3.png"));

3.5.2 按照檔案Base64處理

pattern.base64ToBase64()的參數為待轉換pdf檔案的base64值

轉換結束後,通過List resultBase64 = pattern.getBase64Results()擷取轉換後的圖檔base64值的集合

WorkableConverter converter = new WorkableConverter();

ConvertPattern pattern = ConvertPatternManager.getInstance();

pattern.base64ToBase64(Base64FileTool.FileToBase64(new File("./data/test5.pdf")));

pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.PDF);

pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PNG);

converter.setConverterType(PdfBoxConverterManager.getInstance()); // pdf box converter manager only support pdf to png

boolean result = converter.convert(pattern.getParameter());

List resultBase64 = pattern.getBase64Results();

assertEquals(true, result);

assertEquals(4, resultBase64.size());

3.6 添加水印

水印的轉換政策為WaterMarkConverter

添加水印注意事項

請確定輸入源檔案字尾為PDF,輸出源檔案字尾也為PDF

水印參數需要new一個WaterMarkRequire來設定

setWaterMarkPage(int page)代表在哪一頁上添加水印,如果為0,則表示所有頁面

水印本身為一個PDF檔案,該檔案隻需要一頁,其第一頁的内容将被視為水印添加到源檔案中

比如說,要添加透明度為0.3的文本作為水印的話,自己使用word等工具繪制透明度為0.3的字型(或者上包含透明度的png圖檔也可以)并另存為一個watermark.pdf檔案

然後使用waterMarkRequire.setWaterMarkPDFBase64(Base64FileTool.FileToBase64(new File("./data/watermark.pdf")))

或者waterMarkRequire.setWaterMarkPDFBytes(FileUtils.readFileToByteArray(new File("./data/watermark.pdf")))将該檔案的base64或者bytes值輸入即可

具體使用可以分為三種方式

3.6.1 按照檔案路徑添加水印

WorkableConverter converter = new WorkableConverter();

converter.setConverterType(WaterMarkConverterManager.getInstance());//選擇具體的水印轉換政策

ConvertPattern pattern = ConvertPatternManager.getInstance();

WaterMarkRequire waterMarkRequire = new WaterMarkRequire();//建立水印所需要的參數

//指定在具體的哪一頁添加水印,0的話則在所有頁面添加水印

waterMarkRequire.setWaterMarkPage(0);//0 means all age

waterMarkRequire.setWaterMarkPDFBase64(Base64FileTool.FileToBase64(new File("./data/watermark.pdf")));

pattern.setWaterMarkRequire(waterMarkRequire);

pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.PDF);

pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PDF);

pattern.fileToFile("./data/test5.pdf", "./data/test5_with_mark01.pdf");//添加水印後的檔案儲存在./data/目錄下,名為test5_with_mark01.pdf

boolean result = converter.convert(pattern.getParameter());

assertEquals(true, result);

3.6.2 按照流添加水印

WorkableConverter converter = new WorkableConverter();

converter.setConverterType(WaterMarkConverterManager.getInstance());

ConvertPattern pattern = ConvertPatternManager.getInstance();

WaterMarkRequire waterMarkRequire = new WaterMarkRequire();

waterMarkRequire.setWaterMarkPage(0);//0 means all age

waterMarkRequire.setWaterMarkPDFBytes(FileUtils.readFileToByteArray(new File("./data/watermark.pdf")));

pattern.setWaterMarkRequire(waterMarkRequire);

pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.PDF);

pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PDF);

pattern.streamToStream(new FileInputStream("./data/test5.pdf"), new FileOutputStream("./data/test5_with_mark02.pdf"));

boolean result = converter.convert(pattern.getParameter());

assertEquals(true, result);

3.6.3 按照base64添加水印

WorkableConverter converter = new WorkableConverter();

converter.setConverterType(WaterMarkConverterManager.getInstance());

ConvertPattern pattern = ConvertPatternManager.getInstance();

WaterMarkRequire waterMarkRequire = new WaterMarkRequire();

waterMarkRequire.setWaterMarkPage(0);//0 means all age

waterMarkRequire.setWaterMarkPDFBase64(Base64FileTool.FileToBase64(new File("./data/watermark.pdf")));

pattern.setWaterMarkRequire(waterMarkRequire);

pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.PDF);

pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PDF);

pattern.base64ToBase64(Base64FileTool.FileToBase64(new File("./data/test5.pdf")));

boolean result = converter.convert(pattern.getParameter());

String base64Result = pattern.getBase64Result();

Base64FileTool.saveBase64File(base64Result, "./data/test5_with_mark03.pdf");

assertEquals(true, result);

4. 待辦事項

已經測試通過的有doc、docx、html 按照不同姿勢轉PDF,其他類型的并沒有編寫測試單元,後續考慮增加

目前隻支援yml配置,後續考慮添加其他類型的配置支援(xml、properties等)

目前Markdown格式很流行,考慮實作markdown格式的字元串轉PDF(markdown -> html -> pdf)

5. 注意事項

因為需要LibreOffice的支援,是以不建議在Docker等容器内運作(LibreOffice暫無Docker穩定發行版的鏡像)

轉換亂碼、轉換耗時過長,請檢查伺服器是否安裝有中文字型

項目啟動後,在執行第一次轉換任務時,因為涉及到與LibreOffice建立連接配接等操作,是以會耗時較長,第二次任務及以後穩定在0.5秒以内(具體時間因機器配置會有所差異)

6. 參考連結