java实现html转PDF

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个转义符:<,>,&,",©;的转义字符分别如下: &lt; &gt;&amp; &quot; &apos;
            content = content.replaceAll("&lt;","<").replaceAll("&gt;",">").replaceAll("&amp;","&").replaceAll("&quot;","\"").replaceAll("&apos;","©");
            content = content.replaceAll(" ","").replaceAll(" ","").replaceAll("&nbsp;","").replaceAll("&ensp;","").replaceAll("&emsp;","");
            content = content.replaceAll("&copy;","©").replaceAll("&reg;","TM").replaceAll("&times;","×").replaceAll("&divide;","÷");

            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("&#xa0;","");
            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();
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值