Html轉換PDF(Java實用版)
阿新 • • 發佈:2022-04-20
前言:
在工作當中,遇到了需要把HTML頁面轉化為PDF文件,有很多中實現,如下進行一個對比,大家個借鑑去進行使用
各實現對比表
於Windows平臺進行測試:
此部落格僅基於IText和基於WKHtmlToPdf來介紹並使用,均為博主親測
其他兩個可自行研究哈
1、基於IText
iText 是業界使用最為廣泛的建立 PDF 的框架,從 iText 5 升級到 iText 7 後,功能模組的劃分更加清晰,兩者在使用上,有較為明顯的區別。
此處就不進行區別的贅述了,直接上程式碼,本次使用的是iText7
1.1、引入依賴
注意兩個依賴的版本對應,進入html2pdf的pom檔案就能看到itext的版本,font-asian的版本最低也要是html2pdf中itext7的版本。
<!-- itext7html轉pdf --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>html2pdf</artifactId> <version>3.0.2</version> </dependency> <!-- 中文字型支援 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>font-asian</artifactId> <version>7.1.13</version> </dependency>
1.2、水印和頁碼
匯出pdf一般是需要水印和頁碼的,我們只要實現com.itextpdf.kernel.events.IEventHandler介面就可以了
水印
水印程式碼
/** * 水印 */ public class WaterMarkEventHandler implements IEventHandler { /** * 水印內容 */ private String waterMarkContent; /** * 一頁中有幾列水印 */ private int waterMarkX; /** * 一頁中每列有多少水印 */ private int waterMarkY; public WaterMarkEventHandler(String waterMarkContent) { this(waterMarkContent, 5, 5); } public WaterMarkEventHandler(String waterMarkContent, int waterMarkX, int waterMarkY) { this.waterMarkContent = waterMarkContent; this.waterMarkX = waterMarkX; this.waterMarkY = waterMarkY; } @Override public void handleEvent(Event event) { PdfDocumentEvent documentEvent = (PdfDocumentEvent) event; PdfDocument document = documentEvent.getDocument(); PdfPage page = documentEvent.getPage(); Rectangle pageSize = page.getPageSize(); PdfFont pdfFont = null; try { pdfFont = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H", false); } catch (IOException e) { e.printStackTrace(); } PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamAfter(), page.getResources(), document); Paragraph waterMark = new Paragraph(waterMarkContent).setOpacity(0.5f); Canvas canvas = new Canvas(pdfCanvas, pageSize) .setFontColor(WebColors.getRGBColor("lightgray")) .setFontSize(16) .setFont(pdfFont); for (int i = 0; i < waterMarkX; i++) { for (int j = 0; j < waterMarkY; j++) { canvas.showTextAligned(waterMark, (150 + i * 300), (160 + j * 150), document.getNumberOfPages(), TextAlignment.CENTER, VerticalAlignment.BOTTOM, 120); } } canvas.close(); } }
頁碼
頁碼程式碼
/**
* 頁碼
*/
public class PageEventHandler implements IEventHandler {
@Override
public void handleEvent(Event event) {
PdfDocumentEvent documentEvent = (PdfDocumentEvent) event;
PdfDocument document = documentEvent.getDocument();
PdfPage page = documentEvent.getPage();
Rectangle pageSize = page.getPageSize();
PdfFont pdfFont = null;
try {
pdfFont = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H", false);
} catch (IOException e) {
e.printStackTrace();
}
PdfCanvas pdfCanvas = new PdfCanvas(page.getLastContentStream(), page.getResources(), document);
Canvas canvas = new Canvas(pdfCanvas, pageSize);
float x = (pageSize.getLeft() + pageSize.getRight()) / 2;
float y = pageSize.getBottom() + 15;
Paragraph paragraph = new Paragraph("第" + document.getPageNumber(page) + "頁/共" + document.getNumberOfPages() + "頁")
.setFontSize(10)
.setFont(pdfFont);
canvas.showTextAligned(paragraph, x, y, TextAlignment.CENTER);
canvas.close();
}
}
1.3、轉換工具類
轉換工具類
/**
* Itext7轉換工具類
*/
@Slf4j
public class HtmlToPdfUtils {
/**
* html轉pdf
*
* @param inputStream 輸入流
* @param waterMark 水印
* @param fontPath 字型路徑,ttc字尾的字型需要新增<b>,0<b/>
* @param outputStream 輸出流
* @date : 2021/1/15 14:07
*/
public static void convertToPdf(InputStream inputStream, String waterMark, String fontPath, OutputStream outputStream) throws IOException {
PdfWriter pdfWriter = new PdfWriter(outputStream);
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
//設定為A4大小
pdfDocument.setDefaultPageSize(PageSize.A4);
//新增水印
pdfDocument.addEventHandler(PdfDocumentEvent.END_PAGE, new WaterMarkEventHandler(waterMark));
//新增中文字型支援
ConverterProperties properties = new ConverterProperties();
FontProvider fontProvider = new FontProvider();
// 設定字型
/*PdfFont sysFont = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H", false);
fontProvider.addFont(sysFont.getFontProgram(), "UniGB-UCS2-H");*/
//新增自定義字型,例如微軟雅黑
if (StringUtils.isNotBlank(fontPath)) {
PdfFont microsoft = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, false);
fontProvider.addFont(microsoft.getFontProgram(), PdfEncodings.IDENTITY_H);
}
properties.setFontProvider(fontProvider);
// 讀取Html檔案流,查找出當中的 或出現類似的符號空格字元
inputStream = readInputStrem(inputStream);
if (inputStream != null) {
// 生成pdf文件
HtmlConverter.convertToPdf(inputStream, pdfDocument, properties);
pdfWriter.close();
pdfDocument.close();
return;
} else {
log.error("轉換失敗!");
}
}
/**
* 讀取HTML 流檔案,並查詢當中的 或類似符號直接替換為空格
*
* @param inputStream
* @return
*/
private static InputStream readInputStrem(InputStream inputStream) {
// 定義一些特殊字元的正則表示式 如:
String regEx_special = "\\&[a-zA-Z]{1,10};";
try {
//<1>建立位元組陣列輸出流,用來輸出讀取到的內容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//<2>建立快取大小
byte[] buffer = new byte[1024]; // 1KB
//每次讀取到內容的長度
int len = -1;
//<3>開始讀取輸入流中的內容
while ((len = inputStream.read(buffer)) != -1) { //當等於-1說明沒有資料可以讀取了
baos.write(buffer, 0, len); //把讀取到的內容寫到輸出流中
}
//<4> 把位元組陣列轉換為字串
String content = baos.toString();
//<5>關閉輸入流和輸出流
// inputStream.close();
baos.close();
// log.info("讀取的內容:{}", content);
// 判斷HTML內容是否具有HTML的特殊字元標記
Pattern compile = Pattern.compile(regEx_special, Pattern.CASE_INSENSITIVE);
Matcher matcher = compile.matcher(content);
String replaceAll = matcher.replaceAll("");
// log.info("替換後的內容:{}", replaceAll);
// 將字串轉化為輸入流返回
InputStream stringStream = getStringStream(replaceAll);
//<6>返回結果
return stringStream;
} catch (Exception e) {
e.printStackTrace();
log.error("錯誤資訊:{}", e.getMessage());
return null;
}
}
/**
* 將一個字串轉化為輸入流
* @param sInputString 字串
* @return
*/
public static InputStream getStringStream(String sInputString) {
if (sInputString != null && !sInputString.trim().equals("")) {
try {
ByteArrayInputStream tInputStringStream = new ByteArrayInputStream(sInputString.getBytes());
return tInputStringStream;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
1.4、測試類
測試程式碼
@Slf4j
public class Test {
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis();
// html檔案所在相對路徑
String htmlFile = "src/main/resources/html/index2.html";
// pdf檔案儲存相對路徑
String pdfFile = "src/main/resources/x6.pdf";
// 自定義水印
String waterMarkText = "";
InputStream inputStream = new FileInputStream(htmlFile);
OutputStream outputStream = new FileOutputStream(pdfFile);
//微軟雅黑在windows系統裡的位置如下,linux系統直接拷貝該檔案放在linux目錄下即可
// String fontPath = "src/main/resources/font/STHeiti Light.ttc,0";
String fontPath = "src/main/resources/font/simsun.ttc,0";
HtmlToPdfUtils.convertToPdf(inputStream, waterMarkText, fontPath, outputStream);
log.info("轉換結束,耗時:{}ms",System.currentTimeMillis()-startTime);
}
}
1.5、注意事項
- 頁面中不能出現html的特殊字元標記,如 等(程式碼中已經處理,所有都替換為空)可忽略
- 頁面中的圖片路徑,必須是在專案根路徑後面的所有地址(相對路徑)例如:
- 頁面中的標籤要符合規範,必須都具有結束標籤等
展示:
HTML
2、基於WKHtmlToPdf