依赖引入

			<dependency>
                <groupId>org.apache.pdfbox</groupId>
                <artifactId>pdfbox</artifactId>
                <version>2.0.21</version>
            </dependency>

            <dependency>
                <groupId>com.itextpdf</groupId>
                <artifactId>itextpdf</artifactId>
                <version>5.5.13.2</version>
            </dependency>

代码示例

import com.itextpdf.text.BadElementException;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

/**
 * @description: PDF印章工具类
 */
@Slf4j
//@Component
//@RequiredArgsConstructor
public class PdfSignetUtil {
//    private final RedisCache redisCache;
public static void headAddSignSeal(String sourceFilePath, String targetFilePath, String imagePath, int type) {
    // 加载印章图片
    Image image;
    try {
        image = Image.getInstance(imagePath);
    } catch (BadElementException | IOException e) {
        log.error("com.aistreamrpa.xtp2.main.util.PdfSignetUtil.headAddSignSeal,{}, 印章图片读取失败", imagePath, e);
        throw new RuntimeException("印章图片读取失败");
    }
    float fit = type == 1 ? 100 : 140;

    image.scaleToFit(fit, fit);

    PdfReader pdfReader = null;
    PdfStamper stamper = null;
    String outputPath = (targetFilePath == null || targetFilePath.isEmpty()) ? sourceFilePath + ".tmp" : targetFilePath;
    Path source = Paths.get(outputPath);
    try {
        // 读取PDF文件
        pdfReader = new PdfReader(sourceFilePath);
        stamper = new PdfStamper(pdfReader, Files.newOutputStream(source));

        // 获取首页尺寸
        PdfContentByte content = stamper.getOverContent(1);
        Rectangle pageSize = pdfReader.getPageSize(1);

        // 设置印章位置在右上角
        // 485.3 为文件印章的x轴,后续可以使用redis存取而不是写死
        float x = type == 1 ? pageSize.getWidth() - image.getScaledWidth() - 10 : (float) (485.3 - image.getScaledWidth());
        float y = pageSize.getHeight() - image.getScaledHeight() - 10;
        image.setAbsolutePosition(x, y);

        // 添加图像到首页
        content.addImage(image);
    } catch (DocumentException | IOException e) {
        log.error("com.aistreamrpa.xtp2.main.util.PdfSignetUtil.headAddSignSeal,{}, 源文件读取失败", sourceFilePath, e);
        throw new RuntimeException(e);
    } finally {
        if (stamper != null) {
            try {
                stamper.close();
            } catch (DocumentException | IOException e) {
                log.error("com.aistreamrpa.xtp2.main.util.PdfSignetUtil.headAddSignSeal,关闭 PdfStamper 失败", e);
            }
        }
        if (pdfReader != null) {
            pdfReader.close();
        }
    }

    // 如果targetFilePath为空,替换原文件
    if (targetFilePath == null || targetFilePath.isEmpty()) {
        try {
            Files.move(source, Paths.get(sourceFilePath), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            log.error("com.aistreamrpa.xtp2.main.util.PdfSignetUtil.headAddSignSeal,替换原文件失败", e);
            throw new RuntimeException("替换原文件失败");
        }
    }
}

    /**
     * 是否包含印章,不包含则添加
     * 如果目标文件路径为空,则将文件直接覆盖源文件
     *
     * @param sourceFilePath 源文件路径
     * @param targetFilePath 目标文件路径
     * @param imagePath      印章图片路径
     * @param type 1.文件章 2.受控分发章
     * @return 是否成功
     */
    public static boolean whetherIsIncludedOfSeal(String sourceFilePath, String targetFilePath, String imagePath, int type) {
        File pdfFile = new File(sourceFilePath);
        File imageFile = new File(imagePath);
        if(!pdfFile.exists() || !imageFile.exists()){
            throw new RuntimeException("图片路径 or 源文件路径 不存在");
        }
        // 加载指定的图片
        BufferedImage specifiedImage;
        try {
            specifiedImage = ImageIO.read(imageFile);
        } catch (IOException e) {
            log.error("com.aistreamrpa.xtp2.main.util.PdfSignetUtil.whetherIsIncludedOfSeal,{}, 图片读取失败", imagePath, e);
            throw new RuntimeException("图片读取失败");
        }

        PdfDocument pdfDocument = new PdfDocument();
        //载入PDF文档
        pdfDocument.loadFromFile(sourceFilePath);
        PdfPageBase pdfPageBase = pdfDocument.getPages().get(0);
        BufferedImage[] bufferedImages = pdfPageBase.extractImages();

        // 比较提取的图片与指定图片
        boolean containsImage = false;
        for (BufferedImage image : bufferedImages) {
            if (imagesAreEqual(image, specifiedImage)) {
                containsImage = true;
                break;
            }
        }

        // 印章不存在,添加印章
        if (!containsImage) {
            headAddSignSeal(sourceFilePath, targetFilePath, imagePath,type);
            containsImage = true;
        }
        return containsImage;
    }

    private static boolean imagesAreEqual(BufferedImage imgA, BufferedImage imgB) {
        if (imgA.getWidth() != imgB.getWidth() || imgA.getHeight() != imgB.getHeight()) {
            return false;
        }

        for (int y = 0; y < imgA.getHeight(); y++) {
            for (int x = 0; x < imgA.getWidth(); x++) {
                if (imgA.getRGB(x, y) != imgB.getRGB(x, y)) {
                    return false;
                }
            }
        }

        return true;
    }
}