多圖片生成PDF(二)HTML生成PDF
阿新 • • 發佈:2022-12-08
HTML生成PDF
一、html生成pdf需要引入jar包
在pom.xml中引入如下jar包
<dependency> <groupId>com.itextpdf</groupId> <artifactId>html2pdf</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf</artifactId> <version>9.1.18</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.4.2</version> </dependency> <dependency> <groupId>org.eclipse.birt.runtime.3_7_1</groupId> <artifactId>com.lowagie.text</artifactId> <version>2.1.7</version> </dependency> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.13</version> <scope>compile</scope> </dependency>
二、Java程式碼
import cn.qcdoc.common.core.exception.BaseException; import com.itextpdf.text.*; import com.itextpdf.text.pdf.*; import com.itextpdf.tool.xml.XMLWorker; import com.itextpdf.tool.xml.css.StyleAttrCSSResolver; import com.itextpdf.tool.xml.html.CssAppliers; import com.itextpdf.tool.xml.html.Tags; import com.itextpdf.tool.xml.parser.XMLParser; import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline; import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline; import com.itextpdf.tool.xml.pipeline.html.AbstractImageProvider; import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline; import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext; import com.itextpdf.tool.xml.pipeline.html.LinkProvider; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * html轉PDF * * @author: wx * @date: 2022/11/21 */ public class HtmlPdfDemo { public static String MakeHtml(List<String> listPath, String distPath, String templatePath){ String fileame = "test.html"; try { String templateContent = ""; // 讀取模板檔案 FileInputStream fileinputstream = new FileInputStream(templatePath); int length = fileinputstream.available(); byte bytes[] = new byte[length]; fileinputstream.read(bytes); fileinputstream.close(); templateContent = new String(bytes); StringBuilder sbPath = new StringBuilder(); for (String path : listPath) { String imgs = "<img src=\""+path+"\"/>"+"\n"+"<div style='page-break-before: always;'>\n" + "\t\t</div>"; sbPath.append(imgs); } String str = sbPath.toString().replace("\\", "/"); //把模板頁面上的 ###image_list### 替換成 img 裡的內容 templateContent = templateContent.replaceAll("###image_list###", str); // 生成的html檔案儲存路徑。 fileame = distPath + fileame; // 建立檔案輸出流 FileOutputStream fileoutputstream = new FileOutputStream(fileame); byte tag_bytes[] = templateContent.getBytes(); fileoutputstream.write(tag_bytes); fileoutputstream.close(); } catch (Exception e) { throw new BaseException("建立html失敗!"); } return fileame; } /** * 建立PDF檔案 * @author: wx * @date: 2022/12/8 * @param: htmlPath html路徑 * @param: outPdfPath 生成pdf路徑 * @param: imagePath 圖片路徑 * @returns: void */ public static void writeToOutputStreamAsPDF(String htmlPath, String outPdfPath, String imagePath) throws Exception { File targeFile = new File(outPdfPath); if(targeFile.exists()) { targeFile.delete(); } //定義pdf檔案尺寸,採用A4橫切 Document document = new Document(PageSize.A4, 20, 20, 20, 20);// 左、右、上、下間距 //定義輸出路徑 PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(outPdfPath)); PdfReportHeaderFooter header = new PdfReportHeaderFooter("", 8, PageSize.A4); writer.setPageEvent(header); writer.addViewerPreference(PdfName.PRINTSCALING, PdfName.NONE); document.open(); // HTML 設定 HtmlPipelineContext htmlContext = getHtmlPipelineContext(imagePath, null); // Pipelines PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer); HtmlPipeline html = new HtmlPipeline(htmlContext, pdf); CssResolverPipeline css = new CssResolverPipeline(new StyleAttrCSSResolver(), html); // XML Worker XMLWorker worker = new XMLWorker(css, true); XMLParser p = new XMLParser(worker); p.parse(new FileInputStream(htmlPath)); document.close(); } /** * html 設定 * @author: wx * @date: 2022/10/13 * @param: imagePath * @param: cssAppliers * @returns: com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext */ private static HtmlPipelineContext getHtmlPipelineContext(String imagePath, CssAppliers cssAppliers) { HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers); htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory()); htmlContext.setImageProvider(new AbstractImageProvider() { public String getImageRootPath() { return imagePath; } }); htmlContext.setLinkProvider(new LinkProvider() { public String getLinkRoot() { return imagePath; } }); return htmlContext; } public static void main(String[] args) throws Exception { List<String> listPath = new ArrayList<>(); listPath.add("1665989812537.jpg"); listPath.add("1665989815178.jpg"); String distPath = "upload\\depot\\electronic\\23335\\NJ01TYQABYM\\"; String templatePath = "upload\\depot\\table.html"; String outFilePath = "upload\\depot\\electronic\\23335\\NJ01TYQABYM\\test.pdf"; String htmlPath = MakeHtml(listPath, distPath, templatePath); writeToOutputStreamAsPDF(htmlPath, outFilePath, distPath); } } /** * 調整pdf樣式 * * @author: wx * @date: 2022/10/13 */ class PdfReportHeaderFooter extends PdfPageEventHelper { /** * 頁首 */ public String header = ""; /** * 文件字型大小,頁尾頁首最好和文字大小一致 */ public int presentFontSize = 12; /** * 文件頁面大小,最好前面傳入,否則預設為A4紙張 */ public Rectangle pageSize = PageSize.A4; /** * 模板 */ public PdfTemplate total; /** * 基礎字型物件 */ public BaseFont bf = null; /** * 利用基礎字型生成的字型物件,一般用於生成中文文字 */ public Font fontDetail = null; /** * @param: yeMei 頁首字串 * @param: presentFontSize 資料體字型大小 * @param: pageSize 頁面文件大小,A4,A5,A6橫轉翻轉等Rectangle物件 * @returns: */ public PdfReportHeaderFooter(String yeMei, int presentFontSize, Rectangle pageSize) { this.header = yeMei; this.presentFontSize = presentFontSize; this.pageSize = pageSize; } /** * 文件開啟時建立模板 * @author: wx * @date: 2022/10/14 * @param: writer * @param: document * @returns: void */ public void onOpenDocument(PdfWriter writer, Document document) { // 頁尾 共 頁 的矩形的長寬高 total = writer.getDirectContent().createTemplate(50, 50); } /** * 關閉每頁的時候,寫入頁首,寫入'第幾頁共'這幾個字。 * @author: wx * @date: 2022/10/14 * @param: writer * @param: document * @returns: void */ public void onEndPage(PdfWriter writer, Document document) { try { if (bf == null) { bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false); } if (fontDetail == null) { fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 資料體字型 } } catch (DocumentException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // 1.寫入頁首 ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_LEFT, new Phrase(header, fontDetail), document.left(), document.top() + 20, 0); // 2.寫入前半部分的 第 X頁/共 int pageS = writer.getPageNumber(); String foot1 = "第 " + pageS + " 頁 /共"; Phrase footer = new Phrase(foot1, fontDetail); // 3.計算前半部分的foot1的長度,後面好定位最後一部分的'Y頁'這倆字的x軸座標,字型長度也要計算進去 = len float len = bf.getWidthPoint(foot1, presentFontSize); // 4.拿到當前的PdfContentByte PdfContentByte cb = writer.getDirectContent(); // 5.寫入頁尾1,x軸就是(右margin+左margin + right() -left()- len)/2.0F 再給偏移20F適合人類視覺感受,否則肉眼看上去就太偏左了 ,y軸就是底邊界-20,否則就貼邊重疊到資料體裡了就不是頁尾了;注意Y軸是從下往上累加的,最上方的Top值是大於Bottom好幾百開外的。 ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer, (document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F + 20F, document.bottom() - 16, 0); // 6.寫入頁尾2的模板(就是頁尾的Y頁這倆字)新增到文件中,計算模板的和Y軸,X=(右邊界-左邊界 - 前半部分的len值)/2.0F + len , y 軸和之前的保持一致,底邊界-20 cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 20F, document.bottom() - 16); // 調節模版顯示的位置 } /** * 關閉文件時,替換模板,完成整個頁首頁尾元件 * @author: wx * @date: 2022/10/14 * @param: writer * @param: document * @returns: void */ public void onCloseDocument(PdfWriter writer, Document document) { // 7.最後一步了,就是關閉文件的時候,將模板替換成實際的 Y 值,至此,page x of y 製作完畢,完美相容各種文件size。 total.beginText(); total.setFontAndSize(bf, presentFontSize);// 生成的模版的字型、顏色 String foot2 = " " + (writer.getPageNumber() - 1) + " 頁"; total.showText(foot2);// 模版顯示的內容 total.endText(); total.closePath(); } }
三、生成PDF檔案
總結:
html生成pdf的時候,如果失敗了,要檢查對應的包是否引入錯誤,或者少引入jar。
本部落格借鑑了網上的例子,在這裡非常感謝其他博主的部落格,讓我在工作中解決了大量圖片生成pdf的功能。