Java实现给PDF文件加水印、图片、签名(含测试类)

  Java   42分钟   610浏览   0评论

前言

你好呀,我是小邹。

昨天给大家分享了PDF文件添加水印后保存,今天再来聊一聊如何实现印章、签名

“Talk is cheap,show me the code.”

效果

实现

① 添加相关依赖

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13</version>
</dependency>
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>

② 工具类PdfUtil

package top.hqxiaozou.utils;

import top.hqxiaozou.entity.PdfAddContentParam;
import com.itextpdf.awt.geom.Rectangle2D;
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

/**
 * @author:邹祥发
 * @date:2022/11/24 10:19
 * @description:PDF工具类,提供 水印、签名、盖章 功能
 */
@Slf4j
public class PdfUtil {

    /**
     * 往PDF上添加文字水印
     *
     * @param inputFile     原文件
     * @param outputFile    加水印后的文件
     * @param waterMarkName 水印字符
     */
    public static void addWaterMark(String inputFile, String outputFile, String waterMarkName) {
        PdfReader reader = null;
        PdfStamper stamper = null;
        try {
            reader = new PdfReader(inputFile);
            stamper = new PdfStamper(reader, Files.newOutputStream(Paths.get(outputFile)));
            //水印字体,放到服务器上对应文件夹下(arial中文不生效)
            //BaseFont base = BaseFont.createFont("D:/workspace/springboot/src/main/resources/arial.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
            Rectangle pageRect;
            PdfGState gs = new PdfGState();
            //填充不透明度  为1完全不透明
            gs.setFillOpacity(0.1f);
            //笔画不透明度, 为1完全不透明
            gs.setStrokeOpacity(0.1f);
            int total = reader.getNumberOfPages() + 1;
            JLabel label = new JLabel();
            FontMetrics metrics;
            int textH;
            int textW;
            label.setText(waterMarkName);
            metrics = label.getFontMetrics(label.getFont());
            textH = metrics.getHeight();
            textW = metrics.stringWidth(label.getText());
            PdfContentByte under;
            int interval = 0;
            for (int i = 1; i < total; i++) {
                pageRect = reader.getPageSizeWithRotation(i);
                //在字体下方加水印
                under = stamper.getOverContent(i);
                under.beginText();
                under.saveState();
                under.setGState(gs);
                //这里修改水印字体大小
                under.setFontAndSize(base, 36);
                //这里设置字体上下间隔
                for (int height = interval + textH; height < pageRect.getHeight(); height = height + textH * 9) {
                    //这里设置字体左右间隔
                    for (int width = interval + textW; width < pageRect.getWidth() + textW; width = width + textW * 4) {
                        //这里设置倾斜角度
                        under.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW, height - textH, 45);
                    }
                }
                under.endText();
            }
            stamper.close();
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (stamper != null) {
                    stamper.close();
                }
            } catch (IOException | com.itextpdf.text.DocumentException e) {
                e.printStackTrace();
            }
            if (reader != null) {
                reader.close();
            }
        }
    }

    /**
     * 根据指定坐标往PDF上添加文字内容
     *
     * @param filePath            原文件路径
     * @param pdfAddContentParams 实体类
     */
    public static byte[] addText(String filePath, List<PdfAddContentParam> pdfAddContentParams) throws Exception {
        PdfReader pdfReader = new PdfReader(filePath);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        //设置输入文件以及输出文件地址
        PdfStamper stamper = new PdfStamper(pdfReader, byteArrayOutputStream);
        //设置字体
        BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        for (PdfAddContentParam pdfAddContentParam : pdfAddContentParams) {
            Font font = new Font(baseFont, 10);
            if (pdfAddContentParam.getPageNum() > pdfReader.getNumberOfPages()) {
                log.error("设置的页码数[" + pdfAddContentParam.getPageNum() + "]大于原文件页码数[" + pdfReader.getNumberOfPages() + "]!请重新输入");
                throw new RuntimeException("设置的页码数[" + pdfAddContentParam.getPageNum() + "]大于原文件页码数[" + pdfReader.getNumberOfPages() + "]!请重新输入");
            }
            PdfContentByte overContent = stamper.getOverContent(pdfAddContentParam.getPageNum());
            ColumnText columnText = new ColumnText(overContent);
            columnText.setSimpleColumn(pdfAddContentParam.getLlx(), pdfAddContentParam.getLly(), pdfAddContentParam.getUrx(), pdfAddContentParam.getUry());
            Paragraph elements = new Paragraph(pdfAddContentParam.getContent());
            elements.setFont(font);
            columnText.addElement(elements);
            columnText.go();
        }
        stamper.close();
        return byteArrayOutputStream.toByteArray();
    }

    /**
     * 根据关键字往PDF上添加文字内容
     *
     * @param filePath            原文件路径
     * @param pdfAddContentParams 实体类
     */
    public static byte[] addTextByKeyword(String filePath, List<PdfAddContentParam> pdfAddContentParams) throws Exception {
        PdfReader pdfReader = new PdfReader(filePath);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        //设置输入文件以及输出文件地址
        PdfStamper stamper = new PdfStamper(pdfReader, byteArrayOutputStream);
        // 获取PDF文件的总页数
        int pageNum = pdfReader.getNumberOfPages();
        PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);
        for (PdfAddContentParam pdfAddContentParam : pdfAddContentParams) {
            StringBuilder stringBuilder = new StringBuilder();
            final boolean[] hasKeyword = {false, true};
            String keyword = pdfAddContentParam.getKeyword();
            int length = keyword.length();
            if (length == 0) {
                throw new RuntimeException("请输入关键字!");
            }
            for (int page = 1; page <= pageNum; page++) {
                if (hasKeyword[0]) {
                    break;
                }
                int finalPage = page;
                pdfReaderContentParser.processContent(page, new RenderListener() {
                    @Override
                    public void beginTextBlock() {
                    }

                    @SneakyThrows
                    @Override
                    public void renderText(TextRenderInfo renderInfo) {
                        // 读取PDF文件的内容
                        String text = renderInfo.getText().trim();
                        stringBuilder.append(text);
                        if (stringBuilder.toString().contains(keyword)) {
                            Rectangle2D.Float boundingRectangle = renderInfo.getBaseline().getBoundingRectange();
                            if (hasKeyword[1]) {
                                // 关键字的坐标
                                double x = boundingRectangle.getX();
                                double y = boundingRectangle.getY();
                                //设置字体
                                BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                                Font font = new Font(baseFont, 10);
                                PdfContentByte overContent = stamper.getOverContent(finalPage);
                                ColumnText columnText = new ColumnText(overContent);
                                // 根据关键字的坐标计算+偏移量得到批注字体的坐标
                                columnText.setSimpleColumn((float) x + pdfAddContentParam.getLlx(), (float) y + pdfAddContentParam.getLly(), (float) x + 100 + pdfAddContentParam.getUrx(), (float) y + pdfAddContentParam.getUry());
                                Paragraph elements = new Paragraph(pdfAddContentParam.getContent());
                                elements.setFont(font);
                                columnText.addElement(elements);
                                columnText.go();
                                hasKeyword[1] = false;
                            }
                            hasKeyword[0] = true;
                        }
                        if (stringBuilder.toString().length() > length * 3) {
                            stringBuilder.setLength(0);
                        }
                    }

                    @Override
                    public void endTextBlock() {
                    }

                    @Override
                    public void renderImage(ImageRenderInfo renderInfo) {
                    }
                });
            }
        }
        stamper.close();
        pdfReader.close();
        return byteArrayOutputStream.toByteArray();
    }

    /**
     * pdf插入图片
     *
     * @param oldPath 插入图片前的路径
     * @param newPath 插入图片后的路径
     * @param imgPath 图片路径
     * @throws IOException
     * @throws DocumentException
     */
    public static void addImage(String oldPath, String newPath, String imgPath) throws IOException, DocumentException {
        InputStream inputStream = Files.newInputStream(Paths.get(oldPath));
        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)));
        //x轴坐标
        int x = 350;
        //y轴坐标
        int y = 20;
        //图片放置的页码
        for (int i = pdfPages; i <= pdfPages; i++) {
            //图片处理
            Image img = Image.getInstance(ImageUtil.imageToBytes((bufferedImage), "png"));
            //设置图片大小
            img.scaleAbsolute(192, 100);
            img.setTransparency(new int[0]);
            //设置图片位置
            img.setAbsolutePosition(x, y);
            stamper.getOverContent(i).addImage(img);
        }
        //关闭资源
        stamper.close();
        out.close();
        reader.close();
    }
}

③ 工具类ImageUtil

package top.hqxiaozou.utils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * @author:邹祥发
 * @date:2022/11/25 14:14
 * @description:转换BufferedImage数据为byte数组
 */
public class ImageUtil {

    /**
     * 转换BufferedImage 数据为byte数组
     *
     * @param image  Image对象
     * @param format image格式字符串.如"gif","png"
     * @return byte数组
     */
    public static byte[] imageToBytes(BufferedImage image, String format) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, format, out);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return out.toByteArray();
    }

    /**
     * 转换byte数组为Image
     *
     * @param bytes
     * @return Image
     */
    public static Image bytesToImage(byte[] bytes) {
        Image image = Toolkit.getDefaultToolkit().createImage(bytes);
        try {
            MediaTracker mt = new MediaTracker(new Label());
            mt.addImage(image, 0);
            mt.waitForAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return image;
    }
}

④ 实体类

package top.hqxiaozou.entity;

import lombok.Data;

/**
 * @author:邹祥发
 * @date:2022/11/25 10:36
 * @description:pdf添加签名实体类
 */
@Data
public class PdfAddContentParam {

    /**
     *  要添加的文字
     */
    private String content;

    /**
     * 页码
     */
    private Integer pageNum;

    /**
     * 关键字
     */
    private String keyword;

    /**
     * 文本框坐标(左下角x,y,右上角x,y)
     */
    private Float llx;
    private Float lly;
    private Float urx;
    private Float ury;

    public PdfAddContentParam() {
    }

    public PdfAddContentParam(String content, Integer pageNum, Float llx, Float lly, Float urx, Float ury) {
        this.content = content;
        this.pageNum = pageNum;
        this.llx = llx;
        this.lly = lly;
        this.urx = urx;
        this.ury = ury;
    }

    public PdfAddContentParam(String content, String keyword, Float llx, Float lly, Float urx, Float ury) {
        this.content = content;
        this.keyword = keyword;
        this.llx = llx;
        this.lly = lly;
        this.urx = urx;
        this.ury = ury;
    }
}

⑤ 测试类

  • 添加水印
package top.hqxiaozou.test;

import top.hqxiaozou.utils.PDFUtils;

/**
 * @author:邹祥发
 * @date:2022/11/24 10:41
 * @description:PDF水印测试类
 */
public class AddWaterMarkTest {
    public static void main(String[] args) {
        PDFUtils.addWaterMark("C:/Users/zou/Desktop/阿里巴巴Java开发手册(终极版).pdf", "C:/Users/zou/Desktop/new.pdf", "https://www.hqxiaozou.top");
    }
}
  • 插入图片
package top.hqxiaozou.pdf;

import top.hqxiaozou.utils.PdfUtil;
import com.itextpdf.text.DocumentException;

import java.io.IOException;

/**
 * @author:邹祥发
 * @date:2022/11/25 14:22
 * @description:pdf插入图片测试类
 */
public class AddImageTest {
    public static void main(String[] args) {
        try {
            PdfUtil.addImage("C:/Users/zou/Desktop/watermark.pdf", "C:/Users/zou/Desktop/image.pdf", "C:/Users/zou/Desktop/sign.bmp");
        } catch (IOException | DocumentException e) {
            throw new RuntimeException(e);
        }
    }
}
  • 根据指定坐标往PDF添加文字
package top.hqxiaozou.pdf;

import top.hqxiaozou.entity.PdfAddContentParam;
import top.hqxiaozou.utils.PdfUtil;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author:邹祥发
 * @date:2022/11/24 20:30
 * @description:根据指定坐标往PDF添加文字内容测试类
 */
public class AddTextTest {
    public static void main(String[] args) {
        // 按坐标添加批注
        PdfAddContentParam name = new PdfAddContentParam("召田最帅boy", 3, 415F, 36F, 610F, 83F);
        List<PdfAddContentParam> pdfAddContentParams = new ArrayList<>();
        Collections.addAll(pdfAddContentParams, name);
        byte[] bytes;
        try {
            bytes = PdfUtil.addText("C:/Users/zou/Desktop/image.pdf", pdfAddContentParams);
            Files.newOutputStream(Paths.get("C:/Users/zou/Desktop/sign.pdf")).write(bytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
  • 根据关键字往PDF添加文字
package top.hqxiaozou.pdf;

import top.hqxiaozou.entity.PdfAddContentParam;
import top.hqxiaozou.utils.PdfUtil;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author:邹祥发
 * @date:2022/11/25 11:16
 * @description:根据关键字往PDF添加文字内容测试类
 */
public class AddTextByKeywordTest {
    public static void main(String[] args) {
        // 按关键字批注
        PdfAddContentParam keyword = new PdfAddContentParam("test", "召田最帅boy", 1F, 2F, 3F, 40F);
        List<PdfAddContentParam> pdfAddContentParams = new ArrayList<>();
        Collections.addAll(pdfAddContentParams, keyword);
        byte[] bytes;
        try {
            bytes = PdfUtil.addTextByKeyword("C:/Users/zou/Desktop/target.pdf", pdfAddContentParams);
            Files.newOutputStream(Paths.get("C:/Users/zou/Desktop/new.pdf")).write(bytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
如果你觉得文章对你有帮助,那就请作者喝杯咖啡吧☕
微信
支付宝
😀
😃
😄
😁
😆
😅
🤣
😂
🙂
🙃
😉
😊
😇
🥰
😍
🤩
😘
😗
☺️
😚
😙
🥲
😋
😛
😜
🤪
😝
🤑
🤗
🤭
🫢
🫣
🤫
🤔
🤨
😐
😑
😶
😏
😒
🙄
😬
😮‍💨
🤤
😪
😴
😷
🤒
🤕
🤢
🤮
🤧
🥵
🥶
🥴
😵
😵‍💫
🤯
🥳
🥺
😠
😡
🤬
🤯
😈
👿
💀
☠️
💩
👻
👽
👾
🤖
😺
😸
😹
😻
😼
😽
🙀
😿
😾
👋
🤚
🖐️
✋️
🖖
🫱
🫲
🫳
🫴
🫷
🫸
👌
🤌
🤏
✌️
🤞
🫰
🤟
🤘
🤙
👈️
👉️
👆️
🖕
👇️
☝️
🫵
👍️
👎️
✊️
👊
🤛
🤜
👏
🙌
👐
🤲
🤝
🙏
✍️
💅
🤳
💪
🦾
🦿
🦵
🦶
👂
🦻
👃
👶
👧
🧒
👦
👩
🧑
👨
👩‍🦱
👨‍🦱
👩‍🦰
👨‍🦰
👱‍♀️
👱‍♂️
👩‍🦳
👨‍🦳
👩‍🦲
👨‍🦲
🧔‍♀️
🧔‍♂️
👵
🧓
👴
👲
👳‍♀️
👳‍♂️
🧕
👮‍♀️
👮‍♂️
👷‍♀️
👷‍♂️
💂‍♀️
💂‍♂️
🕵️‍♀️
🕵️‍♂️
👩‍⚕️
👨‍⚕️
👩‍🌾
👨‍🌾
👩‍🍳
👨‍🍳
🐶
🐱
🐭
🐹
🐰
🦊
🐻
🐼
🐨
🐯
🦁
🐮
🐷
🐸
🐵
🐔
🐧
🐦
🦅
🦉
🐴
🦄
🐝
🪲
🐞
🦋
🐢
🐍
🦖
🦕
🐬
🦭
🐳
🐋
🦈
🐙
🦑
🦀
🦞
🦐
🐚
🐌
🦋
🐛
🦟
🪰
🪱
🦗
🕷️
🕸️
🦂
🐢
🐍
🦎
🦖
🦕
🐊
🐢
🐉
🦕
🦖
🐘
🦏
🦛
🐪
🐫
🦒
🦘
🦬
🐃
🐂
🐄
🐎
🐖
🐏
🐑
🐐
🦌
🐕
🐩
🦮
🐕‍🦺
🐈
🐈‍⬛
🐓
🦃
🦚
🦜
🦢
🦩
🕊️
🐇
🦝
🦨
🦡
🦫
🦦
🦥
🐁
🐀
🐿️
🦔
🌵
🎄
🌲
🌳
🌴
🌱
🌿
☘️
🍀
🎍
🎋
🍃
🍂
🍁
🍄
🌾
💐
🌷
🌹
🥀
🌺
🌸
🌼
🌻
🌞
🌝
🌛
🌜
🌚
🌕
🌖
🌗
🌘
🌑
🌒
🌓
🌔
🌙
🌎
🌍
🌏
🪐
💫
🌟
🔥
💥
☄️
☀️
🌤️
🌥️
🌦️
🌧️
⛈️
🌩️
🌨️
❄️
☃️
🌬️
💨
💧
💦
🌊
🍇
🍈
🍉
🍊
🍋
🍌
🍍
🥭
🍎
🍏
🍐
🍑
🍒
🍓
🥝
🍅
🥥
🥑
🍆
🥔
🥕
🌽
🌶️
🥒
🥬
🥦
🧄
🧅
🍄
🥜
🍞
🥐
🥖
🥨
🥯
🥞
🧇
🧀
🍖
🍗
🥩
🥓
🍔
🍟
🍕
🌭
🥪
🌮
🌯
🥙
🧆
🥚
🍳
🥘
🍲
🥣
🥗
🍿
🧈
🧂
🥫
🍱
🍘
🍙
🍚
🍛
🍜
🍝
🍠
🍢
🍣
🍤
🍥
🥮
🍡
🥟
🥠
🥡
🦪
🍦
🍧
🍨
🍩
🍪
🎂
🍰
🧁
🥧
🍫
🍬
🍭
🍮
🍯
🍼
🥛
🍵
🍶
🍾
🍷
🍸
🍹
🍺
🍻
🥂
🥃
🥤
🧃
🧉
🧊
🗺️
🏔️
⛰️
🌋
🏕️
🏖️
🏜️
🏝️
🏞️
🏟️
🏛️
🏗️
🏘️
🏙️
🏚️
🏠
🏡
🏢
🏣
🏤
🏥
🏦
🏨
🏩
🏪
🏫
🏬
🏭
🏯
🏰
💒
🗼
🗽
🕌
🛕
🕍
⛩️
🕋
🌁
🌃
🏙️
🌄
🌅
🌆
🌇
🌉
🎠
🎡
🎢
💈
🎪
🚂
🚃
🚄
🚅
🚆
🚇
🚈
🚉
🚊
🚝
🚞
🚋
🚌
🚍
🚎
🚐
🚑
🚒
🚓
🚔
🚕
🚖
🚗
🚘
🚙
🚚
🚛
🚜
🏎️
🏍️
🛵
🦽
🦼
🛺
🚲
🛴
🛹
🚏
🛣️
🛤️
🛢️
🚨
🚥
🚦
🚧
🛶
🚤
🛳️
⛴️
🛥️
🚢
✈️
🛩️
🛫
🛬
🪂
💺
🚁
🚟
🚠
🚡
🛰️
🚀
🛸
🧳
📱
💻
⌨️
🖥️
🖨️
🖱️
🖲️
💽
💾
📀
📼
🔍
🔎
💡
🔦
🏮
📔
📕
📖
📗
📘
📙
📚
📓
📒
📃
📜
📄
📰
🗞️
📑
🔖
🏷️
💰
💴
💵
💶
💷
💸
💳
🧾
✉️
📧
📨
📩
📤
📥
📦
📫
📪
📬
📭
📮
🗳️
✏️
✒️
🖋️
🖊️
🖌️
🖍️
📝
📁
📂
🗂️
📅
📆
🗒️
🗓️
📇
📈
📉
📊
📋
📌
📍
📎
🖇️
📏
📐
✂️
🗃️
🗄️
🗑️
🔒
🔓
🔏
🔐
🔑
🗝️
🔨
🪓
⛏️
⚒️
🛠️
🗡️
⚔️
🔫
🏹
🛡️
🔧
🔩
⚙️
🗜️
⚗️
🧪
🧫
🧬
🔬
🔭
📡
💉
🩸
💊
🩹
🩺
🚪
🛏️
🛋️
🪑
🚽
🚿
🛁
🧴
🧷
🧹
🧺
🧻
🧼
🧽
🧯
🛒
🚬
⚰️
⚱️
🗿
🏧
🚮
🚰
🚹
🚺
🚻
🚼
🚾
🛂
🛃
🛄
🛅
⚠️
🚸
🚫
🚳
🚭
🚯
🚱
🚷
📵
🔞
☢️
☣️
❤️
🧡
💛
💚
💙
💜
🖤
💔
❣️
💕
💞
💓
💗
💖
💘
💝
💟
☮️
✝️
☪️
🕉️
☸️
✡️
🔯
🕎
☯️
☦️
🛐
🆔
⚛️
🉑
☢️
☣️
📴
📳
🈶
🈚
🈸
🈺
🈷️
✴️
🆚
💮
🉐
㊙️
㊗️
🈴
🈵
🈹
🈲
🅰️
🅱️
🆎
🆑
🅾️
🆘
🛑
💢
💯
💠
♨️
🚷
🚯
🚳
🚱
🔞
📵
🚭
‼️
⁉️
🔅
🔆
🔱
⚜️
〽️
⚠️
🚸
🔰
♻️
🈯
💹
❇️
✳️
🌐
💠
Ⓜ️
🌀
💤
🏧
🚾
🅿️
🈳
🈂️
🛂
🛃
🛄
🛅
  0 条评论