html转PDF方法类
import com.itextpdf.text.*; import com.itextpdf.text.Image; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.*; import com.itextpdf.tool.xml.XMLWorkerHelper; import com.lingzhi.common.utils.file.FileUploadUtils; import com.lingzhi.common.utils.html.HtmlConvertWordUtil; import com.lowagie.text.Font; import com.lowagie.text.pdf.BaseFont; import com.spire.ms.System.Collections.ArrayList; import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter; import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions; import fr.opensagres.xdocreport.itext.extension.font.IFontProvider; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.jsoup.Jsoup; import org.jsoup.nodes.Attributes; import org.jsoup.nodes.Document; import org.jsoup.nodes.Entities; import org.jsoup.parser.Parser; import org.jsoup.select.Elements; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xhtmlrenderer.pdf.ITextFontResolver; import org.xhtmlrenderer.pdf.ITextRenderer; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.io.*; import java.nio.charset.Charset; import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; /** * PDF相关处理 * */ public class PdfUtils { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); public static final String DEFAULT_ORDER_CSS = "table{border-collapse:collapse;border-spacing:0;width:100%;border-bottom:1px solid #222;border-right:1px solid #222;margin-top:20pt;margin-bottom:20pt;}*{font-size:10.5pt;font-family:SimSun;line-height:1.8}a{text-decoration:none;color:black}td,th{border-top:1px solid #222;border-left:1px solid #222;padding:8px 0;text-align:center;white-space:normal;word-wrap:break-word;word-break:break-all;}h1,h1 a,h1 a strong{font-size:29.26pt;font-weight:bold;}h2,h2 a,h2 a strong{font-size:17.56pt;font-weight:bold;}h3,h3 a,h3 a strong{font-size:15.61pt;font-weight:bold;}h4,h4 a,h4 a strong{font-size:13.66pt;font-weight:bold;}h5,h5 a,h5 a strong{font-size:11.70pt;font-weight:bold;}h6,h6 a,h6 a strong{font-size:9.75pt;font-weight:bold;}h1,h2,h3,h4,h5,h6{font-weight:bolder}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{font-weight:bolder}thead tr:nth-child(1){width:12% !important;}thead tr:nth-child(2){width:12% !important;}thead tr:nth-child(3){width:10% !important;}thead tr:nth-child(4){width:8% !important;}thead tr:nth-child(5){width:8% !important;}thead tr:nth-child(6){width:8% !important;}thead tr:nth-child(7){width:11% !important;}thead tr:nth-child(8){width:11% !important;}thead tr:nth-child(9){width:10% !important;}thead tr:nth-child(10){width:10% !important;}thead th:nth-child(1){font-weight:normal;font-size:14px;width:12% !important;}thead th:nth-child(2){font-weight:normal;font-size:14px;width:12% !important;}thead th:nth-child(3){font-weight:normal;font-size:14px;width:10% !important;}thead th:nth-child(4){font-weight:normal;font-size:14px;width:8% !important;}thead th:nth-child(5){font-weight:normal;font-size:14px;width:8% !important;}thead th:nth-child(6){font-weight:normal;font-size:14px;width:8% !important;}thead th:nth-child(7){font-weight:normal;font-size:14px;width:11% !important;}thead th:nth-child(8){font-weight:normal;font-size:14px;width:11% !important;}thead th:nth-child(9){font-weight:normal;font-size:14px;width:10% !important;}thead th:nth-child(10){font-weight:normal;font-size:14px;width:10% !important;}.left{width:100%;display:table:text-align:left;float:left}.right{width:100%;display:table:text-align:right;float:right}.none-border,.none-border td,.none-border th{border:none;}"; final static String[] colWidth = {"12%", "12%", "10%", "8%", "8%", "8%", "12%", "10%", "10%", "10%"}; /** * 导出PDF * */ public void exportPdf(HttpServletResponse response, String filename, String content, String watermark) throws Exception { if (content == null || content.length() <= 0) return; OutputStream os = null; OutputStream tempos = null; InputStream tempStream = null; try { content=content.replace("<mark>","").replace("</mark>",""); // XML5个转义符:<,>,&,",©;的转义字符分别如下: < >& " ' content = content.replaceAll("<","<").replaceAll(">",">").replaceAll("&","&").replaceAll(""","\"").replaceAll("'","©"); content = content.replaceAll(" ","").replaceAll(" ","").replaceAll(" ","").replaceAll(" ","").replaceAll(" ",""); content = content.replaceAll("©","©").replaceAll("®","TM").replaceAll("×","×").replaceAll("÷","÷"); String html="" + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" + "<head>\n" + " <meta charset=\"utf-8\"></meta>\n" + " <title>"+filename+"</title>\n" + "<style type=\"text/css\">"+ "@page{size:a4 portrait;}"+ "body{font-family: SimSun;}"+ DEFAULT_ORDER_CSS+ " </style>"+ "</head>\n" + "<body>\n" + content + "\n</body>\n" + "</html>"; // 通过Jsoup格式化html Document parse = Jsoup.parse(html); // 获取html中所有的标签元素 Elements es = parse.body().getAllElements(); List<HashMap<String,String>> imglist = new ArrayList(); // 筛选标签 java.util.List<org.jsoup.nodes.Element> tag1 = es.stream().filter(x -> "img".equals(x.tagName())).collect(Collectors.toList()); for (org.jsoup.nodes.Element imgElement : tag1) { //处理图片 Attributes as = imgElement.attributes(); String src = as.get("src"); HttpServletRequest request = ServletUtils.getRequest(); String ur = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort(); String pictureUrl = ""; if(src.contains("//")){ pictureUrl = src; }else{ pictureUrl = ur+src; HashMap<String,String> imgmap=new HashMap<>(); imgmap.put("src1",src); imgmap.put("src2",pictureUrl); imglist.add(imgmap); } //设置图片宽度 int pagewidth = Math.round(PageSize.A4.getWidth()); try { Image img = Image.getInstance(pictureUrl); if(img.getWidth()>pagewidth) { imgElement.attr("style","width:100%"); } } catch (Exception ex) { } } String _html = parse.html(); String xhtml = htmlToxhtml(_html); xhtml=xhtml.replace(" ",""); for(HashMap<String,String> item : imglist) { xhtml = xhtml.replace(item.get("src1"),item.get("src2")); } ITextRenderer renderer = new ITextRenderer(); renderer.setDocumentFromString(xhtml); ITextFontResolver fontResolver = renderer.getFontResolver(); fontResolver.addFont("/Fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("/Fonts/SimSun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("/Fonts/simsunbd.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); //浏览器导出 renderer.layout(); response.setCharacterEncoding("utf-8"); response.setContentType("application/pdf"); response.setHeader("Content-disposition", "attachment;filename="+new String((filename+".pdf").getBytes("utf-8"),"ISO8859-1")); os = response.getOutputStream(); //创建输出流 if(StringUtils.isEmpty(watermark)) { renderer.createPDF(os); renderer.finishPDF(); } else { //添加水印 String tempPath = FileUploadUtils.getDefaultBaseDir()+"/Temporary"; File file = new File(tempPath); if (!file.exists() && !file.isDirectory()) { file.mkdir(); } String tempPath1 = tempPath+"/temp1.pdf"; String tempPath2 = tempPath+"/temp2.pdf"; tempos = new FileOutputStream(new File(tempPath1)); renderer.createPDF(tempos); renderer.finishPDF(); tempos.flush(); tempos.close(); addPdfTextMark(tempPath1,tempPath2,watermark,50,50); tempStream = new FileInputStream(tempPath2); int c = 0; byte[] buf = new byte[8192]; while ((c = tempStream.read(buf, 0, buf.length)) > 0) { os.write(buf, 0, c); os.flush(); } tempStream.close(); FileUploadUtils.deFile(tempPath1); FileUploadUtils.deFile(tempPath2); } os.flush(); os.close(); } catch (Exception e) { if(os != null) os.close(); if(tempos != null) tempos.close(); if(tempStream != null) tempStream.close(); throw e; } } public void exportPdf2(HttpServletResponse response, String filename, String content, String watermark) throws Exception { if (content == null || content.length() <= 0) return; OutputStream os = null; OutputStream tempos = null; InputStream tempStream = null; try { String tempPath = FileUploadUtils.getDefaultBaseDir()+"/Temporary"; File file = new File(tempPath); if (!file.exists() && !file.isDirectory()) { file.mkdir(); } String tempPath1 = tempPath+"/temp1.pdf"; String tempPath2 = tempPath+"/temp2.pdf"; String tempPath0 = tempPath + "/temp0.docx"; XWPFDocument docxDocument = HtmlConvertWordUtil.htmlConvertWord(content); FileOutputStream out = new FileOutputStream(tempPath0); docxDocument.write(out); out.close(); ConvertDocxToPdf(new FileInputStream(tempPath0), new FileOutputStream(tempPath1)); tempos = new FileOutputStream(new File(tempPath1)); tempos.flush(); tempos.close(); response.setCharacterEncoding("utf-8"); response.setContentType("application/pdf"); response.setHeader("Content-disposition", "attachment;filename="+new String((filename+".pdf").getBytes("utf-8"),"ISO8859-1")); os = response.getOutputStream(); //创建输出流 createWithHtml(content,"",new FileOutputStream(new File(tempPath1))); if(StringUtils.isEmpty(watermark)) { tempStream = new FileInputStream(tempPath1); } else { //添加水印 addPdfTextMark(tempPath1,tempPath2,watermark,50,50); tempStream = new FileInputStream(tempPath2); } int c = 0; byte[] buf = new byte[8192]; while ((c = tempStream.read(buf, 0, buf.length)) > 0) { os.write(buf, 0, c); os.flush(); } tempStream.close(); //FileUploadUtils.deFile(tempPath0); FileUploadUtils.deFile(tempPath1); FileUploadUtils.deFile(tempPath2); os.flush(); os.close(); } catch (Exception e) { if (os != null) os.close(); if (tempos != null) tempos.close(); if (tempStream != null) tempStream.close(); throw e; } } /** * html转xhtml * */ public String htmlToxhtml(String html) { Document doc = Jsoup.parse(html); doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml).escapeMode(Entities.EscapeMode.xhtml); return doc.html(); } /** * Word转PDF * */ public void ConvertDocxToPdf(InputStream fileInputStream, OutputStream fileOutputStream){ try { //添加依赖org.apache.poi.xwpf.converter.pdf和xdocreport都需要 XWPFDocument xwpfDocument = new XWPFDocument(fileInputStream); PdfOptions pdfOptions = PdfOptions.create(); //中文字体处理 pdfOptions.fontProvider(new IFontProvider() { @Override public Font getFont(String familyName, String s1, float v, int i, Color color) { try { BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font fontChinese = new Font(bfChinese, v, i, color); if (familyName != null) fontChinese.setFamily(familyName); return fontChinese; } catch (Exception e) { e.printStackTrace(); return null; } } }); PdfConverter.getInstance().convert(xwpfDocument,fileOutputStream,pdfOptions); fileInputStream.close(); fileOutputStream.close(); } catch (Exception ex) { String aa=ex.getMessage(); } } /** * pdf文件添加文字水印 * @param InPdfFile 要添加文字水印的pdf路径 * @param outPdfFile 添加水印之后的输出路径 * @param textMark 水印内容 * @param textWidth 文字横坐标 * @param textHeight 文字纵坐标 * @throws Exception */ public static void addPdfTextMark(String InPdfFile, String outPdfFile, String textMark, int textWidth, int textHeight) throws Exception { PdfReader reader = new PdfReader(InPdfFile, "PDF".getBytes()); PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(new File(outPdfFile))); try { PdfContentByte under; PdfGState gs1 = new PdfGState(); gs1.setFillOpacity(0.8f);// 透明度设置 com.itextpdf.text.pdf.BaseFont font =com.itextpdf.text.pdf.BaseFont.createFont("C:/WINDOWS/Fonts/SIMSUN.TTC,1", "Identity-H", true);// 使用系统字体 int pageSize = reader.getNumberOfPages();// 原pdf文件的总页数 for (int i = 1; i <= pageSize; i++) { //under = stamp.getUnderContent(i);// 水印在之前文本下 under = stamp.getOverContent(i);//水印在之前文本上 under.beginText(); under.setColorFill(new BaseColor(211,211,211));// 文字水印 颜色 under.setGState(gs1);// 图片水印 透明度 under.setFontAndSize(font, 32);// 文字水印 字体及字号 under.setTextMatrix(textWidth, textHeight);// 文字水印 起始位置 //under.showTextAligned(Element.ALIGN_CENTER, textMark, textWidth, textHeight, 45); for (int x = 0; x < 2; x++) { for (int y = 0; y < 3; y++) { under.showTextAligned(Element.ALIGN_LEFT, textMark, x*200+100, y*200+x*100, 45); } } under.endText(); } stamp.close();// 关闭 reader.close(); } catch (Exception e) { if(reader != null) reader.close(); if(stamp != null) stamp.close(); throw e; } } /** * pdf文件添加图片水印 * @param InPdfFile 要添加水印的pdf路径 * @param outPdfFile 添加水印完成的pdf输入路径 * @param markImagePath 添加图片水印的路径 * @param imgWidth 添加水印X坐标:文件的四个角,左下方的角坐标为(0,0) * @param imgHeight 添加水印的Y坐标 * @throws Exception */ public static void addPdfImgMark(String InPdfFile, String outPdfFile, String markImagePath, int imgWidth, int imgHeight) throws Exception { PdfReader reader = new PdfReader(InPdfFile, "PDF".getBytes()); PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(new File(outPdfFile))); PdfContentByte under; PdfGState gs1 = new PdfGState(); gs1.setFillOpacity(0.8f);// 透明度设置 Image img = Image.getInstance(markImagePath);// 插入图片水印 img.setAbsolutePosition(imgWidth, imgHeight); // 坐标 img.setRotation(0);// 旋转 弧度 img.setRotationDegrees(0);// 旋转 角度 img.scaleAbsolute(595, 842);// 自定义大小 // img.scalePercent(50);//依照比例缩放 int pageSize = reader.getNumberOfPages();// 原pdf文件的总页数 for (int i = 1; i <= pageSize; i++) { under = stamp.getUnderContent(i);// 水印在之前文本下 // under = stamp.getOverContent(i);//水印在之前文本上 under.setGState(gs1);// 图片水印 透明度 under.addImage(img);// 图片水印 } stamp.close();// 关闭 } public void createWithHtml(String templateString,String extraHtml, OutputStream outputStream) throws Exception{ com.itextpdf.text.Document document = new com.itextpdf.text.Document(); //页面竖向 Rectangle pageSize = new Rectangle(PageSize.A4.getWidth(), PageSize.A4.getHeight()); pageSize.rotate(); document.setPageSize(pageSize); PdfWriter pdfWriter = PdfWriter.getInstance(document,outputStream); int width = Math.round(PageSize.A4.getWidth()); document.open(); document.addCreationDate(); XMLWorkerHelper worker = XMLWorkerHelper.getInstance(); String mdContent = templateString; Charset charset = Charset.forName("utf-8"); //Charset.forName("GBK"); String htmlContent = "<html lang=\"en\"><meta http-equiv=\"Content-Type\" content=\"text/html; charset="+charset.name()+"\" /><body>" + templateString + "</body></html>"; org.jsoup.nodes.Document htmlDoc = Jsoup.parse(htmlContent, "", Parser.xmlParser()); org.jsoup.select.Elements centerEle = htmlDoc.select("center"); Elements tblist = htmlDoc.select("table"); if(tblist!=null){ for(org.jsoup.nodes.Element element : tblist){ element.attr("width","100%"); } } //处理h1~h6问题 Elements aList = htmlDoc.select("h1 a,h2 a,h3 a,h4 a,h5 a,h6 a"); if(aList != null) { for (org.jsoup.nodes.Element a : aList) { String text = a.text(); a.text(""); a.appendElement("strong"); a.child(0).text(text); } } Elements imglist = htmlDoc.select("img"); if(imglist != null) { for (org.jsoup.nodes.Element a : imglist) { //处理图片 Attributes as = a.attributes(); String src = as.get("src"); HttpServletRequest request = ServletUtils.getRequest(); String ur = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort(); String pictureUrl = ""; if(src.contains("//")){ pictureUrl = src; }else{ pictureUrl = ur+src; } try { Image img = Image.getInstance(pictureUrl); if(img.getWidth()>width) { int imgwidth = Math.round(width*100/80); int imgheight = Math.round(img.getHeight()*width/imgwidth); img.scaleAbsolute(imgwidth,imgheight); } } catch (Exception e) { e.printStackTrace(); } } } String bodyContent = htmlDoc.select("body").html(); bodyContent = htmlToxhtml(bodyContent); worker.parseXHtml(pdfWriter, document, new ByteArrayInputStream(bodyContent.getBytes(charset)) , new ByteArrayInputStream(DEFAULT_ORDER_CSS.getBytes()) ,charset , new AsianFontProvider("/Fonts/SimSun.ttf","/Fonts/simsunbd.ttf")); document.close(); pdfWriter.close(); } }