You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在OpenPDF中实现图片浮于文字上方的盖章功能?

实现OpenPDF中印章图片浮于文字上方的动态定位方案

OpenPDF的Image类确实没有直接提供图片浮于文字上方的定位选项,但可以通过操作PdfContentByte的上层内容流来实现,同时结合自定义元素满足你想用Document#add方式操作的需求,以下是具体实现步骤:

核心原理

OpenPDF的PDF页面内容分为两层:

  • 底层内容流(通过getUnderContent()获取):对应Image.UNDERLYING,内容显示在文字下方
  • 上层内容流(通过getOverContent()获取):内容会覆盖在已添加的文字上方,这正是印章需要的层级

实现步骤

1. 自定义可添加到Document的印章元素

创建实现Element接口的自定义类,让它能像Paragraph一样通过Document#add添加,内部封装图片定位与绘制逻辑:

import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

public class StampElement implements Element {
    private Image stampImage;
    private float x;
    private float y;
    private float width;
    private float height;

    // 构造方法:传入印章图片、目标坐标(页面左下角为原点)、宽高
    public StampElement(Image stampImage, float x, float y, float width, float height) throws DocumentException {
        this.stampImage = stampImage;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        stampImage.scaleAbsolute(width, height);
    }

    @Override
    public int type() {
        return Element.OBJECT;
    }

    @Override
    public boolean isContent() {
        return true;
    }

    @Override
    public boolean isNestable() {
        return false;
    }

    @Override
    public boolean process(ElementListener listener) {
        try {
            return listener.add(this);
        } catch (DocumentException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public void write(PdfWriter writer) throws DocumentException {
        // 获取当前页面的上层内容流
        PdfContentByte contentByte = writer.getOverContent(writer.getCurrentPageNumber());
        // 设置图片绝对位置
        stampImage.setAbsolutePosition(x, y);
        // 将图片绘制到上层内容流
        stampImage.write(contentByte);
    }
}

2. 动态计算印章位置

结合文档当前文本位置,动态计算印章坐标:

public static void main(String[] args) throws Exception {
    Document document = new Document(PageSize.A4);
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("contract.pdf"));
    document.open();

    // 添加合同主体文本
    Paragraph contractContent = new Paragraph("这里是合同的主体文本内容,长度可能变化甚至跨页...");
    document.add(contractContent);

    // 加载印章图片
    Image stamp = Image.getInstance("stamp.png");

    // 动态计算位置:比如放在文本结束位置下方20单位、左边界100单位处
    float currentTextEndY = writer.getVerticalPosition(false);
    float stampX = 100;
    float stampY = currentTextEndY - 20;
    float stampSize = 100;

    // 添加自定义印章元素
    document.add(new StampElement(stamp, stampX, stampY, stampSize, stampSize));

    document.close();
}

3. 处理分页场景

如果合同文本跨页,可通过PdfPageEvent监听页面切换,在指定页面添加印章:

class StampPageEvent extends PdfPageEventHelper {
    private Image stamp;
    private float targetX;
    private float targetY;

    public StampPageEvent(Image stamp, float targetX, float targetY) {
        this.stamp = stamp;
        this.targetX = targetX;
        this.targetY = targetY;
        stamp.scaleAbsolute(100, 100);
    }

    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        // 示例:在第2页指定位置添加印章
        if (writer.getCurrentPageNumber() == 2) {
            PdfContentByte contentByte = writer.getOverContent(writer.getCurrentPageNumber());
            stamp.setAbsolutePosition(targetX, targetY);
            try {
                stamp.write(contentByte);
            } catch (DocumentException e) {
                e.printStackTrace();
            }
        }
    }
}

// 使用方式
writer.setPageEvent(new StampPageEvent(stamp, 100, 200));

关键注意点

  • OpenPDF坐标系以页面左下角为原点,Y轴向上递增,计算位置时需转换日常左上角的坐标逻辑
  • 若需将印章固定在某段文字旁,可使用ColumnText获取段落的精确坐标后再计算印章位置
  • 确保图片资源路径正确,支持JPG、PNG等常见格式

内容的提问来源于stack exchange,提问作者etherealss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 18:05:29