java中使用Jsoup和Itext实现将html转换为PDF

1.在build.gradle中安装所需依赖:

java 复制代码
implementation group: 'com.itextpdf', name: 'itextpdf', version: '5.5.13'
implementation group: 'com.itextpdf.tool', name: 'xmlworker', version: '5.5.13'
implementation group: 'org.jsoup', name: 'jsoup', version: '1.15.3'

2.创建工具类,实现转换方法

java 复制代码
/**
     * convert the html to pdf.
     */
    public void htmlToPdf(String oldFilePath, String newFilePath) throws IOException, com.itextpdf.text.DocumentException {
        Document doc = Jsoup.parse(new File(oldFilePath), "UTF-8");
        // jsoup标准化标签,生成闭合标签
        doc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);
        doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);

        com.itextpdf.text.Document document = new com.itextpdf.text.Document(PageSize.A4, 36, 36, 36, 36);
        PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(newFilePath));
        document.open();
        //html to pdf, base64 image support.
        final TagProcessorFactory tagProcessorFactory = Tags.getHtmlTagProcessorFactory();
        tagProcessorFactory.removeProcessor(HTML.Tag.IMG);
        tagProcessorFactory.addProcessor(new ImageTagRefreshFilter(), HTML.Tag.IMG);
        
        //设置中文字体
        final CssFilesImpl cssFiles = new CssFilesImpl();
        cssFiles.add(XMLWorkerHelper.getInstance().getDefaultCSS());
        final StyleAttrCSSResolver cssResolver = new StyleAttrCSSResolver(cssFiles);
        final HtmlPipelineContext hpc = new HtmlPipelineContext(new CssAppliersImpl(asianFontRefreshFilter));
        hpc.setAcceptUnknown(true).autoBookmark(true).setTagFactory(tagProcessorFactory);
        final HtmlPipeline htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(document, pdfWriter));
        final Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);

        final XMLWorker worker = new XMLWorker(pipeline, true);
        final Charset charset = StandardCharsets.UTF_8;
        final XMLParser xmlParser = new XMLParser(true, worker, charset);
        InputStream inputStream = new ByteArrayInputStream(doc.html().getBytes());
        xmlParser.parse(inputStream, charset);
//        XMLWorkerHelper.getInstance().parseXHtml(pdfWriter, document, inputStream, Charset.forName("UTF-8"));
        document.close();
    }

3.base64过滤类:

java 复制代码
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Element;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.codec.Base64;
import com.itextpdf.tool.xml.NoCustomContextException;
import com.itextpdf.tool.xml.Tag;
import com.itextpdf.tool.xml.WorkerContext;
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
import com.itextpdf.tool.xml.html.HTML;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;

public class ImageTagRefreshFilter extends com.itextpdf.tool.xml.html.Image {

    /**
     * html to pdf, base64 image support.
     * */

    @Override
    public List<Element> end(final WorkerContext ctx, final Tag tag, final List<Element> currentContent) {
        final Map<String, String> attributes = tag.getAttributes();
        String src = attributes.get(HTML.Attribute.SRC);
        List<Element> elements = new ArrayList<Element>(1);
        if (null != src && src.length() > 0) {
            Image img = null;
            if (src.startsWith("data:image/")) {
                final String base64Data = src.substring(src.indexOf(",") + 1);
                try {
                    img = Image.getInstance(Base64.decode(base64Data));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                if (img != null) {
                    try {
                        final HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
                        elements.add(getCssAppliers().apply(new Chunk((com.itextpdf.text.Image) getCssAppliers().apply(img, tag, htmlPipelineContext), 0, 0, true), tag,
                                htmlPipelineContext));
                    } catch (NoCustomContextException e) {
                        throw new RuntimeWorkerException(e);
                    }
                }
            }

            if (img == null) {
                elements = super.end(ctx, tag, currentContent);
            }
        }
        return elements;
    }
}

4.字体类代码,window用户可在C:\windows\font\中寻找自己所需字体即可。我这里用的为黑体:

simhei.ttf

java 复制代码
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


@Component
public class AsianFontRefreshFilter extends XMLWorkerFontProvider {
    //此处写字体文件的绝对路径
    private String fontPath;

    @Override
    public Font getFont(String fontname, String encoding, float size, final int style) {
        try {
            //字体文件绝对路径
            BaseFont bfChinese = BaseFont.createFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            return new Font(bfChinese, size, style);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.getFont(fontname, encoding, size, style);
    }
}

效果如下:

html页面预览:

pdf页面预览:

相关推荐
sg_knight1 小时前
Eureka 高可用集群搭建实战:服务注册与发现的底层原理与避坑指南
java·spring boot·spring·spring cloud·微服务·云原生·eureka
数据潜水员6 小时前
C#基础语法
java·jvm·算法
你这个代码我看不懂6 小时前
Java项目OOM排查
java·开发语言
Zong_09156 小时前
AutoCompose - 携程自动编排【开源】
java·spring boot·开源·自动编排
.生产的驴7 小时前
SpringCloud 分布式锁Redisson锁的重入性与看门狗机制 高并发 可重入
java·分布式·后端·spring·spring cloud·信息可视化·tomcat
虾球xz7 小时前
CppCon 2014 学习:C++ Memory Model Meets High-Update-Rate Data Structures
java·开发语言·c++·学习
攒了一袋星辰7 小时前
Spring @Autowired自动装配的实现机制
java·后端·spring
Bug缔造者8 小时前
若依+vue2实现模拟登录
java·前端框架
麦兜*8 小时前
【后端架构师的发展路线】
java·spring boot·spring·spring cloud·kafka·tomcat·hibernate
占星安啦8 小时前
一个html实现数据库自定义查询
java·前端·javascript·数据库·动态查询