Java實現(xiàn)無損Word轉(zhuǎn)PDF的示例代碼
前言
本來想寫word轉(zhuǎn)pdf和pdf轉(zhuǎn)word的代碼呢,沒想到word轉(zhuǎn)pdf就寫了很多很多行代碼才實現(xiàn),為了方便大家消化理解,先寫了word轉(zhuǎn)pdf方法實現(xiàn)作為一篇文章。
word轉(zhuǎn)pdf實現(xiàn)思路
代碼實現(xiàn)主要依賴兩個第三方j(luò)ar包,一個是pdfbox,一個是aspose-words。pdfbox包完全開源免費,aspose-words免費版生成有水印,且生成數(shù)量有限制。單純用pdfbox 實現(xiàn)word轉(zhuǎn)pdf的話,實現(xiàn)非常復(fù)雜,且樣式和原來樣式,保持一致的的比例很低。所以,我先用aspose-words生成了帶水印的pdf,再用pdfbox去除aspose-words生成的水印的,最終得到了一個無水印的pdf。
項目遠(yuǎn)程倉庫
aspose-words 這個需要配置單獨的倉庫地址才能下載,不會配置的可以去官網(wǎng)直接下載jar引入項目代碼中。
<repositories> <repository> <id>AsposeJavaAPI</id> <name>Aspose Java API</name> <url>https://repository.aspose.com/repo/</url> </repository>
Maven項目pom文件依賴
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox --> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>3.0.0-RC1</version> </dependency> <dependency> <groupId>com.github.jai-imageio</groupId> <artifactId>jai-imageio-jpeg2000</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>com.aspose</groupId> <artifactId>aspose-words</artifactId> <version>21.9</version> <type>pom</type> </dependency>
核心代碼實現(xiàn)
import com.aspose.words.Document;
import com.aspose.words.SaveFormat;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.pdfparser.PDFStreamParser;
import org.apache.pdfbox.pdfwriter.ContentStreamWriter;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class PDFHelper3 {
public static void main(String[] args) throws IOException {
doc2pdf("C:\\Users\\liuya\\Desktop\\word\\帆軟報表幫助文檔.docx");
}
//替換pdf文本內(nèi)容
public static void replaceText(PDPage page, String searchString, String replacement) throws IOException {
PDFStreamParser parser = new PDFStreamParser(page);
List<?> tokens = parser.parse();
for (int j = 0; j < tokens.size(); j++) {
Object next = tokens.get(j);
if (next instanceof Operator) {
Operator op = (Operator) next;
String pstring = "";
int prej = 0;
if (op.getName().equals("Tj")) {
COSString previous = (COSString) tokens.get(j - 1);
String string = previous.getString();
string = string.replaceFirst(searchString, replacement);
previous.setValue(string.getBytes());
} else if (op.getName().equals("TJ")) {
COSArray previous = (COSArray) tokens.get(j - 1);
for (int k = 0; k < previous.size(); k++) {
Object arrElement = previous.getObject(k);
if (arrElement instanceof COSString) {
COSString cosString = (COSString) arrElement;
String string = cosString.getString();
if (j == prej) {
pstring += string;
} else {
prej = j;
pstring = string;
}
}
}
if (searchString.equals(pstring.trim())) {
COSString cosString2 = (COSString) previous.getObject(0);
cosString2.setValue(replacement.getBytes());
int total = previous.size() - 1;
for (int k = total; k > 0; k--) {
previous.remove(k);
}
}
}
}
}
List<PDStream> contents = new ArrayList<>();
Iterator<PDStream> streams = page.getContentStreams();
while (streams.hasNext()) {
PDStream updatedStream = streams.next();
OutputStream out = updatedStream.createOutputStream(COSName.FLATE_DECODE);
ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
tokenWriter.writeTokens(tokens);
contents.add(updatedStream);
out.close();
}
page.setContents(contents);
}
//移除圖片水印
public static void removeImage(PDPage page, String cosName) {
PDResources resources = page.getResources();
COSDictionary dict1 = resources.getCOSObject();
resources.getXObjectNames().forEach(e -> {
if (resources.isImageXObject(e)) {
COSDictionary dict2 = dict1.getCOSDictionary(COSName.XOBJECT);
if (e.getName().equals(cosName)) {
dict2.removeItem(e);
}
}
page.setResources(new PDResources(dict1));
});
}
//移除文字水印
public static boolean removeWatermark(File file) {
try {
//通過文件名加載文檔
PDDocument document = Loader.loadPDF(file);
PDPageTree pages = document.getPages();
Iterator<PDPage> iter = pages.iterator();
while (iter.hasNext()) {
PDPage page = iter.next();
//去除文字水印
replaceText(page, "Evaluation Only. Created with Aspose.Words. Copyright 2003-2021 Aspose", "");
replaceText(page, "Pty Ltd.", "");
replaceText(page, "Created with an evaluation copy of Aspose.Words. To discover the full", "");
replaceText(page, "versions of our APIs please visit: https://products.aspose.com/words/", "");
replaceText(page, "This document was truncated here because it was created in the Evaluation", "");
//去除圖片水印
removeImage(page, "X1");
}
document.removePage(document.getNumberOfPages() - 1);
file.delete();
document.save(file);
document.close();
return true;
} catch (IOException ex) {
ex.printStackTrace();
return false;
}
}
//doc文件轉(zhuǎn)pdf(目前最大支持21頁)
public static void doc2pdf(String wordPath) {
long old = System.currentTimeMillis();
try {
//新建一個pdf文檔
String pdfPath=wordPath.substring(0,wordPath.lastIndexOf("."))+".pdf";
File file = new File(pdfPath);
FileOutputStream os = new FileOutputStream(file);
//Address是將要被轉(zhuǎn)化的word文檔
Document doc = new Document(wordPath);
//全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互轉(zhuǎn)換
doc.save(os, SaveFormat.PDF);
os.close();
//去除水印
removeWatermark(new File(pdfPath));
//轉(zhuǎn)化用時
long now = System.currentTimeMillis();
System.out.println("Word 轉(zhuǎn) Pdf 共耗時:" + ((now - old) / 1000.0) + "秒");
} catch (Exception e) {
System.out.println("Word 轉(zhuǎn) Pdf 失敗...");
e.printStackTrace();
}
}
}結(jié)果分析
以一個帶文字和圖片,工21頁的doc文件為例,word轉(zhuǎn)pdf花費時長4.398秒

原word樣式


轉(zhuǎn)化后pdf效果圖


通過對比,word原來的樣式和轉(zhuǎn)換pdf文件后的樣式基本沒有變化。
到此這篇關(guān)于Java實現(xiàn)無損Word轉(zhuǎn)PDF的示例代碼的文章就介紹到這了,更多相關(guān)Java無損Word轉(zhuǎn)PDF內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
通過Java實現(xiàn)反向代理集群服務(wù)的平滑分配
這篇文章主要介紹了如何通過Java語言,自己編寫的平滑加權(quán)輪詢算法,結(jié)合線程池和Socket?網(wǎng)絡(luò)編程等,并實現(xiàn)反向代理集群服務(wù)的平滑分配,需要的可以參考一下2022-04-04
Java Iterator迭代器與foreach循環(huán)代碼解析
這篇文章主要介紹了Java-Iterator迭代器與foreach循環(huán),主要包括Iterator迭代器接口的操作方法和foreach 循環(huán)語法解析,需要的朋友可以參考下2022-04-04
關(guān)于mybatis plus 中的查詢優(yōu)化問題
這篇文章主要介紹了關(guān)于mybatis plus 中的查詢優(yōu)化問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
Spring Security 在 Spring Boot 中的使用詳解【集中式】
這篇文章主要介紹了Spring Security 在 Spring Boot 中的使用【集中式】,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
Java實現(xiàn)線程按序交替執(zhí)行的方法詳解
這篇文章主要為大家詳細(xì)介紹了Java如何實現(xiàn)線程按序交替執(zhí)行,文中的示例代碼講解詳細(xì),對我們了解線程有一定幫助,需要的可以參考一下2022-10-10
SpringBoot前后端分離跨域問題:狀態(tài)碼403拒絕訪問解決辦法
這篇文章主要給大家介紹了關(guān)于SpringBoot前后端分離跨域問題:狀態(tài)碼403拒絕訪問的解決辦法,403是被服務(wù)器拒絕了,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01

