利用iTextPDF将Html转成PDF中图片img中包含base64的处理

2021-09-23 145点热度 0人点赞 0条评论

在之前的文章里,有介绍如何将Html转成PDF的,详见:https://blog.terrynow.com/2021/08/10/itextpdf-5-x-convert-html-to-pdf-support-css-and-chinese/

本次又遇到一个新需求,就是Html里面有图片<img src="xxx" /> 期中xxx是http://192.168.1.1/xxx.jpg,这种链接方式的图片,发现图片是无法显示出来的,所以想办法src里面的图片转成base64的格式,例如<img src="data:image/png;base64,xxxxx" />,不过默认的情况下,iTextPDF还是无法识别并显示出来。

实现

这里,我们需要做一些特别的处理,让iTextPDF能识别这样的img格式。

新建ImageTagProcessor.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;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author Terry E-mail: yaoxinghuo at 126 dot com
 * @date 2021/9/22 17:53
 * @description
 */
public class ImageTagProcessor extends com.itextpdf.tool.xml.html.Image {
    @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<>(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 ignored) {
                }
                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;
    }
}

新建AsianFontProvider.java 实现中文支持,解决中文乱码或者不显示的问题

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;

/**
 * @author Terry E-mail: yaoxinghuo at 126 dot com
 * @date 2021/9/22 19:55
 * @description
 */
public class AsianFontProvider extends XMLWorkerFontProvider {

    private BaseFont baseFont;
    private String pdfFontBold;

    public AsianFontProvider(String pdfFontBasic, String pdfFontBold) {
        this.baseFont = createBaseFont(pdfFontBasic);
        this.pdfFontBold = pdfFontBold;
    }

    @Override
    public Font getFont(String face, String encode, boolean b, float size, int style, BaseColor baseColor) {
        BaseFont bfChinese;
//                if (style == Font.BOLD) {
//                    bfChinese = createBaseFont("/Users/Terry/Downloads/WeiRuanYaQiHei-Bold/MicrosoftYaqiHeiBold-2.ttf");
//                } else {
//                    bfChinese = createBaseFont("/Users/Terry/Downloads/WeiRuanYaHeiTi/WeiRuanYaHei-1.ttf");
//                }
        if (style == Font.BOLD) {
            bfChinese = createBaseFont(pdfFontBold);
        } else {
            bfChinese = baseFont;
        }
//                System.out.println("get font called, s:" + face + ",s1:" + encode);
//                    BaseFont bfChinese = BaseFont.createFont("/Users/Terry/Downloads/STSong.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
//                    BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        return new Font(bfChinese, size, style, baseColor);
    }

    private static BaseFont createBaseFont(String fontDir) {
        try {
            return BaseFont.createFont(fontDir, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

生成PDF的工具方法:

/**
 * @param htmlFile 原始html文件
 * @param pdfFontBasic 中文ttf字体的路径
 * @param pdfFontBasic 中文ttf字体粗体的路径
 * @return 这里返回的PDF我返回成了bytes,也可以稍加修改ByteArrayOutputStream改成FileOutputStream 输出到文件
 */
public static byte[] convertHtmlToPDF(String pdfFontBasic, String pdfFontBold, InputStream htmlFile) throws Exception {
    Document document = new com.itextpdf.text.Document(PageSize.LETTER);
    try {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        PdfWriter pdfWriter = PdfWriter.getInstance(document, bos);
        document.open();

        TagProcessorFactory tagProcessorFactory = Tags.getHtmlTagProcessorFactory();
        tagProcessorFactory.removeProcessor(HTML.Tag.IMG);
        tagProcessorFactory.addProcessor(new ImageTagProcessor(), HTML.Tag.IMG);

        CssFilesImpl cssFiles = new CssFilesImpl();
        cssFiles.add(XMLWorkerHelper.getInstance().getDefaultCSS());
        StyleAttrCSSResolver cssResolver = new StyleAttrCSSResolver(cssFiles);
        HtmlPipelineContext hpc = new HtmlPipelineContext(new CssAppliersImpl(new AsianFontProvider(pdfFontBasic, pdfFontBold)));
        hpc.setAcceptUnknown(true).autoBookmark(true).setTagFactory(tagProcessorFactory);
        HtmlPipeline htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(document, pdfWriter));
        CssResolverPipeline pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
        XMLWorker worker = new XMLWorker(pipeline, true);
        Charset charset = StandardCharsets.UTF_8;
        XMLParser parser = new XMLParser(true, worker, StandardCharsets.UTF_8);
        parser.parse(htmlFile, charset);
        pdfWriter.flush();
        pdfWriter.close();
        return bos.toByteArray();
    } finally {
        document.close();
    }
}

 

admin

这个人很懒,什么都没留下

文章评论

*

code