iTEXT将html文档转PDF,spire.doc包html转word(包括样式修改和添加图片/页码等设置)

项目需求

使用velocity模板生成html内容,将含有标题 / 段落 / 表格 / 图片 的html文件转化成PDF和word格式,并保留良好样式。

iText

起初只想实现word功能,但经过尝试和查询一些例如poi等工具,都无法较好的保留原有的复杂样式,后更换pdf需求进行尝试,itext生成pdf已经非常完美了。
生成word样式没有尝试,感觉比较麻烦。
后来采用spire的free包将pdf转word样式保持很好,但是项目环境中遇到问题,转战html转word。
注意:不要将spire的pdf和word包同时引用,如果需要可以直接使用office包,会产生一些例如注册许可方面的冲突。

spire.pdf / spire.doc / spire.office

很好的第三方工具,能完美实现html转pdf和word等格式文件,最关键的是有free版本,虽然有10页的限制,结合需求页可能够用和付费版功能上无差别。
付费版本也一样可以用,只是会在左上角有红色警告信息,其实word可以手动删除,pdf可以通过添加图片的方式遮盖掉。
注意:我们的项目环境是Linux / jdk1.7 / weblogic12.1.3.0.0(pdf转word–使用doc包就会报错UnkownSource【原因不明】,最好直接html转word最终解决问题),html转word表头的css样式可能会无法解析,使用基本样式就好。

spire.pdf / spire.doc 冰蓝科技 中文文档

html转pdf

引入jar包

引入itext仓库
        <repository>
            <id>itext</id>
            <name>iText Repository - releases</name>
            <url>https://repo.itextsupport.com/releases</url>
        </repository>
在pom.xml引入maven(不包括spire.pdf)
         <!-- itextpdf -->
        <dependency>
            <groupId>com.lowagie</groupId>
            <artifactId>itext</artifactId>
            <version>2.1.7</version>
        </dependency>
        <dependency>
            <groupId>com.lowagie</groupId>
            <artifactId>itext-rtf</artifactId>
            <version>2.1.7</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.10</version>
        </dependency>
        <!-- pdfHTML -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext7-core</artifactId>
            <version>7.1.0</version>
            <type>pom</type>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>html2pdf</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.0.8</version>
        </dependency>
    </dependencies>
可以下载spire.pdf.free以及各种实用jar包的maven仓库

maven仓库(内含spire.pdf.free和spire.doc.free)

生成pdf

package com.sy.util;

import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.attach.impl.DefaultTagWorkerFactory;
import com.itextpdf.html2pdf.css.media.MediaDeviceDescription;
import com.itextpdf.html2pdf.css.media.MediaType;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.layout.font.FontProvider;
import org.apache.commons.io.FileUtils;
import org.apache.poi.util.IOUtils;
import java.io.*;
import static com.itextpdf.kernel.geom.PageSize.A4;
import static com.itextpdf.kernel.geom.PageSize.A3;

public class PdfService {
    //private static final Logger LOGGER = LoggerFactory.getLogger(PdfFromHTML.class);
    public static final String FONT_NAME = "simsun.ttf";

    public void copyFont(String targetDir,String fontPath) {
        FileOutputStream fout = null;
        FileInputStream fileInputStream = null;
        try {
            //InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(FONT_CLASS_PATH);
            fileInputStream = new FileInputStream(fontPath+"/WEB-INF/fonts/simsun.ttf");
            File dir = new File(targetDir);
            FileUtils.forceMkdir(dir);
            fout = new FileOutputStream(targetDir + "simsun.ttf");
            if (fileInputStream != null && fout != null) {
                org.apache.commons.io.IOUtils.copy(fileInputStream, fout);
            }
        } catch (Exception e) {
            //LOGGER.error("failed to copy font: ", e);
            e.printStackTrace();
        } finally {
            if(null!=fileInputStream){
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null!=fout){
                try {
                    fout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void createPdfFromHtml(String pdfFileName, InputStream htmlInputStream, String resourcePrefix){
        PdfDocument pdfDoc = null;
        FileOutputStream outputStream = null;
        PdfWriter pdfWriter = null;
        try {
            outputStream = new FileOutputStream(resourcePrefix + pdfFileName);
            WriterProperties writerProperties = new WriterProperties();
            writerProperties.addXmpMetadata();
            pdfWriter = new PdfWriter(outputStream, writerProperties);

            pdfDoc = createPdfDoc(pdfWriter);
            PdfDocument pdfDocument = new PdfDocument(pdfWriter);
            pdfDocument.setDefaultPageSize(A3);

            //转换器
            ConverterProperties props = createConverterProperties(resourcePrefix);
            props.setBaseUri(resourcePrefix);
            //设置媒体的描述方式
            MediaDeviceDescription mediaDeviceDescription = new MediaDeviceDescription(MediaType.SCREEN);
            props.setMediaDeviceDescription(mediaDeviceDescription);

            HtmlConverter.convertToPdf(htmlInputStream,pdfDocument, props);

            pdfDocument.close();

        } catch (Exception e) {
            //LOGGER.error("failed to create pdf from html exception: ", e);
            e.printStackTrace();
        } finally {
            try {
                outputStream.close();
                pdfWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                outputStream = null;
                pdfWriter = null;
            }
            IOUtils.closeQuietly(pdfDoc);
        }
    }
    private PdfDocument createPdfDoc(PdfWriter pdfWriter) {
        PdfDocument pdfDoc;
        pdfDoc = new PdfDocument(pdfWriter);
        pdfDoc.getCatalog().setLang(new PdfString("zh-CN"));
        pdfDoc.setTagged();
        pdfDoc.getCatalog().setViewerPreferences(new PdfViewerPreferences().setDisplayDocTitle(true));
        return pdfDoc;
    }
    private ConverterProperties createConverterProperties(String resourcePrefix) {
        ConverterProperties props = new ConverterProperties();
        props.setFontProvider(createFontProvider(resourcePrefix));
        props.setBaseUri(resourcePrefix);
        props.setCharset("UTF-8");
        DefaultTagWorkerFactory tagWorkerFactory = new DefaultTagWorkerFactory();
        props.setTagWorkerFactory(tagWorkerFactory);
        return props;
    }
    private FontProvider createFontProvider(String resourcePrefix) {
        FontProvider fp = new FontProvider();
        fp.addStandardPdfFonts();
        fp.addDirectory(resourcePrefix);
        return fp;
    }
}
下面为main方法
 //pdf文件加载和生成统一路径
                String pdfPath = localFilePath + name + ".pdf";
                File temFile = new File(localFilePath);
                if (!temFile.exists()) {
                    temFile.mkdirs();
                }
                // 添加字体,这一步很关键,否则中文会显示不出来
                PdfService pdfService = new PdfService();
                File file = new File(localFilePath + PdfService.FONT_NAME);
                if (!file.exists()) {
                    //加载字体库
                    pdfService.copyFont(localFilePath,realPath);
                }

                //---------------------
                FileInputStream inputStream = new FileInputStream(url);

                File pdfFile = new File(pdfPath);
                //TODO html To PDF
                pdfService.createPdfFromHtml(pdfFile.getName(), inputStream, localFilePath);

pdf布局设置(以下内容通过spire.doc/pdf包处理)

package com.sy.util;

import com.spire.doc.FileFormat;
import com.spire.doc.documents.*;
import com.spire.doc.fields.DocPicture;
import com.spire.doc.fields.TextRange;
import com.spire.pdf.*;
import com.spire.doc.*;
import com.spire.pdf.annotations.PdfRubberStampAnnotation;
import com.spire.pdf.annotations.appearance.PdfAppearance;
import com.spire.pdf.automaticfields.PdfCompositeField;
import com.spire.pdf.automaticfields.PdfPageCountField;
import com.spire.pdf.automaticfields.PdfPageNumberField;
import com.spire.pdf.graphics.*;
import java.awt.*;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import com.spire.doc.FileFormat.*;

public class PdfPageSetting {

    public static final int FLAG = 2;

    public void pdfPageSetting(String url,int flag){

        //创建PdfDocument对象
        PdfDocument originalDoc = new PdfDocument();
        //加载PDF文件
        originalDoc.loadFromFile(url);
		//第一页插入空白页(目的是删除spirefree的内置红色警告语,主要是为了生成word使用,
		pdf可以用添加图片方法进行遮盖)
        originalDoc.getPages().insert(0);

        //创建一个新的PdfDocument实例
        PdfDocument newDoc = new PdfDocument();

        //遍历所有PDF 页面
        Dimension2D dimension2D = new Dimension();
        for (int i = 0; i < originalDoc.getPages().getCount(); i++) {
            PdfPageBase page = originalDoc.getPages().get(i);

            if (flag==1){
                //设置新文档页面宽、高为原来的1倍
                float scale = 1.0f;
                float width = (float) page.getSize().getWidth() * scale;
                float height = (float) page.getSize().getHeight() * scale;
                dimension2D.setSize(width, height);
                //设置新文档第一页的页边距为左右
                PdfMargins margins = new PdfMargins(0, 20);
                PdfPageBase newPage = newDoc.getPages().add(dimension2D, margins);
                //复制原文档的内容到新文档
                newPage.getCanvas().drawTemplate(page.createTemplate(), new Point2D.Float());
            }

            if (flag==2){
                //设置新文档页边距为左右0、上下20(不能随意更改,会影响主标题位置)
                PdfMargins margins = new PdfMargins(0,20,0,0);
                //设置新文档页面大小为A3
                PdfPageBase newPage = newDoc.getPages().add(PdfPageSize.A3, margins);
                //调整画布,设置内容也根据页面的大小进行缩放
                double wScale = (PdfPageSize.A3.getWidth() - 10) / PdfPageSize.A3.getWidth();
                double hScale = (PdfPageSize.A3.getHeight() - 10) / PdfPageSize.A3.getHeight();
                newPage.getCanvas().translateTransform(wScale, hScale);
                //复制原文档的内容到新文档
                newPage.getCanvas().drawTemplate(page.createTemplate(), new Point2D.Float());
            }

             if (flag==3){
                 //设置新文档页边距
                 PdfMargins margins = new PdfMargins(0, 0);
                 //设置新文档页面大小为A3, 页面旋转角度为0,纸张方向为水平
                 PdfPageBase newPage = newDoc.getPages().add(PdfPageSize.A4, margins, PdfPageRotateAngle.Rotate_Angle_0, PdfPageOrientation.Landscape);
                 //调整画布,设置内容也根据页面的大小进行缩放
                 double wScale = PdfPageSize.A4.getHeight() / page.getSize().getWidth();
                 double hScale = PdfPageSize.A4.getWidth() / page.getSize().getHeight();
                 newPage.getCanvas().translateTransform(wScale, hScale);
                 //复制原文档的内容到新文档
                 newPage.getCanvas().drawTemplate(page.createTemplate(), new Point2D.Float());
             }
        }
        //保存PDF
        newDoc.saveToFile(url);
        newDoc.close();
        originalDoc.close();

    }

pdf添加页码

  /**
     * 添加页码
     * @param targetPath
     */
    public void addPageNum(String targetPath) {
        //加载PDF文档
        PdfDocument doc = new PdfDocument();
        doc.loadFromFile(targetPath);
        //删除第一页空白页
        doc.getPages().removeAt(0);
        //创建字体
        PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("Default", Font.PLAIN, 10),true);
        //获取页面尺寸
        Dimension2D pageSize = doc.getPages().get(0).getSize();
        //初始化y坐标
        float y = (float) pageSize.getHeight() - 20;
        //遍历文档中的页
        for (int i = 0; i < doc.getPages().getCount(); i++) {

            //初始化页码域
            PdfPageNumberField number = new PdfPageNumberField();

            //初始化总页数域
            //PdfPageCountField count = new PdfPageCountField();

            //创建复合域
            PdfCompositeField compositeField = new PdfCompositeField(font, PdfBrushes.getBlack(),"{0}", number);

            //设置复合域内文字对齐方式
            compositeField.setStringFormat(new PdfStringFormat(PdfTextAlignment.Right, PdfVerticalAlignment.Top));

            //测量文字大小
            Dimension2D textSize = font.measureString(compositeField.getText());

            //设置复合域的在PDF页面上的位置及大小
            compositeField.setBounds(new Rectangle2D.Float(((float) pageSize.getWidth() - (float) textSize.getWidth())/2, y, (float) textSize.getWidth(), (float) textSize.getHeight()));

            //将复合域添加到PDF页面
            compositeField.draw(doc.getPages().get(i).getCanvas());
        }
        //保存为另外一个文档
        doc.saveToFile(targetPath);
        doc.close();
    }

pdf添加图片

   /**
     * 添加图片到PDF
     * @param url  pdf文件
     * @param baseUrl  项目路径
     * @param savePath  文件保存路径
     */

    public static void addImgToPdf(String url,String baseUrl) {

        //创建PdfDocument对象
        PdfDocument doc = new PdfDocument();

        //加载PDF文档
        doc.loadFromFile(url);

        //删除第一页空白页
        //doc.getPages().removeAt(0);

        for (int i = 0; i < doc.getPages().getCount(); i++) {
            //获取第i页
            PdfPageBase page = doc.getPages().get(i);

            //加载图片到PdfImage对象
            PdfImage image = PdfImage.fromFile(baseUrl + "img\\custom\\pdf.png");

            //获取图片高宽
            int width = image.getWidth();
            int height = image.getHeight();

            //创建PdfTemplate对象,大小跟图片一致
            PdfTemplate template = new PdfTemplate(width, height);

            //在模板上绘制图片
            template.getGraphics().drawImage(image, 0, 0, width, height);

            //创建PdfRubebrStampAnnotation对象,指定大小和位置
            Rectangle2D rect = new Rectangle2D.Float((float)
                    (0), (float)(0), 835, 50);
            PdfRubberStampAnnotation stamp = new PdfRubberStampAnnotation(rect);

            //创建PdfAppearance对象
            PdfAppearance pdfAppearance = new PdfAppearance(stamp);

            //将模板应用为PdfAppearance的一般状态
            pdfAppearance.setNormal(template);

            //将PdfAppearance 应用为图章的样式
            stamp.setAppearance(pdfAppearance);

            //添加图章到PDF
            page.getAnnotationsWidget().add(stamp);
        }

        //保存文档
        doc.saveToFile(url);

        doc.close();
    }

pdf转word(windows/linux和tomcat下测试可用)

 		//创建PdfDocument对象
        PdfDocument doc = new PdfDocument();

        //加载PDF文档
        doc.loadFromFile(url);

		  //保存文档
        doc.saveToFile(url);

html转word

		//TODO html To DOCX
        Document word = new Document();
        //html文件地址
        word.loadFromFile(url);
        word.saveToFile(wordPath, FileFormat.Docx);
        word.close();
        //TODO 添加页眉和页脚,设置word页边距(realPath为页眉图片地址)
         setUpPageOfWord(wordPath,realPath);

word添加页眉页脚和页码

  /**
     * word添加页眉
     * @param url
     * @param baseUrl
     * @param
     */
    public static void setUpPageOfWord(String url,String baseUrl) {
        //创建Document对象
        Document doc = new Document();

        doc.loadFromFile(url);

        //获取第一页
        Section section = doc.getSections().get(0);

        Dimension2D dimension2D = new Dimension();
        dimension2D.setSize(800,1200);

        section.getPageSetup().setPageSize(dimension2D);

        //设置页边距
        section.getPageSetup().getMargins().setTop(40f);
        section.getPageSetup().getMargins().setBottom(40f);
        section.getPageSetup().getMargins().setLeft(60f);
        section.getPageSetup().getMargins().setRight(60f);

        //调用insertHeaderAndFooter方法插入页眉页脚到第一个section
        insertHeaderAndFooter(section,baseUrl);

        //保存
        doc.saveToFile(url);

        doc.close();
    }

    private static void insertHeaderAndFooter(Section section,String baseUrl) {

        //分别获取section的页眉页脚
        HeaderFooter header = section.getHeadersFooters().getHeader();
        HeaderFooter footer = section.getHeadersFooters().getFooter();

        //添加段落到页眉
        Paragraph headerParagraph = header.addParagraph();

        //插入图片到页眉的段落
        DocPicture headerPicture = headerParagraph.appendPicture(baseUrl + "img/custom/word.png");
        headerPicture.setHorizontalAlignment(ShapeHorizontalAlignment.Left);
        headerPicture.setVerticalOrigin(VerticalOrigin.Top_Margin_Area);
        headerPicture.setVerticalAlignment(ShapeVerticalAlignment.Bottom);

        //添加文字到页眉的段落
        TextRange text = headerParagraph.appendText("上海烟草集团");
        //text.getCharacterFormat().setFontName("default");
        text.getCharacterFormat().setFontSize(10);
        text.getCharacterFormat().setItalic(true);
        headerParagraph.getFormat().setHorizontalAlignment(HorizontalAlignment.Right);

        //设置文字环绕方式
        headerPicture.setTextWrappingStyle(TextWrappingStyle.Behind);

        //设置页眉段落的底部边线样式
        headerParagraph.getFormat().getBorders().getBottom().setBorderType(BorderStyle.Single);
        headerParagraph.getFormat().getBorders().getBottom().setLineWidth(1f);

        //添加段落到页脚
        Paragraph footerParagraph = footer.addParagraph();

        //添加Field_Page和Field_Num_Pages域到页脚段落,用于显示当前页码和总页数
        footerParagraph.appendField("page number", FieldType.Field_Page);
        footerParagraph.appendText(" of ");
        footerParagraph.appendField("number of pages", FieldType.Field_Num_Pages);
        footerParagraph.getFormat().setHorizontalAlignment(HorizontalAlignment.Right);

        //设置页脚段落的顶部边线样式
        footerParagraph.getFormat().getBorders().getTop().setBorderType(BorderStyle.Single);
        footerParagraph.getFormat().getBorders().getTop().setLineWidth(1f);
    }

highcharts转svg插入html模板

 /**将highcharts生成<img>的src标签插入html中方便pdf转化**/
    function img() {
        $(".highchartImg").css("display","none");
        $.each($(".highchartImg"),function (idx,c) {
            var charData = $(this).highcharts().getSVG();
            var canvas = document.getElementById("canvas");
            canvg(canvas,charData);
            var image = new Image();
            image.src = canvas.toDataURL("image/png");
            $(this).next().attr("src",image.src);
        })
    }
设置highcharts原始和导出图片大小
        chart: {
            zoomType: 'xy',  //图片可拉伸
            type: 'column',
            width: 1200
        },
        exporting: {
            sourceWidth: 650,
            sourceHeight: 360,
            enabled: false,  //屏蔽下载图片选择框
        }

总结:html的元素标签一定要注意规范性,否则样式会有偏差,不过慢慢调试也能弄出来,比如一些表头的格式偏差,rowspan=“0” 这种就不要显示在标签里了,默认就好。
好吧,先到这里。这只是个人一个阶段性的总结和记录,感谢很多提供思路的朋友,最终解决了问题。如果能帮到有同样需求的伙伴就更好了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值