思路

  1. 若html不是工整的,先将html格式化一下(jsoup),若html是文件则直接引入
  2. 将标签里面的src替换成绝对路径
  3. 将html转成pdf(itext)
  4. 再将pdf转jpg(pdfbox)
  5. 将jpg输出到浏览器

html格式化(jsoup)

  • 因为我的HTML代码是从数据库里面取的,所以不是工整的,先格式化一下
  1. 引入jsoup
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.14.3</version>
        </dependency>
  1. 格式化的代码
		//str是HTML的字符串,返回的docHtml是格式化之后的
		//一定要这样写不要直接
        Document document= Jsoup.parse(str,"utf-8");
        Document.OutputSettings setting=new Document.OutputSettings();
        setting.syntax(Document.OutputSettings.Syntax.xml);
        Document doc = document.outputSettings(setting);
        String docHtml = doc.outerHtml();

替换标签的路径

  • 我的需求里面里面的路径是相对路径,我需要换成绝对路径
//我这里的sysParam是图片路径的前缀
String docHtmlImg = docHtml .replaceAll("<img src=\"", "<img src=\"" + sysParam);

将HTML转成PDF(itext)

  1. 引入iText
        <!--用itext将html转成pdf-->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.5</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.5.11</version>
        </dependency>
  1. HTML转PDF的代码
  • 注意生成的PDF要先创建好相关路径
        //第一步,创建一个 iTextSharp.text.Document对象的实例:
        com.itextpdf.text.Document docu = new com.itextpdf.text.Document();
        //第二步,为该Document创建一个Writer实例:
        PdfWriter writer = null;
        try {
            writer = PdfWriter.getInstance(docu, new FileOutputStream("D:\\test\\HelloWorld.pdf"));
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            //第三步,打开当前Document
            docu.open();
        }
        //第四步,为当前Document添加内容:

        // 4.1 该为加载html文件字符串生成pdf方式,直接从文件你取html代码
        // File file2 = ResourceUtils.getFile("D:\\test\\HelloWorld.html");
        // String s = FileReader.create(file2).readString();
        //用Jsoup格式化html文字
        Document document= Jsoup.parse(str,"utf-8");
        Document.OutputSettings setting=new Document.OutputSettings();
        setting.syntax(Document.OutputSettings.Syntax.xml);
        Document doc = document.outputSettings(setting);
        String docHtml = doc.outerHtml();
        log.info(docHtml);

        ByteArrayInputStream fis = new ByteArrayInputStream(docHtml.getBytes());

        // 4.2 该为加载html文件生成pdf方式
        //FileInputStream fis = new FileInputStream("D:\\test\\HelloWorld.html");
        try {
        	//这里的FontProviderUtil重写了字体
            XMLWorkerHelper.getInstance().parseXHtml(writer, docu,fis ,null, Charset.defaultCharset(),new FontProviderUtil());
            //第五步,关闭Document
        } catch (IOException e) {
            e.printStackTrace();
        }
        docu.close();
        log.info("生成PDF成功!");
public class FontProviderUtil extends XMLWorkerFontProvider {
    @Override
    public Font getFont(final String fontname, final String encoding,
                        final boolean embedded, final float size, final int style,
                        final BaseColor color) {
        BaseFont bf = null;
        try {
            bf = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Font font = new Font(bf, size, style, color);
        font.setColor(color);
        return font;
    }
}
  1. 生成了D:\test\HelloWorld.pdf

将pdf转jpg(pdfbox)

  1. 引入pdfbox
        <!--pdf转jpg-->
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>fontbox</artifactId>
            <version>2.0.26</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.26</version>
        </dependency>
  1. PDF转JPG的代码
@Slf4j
public class PdfUtil {

    public static final int DEFAULT_DPI = 150;
    /**
     * pdf转图片
     * 多页PDF会每页转换为一张图片,下面会有多页组合成一页的方法
     *
     * @param pdfFile pdf文件路径
     * @param outPath 图片输出路径
     * @param dpi 相当于图片的分辨率,值越大越清晰,但是转换时间变长
     */
    public static void pdf2multiImage(String pdfFile, String outPath, int dpi) throws IOException, DocumentException {

        if (ObjectUtil.isEmpty(dpi)) {
            // 如果没有设置DPI,默认设置为150
            dpi = DEFAULT_DPI;
        }
        try (PDDocument pdf = PDDocument.load(new FileInputStream(pdfFile))) {
            int actSize = pdf.getNumberOfPages();
            List<BufferedImage> picList = Lists.newArrayList();
            for (int i = 0; i < actSize; i++) {
                BufferedImage image = new PDFRenderer(pdf).renderImageWithDPI(i, dpi, ImageType.RGB);
                picList.add(image);
            }
            // 组合图片
            yPic(picList, outPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 将宽度相同的图片,竖向追加在一起 ##注意:宽度必须相同
     *
     * @param picList 文件流数组
     * @param outPath 输出路径
     */
    public static void yPic(List<BufferedImage> picList, String outPath) {// 纵向处理图片
        if (picList == null || picList.size() <= 0) {
            log.info("图片数组为空!");
            return;
        }
        try {
            // 总高度
            int height = 0,
                    // 总宽度
                    width = 0,
                    // 临时的高度 , 或保存偏移高度
                    offsetHeight = 0,
                    // 临时的高度,主要保存每个高度
                    tmpHeight = 0,
                    // 图片的数量
                    picNum = picList.size();
            // 保存每个文件的高度
            int[] heightArray = new int[picNum];
            // 保存图片流
            BufferedImage buffer = null;
            // 保存所有的图片的RGB
            List<int[]> imgRgb = new ArrayList<int[]>();
            // 保存一张图片中的RGB数据
            int[] tmpImgRgb;
            for (int i = 0; i < picNum; i++) {
                buffer = picList.get(i);
                // 图片高度
                heightArray[i] = offsetHeight = buffer.getHeight();
                if (i == 0) {
                    // 图片宽度
                    width = buffer.getWidth();
                }
                // 获取总高度
                height += offsetHeight;
                // 从图片中读取RGB
                tmpImgRgb = new int[width * offsetHeight];
                tmpImgRgb = buffer.getRGB(0, 0, width, offsetHeight, tmpImgRgb, 0, width);
                imgRgb.add(tmpImgRgb);
            }
            // 设置偏移高度为0
            offsetHeight = 0;
            // 生成新图片
            BufferedImage imageResult = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int i = 0; i < picNum; i++) {
                tmpHeight = heightArray[i];
                if (i != 0) {
                    // 计算偏移高度
                    offsetHeight += tmpHeight;
                }
                // 写入流中
                imageResult.setRGB(0, offsetHeight, width, tmpHeight, imgRgb.get(i), 0, width);
            }
            File outFile = new File(outPath);
            // 写图片
            ImageIO.write(imageResult, "png", outFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws IOException, DocumentException {
        PdfUtil.pdf2multiImage("D:/file/1.pdf","D:/file/1.jpg",150);
    }
}
  1. 这里转JPG可能会中文乱码,出现方块等问题
  • 日志会出现下面的语句
    在这里插入图片描述
  • 这个语句的意思是系统没有安装STSong-Light字体,pdfbox使用STSongStd-Light-Acro字体来替代了
  • 看看你的日志里面是什么字体替代了STSong-Light字体(博主找到的STSong-Light字体都不能用,所以就找了STSongStd-Light-Acro字体,有找到的可以留言,STSongStd-Light-Acro字体的链接放下面了)

将jpg输出到浏览器

            FileInputStream fis = new FileInputStream(new File(jpgSource));
            response.setContentType("image/png");
            fis.getChannel().transferTo(0, fis.available(), Channels.newChannel(response.getOutputStream()));
            return null;
  • 字体的链接:https://www.fontke.com/font/26348617/
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐