-->

Java代码生成PDF2.0(包括文字图片)+PDF加水印+PDF转图片

1. 开源框架支持

iText,生成PDF文档,还支持将XML、Html文件转化为PDF文件;(简单但是得下载软件)
Apache PDFBox,生成、合并PDF文档;(类似于itext)
docx4j,生成docx、pptx、xlsx文档,支持转换为PDF格式。(需要一直转文件格式,麻烦,不过生成的PDF看不出生成的痕迹,非常标准)

注:由于个人喜好,这里还是用itext(之前用过而且简单)

2. 代码实现

导包

    implementation 'com.itextpdf:itextpdf:5.5.13.3'
    implementation 'com.itextpdf:itext-asian:5.2.0'
    implementation 'com.itextpdf:itext7-core:7.2.5'
    implementation 'org.apache.pdfbox:pdfbox:2.0.27'

注意:这里pdfbox包用的是老版的,新版的PDDocument中的load方法已经没了或者已经改名被替代(下面的pdftoimage将无法使用),我这里为了省事,就用老版了

工具类(包含将文件转为byte[]、生成PDF文档与PDF加水印方法)

点击查看代码
package com.example.studydemo.common;


import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Map;

import static com.itextpdf.commons.utils.FileUtil.deleteFile;


@Component
public class GeneratePDF {

    public static byte[] getBytes(String filePath){
        byte[] buffer = null;
        try {
            File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(8192);
            byte[] b = new byte[8192];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer;
    }

    public static String generetePdf(String temp,String storepath,Map<String,String> map,Map<String,byte[]> images) throws IOException, DocumentException {

        /*创建一个pdf读取对象*/
        PdfReader reader = new PdfReader(temp);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        /*创建pdf模板,参数reader  bos*/
        PdfStamper ps = new PdfStamper(reader, bos);
        /*定义字体*/
//            BaseFont baseFont = BaseFont.createFont("/usr/share/fonts/SIMSUN.TTC,1",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        BaseFont baseFont = BaseFont.createFont("c://windows//fonts//simsun.ttc,1",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        ArrayList<BaseFont> fontArrayList = new ArrayList<>();
        fontArrayList.add(baseFont);
        /*读取模板文本域并封装数据(注意名字应与文本域中的名字一致)*/
        AcroFields s = ps.getAcroFields();
        /*定义字体,若不定义,会使用模板中的文本域设置的字体*/
        s.setSubstitutionFonts(fontArrayList);
        for (String a:map.keySet()
        ) {
            s.setField(a, map.get(a));
        }

        for (String b :images.keySet()
        ) {
            /*插入图片*/
            int pageNo = s.getFieldPositions(b).get(0).page;
            Rectangle signRect = s.getFieldPositions(b).get(0).position;
            float x = signRect.getLeft();
            float y = signRect.getBottom();
            Image image = Image.getInstance(images.get(b));

            /*获取操作的页面*/
            PdfContentByte under = ps.getOverContent(pageNo);
            /*根据域的大小缩放图片*/
            image.scaleToFit(signRect.getWidth(), signRect.getHeight());
            /*添加图片*/
            image.setAbsolutePosition(x, y);
            under.addImage(image);
        }
        /*这里true表示pdf可编辑*/
        ps.setFormFlattening(false);
        /*关闭PdfStamper*/
        ps.close();
        FileOutputStream file=new FileOutputStream(storepath);
        file.write(bos.toByteArray());
        return storepath;


    }




    /**
     * pdf生成水印
     *
     * @param srcPdfPath       插入前的文件路径
     * @param tarPdfPath       插入后的文件路径
     * @param WaterMarkContent 水印文案
     * @param numberOfPage     每页需要插入的条数
     * @throws Exception
     */
    public static void addWaterMark(String srcPdfPath, String tarPdfPath, String WaterMarkContent, int numberOfPage) throws Exception {
        PdfReader reader = new PdfReader(srcPdfPath);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(tarPdfPath));
        PdfGState gs = new PdfGState();
        System.out.println("adksjskalfklsdk");
        //设置字体
        BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

        // 设置透明度
        gs.setFillOpacity(0.4f);

        int total = reader.getNumberOfPages() + 1;
        PdfContentByte content;
        for (int i = 1; i < total; i++) {
            content = stamper.getOverContent(i);
            content.beginText();
            content.setGState(gs);
            //水印颜色
            content.setColorFill(BaseColor.DARK_GRAY);
            //水印字体样式和大小
            content.setFontAndSize(font, 35);
            //插入水印  循环每页插入的条数
            for (int j = 0; j < numberOfPage; j++) {
                content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 150, 100 * (j + 1), 30);
                content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 450, 100 * (j + 1), 30);
                content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 750, 100 * (j + 1), 30);
            }
            content.endText();
        }
        stamper.close();
        reader.close();
        boolean b = deleteFile(new File(srcPdfPath));
        System.out.println("PDF水印添加完成!");
    }

    public static ArrayList<String> pdftoimage(String pdfpath,String temppath,String storepath) {
        File file = new File(pdfpath);
        ArrayList<String> paths = new ArrayList<>();
        try {
            PDDocument doc = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            // 循环pdf每个页码,1页pdf转成1张图片,多页pdf会转成多张图片
            for (int i = 0; i < pageCount; i++) {
                // dpi表示图片清晰度 dpi越大转换后越清晰,相对转换速度越慢
                BufferedImage image = renderer.renderImageWithDPI(i, 144);
                String path = storepath+temppath+i+".jpg";

                //亲测 图片格式支持:jpg,png,gif,bmp,jpeg
                ImageIO.write(image, "jpg", new File(path));//写入图片
                paths.add("http://101.42.99.134:8888/jeecg-boot/"+temppath+i+".jpg");
//                ImgUtil.pressText(//
//                        FileUtil.file(storepath+"temp/"+i+".jpg"), //
//                        FileUtil.file(finalpath), //
//                        "小北工作室", Color.lightGray, //文字
//                        new Font("黑体", Font.BOLD, 100), //字体
//                        300, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
//                        300 * (i + 1), //y坐标修正值。 默认在中间,偏移量相对于中间偏移
//                        0.4f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
//                );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return paths;
    }


}


实体类(放进PDF中的实体类,这里根据实际情况换成自己的,下面Controller中,我为了比较大众一点就直接将数据写死了,所以理论上这个实体类可以暂时不用了)

点击查看代码
package com.example.springboot.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@NoArgsConstructor
@TableName("jggl")
public class Jggl {

  @TableId(type =IdType.ASSIGN_ID)
  private String id;

  private String createBy;

  private java.sql.Timestamp createTime;
  private String updateBy;
  private java.sql.Timestamp updateTime;
  private String sysOrgCode;
  private String name;
  private String tyxydm;
  private String address;
  private String jglx;
  private String fr;
  private String frdh;
  private String frsfzh;
  private String dwlxr;
  private String lxrdh;
  private String gslxyx;
  private String sjrxm;
  private String sjrdh;
  private String sjrdz;
  private String ssqy;
  private String hysqb;
  private String bahzsdjb;
  private String jytjb;
  private String frsfz;
  private String zyfwbg;
  private String cns;
  private String gstg;
  private String xhyz;
  private String splx;
  private String clrq;
  private String zsbh;
  private String dzzs;
  private String spzt;
  private String xydj;
  private String thyj;
  private String yxqx;
  private String ewm;
  private String fzrq;
  private String yyzz;
  private String sndcwbb;
}

Controller类(生成PDF->加水印->PDF转图片返回图片地址)

点击查看代码
package com.example.studydemo.PDF;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.example.studydemo.common.ReturnResult;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import static com.example.studydemo.common.GeneratePDF.*;


@RestController
@Validated
@RequestMapping("/zscx")
public class FindlicenseController {

    @Value("E:/桌面/新建文件夹/")
    String storepath;
    @Value("${file.location}")
    String filelocation;
    @Value("${file.path}")
    String filepath;
    @Value("${file.domainname}")
    String domainname;




    public String createEwm(String startpath,String endpath){
        File file = new File(endpath);
        if (!file.exists()) {
            QrConfig config = new QrConfig(300, 300);
// 设置边距,既二维码和背景之间的边距
//        config.setMargin(3);
// 设置前景色,既二维码颜色(青色)
//        config.setForeColor(Color.yellow.getRGB());
// 设置背景色(灰色)
//        config.setBackColor(Color.green.getRGB());
// 高纠错级别
            config.setErrorCorrection(ErrorCorrectionLevel.H);
//附带logo

// 生成二维码到文件,也可以到流
//        QrCodeUtil.generate("http://hutool.cn/", config, FileUtil.file("e:/qrcode.jpg"));
            System.out.println(startpath+filelocation+endpath);
            QrCodeUtil.generate(startpath, config.setImg(filelocation+"QQ头像.jpg"),FileUtil.file(endpath));
            System.out.println("文件已创建");
        } else {
            System.out.println("文件已存在");
        }
        return endpath;
    }

    @PostMapping("/createxyzsPdf")
    public ReturnResult createxyzsPdf() throws Exception {
//        List<Jggl> list = jgglService.listByMap(message);
//        if (list.size() == 1 && Objects.equals(list.get(0).getSpzt(),"通过") && !Objects.equals(list.get(0).getXydj(),"")) {
//            Jggl jggl = list.get(0);
            /*读取图片地址*/
            Map<String, String> map = new HashMap<>();
            map.put("name","小北车企");
            map.put("tyxydm","12345678910");
            map.put("xydj", "三级");
            map.put("fzrq", "2024-01-09");
            Map<String, byte[]> images = new HashMap<>();
            images.put("ewm",getBytes(createEwm("https://home.cnblogs.com/u/beijie/","E:/usr/local/apps/zscx-download/"+System.currentTimeMillis()+"xyzsewm.jpg")));
            String path = generetePdf("E:/usr/local/apps/zscx-download/辽宁省汽车流通协会信用证书.pdf", "E:/usr/local/apps/zscx-download"+"/temp/"+"12345678910"+"辽宁省汽车流通协会信用证书.pdf", map, images);
            System.out.println(path);
            String waterpath = "E:/usr/local/apps/zscx-download"+"/temp/"+"12345678910"+"xyzs.pdf";
            try {
                addWaterMark(path, waterpath, "小北工作室", 10);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return ReturnResult.buildSuccessResult(pdftoimage(waterpath, "temp/"+"12345678910", "E:/usr/local/apps/zscx-download/").get(0));
        }



    /**
     * 转换全部的pdf
     * pdf转图片
     */
    @GetMapping("/pdfToImg")
    public void pdfToImg(String path) {
        // 将pdf转图片 并且自定义图片得格式大小
        File file = new File(path);
        try {
            PDDocument doc = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            // 循环pdf每个页码,1页pdf转成1张图片,多页pdf会转成多张图片
            for (int i = 1; i < pageCount; i++) {
                // dpi表示图片清晰度 dpi越大转换后越清晰,相对转换速度越慢
                BufferedImage image = renderer.renderImageWithDPI(i, 144);
                //亲测 图片格式支持:jpg,png,gif,bmp,jpeg
                ImageIO.write(image, "png", new File("E:/桌面/新建文件夹/"+i+".png"));//写入图片
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


参考文档:(主要参考,让人醍醐灌顶)https://blog.csdn.net/a_lllk/article/details/109450972

(辅助参考,对pdf操作介绍比较全面)https://wanghj.blog.csdn.net/article/details/127495462

(辅助参考,itext表单域传值介绍比较全面)https://blog.csdn.net/qq_42130324/article/details/122937657

3. 加水印

方式一 PDF加水印(在工具类里已经包含)

点击查看代码
/**
         * pdf生成水印
         *
         * @param srcPdfPath       插入前的文件路径
         * @param tarPdfPath       插入后的文件路径
         * @param WaterMarkContent 水印文案
         * @param numberOfPage     每页需要插入的条数
         * @throws Exception
         */
        public static void addWaterMark(String srcPdfPath, String tarPdfPath, String WaterMarkContent, int numberOfPage) throws Exception {
            PdfReader reader = new PdfReader(srcPdfPath);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(tarPdfPath));
            PdfGState gs = new PdfGState();
            System.out.println("adksjskalfklsdk");
            //设置字体
            BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

            // 设置透明度
            gs.setFillOpacity(0.4f);

            int total = reader.getNumberOfPages() + 1;
            PdfContentByte content;
            for (int i = 1; i < total; i++) {
                content = stamper.getOverContent(i);
                content.beginText();
                content.setGState(gs);
                //水印颜色
                content.setColorFill(BaseColor.DARK_GRAY);
                //水印字体样式和大小
                content.setFontAndSize(font, 35);
                //插入水印  循环每页插入的条数
                for (int j = 0; j < numberOfPage; j++) {
                    content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 150, 100 * (j + 1), 30);
                    content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 450, 100 * (j + 1), 30);
                    content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 750, 100 * (j + 1), 30);
                }
                content.endText();
            }
            stamper.close();
            reader.close();
            boolean b = deleteFile(new File(srcPdfPath));
            System.out.println("PDF水印添加完成!");
        }

方式二 图片加水印

                ImgUtil.pressText(//
                        FileUtil.file(storepath+"temp/"+i+".jpg"), //
                        FileUtil.file(finalpath), //
                        "小北工作室", Color.lightGray, //文字
                        new Font("黑体", Font.BOLD, 100), //字体
                        300, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
                        300 * (i + 1), //y坐标修正值。 默认在中间,偏移量相对于中间偏移
                        0.4f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
                );

这里用的hutool的图片工具类,链接在这:http://hutool.cn/docs/index.html#/core/图片/图片工具-ImgUtil

PDF转图片

点击查看代码
    public void pdfToImg(String path) {
        // 将pdf转图片 并且自定义图片得格式大小
        File file = new File(path);
        try {
            PDDocument doc = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            // 循环pdf每个页码,1页pdf转成1张图片,多页pdf会转成多张图片
            for (int i = 1; i < pageCount; i++) {
                // dpi表示图片清晰度 dpi越大转换后越清晰,相对转换速度越慢
                BufferedImage image = renderer.renderImageWithDPI(i, 144);
                //亲测 图片格式支持:jpg,png,gif,bmp,jpeg
                ImageIO.write(image, "png", new File("/usr/local/apps/zscx-download/"+i+".png"));//写入图片
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

代码不全,因为是直接在controller里用的,若有需要可以看生成PDF的controller或者参考文档:https://blog.csdn.net/suya2011/article/details/121368330

Maven项目可以用spire,我是特别想用的,因为这个对PDF操作更全,但是这个全是Maven导包,自己在Maven仓库找到依赖还不能用,所以你可以试试,建议Java使用Free Spire.PDF for Java
官网在这:https://www.e-iceblue.cn/Introduce/Free-Spire-PDF-JAVA.html
image

posted @   ꧁ʚ星月天空ɞ꧂  阅读(420)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示