返回顶部
首页 > 资讯 > 后端开发 > JAVA >java生成PDF(图片,模板,表格)
  • 900
分享到

java生成PDF(图片,模板,表格)

javapdfecharts 2023-08-16 14:08:05 900人浏览 独家记忆
摘要

刚接到了一个需求,生成一个pdf,一开始以为挺简单的,通过模板生成嘛,我也发过相应的文章,根据模板直接生成pdf,响应到前端或者根据模板生成pdf,直接指定下载位置,这两种方案都可以,不过这篇文章主要讲的生成的pdf是既有模板填充还需要自己

刚接到了一个需求,生成一个pdf,一开始以为挺简单的,通过模板生成嘛,我也发过相应的文章,根据模板直接生成pdf,响应到前端或者根据模板生成pdf,直接指定下载位置,这两种方案都可以,不过这篇文章主要讲的生成的pdf是既有模板填充还需要自己动态生成表格,包括还需要通过java去生成Echarts图形,通过java后台生成Echarts图形我专门写了一篇文章介绍,java后台生成统计图,这个生成统计图的文章中有两种生成统计图的方式,可以自己选择。

本篇文章的重点还是在讲通过java生成pdf,其实如果是单纯的模板填充挺简单的,但是又要填充模板还要动态生成表格就比较麻烦了,因为如果在模板中画表格的框去生成的话,超过模板框的位置就会隐藏,我刚接到需求的时候也是有点难受,在网上也是找了大量的资料,研究了半天,发现好多都是你粘贴我,我粘贴你,最终我也算是搞成了,把这些整合一下,让大家用的好用一些,废话不多说,直接上代码!

这里说一下啊,如果需要生成echarts图片,先去看我的生成echarts图片文章,不然这个搞不了。

最近很多人都找我要模板链接,我把他放到网盘了,需要的可以去下载https://pan.baidu.com/s/1YJZtLdiySxUry4h2Gd1V7g
提取码:j1l5,不想从网盘下的也可以从的我csdn资源里面下载,资源里面我也放了一份,0积分下载的,大家自取就好。

一、pom依赖

首先先引入咱们需要的pom依赖,我这里只粘贴pdf的吧,lombok和hutool经常用我就不粘贴了。

            com.itextpdf            itextpdf            5.5.9                            com.itextpdf            itext-asian            5.2.0 

二、生成pdf,模板和图片及动态生成表格

我这个没有搞页眉,只搞了页脚,设置页眉/页脚和水印的类我会在最后粘贴出来,因为这几个案例用的都是一个配置类。

实体类

package com.example.demo.domain;import lombok.Data;import lombok.experimental.Accessors;import java.math.BigDecimal;@Data@Accessors(chain = true)public class DuizhangDomain {    private String jg;    private Integer ydz;    private Integer wdz;    private BigDecimal dzl;}
package com.example.demo.domain;import lombok.Data;import lombok.experimental.Accessors;import java.io.Serializable;@Data@Accessors(chain = true)public class YQtable implements Serializable {    private String jg;    private Integer yqs;}

生成pdf代码

import cn.hutool.core.date.DateUtil;import com.example.demo.domain.DuizhangDomain;import com.example.demo.domain.YqTable;import com.example.demo.pdf.phantom.App;import com.example.demo.pdf.phantom.PageEvent;import com.itextpdf.text.*;import com.itextpdf.text.pdf.*;import freemarker.template.TemplateException;import org.springframework.core.io.ClassPathResource;import javax.servlet.Http.HttpServletResponse;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.math.BigDecimal;import java.util.ArrayList;import java.util.List;public class CreatePdfEchrtsAndTableMain2 {    private final static String TITLE = "这个是标题,可有可无";    public void createPdfFile(HttpServletResponse response) throws IOException, DocumentException, TemplateException {        //设置请求返回类型        response.setHeader("Content-Disposition", "attachment; filename=测试.pdf");        OutputStream outputStream = response.getOutputStream();        //模板路径,放到项目里用这个ClassPathResource        ClassPathResource classPathResource = new ClassPathResource("templates/test1.pdf");        InputStream inputStream = classPathResource.getInputStream();        PdfReader reader = new PdfReader(inputStream);        ByteArrayOutputStream bos = new ByteArrayOutputStream();        PdfStamper ps = new PdfStamper(reader, bos);        //设置字体        final BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);        ArrayList fontList = new ArrayList<>();        fontList.add(font);        //提取表单,这个是模板画好的文本框        AcroFields s = ps.getAcroFields();        s.setSubstitutionFonts(fontList);        s.setFieldProperty("jrfk","textfont",font,null);        s.setFieldProperty("bjzs","textfont",font,null);        s.setFieldProperty("type","textfont",font,null);        s.setFieldProperty("createTime","textfont",font,null);        s.setFieldProperty("title","textfont",font,null);        s.setField("jrfk","10");        s.setField("bjzs","20");        s.setField("type","日报");        s.setField("createTime", DateUtil.now());        s.setField("title", TITLE);        //添加图片        PdfContentByte cb = ps.getOverContent(1);        //添加loGo        Rectangle logo = s.getFieldPositions("logo").get(0).position;        Image logoImage = Image.getInstance("https://img1.baidu.com/it/u=3646261857,3326755268&fm=253&app=138&size=w931&n=0&f=JPG&fmt=auto?sec=1668186000&t=20050fc88fc3feb1f9d28392f4595ec6");        //根据域的大小缩放图片,我这里宽度在原有的域基础上加了100,你们可以自己调节        logoImage.scaleToFit(logo.getWidth() + 100,logo.getHeight());        logoImage.setAlignment(Image.MIDDLE);        logoImage.setAbsolutePosition(logo.getLeft(),logo.getBottom());        cb.addImage(logoImage);        //获取统计图        //获取域        Rectangle rlt = s.getFieldPositions("rlt").get(0).position;        //热力图        Image rltImage = Image.getInstance("https://img0.baidu.com/it/u=4043177345,1055141017&fm=253&app=138&size=w931&n=0&f=PNG&fmt=auto?sec=1668186000&t=8cfdc5c95cc0070eb91946d780ee8dc3");        //根据域大小设置缩放图片        rltImage.scaleToFit(rlt.getWidth() + 100,rlt.getHeight());        // 设置居中        rltImage.setAlignment(Image.MIDDLE);        //绝对定位        rltImage.setAbsolutePosition(rlt.getLeft(),rlt.getBottom());        //图片旋转,这个可以将图片进行一个旋转,看自己需求//        rltImage.setRotationDegrees(90);        cb.addImage(rltImage);        //按机构统计图       //这个是生成echarts的类,如果需要生成echarts可以去看我的另一个文章,上面前言已经提到了        App app1 = new App();        byte[] echarts1 = app1.createEcharts("ajg.ftl");        Image ajgImage = Image.getInstance(echarts1);        Rectangle ajg = s.getFieldPositions("ajg").get(0).position;        // 根据域大小设置缩放图片        ajgImage.scaleToFit(ajg.getWidth(),400);        // 设置居中        ajgImage.setAlignment(Image.MIDDLE);        // 绝对定位        ajgImage.setAbsolutePosition(ajg.getLeft(),ajg.getBottom());        cb.addImage(ajgImage);        //按机构排名,这个是在图片的基础上还要添加数据,这个模板可以画好        for (int i = 1; i <= 3; i++) {            s.setFieldProperty("ajg" + i,"textfont",font,null);            s.setField("ajg" + i,"机构" + i);        }        App app = new App();        byte[] echarts = app.createEcharts("option.ftl");        //按业务        Rectangle ayw = s.getFieldPositions("ayw").get(0).position;        Image aywImage = Image.getInstance(echarts);        // 设根据域大小设置缩放图片        aywImage.scaleToFit(ayw.getWidth(), 400);        // 设置居中        aywImage.setAlignment(Image.MIDDLE);        // 绝对定位        aywImage.setAbsolutePosition(ayw.getLeft(),ayw.getBottom());        cb.addImage(aywImage);        //按业务排名        for (int i = 1; i <= 3; i++) {            s.setFieldProperty("ayw" + i,"textfont",font,null);            s.setField("ayw" + i,"机构" + i);        }        //按场合        Rectangle acj = s.getFieldPositions("acj").get(0).position;        Image acjImage = Image.getInstance(echarts);        // 设根据域大小设置缩放图片        acjImage.scaleToFit(acj.getWidth(), 400);        // 设置居中        acjImage.setAlignment(Image.MIDDLE);        // 绝对定位        acjImage.setAbsolutePosition(acj.getLeft(),acj.getBottom());        cb.addImage(acjImage);        //按场景排名        for (int i = 1; i <= 3; i++) {            s.setFieldProperty("acj" + i,"textfont",font,null);            s.setField("acj" + i,"机构" + i);        }        //按等级        Rectangle adj = s.getFieldPositions("adj").get(0).position;        Image adjImage = Image.getInstance(echarts);        // 设根据域大小设置缩放图片        adjImage.scaleToFit(adj.getWidth(),400);        // 设置居中        adjImage.setAlignment(Image.MIDDLE);        // 绝对定位        adjImage.setAbsolutePosition(adj.getLeft(),adj.getBottom());        cb.addImage(adjImage);        //按场景排名        for (int i = 1; i <= 3; i++) {            s.setFieldProperty("adj" + i,"textfont",font,null);            s.setField("adj" + i,"机构" + i);        }        ps.setFORMFlattening(true);        ps.close();        /public class CreatePdfEchrtsAndTableMain3 {    public void createPdfFile(HttpServletResponse response) throws IOException, DocumentException, TemplateException {        //设置请求返回类型        response.setHeader("Content-Disposition", "attachment; filename=测试.pdf");        OutputStream outputStream = response.getOutputStream();        //模板路径,放到项目里用这个ClassPathResource        ClassPathResource classPathResource = new ClassPathResource("templates/test3.pdf");        InputStream inputStream = classPathResource.getInputStream();        PdfReader reader = new PdfReader(inputStream);        ByteArrayOutputStream bos = new ByteArrayOutputStream();        PdfStamper ps = new PdfStamper(reader, bos);        //设置字体        final BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);        ArrayList fontList = new ArrayList<>();        fontList.add(font);        //提取表单        AcroFields s = ps.getAcroFields();        s.setSubstitutionFonts(fontList);        s.setFieldProperty("type", "textfont", font, null);        s.setFieldProperty("createTime", "textfont", font, null);        s.setFieldProperty("title", "textfont", font, null);        s.setField("type", "日报");        s.setField("createTime", DateUtil.now());        s.setField("title", "这是title,模板画的位置框");        ps.setFormFlattening(true);        ps.close();        /    public void createBlankTable(PdfWriter writer, Document document, BaseFont font, int height) throws DocumentException {        PdfPTable table = new PdfPTable(new float[]{30});        table.setTotalWidth(520);        table.setPaddingTop(500);        table.setLockedWidth(true);        table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中        table.writeSelectedRows(0, -1, 500, 800, writer.getDirectContentUnder());        Font textFont = new Font(font, 10, Font.NORMAL);        PdfPCell cell = new PdfPCell(new Paragraph(" ", textFont));        cell.setHorizontalAlignment(Element.ALIGN_LEFT);        cell.setVerticalAlignment(Element.ALIGN_BOTTOM);        cell.setBorder(Rectangle.NO_BORDER);        cell.setFixedHeight(height);        cell.setColspan(1);        table.addCell(cell);        document.add(table);    }}

这是第二种生成pdf的方法,生成的结果不一样,因为模板第一页没有太多的东西,所以会空出来很多空白,这个时候生成动态表格如果重开一页比较浪费,而且客户看着也不好看,所以我封装了一下生成间隙的方法,直接用间隙把模板内容和表格隔开即可,看一下效果。

生成结果示例

在这里插入图片描述
可以看到,我们在代码中并没有新开一页,只是加了一个间隙,就可以保证动态生成的表格和模板在一个页面,就此,基本上就算完成了。

页眉/页脚和水印类

package com.example.demo.pdf.phantom;import com.itextpdf.text.*;import com.itextpdf.text.pdf.*;import java.io.IOException;public class PageEvent extends PdfPageEventHelper {        //public String header = "itext测试页眉";        public int presentFontSize = 10;        public Rectangle pageSize = PageSize.A4;    // 模板    public PdfTemplate total;    // 基础字体对象    public BaseFont bf = null;    // 利用基础字体生成的字体对象,一般用于生成中文文字    public Font fontDetail = null;        public PageEvent() {    }    //    public PDFBuilder(String yeMei, int presentFontSize, Rectangle pageSize) {//        this.header = yeMei;//        this.presentFontSize = presentFontSize;//        this.pageSize = pageSize;//    }    public PageEvent( int presentFontSize, Rectangle pageSize) {        this.presentFontSize = presentFontSize;        this.pageSize = pageSize;    }//    public void setHeader(String header) {//        this.header = header;//    }    public void setPresentFontSize(int presentFontSize) {        this.presentFontSize = presentFontSize;    }        public void onOpenDocument(PdfWriter writer, Document document) {        total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高    }        public void onEndPage(PdfWriter writer, Document document) {        this.addPage(writer, document);        //加水印        this.addWatermark(writer);    }    //加分页    public void addPage(PdfWriter writer, Document document){        //设置分页页眉页脚字体        try {            if (bf == null) {                bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);            }            if (fontDetail == null) {                fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体            }        } catch (DocumentException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }        // 1.写入页眉//        ColumnText.showTextAligned(writer.getDirectContent(),//                Element.ALIGN_LEFT, new Phrase(header, fontDetail),//                document.left(), document.top() + 20, 0);//页眉添加图片//String path = ResourceUtils.getFile("classpath:").getPath();//      Image img = Image.getInstance(path + "/pdfTemplates/logo.jpg");//      img.setAlignment(Image.MIDDLE);//      img.setWidthPercentage(80);//      img.scaleToFit(50,40);//      img.setAbsolutePosition(document.left(),document.top());//      writer.getDirectContent().addImage(img);        //页眉加下划线//        PdfPTable tableHeader = new PdfPTable(1);//        tableHeader.setTotalWidth(PageSize.A4.getWidth() - 60);//        PdfPCell pCell = new PdfPCell();//        pCell.setBorderWidthBottom(0.3f);//        tableHeader.addCell(pCell);//        tableHeader.writeSelectedRows(0, -1, 30, 805, writer.getDirectContent());        // 2.写入前半部分的 第 X页/共        int pageS = writer.getPageNumber();        String foot1 = "第 " + pageS + " 页 /共";//        String foot1 = pageS  +"/";        Phrase footer = new Phrase(foot1, fontDetail);        // 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len        float len = bf.getWidthPoint(foot1, presentFontSize);        // 4.拿到当前的PdfContentByte        PdfContentByte cb = writer.getDirectContent();        // 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F        // 再给偏移20F适合人类视觉感受,否则肉眼看上去就太偏左了        // ,y轴就是底边界-20,否则就贴边重叠到数据体里了就不是页脚了;注意Y轴是从下往上累加的,最上方的Top值是大于Bottom好几百开外的。        ColumnText                .showTextAligned(                        cb,                        Element.ALIGN_CENTER,                        footer,                        (document.rightMargin() + document.right()    + document.leftMargin() - document.left() - len) / 2.0F ,                        document.bottom() - 20, 0);        // 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F +        // len , y 轴和之前的保持一致,底边界-20        cb.addTemplate(total, (document.rightMargin() + document.right()                        + document.leftMargin() - document.left()) / 2.0F ,                document.bottom() - 20); // 调节模版显示的位置    }    //加水印    public void addWatermark(PdfWriter writer) {        // 水印图片//        Image image;//        try {//            image = Image.getInstance("./WEB/images/001.jpg");//            PdfContentByte content = writer.getDirectContentUnder();//            content.beginText();//            // 开始写入水印//            for(int k=0;k<5;k++){//                for (int j = 0; j <4; j++) {//                    image.setAbsolutePosition(150*j,170*k);//                    content.addImage(image);//                }//            }//            content.endText();//        } catch (IOException | DocumentException e) {//            // TODO Auto-generated catch block//            e.printStackTrace();//        }        BaseFont font = null;        try {            font = BaseFont.createFont("STSong-Light","UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);        } catch (DocumentException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }        PdfGState gs = new PdfGState();        //添加透明度        gs.setFillOpacity(0.4f);        PdfContentByte content = writer.getDirectContentUnder();        content.beginText();        //水印颜色        content.setColorFill(BaseColor.DARK_GRAY);        content.setGState(gs);        //水印字体样式和大小        content.setFontAndSize(font, 35);        //插入水印  循环每页插入的条数        for (int j = 0; j < 3; j++) {            content.showTextAligned(Element.ALIGN_CENTER, "锦鲤飞上天测试水印", 300, 200 * (j + 1), 30);        }        content.endText();    }        public void onCloseDocument(PdfWriter writer, Document document) {        // 7.最后一步了,就是关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。        total.beginText();        total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色        String foot2 = " " + (writer.getPageNumber()) + " 页"; //页脚内容拼接  如  第1页/共2页//        String foot2 = String.valueOf(writer.getPageNumber()); //页脚内容拼接  如  1/2        total.showText(foot2);// 模版显示的内容        total.endText();        total.closePath();    }}

四、生成pdf,多页模板方式

2023-03-27更新,各位粉丝本人在用过一段时间pdf生成以后,突然有了多页模板图片和描述的需求,需要多页画模板域,因此呢有了下面的代码。

import cn.hutool.core.date.DateUtil;import com.example.demo.domain.DuizhangDomain;import com.example.demo.domain.YqTable;import com.example.demo.pdf.phantom.App;import com.example.demo.pdf.phantom.PageEvent;import com.itextpdf.text.*;import com.itextpdf.text.pdf.*;import freemarker.template.TemplateException;import org.springframework.core.io.ClassPathResource;import javax.servlet.http.HttpServletResponse;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.math.BigDecimal;import java.util.ArrayList;import java.util.List;public class CreatePdfEchrtsAndTableMain2 {    private final static String TITLE = "这个是标题,可有可无";    public void createPdfFile(HttpServletResponse response) throws IOException, DocumentException, TemplateException {        //设置请求返回类型        response.setHeader("Content-Disposition", "attachment; filename=测试.pdf");        OutputStream outputStream = response.getOutputStream();        //模板路径,放到项目里用这个ClassPathResource        ClassPathResource classPathResource = new ClassPathResource("templates/test1.pdf");        InputStream inputStream = classPathResource.getInputStream();        PdfReader reader = new PdfReader(inputStream);        ByteArrayOutputStream bos = new ByteArrayOutputStream();        PdfStamper ps = new PdfStamper(reader, bos);        //设置字体        final BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);        ArrayList fontList = new ArrayList<>();        fontList.add(font);        //提取表单,这个是模板画好的文本框        AcroFields s = ps.getAcroFields();        s.setSubstitutionFonts(fontList);        //这里需要注意一下,多模块的时候文本域是可以随便填写的,但是图片的文本域需要获取下一页的坐标。        s.setFieldProperty("jrfk","textfont",font,null);        s.setFieldProperty("bjzs","textfont",font,null);        s.setFieldProperty("type","textfont",font,null);        s.setFieldProperty("createTime","textfont",font,null);        s.setFieldProperty("title","textfont",font,null);        s.setField("jrfk","10");        s.setField("bjzs","20");        s.setField("type","日报");        s.setField("createTime", DateUtil.now());        s.setField("title", TITLE);        //添加图片,这是获取的第一页的PdfContentByte         PdfContentByte cb = ps.getOverContent(1);        //添加logo        Rectangle logo = s.getFieldPositions("logo").get(0).position;        Image logoImage = Image.getInstance("https://img1.baidu.com/it/u=3646261857,3326755268&fm=253&app=138&size=w931&n=0&f=JPG&fmt=auto?sec=1668186000&t=20050fc88fc3feb1f9d28392f4595ec6");        //根据域的大小缩放图片,我这里宽度在原有的域基础上加了100,你们可以自己调节        logoImage.scaleToFit(logo.getWidth() + 100,logo.getHeight());        logoImage.setAlignment(Image.MIDDLE);        logoImage.setAbsolutePosition(logo.getLeft(),logo.getBottom());        cb.addImage(logoImage);        //获取统计图        //获取域        Rectangle rlt = s.getFieldPositions("rlt").get(0).position;        //热力图        Image rltImage = Image.getInstance("https://img0.baidu.com/it/u=4043177345,1055141017&fm=253&app=138&size=w931&n=0&f=PNG&fmt=auto?sec=1668186000&t=8cfdc5c95cc0070eb91946d780ee8dc3");        //根据域大小设置缩放图片        rltImage.scaleToFit(rlt.getWidth() + 100,rlt.getHeight());        // 设置居中        rltImage.setAlignment(Image.MIDDLE);        //绝对定位        rltImage.setAbsolutePosition(rlt.getLeft(),rlt.getBottom());        //图片旋转,这个可以将图片进行一个旋转,看自己需求//        rltImage.setRotationDegrees(90);        cb.addImage(rltImage);        //按机构统计图       //这个是生成echarts的类,如果需要生成echarts可以去看我的另一个文章,上面前言已经提到了        App app1 = new App();        byte[] echarts1 = app1.createEcharts("ajg.ftl");        Image ajgImage = Image.getInstance(echarts1);        Rectangle ajg = s.getFieldPositions("ajg").get(0).position;        // 根据域大小设置缩放图片        ajgImage.scaleToFit(ajg.getWidth(),400);        // 设置居中        ajgImage.setAlignment(Image.MIDDLE);        // 绝对定位        ajgImage.setAbsolutePosition(ajg.getLeft(),ajg.getBottom());        cb.addImage(ajgImage);        //按机构排名,这个是在图片的基础上还要添加数据,这个模板可以画好        for (int i = 1; i <= 3; i++) {            s.setFieldProperty("ajg" + i,"textfont",font,null);            s.setField("ajg" + i,"机构" + i);        }        App app = new App();        byte[] echarts = app.createEcharts("option.ftl");        //按业务        Rectangle ayw = s.getFieldPositions("ayw").get(0).position;        Image aywImage = Image.getInstance(echarts);        // 设根据域大小设置缩放图片        aywImage.scaleToFit(ayw.getWidth(), 400);        // 设置居中        aywImage.setAlignment(Image.MIDDLE);        // 绝对定位        aywImage.setAbsolutePosition(ayw.getLeft(),ayw.getBottom());        cb.addImage(aywImage);        //按业务排名        for (int i = 1; i <= 3; i++) {            s.setFieldProperty("ayw" + i,"textfont",font,null);            s.setField("ayw" + i,"机构" + i);        }        //按场合        Rectangle acj = s.getFieldPositions("acj").get(0).position;        Image acjImage = Image.getInstance(echarts);        // 设根据域大小设置缩放图片        acjImage.scaleToFit(acj.getWidth(), 400);        // 设置居中        acjImage.setAlignment(Image.MIDDLE);        // 绝对定位        acjImage.setAbsolutePosition(acj.getLeft(),acj.getBottom());        cb.addImage(acjImage);        //按场景排名        for (int i = 1; i <= 3; i++) {            s.setFieldProperty("acj" + i,"textfont",font,null);            s.setField("acj" + i,"机构" + i);        }        //按等级        Rectangle adj = s.getFieldPositions("adj").get(0).position;        Image adjImage = Image.getInstance(echarts);        // 设根据域大小设置缩放图片        adjImage.scaleToFit(adj.getWidth(),400);        // 设置居中        adjImage.setAlignment(Image.MIDDLE);        // 绝对定位        adjImage.setAbsolutePosition(adj.getLeft(),adj.getBottom());        cb.addImage(adjImage);        //按场景排名        for (int i = 1; i <= 3; i++) {            s.setFieldProperty("adj" + i,"textfont",font,null);            s.setField("adj" + i,"机构" + i);        }//第二页的图片域,如果第三页有模板写3即可PdfContentByte cb2 = ps.getOverContent(2);//添加图片Rectangle test = s.getFieldPositions("test").get(0).position;byte[] base = bankReportPdfService.getBankHistogramDataBase64All(bankId, startTime, endTime, reportTimeType, bank);Image testImage = Image.getInstance(base);//这里需要注意一下,如果没有获取第二页的PdfContentByte的话直接填充第二页的图片域图片会顶上去// 设根据域大小设置缩放图片        testImage .scaleToFit(test .getWidth(),400);        // 设置居中        testImage .setAlignment(Image.MIDDLE);        // 绝对定位        testImage .setAbsolutePosition(test .getLeft(),test .getBottom());        cb2.ddImage(testImage );        ps.setFormFlattening(true);        ps.close();        //*******************填充编辑好后的pdf**************        reader = new PdfReader(bos.toByteArray());        Rectangle pageSize = reader.getPageSize(1);        Document document = new Document(pageSize);        PdfWriter writer = PdfWriter.getInstance(document, outputStream);        writer.setPageEvent(new PageEvent());        // 打开文档        document.open();        PdfContentByte cbUnder = writer.getDirectContentUnder();         //多页模板,你有几页模板写几页就行,我这是两页模板        for (int i = 1; i <= 2; i++) {              PdfImportedPage pageTemplate = writer.getImportedPage(reader, i);              cbUnder.addTemplate(pageTemplate, 0, 0);              //这里每次循环都要创建一个新的页              document.newPage();        }        createTable(writer,document);//        document.newPage();        createTableYq(writer,document);        document.close();        outputStream.close();    }    //为一个表格添加内容    public PdfPCell createSetCell(String value,Font font){        PdfPCell cell = new PdfPCell();        cell.setPhrase(new Phrase(value,font));        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);        cell.setHorizontalAlignment(Element.ALIGN_CENTER);        return cell;    }    //添加表格    public void createTable(PdfWriter writer,Document document) throws DocumentException, IOException {        PdfPTable table = new PdfPTable(new float[] { 30, 80, 50, 50, 50});        table.setTotalWidth(520);        table.setPaddingTop(500);        table.setLockedWidth(true);        table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中        table.writeSelectedRows(0, -1,500,800,writer.getDirectContentUnder());        //每页都显示表头,输入几就是第几行的表头固定        table.setHeaderRows(2);        table.setHeaderRows(3);        //定义数据的字体        BaseFont baseFont = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);        Font textFont = new Font(baseFont, 10, Font.NORMAL);        PdfPCell cell = new PdfPCell(new Paragraph(" ", textFont));        cell.setHorizontalAlignment( Element.ALIGN_LEFT);        cell.setVerticalAlignment(Element.ALIGN_BOTTOM);        cell.setBorder(Rectangle.NO_BORDER);        cell.setColspan(5);        table.addCell(cell);        //表头信息        PdfPCell heandCell = new PdfPCell();        heandCell.setRowspan(1);        heandCell.setColspan(5);        heandCell.setFixedHeight(60);        heandCell.setVerticalAlignment(Element.ALIGN_MIDDLE);        heandCell.setHorizontalAlignment(Element.ALIGN_CENTER);        heandCell.setPhrase(new Phrase(TITLE + "对账情况表",textFont));        table.addCell(heandCell);        //表字段        String title[] = {"序号","机构","已对账","未对账","对账率%"};        for (int i = 0; i < title.length; i++) {            PdfPCell heardCell = new PdfPCell();            heardCell.setVerticalAlignment(Element.ALIGN_MIDDLE);            heardCell.setHorizontalAlignment(Element.ALIGN_CENTER);            heardCell.setPhrase(new Phrase(title[i], textFont));            heardCell.setMinimumHeight(20);            table.addCell(heardCell);        }        //列表数据        List duizhangDomains = new ArrayList<>();        for (int i = 1; i <= 1000; i++) {            DuizhangDomain duizhangDomain = new DuizhangDomain();            duizhangDomain.setJg("机构" + i).setYdz(i).setWdz(i).setDzl(new BigDecimal(i));            duizhangDomains.add(duizhangDomain);        }        for (int i = 0; i < duizhangDomains.size(); i++) {            PdfPCell setCell1 = createSetCell((i + 1) + "", textFont);            PdfPCell setCell2 = createSetCell(duizhangDomains.get(i).getJg(), textFont);            PdfPCell setCell3 = createSetCell(duizhangDomains.get(i).getYdz().toString(), textFont);            PdfPCell setCell4 = createSetCell(duizhangDomains.get(i).getWdz().toString(), textFont);            PdfPCell setCell5 = createSetCell(duizhangDomains.get(i).getDzl() + "%", textFont);            table.addCell(setCell1);            table.addCell(setCell2);            table.addCell(setCell3);            table.addCell(setCell4);            table.addCell(setCell5);        }        document.add(table);    }    public void createTableYq(PdfWriter writer,Document document) throws DocumentException, IOException {        PdfPTable table = new PdfPTable(new float[] {80, 50});        table.setTotalWidth(520);        table.setPaddingTop(500);        table.setLockedWidth(true);        table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中        table.writeSelectedRows(0, -1,500,800,writer.getDirectContentUnder());        //每页都显示表头,输入几就是第几行的表头固定        table.setHeaderRows(2);        table.setHeaderRows(3);        //定义数据的字体        BaseFont baseFont = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);        Font textFont = new Font(baseFont, 10, Font.NORMAL);                //这个是为了区分两个表格加的一个间隔,可以去掉        PdfPCell cell = new PdfPCell(new Paragraph(" ", textFont));        cell.setHorizontalAlignment( Element.ALIGN_LEFT);        cell.setVerticalAlignment(Element.ALIGN_BOTTOM);        cell.setBorder(Rectangle.NO_BORDER);        cell.setColspan(2);        table.addCell(cell);        //表头信息        PdfPCell heandCell = new PdfPCell();        heandCell.setRowspan(1);        heandCell.setColspan(2);        heandCell.setFixedHeight(60);        heandCell.setVerticalAlignment(Element.ALIGN_MIDDLE);        heandCell.setHorizontalAlignment(Element.ALIGN_CENTER);        heandCell.setPhrase(new Phrase(TITLE + "逾期表",textFont));        table.addCell(heandCell);        //表字段        String title[] = {"机构名称","逾期数"};        for (int i = 0; i < title.length; i++) {            PdfPCell heardCell = new PdfPCell();            heardCell.setVerticalAlignment(Element.ALIGN_MIDDLE);            heardCell.setHorizontalAlignment(Element.ALIGN_CENTER);            heardCell.setPhrase(new Phrase(title[i], textFont));            heardCell.setMinimumHeight(20);            table.addCell(heardCell);        }        //列表数据        List yqTables = new ArrayList<>();        for (int i = 1; i <= 1000; i++) {            YqTable yq = new YqTable();            yq.setJg("逾期机构" + i).setYqs(i);            yqTables.add(yq);        }        for (int i = 0; i < yqTables.size(); i++) {            PdfPCell setCell2 = createSetCell(yqTables.get(i).getJg(), textFont);            PdfPCell setCell3 = createSetCell(yqTables.get(i).getYqs().toString(), textFont);            table.addCell(setCell2);            table.addCell(setCell3);        }        document.add(table);    }}

生成结果示例
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
可以看到第二页我也是通过模板的图片文本域生成图片,我们可以通过这种方法来进行多页模板生成。

五、图片加入pdf动态生成,不需要添加指定模板域

2023-06-30更新,今天有朋友问图片能不能动态渲染位置,不需要添加模板域,其实是可以的,我把代码粘贴到下面,大家可以做个参考,其实看到这里基本上套路大家也就知道了,所以我就不粘贴那些繁琐的创建pdf的document之类的代码了,直接上面粘贴就行,这里只粘贴关于无指定域添加图片的代码。

//获取图片的字节码,这里我是用echarts生成的统计图,如果对echarts后台生成感兴趣的话可以看我另一篇文章(文章是收费的哦,白嫖客不用点了)。byte[] base = bankReportPdfService.getBankHistogramDataBase64All(bankId, startTime, endTime, reportTimeType, bank);            Image ajgAllImage = Image.getInstance(base);            //设置图片位置的x轴和y轴            ajgAllImage.setAbsolutePosition(80, 400);//注意是从文档的左下角往右、往上计算的            //设置图片的宽度和高度            ajgAllImage.scaleToFit(1000, 300);            // 设置居中            ajgAllImage.setAlignment(Image.MIDDLE);            //将图片添加到pdf文件中            document.add(ajgAllImage);

只需要这一段代码就可以实现动态添加无模块域图片了,如果需要好多页面添加的话就加上document.newPage();,重新new一页,就可以了,注意间距,每页的xy轴都是从0开始的。

好了这就是生成pdf的代码了,controller层我就不粘出来了自己搞一下吧,希望可以帮助各位有需要的人,如果帮助到你了就帮忙点个赞,关注一下,我会不定时更新一些自己解决过的业务,希望可以帮助大家!!!

来源地址:https://blog.csdn.net/qq_45699784/article/details/127791747

--结束END--

本文标题: java生成PDF(图片,模板,表格)

本文链接: https://lsjlt.com/news/371447.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • java生成PDF(图片,模板,表格)
    刚接到了一个需求,生成一个pdf,一开始以为挺简单的,通过模板生成嘛,我也发过相应的文章,根据模板直接生成pdf,响应到前端或者根据模板生成pdf,直接指定下载位置,这两种方案都可以,不过这篇文章主要讲的生成的pdf是既有模板填充还需要自己...
    99+
    2023-08-16
    java pdf echarts
  • 【生成PDF】【JAVA】纯后台生成Echarts图片,并将图片生成到PDF文档
    目录 前言 一、如何后台生成Echarts图片? 1.PhantomJS 2.PhantomJS的下载  3.用phantomjs调用echarts-converts.js生成图片 二、Java如何将Echarts图生成到PDF 1.生成P...
    99+
    2023-09-07
    pdf java echarts
  • java根据模板动态生成PDF实例
    一、需求说明:根据业务需要,需要在服务器端生成可动态配置的PDF文档,方便数据可视化查看。二、解决方案:iText+FreeMarker+JFreeChart生成可动态配置的PDF文档iText有很强大的PDF处理能力,但是样式和排版不好控...
    99+
    2023-05-31
    java 生成pdf ava
  • Python怎么生成表格图片
    本篇内容介绍了“Python怎么生成表格图片”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!pytab首先安装pip install...
    99+
    2023-06-29
  • java集成itextpdf实现通过pdf模板填充数据生成pdf
    文章目录 一、制作pdf模板1.1、使用excel制作一个表格1.2、转成pdf1.3、设置表单域1.4、最终模版效果 二、引入POM依赖三、代码实现3.1、工具类3.2、实体对象3.3、Controller 一、制作...
    99+
    2023-08-18
    java pdf
  • python生成带有表格的图片
    因为工作中需要,需要生成一个带表格的图片 例如: 直接在html中写一个table标签,然后单独把表格部分保存成图片 或者是直接将excel中的内容保存成一个图片 刚开始的思路,是直接生成一个带有table标签的html文件,然后...
    99+
    2023-01-31
    表格 图片 python
  • java用模板生成word(docx)文档(含动态表格)
    生成word思路 用WPS或者office编辑好word的样式,然后另存为word xml文档,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板并输出Docx。 编辑好需要使用的word文档 把需要注入的...
    99+
    2023-09-16
    word java 开发语言
  • Java根据word模板生成word文档并转成PDF文件
    1. 处理word模板 1.1 定义word模版 1.2 定义完我们的模板之后,我们要将文档保存为xml的格式 定义完我们的模板之后,我们要将文档保存为xml的格式 1.3 xml格式化 ...
    99+
    2023-09-09
    java word pdf chart
  • Python数据展示之生成表格图片
    目录pytabplotly前言: 本文来讲讲如何用Python生成表格图片。 选一个合适库 Python最大的优点就是第三方库丰富,基本你要什么功能,都能找到别人实现好的库,几行代码...
    99+
    2024-04-02
  • 【Java】itext 实现 html根据模板生成pdf 中文不显示/图片不显示问题解决
    引言: 工作中需要使用生成pdf记录,选取使用的是itext 生成 pdf方式。分享下实现方式及遇到的问题。 实现效果 这里随便找个html课程表作为示例,添加了几张图片为了展示图片转pdf功能。 ...
    99+
    2023-10-27
    java html pdf
  • JAVA之利用easypoi将word模板导出为pdf(可带图片)
    1.介绍easypoi EasyPoi是一款基于POI的Java快速导出/导入Excel工具。它在POI的基础上进行了封装,提供了更加简洁易用的API,使得生成Excel文件更加容易和高效。 使用EasyPoi可以轻松地生成Excel文件,...
    99+
    2023-10-24
    java
  • Python实现合成多张图片到PDF格式
    目录1.准备2.合成原理3.多张照片合成PDF在日常生活中,经常会遇到需要提交身份证正反面证明资料的情况,而且这些网站大部分只接受pdf格式,这时候我们就需要把身份证正反面两张图片合...
    99+
    2024-04-02
  • java如何生成echarts图片
    要在Java中生成ECharts图片,您可以使用ECharts官方提供的Java工具库echarts-java。以下是生成EChar...
    99+
    2023-09-15
    java
  • java使用Abobe Acrobat DC生成模板
    一、利用word生成一个文档转成pdf 说明:转换成pdf格式 二、Abobe Acrobat DC图解 利用Abobe Acrobat DC打开pdf 步骤:文件 ----&g...
    99+
    2024-04-02
  • Java图片转字符图片的生成方法
    前面介绍了一篇java实现图片灰度化处理的小demo,接下来再介绍一个有意思的东西,将一个图片转换成字符图片 借助前面图片灰度化处理的知识点,若我们希望将一张图片转成字符图片,同样可...
    99+
    2024-04-02
  • Python+SeaTable实现生成条形码图片并写入表格
    目录在 SeaTable 中用 Python 生成条形码新建 Python 脚本写入代码运行脚本设置条码参考应用场景打印条形码用于粘贴答题卡设计准考证页面用于识别信息总结不管是录入信...
    99+
    2024-04-02
  • Java如何实现将PDF转为图片格式
    本文小编为大家详细介绍“Java如何实现将PDF转为图片格式”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java如何实现将PDF转为图片格式”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。代码编译环境Intel...
    99+
    2023-07-05
  • java怎么生成echarts图表
    要在Java中生成Echarts图表,可以使用Echarts的Java库。以下是一些步骤:1. 通过添加Echarts Java库的...
    99+
    2023-08-28
    java
  • Node.js在图片模板上如何生成二维码图片并附带底部文字说明
    小编给大家分享一下Node.js在图片模板上如何生成二维码图片并附带底部文字说明,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在...
    99+
    2024-04-02
  • Node.js在图片模板上怎么生成二维码图片并附带底部文字说明
    今天小编给大家分享一下Node.js在图片模板上怎么生成二维码图片并附带底部文字说明的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作