【Java】制作pdf模板使用后端程序填充字段生成pdf或者图片

这篇具有很好参考价值的文章主要介绍了【Java】制作pdf模板使用后端程序填充字段生成pdf或者图片。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.安装软件: Adobe Acrobat 9 Pro

自行下载安装;

2.制作模板pdf文件

打开pdf文件,表单-添加或编辑域
添加文本域,调整大小,可以编辑域的名字,默认fill_1这种名字。域鼠标右键-属性,可以调整字体大小等样式,编辑好还可以锁定;
【Java】制作pdf模板使用后端程序填充字段生成pdf或者图片,java,pdf
编辑好保存,这个pdf文件就可以当模板使用了;

3.maven依赖

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13.3</version>
</dependency>
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.12</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/fontbox -->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>fontbox</artifactId>
    <version>2.0.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.9</version>
</dependency>

4. 后端-字体引入

防止中文乱码,需要在网上下载字体ttf文件,这个是宋体的字体文件STSong-Light.ttf
【Java】制作pdf模板使用后端程序填充字段生成pdf或者图片,java,pdf
字体文件放在配置文件的文件夹里,在程序里引用,这个工具类只加载字体用,别的方法没用到;

/**
 * pdf工具类
 *
 * @author xwt
 * @date 2022/12/7 11:00
 */
@Slf4j
public class PdfUtils {
 
    public static final Base64.Decoder DECODER = Base64.getDecoder();
 
    private static Map<String, FontInfo> fontInfoMap = null;
 
    private static final String TTC_TYPE = "TTC";
 
    private static final String OTC_TYPE = "OTC";
 
   
    /***
     * pdfBase64转图片,返回图片对象
     *
     * @param pdfBase64  pdf类型base64
     * @return BufferedImage
     */
    public static List<BufferedImage> pdfToImage(String pdfBase64){
        List<BufferedImage> list = new ArrayList<>();
        if (CharSequenceUtil.isEmpty(pdfBase64)){
            return list;
        }
        byte[] decode = DECODER.decode(pdfBase64.getBytes(StandardCharsets.UTF_8));
        try(
                ByteArrayInputStream stream = new ByteArrayInputStream(decode);
                // 加载解析PDF文件
                PDDocument doc = PDDocument.load(stream);
        ) {
            // 业务处理
            PDFRenderer pdfRenderer = new PDFRenderer(doc);
            PDPageTree pages = doc.getPages();
            int pageCount = pages.getCount();
            for (int i = 0; i < pageCount; i++) {
                list.add(pdfRenderer.renderImageWithDPI(i, 200));
            }
        } catch (Exception e) {
            log.error("pdfBase64转图片异常", e);
        }
        return list;
    }
 
    /***
     * 设置字体
     * @param fontFormat 字体文件类型
     * @param fontName 字体名称
     * @param file 字体文件
     */
    public static void setFonts(FontFormat fontFormat, String fontName, File file){
        FontInfo fontInfo = getFontInfoMap().get(fontName);
        if(fontInfo != null){
            log.warn("pdfFont添加字体已经存在");
            return;
        }
        // 后缀
        log.info("pdfFont 添加字体{}", file.getName());
        String suffix = FileUtil.getSuffix(file);
        if(TTC_TYPE.equalsIgnoreCase(suffix) || OTC_TYPE.equalsIgnoreCase(suffix)){
            try(TrueTypeCollection trueTypeCollection = new TrueTypeCollection(file);) {
                trueTypeCollection.processAllFonts(trueTypeFont -> addTrueTypeFontImpl(trueTypeFont, file));
            } catch (IOException e) {
                log.warn("无法加载字体:{}", file.getAbsolutePath());
            }
            return;
        }
        getFontInfoMap().put(fontName, new MyFontInfo(file, fontFormat, fontName));
    }
 
    /***
     * 设置字体,扫描目录下所有字体
     * @param dir 目录
     */
    public static void setFonts(File dir){
        if (dir == null || !dir.exists() || !dir.isDirectory()) {
            log.warn("pdfFont添加字体为空");
            return;
        }
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                setFonts(file);
            } else {
                String fileName = file.getName();
                // 后缀
                String suffix = FileUtil.getSuffix(fileName);
                // 文件名称,不带后缀
                String prefix = FileUtil.getPrefix(fileName);
                if(FontFormat.OTF.name().equalsIgnoreCase(suffix)){
                    setFonts(FontFormat.OTF, prefix, file);
                }else if(FontFormat.TTF.name().equalsIgnoreCase(suffix) || TTC_TYPE.equalsIgnoreCase(suffix) || OTC_TYPE.equalsIgnoreCase(suffix)) {
                    setFonts(FontFormat.TTF, prefix, file);
                }else if(FontFormat.PFB.name().equalsIgnoreCase(suffix)) {
                    setFonts(FontFormat.PFB, prefix, file);
                }else{
                    log.warn("无法识别字体:{}", file.getAbsolutePath());
                }
            }
        }
    }
 
    /***
     * 获取系统字体缓存
     * @return 字体缓存
     */
    private static Map<String, FontInfo> getFontInfoMap(){
        if(fontInfoMap != null){
            return fontInfoMap;
        }
        FontMapper instance = FontMappers.instance();
        // 初始化加载系统字体
        instance.getCIDFont("STSong-Light", null, null);
        Class<? extends FontMapper> aClass = instance.getClass();
        try {
            Field field = aClass.getDeclaredField("fontInfoByName");
            if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
                field.setAccessible(true);
            }
            // 获取系统字体缓存
            fontInfoMap = (Map<String, FontInfo>) field.get(instance);
        }catch (Exception e){
            log.error("PdfUtils初始化异常", e);
            throw new RuntimeException("PdfUtils初始化异常");
        }
        return fontInfoMap;
    }
 
    /***
     * 将OTF或TTF字体添加到文件缓存
     * @param ttf 字体
     * @param file 字体文件
     * @throws IOException 异常
     */
    private static void addTrueTypeFontImpl(TrueTypeFont ttf, File file) throws IOException {
        if(ttf.getName() != null){
            if (ttf.getHeader() == null) {
                getFontInfoMap().put(ttf.getName(), new MyFontInfo(file, FontFormat.TTF, ttf.getName()));
                return;
            }
            int macStyle = ttf.getHeader().getMacStyle();
 
            int sFamilyClass = -1;
            int usWeightClass = -1;
            int ulCodePageRange1 = 0;
            int ulCodePageRange2 = 0;
            // Apple's AAT fonts don't have an OS/2 table
            if (ttf.getOS2Windows() != null)
            {
                sFamilyClass = ttf.getOS2Windows().getFamilyClass();
                usWeightClass = ttf.getOS2Windows().getWeightClass();
                ulCodePageRange1 = (int)ttf.getOS2Windows().getCodePageRange1();
                ulCodePageRange2 = (int)ttf.getOS2Windows().getCodePageRange2();
            }
 
            CIDSystemInfo ros = null;
            String registry = null;
            String ordering = null;
            int supplement = 0;
            FontFormat fontFormat;
            if (ttf instanceof OpenTypeFont && ((OpenTypeFont)ttf).isPostScript()) {
                CFFFont cff = ((OpenTypeFont)ttf).getCFF().getFont();
                fontFormat = FontFormat.OTF;
                if (cff instanceof CFFCIDFont) {
                    CFFCIDFont cidFont = (CFFCIDFont)cff;
                    registry = cidFont.getRegistry();
                    ordering = cidFont.getOrdering();
                    supplement = cidFont.getSupplement();
                }
            } else {
                fontFormat = FontFormat.TTF;
                if (ttf.getTableMap().containsKey("gcid")) {
                    // Apple's AAT fonts have a "gcid" table with CID info
                    byte[] bytes = ttf.getTableBytes(ttf.getTableMap().get("gcid"));
                    String reg = new String(bytes, 10, 64, Charsets.US_ASCII);
                    registry = reg.substring(0, reg.indexOf('\0'));
                    String ord = new String(bytes, 76, 64, Charsets.US_ASCII);
                    ordering = ord.substring(0, ord.indexOf('\0'));
                    supplement = bytes[140] << 8 & bytes[141];
                }
            }
            try {
                Constructor<CIDSystemInfo> constructor = CIDSystemInfo.class.getDeclaredConstructor(String.class, String.class, int.class);
                if ((!Modifier.isPublic(constructor.getModifiers()) || !Modifier.isPublic(constructor.getDeclaringClass().getModifiers()) || Modifier.isFinal(constructor.getModifiers())) && !constructor.isAccessible()) {
                    constructor.setAccessible(true);
                }
                ros = constructor.newInstance(registry, ordering, supplement);
            }catch (Exception e){
                e.printStackTrace();
            }
            getFontInfoMap().put(ttf.getName(), new MyFontInfo(file, fontFormat, ttf.getName(), ros, usWeightClass, sFamilyClass, ulCodePageRange1, ulCodePageRange2,
                    macStyle));
        }
    }
}

在程序启动类里面调用上面的代码(也可以在使用的地方调用,就是每次都要调用一下感觉不太好),就引入字体了

    public static void main(String[] args) {
        SpringApplication.run(ReceiptApplication.class, args);
        PdfUtil.setFonts(FontFormat.TTF, "STSong-Light", new File("/app/conf/STSong-Light.ttf"));
    }

5. 后端-PdfUtil代码

项目使用的pdf只有一页,我的代码是可行的;实现了功能:
1.pdf模板填充生成pdf文件(step1.pdf);
outputPdf(Map<String, Object> o, String templatePath, String outPutPath)
2.step1.pdf上加一张图片,例如加签名,生成step2.pdf;
addImgOnPdf(String imgPath, String oldPath, String newPath)
3.将step2.pdf转成jpg图片文件;
pdf2png(String fileAddress, String filename, int indexOfStart, int indexOfEnd, String type)
工具类使用Map传参,接口参数放到map里,key对应域的名字

        map.put("fill_1", params.getAccountTitle());//户名
        map.put("fill_2", d_cardNo);//账号

工具类文章来源地址https://www.toymoban.com/news/detail-811775.html

@Slf4j
public class PdfUtil {
    /**
     * @param o            写入的数据
     * @param templatePath pdf模板路径
     */
    // 利用模板生成pdf
    public static String outputPdf(Map<String, Object> o, String templatePath, String outPutPath) throws IOException {
        PdfReader reader;
        ByteArrayOutputStream bos = null;
        PdfStamper stamper;
        FileOutputStream out = null;

        try {
            File file = new File(outPutPath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            out = new FileOutputStream(file);
            reader = new PdfReader(templatePath);// 读取pdf模板
            bos = new ByteArrayOutputStream();
            stamper = new PdfStamper(reader, bos);

            AcroFields form = stamper.getAcroFields();
            // 设置字体,否则可能会不显示中文
            //BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
            BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
            form.addSubstitutionFont(bf);
            // 设置文本
            form.setField("processingTime", "20");
            java.util.Iterator<String> it = form.getFields().keySet().iterator();
            while (it.hasNext()) {
                String name = it.next().toString();
                //log.info(name);
                String value = o.get(name) != null ? o.get(name).toString() : null;
                if (value != null) {
                    // 设置支持中文
                    form.setFieldProperty(name, "textfont", bf, null);
                    form.setField(name, value);
                }
            }
            stamper.setFormFlattening(true);// 如果为false那么生成的PDF文件还能编辑,一定要设为true
            stamper.close();
            Document doc = new Document();
            PdfCopy copy = new PdfCopy(doc, out);
            doc.open();
            byte[] bytes = bos.toByteArray();
            //log.info("[pdf bytes size] " + bytes.length);
            PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bytes), 1);
            copy.addPage(importPage);
            doc.close();
        } catch (IOException e) {
            log.error("生成pdf IOException", e);
            throw e;
        } catch (DocumentException e) {
            log.error("生成pdf DocumentException", e);
        } finally {
            if (out != null) {
                out.close();
            }
            if (bos != null) {
                bos.close();
            }
        }
        return outPutPath;
    }


    public static void addImgOnPdf(String imgPath, String oldPath, String newPath) {
        try {
            InputStream inputStream = Files.newInputStream(Paths.get(oldPath));
//            System.out.println(inputStream == null? "in null":inputStream.available());
            log.info(inputStream + ":" + inputStream.available());
            FileOutputStream out = new FileOutputStream(newPath);
            PdfReader reader = new PdfReader(inputStream);
            //pdf页数
            int pdfPages = reader.getNumberOfPages();
            PdfStamper stamper = new PdfStamper(reader, out);
            //图片
            BufferedImage bufferedImage = ImageIO.read(Files.newInputStream(Paths.get(imgPath)));
//            System.out.println(bufferedImage == null? "img null":bufferedImage.getMinX());
            log.info(bufferedImage + ":" + bufferedImage.getMinX());
            //x轴坐标
            int x = 450;
            //y轴坐标
            int y = 440;
            //图片放置的页码
            for (int i = pdfPages; i <= pdfPages; i++) {
                //图片处理
                Image img = Image.getInstance(ImageUtil.imageToBytes(bufferedImage, "png"));
                //设置图片大小
                img.scaleAbsolute(40, 22);
                img.setTransparency(new int[0]);
                //设置图片位置
                img.setAbsolutePosition(x, y);
                stamper.getOverContent(i).addImage(img);
            }
            //关闭资源
            stamper.close();
            out.close();
            reader.close();
        } catch (DocumentException e) {
            log.error("DocumentException :{0}", e);
        } catch (IOException e) {
            log.error("IOException :{0}", e);
        }

    }

    /**
     * 转换全部的pdf
     *
     * @param fileAddress 文件地址
     */
    public static void pdf2png(String fileAddress, String imgAddress) {
        String type = "png";
        // 将pdf装图片 并且自定义图片得格式大小
        File file = new File(fileAddress);
        try {
            PDDocument doc = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            for (int i = 0; i < pageCount; i++) {
                BufferedImage image = renderer.renderImageWithDPI(i, 144); // Windows native DPI
                // BufferedImage srcImage = resize(image, 240, 240);//产生缩略图
                ImageIO.write(image, type, new File(imgAddress));
            }
        } catch (IOException e) {
            log.error("IOException : {0}", e);
        }
    }


    /**
     * 自由确定起始页和终止页
     *
     * @param fileAddress  文件地址
     * @param filename     pdf文件名
     * @param indexOfStart 开始页  开始转换的页码,从0开始
     * @param indexOfEnd   结束页  停止转换的页码,-1为全部
     * @param type         图片类型
     */
    public static void pdf2png(String fileAddress, String filename, int indexOfStart, int indexOfEnd, String type) {
        // 将pdf装图片 并且自定义图片得格式大小
        File file = new File(fileAddress + "\\" + filename + ".pdf");
        try {
            PDDocument doc = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            for (int i = indexOfStart; i < indexOfEnd; i++) {
                BufferedImage image = renderer.renderImageWithDPI(i, 144); // Windows native DPI
                // BufferedImage srcImage = resize(image, 240, 240);//产生缩略图
                ImageIO.write(image, type, new File(fileAddress + "\\" + filename + "_" + (i + 1) + "." + type));
            }
        } catch (IOException e) {
            log.error("IOException : {0}", e);
        }
    }

}

到了这里,关于【Java】制作pdf模板使用后端程序填充字段生成pdf或者图片的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java后端大写字段传到前端,或者使用postman调用后,返回变为小写

    比如,我有一个类,然后该类中有一个字段 默认使用的是Jackson解析。Jackson在解析返回的json字符串时,全部大写字段被转为小写了,首字母如果是大写也会被转为小写 我在传输给前端,或者使用postman调用,或者存储到redis的时候,发现该字段不是YTD,而是ytd,没办法满足我

    2024年02月12日
    浏览(28)
  • 【Java结合EasyExcel,模板文件填充并导出Excel】

    需求描述: 客户网页上填一个Excel表格,数据存到数据库,这个导出接口要做的就是从数据库中的获取数据并填充到模板文件,最后通过response返给前端一个下载链接,用户即可获取填充好的Excel文件。 方案一: 一开始使用的是easypoi,发现当填充一行数据时是OK的,但是如果

    2024年02月09日
    浏览(40)
  • EasyExcel的使用:入门到模板填充

    官网:https://easyexcel.opensource.alibaba.com/ Github:https://github.com/alibaba/easyexcel 3.0.5版本的JavaDoc:https://javadoc.io/doc/com.alibaba/easyexcel/3.0.5/index.html 准备Excel文件 准备Excel文件对应的实体类: Student 注意:在没有任何配置的情况下,Excel中的数据列顺序要与实体类的属性顺序保持一致

    2024年02月02日
    浏览(24)
  • Java使用ftl模板文件生成Word,以及Word转换图片或Pdf工具类

    一、写在前面 最近在项目中使用打印功能,发现这个功能我已经写过多次了,下面这个文章的发步日期在2020年,不得不感慨时间之快啊。 https://blog.csdn.net/weixin_43238452/article/details/109636200?spm=1001.2014.3001.5501 下面介绍一下应用场景:这次项目依旧是springboot项目,使用ftl模版生

    2024年02月15日
    浏览(38)
  • Java 使用 poi 和 aspose 实现 word 模板数据写入并转换 pdf 增加水印

    本项目所有源码和依赖资源都在文章顶部链接,有需要可以下载使用 1. 需求描述 从指定位置读取一个 word 模板 获取业务数据并写入该 word 模板,生成新的 word 文档 将新生成的 word 文档转换为 pdf 格式 对 pdf 文档添加水印 2. 效果预览 word 模板 带水印的 pdf 文档 3. 实现思路

    2024年02月08日
    浏览(36)
  • 使用easyexcel填充模板数据,并导出excel

    导出excel功能非常场景,本片文章记录如何使用模板填充数据后再导出。因直接导出excel数据样式不符合要求,所以做了模板填充然后再导出excel。 效果如下: 注意:列表数据变量名前面要写点{.id},如果单条数据可以不写。 使用表单提交: 实体代码: controller代码: 只对je

    2024年03月11日
    浏览(33)
  • 「实战教程」如何使用POI读取模板PPT填充数据并拼接至目标文件

    POI是一个用于操作Microsoft Office格式文件的Java API库。它可用于读取、写入和操作Word、Excel和PowerPoint等Microsoft Office格式文件。在日常工作中,我们经常需要处理PPT文件,例如制作报告、演示文稿等。而对于一些重复性工作,使用POI库读取模板PPT并填充数据,再拼接至目标文件

    2024年02月05日
    浏览(33)
  • 工具类——Java导出EXCEL2(设置样式、加载并填充图片、加载指定模板、大数据量设置窗口大小与刷新频率)

    书接上篇:工具类——Java 浏览器导入、导出Excel(Java import、export)demo POI的导出方式:创建/加载Workbook,设置样式,填充数据,然后生成本地临时文件,最终以浏览器的形式打开,完成整个导出动作。 demo如下, demo如下, XSSFClientAnchor anchor = new XSSFClientAnchor(int dx1, int dy1,

    2024年02月01日
    浏览(29)
  • Java-根据模板生成PDF

    在有些场景下我们可能需要根据指定的模板来生成 PDF,比如说合同、收据、发票等等。因为 PDF 是不可编辑的,所以用代码直接对 PDF 文件进行修改是很不方便的,这里我是通过 itext 和 Adobe Acrobat 来实现的,以下就是具体实现方法。 Adobe Acrobat 是由 Adobe 公司开发的一款 PDF (

    2024年02月04日
    浏览(39)
  • Java后端返回PDF预览给前端

    前端要预览服务器PDF 可直接将要blob流返回给前端 即可用浏览器自带pdf预览功能打开,现有两种方式 方式1 返回blob流给前端 代码如下        此时 前端解析可直接拿返回的文件流 例子如下 但有的时候 不想返回文件流 可把文件返回为base64 (注意 base64可能超长)此时代码修

    2024年02月08日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包