在 Java 中使用 GroupDocs 添加数字签名 PDF

如果您正在构建处理合同、发票或任何法律文档的 Java 应用程序,您可能已经遇到这样的问题:如何在不从头开始构建的情况下,为 PDF 添加合法有效的数字签名 java?

手动签署文档既慢又容易出错,还会在工作流中形成瓶颈。如果能够只用几行 Java 代码就自动完成整个签署过程,那会怎样?

本指南正是为此而写。使用 GroupDocs.Signature for Java,您将学习如何以编程方式为 PDF、Word 文档以及其他格式添加数字签名——包括可视化签名、证书验证以及完善的异常处理。

您将掌握的内容:

  • 在 Maven 或 Gradle 项目中配置 GroupDocs.Signature(仅需 2 分钟)
  • 使用数字证书和可选签名图片对文档进行签署
  • 处理常见错误并排查证书问题
  • 了解何时使用数字签名以及何时使用其他签名类型
  • 为生产环境实现安全最佳实践

无论您是构建合同管理系统、自动化发票工作流,还是为 SaaS 产品添加电子签名功能,本教程都能满足需求。让我们开始吧。

快速答案

  • 哪个库支持 digital signature PDF java? GroupDocs.Signature for Java。
  • 基本的 PDF 签名需要多少行代码? 只需两行:加载文档并调用 sign。
  • 生产环境需要许可证吗? 是的,商业许可证可去除水印并解锁全部功能。
  • 可以签署 Word、Excel 和 PowerPoint 文件吗? 当然——GroupDocs.Signature 支持 50 多种格式。
  • 是否必须进行证书管理? 对于加密签名,必须使用 .pfx 证书;请妥善保存。

什么是 digital signature PDF java?

Digital signature PDF java 指的是使用 Java 代码对 PDF 文件应用加密签名的过程。该过程会生成防篡改的封印,可通过签署者的公钥证书进行验证,从而为签署的文档提供法律效力、完整性保护和不可否认性。

digital signature 在 Java 中如何工作?

数字签名使用签署者的私钥对文档生成唯一哈希值,然后将该哈希嵌入签名对象中。拥有相应公钥的任何人都可以重新计算哈希并确认文档未被修改,从而实现法律不可否认性和完整性验证。

为什么选择 GroupDocs.Signature 进行数字签名?

GroupDocs.Signature 支持 50+ 输入和输出格式,可在不将整个文件加载到内存的情况下处理上百页的 PDF,并提供内置的可视化签名渲染。其 API 抽象了格式特定的细节,让您只需编写一套代码即可同时处理 PDF、DOCX、XLSX、PPTX 等多种文档。

前置条件

在开始编码之前,请确保以下必备条件已就绪:

必需的库和依赖

  • GroupDocs.Signature for Java 版本 23.12(最新稳定版)
  • 数字证书文件(.pfx 格式),用于签署具有法律约束力的文档
  • 图片文件(PNG、JPG),用于可视化签名(可选,但推荐用于专业文档)

环境搭建要求

  • 已安装并配置 JDK 8 或更高版本
  • 您喜欢的 IDE(IntelliJ IDEA、Eclipse 或带有 Java 扩展的 VS Code)
  • 使用 Maven 或 Gradle 完成基础项目搭建(后续会演示依赖配置)

知识前置条件

  • 基本的 Java 编程 经验(只要会写一个简单类即可)
  • 文件 I/O 操作 的理解
  • 异常处理(try-catch 块)的熟悉度

即使您不是专家,也无需担心——我们会一步步提供清晰的解释。准备好了吗?让我们先配置 GroupDocs.Signature。

设置 GroupDocs.Signature for Java

将 GroupDocs.Signature 引入项目非常简单。请选择您的构建工具并添加相应依赖:

Maven 配置

在 pom.xml 中加入以下内容:

<dependency>
    <groupId>com.groupdocs</groupId>
    <artifactId>groupdocs-signature</artifactId>
    <version>23.12</version>
</dependency>

Gradle 配置

在 build.gradle 中加入以下内容:

implementation 'com.groupdocs:groupdocs-signature:23.12'

小技巧: 如果您所在的企业网络受限,无法直接访问互联网,可从 GroupDocs.Signature releases page 手动下载 JAR 包并手动加入项目类路径。

许可证获取步骤

GroupDocs.Signature 在生产环境下需要许可证,但您有以下几种选择:

  1. 免费试用 – 适合测试和概念验证。立即开始,免费体验全部功能。
  2. 临时许可证 – 在开发和测试期间提供 30 天的完整 API 访问,无水印、无功能限制。
  3. 商业许可证 – 生产部署必备。请前往 Purchase here 根据需求购买。

基础初始化与配置

添加依赖后,使用下面的快速测试验证环境是否配置成功。该代码会初始化 GroupDocs.Signature 库并确认能够访问文档:

import com.groupdocs.signature.Signature;

public class DocumentSigner {
    public static void main(String[] args) {
        // Initialize with a sample document path
        Signature signature = new Signature("path/to/your/document.docx");
        System.out.println("GroupDocs.Signature initialized successfully!");
    }
}

定义锚点: Signature 是 GroupDocs.Signature 的核心类,代表待签署的文档。

这段代码在做什么? Signature 类是入口点——它将文档加载到内存并为签名操作做好准备。如果看到成功提示,说明可以继续进行实际签署。

快速排查: 若出现 FileNotFoundException,请检查文档路径。调试阶段建议使用绝对路径,以避免相对路径带来的混淆。

下面我们进入数字签名的实际实现。

实现指南

理解 Java 中的数字签名

在编写代码之前,先明确我们要实现的目标。数字签名 使用加密证书来验证文档的真实性并检测篡改。当您对文档进行数字签名时:

  1. 证书的私钥对文档生成唯一哈希
  2. 该哈希被嵌入文档作为签名对象
  3. 任何人都可以使用公钥进行验证

这与仅放置图片印章不同——数字签名提供法律效力和防篡改能力。因此,需要使用包含私钥的 .pfx 证书文件。

步骤式实现

我们将完整的文档签署工作流拆解为若干易于消化的步骤。

步骤 1:准备环境

首先定义文件路径。请将占位路径替换为实际目录:

final String DOCUMENT_DIRECTORY = "YOUR_DOCUMENT_DIRECTORY";
final String OUTPUT_DIRECTORY = "YOUR_OUTPUT_DIRECTORY";
final String CERTIFICATE_FILE_PATH = "path/to/your/certificate.pfx"; // Your .pfx certificate
final String IMAGE_FILE_PATH = "path/to/your/image.png"; // Optional: signature image

String filePath = DOCUMENT_DIRECTORY + "/sample.docx";
String fileName = new java.io.File(filePath).getName();
String outputFilePath = OUTPUT_DIRECTORY + "/Signed/" + fileName;

为何要分目录? 将原始文档与签署后文档放在不同文件夹,可防止意外覆盖,并便于版本管理。生产环境中,建议在输出文件名中加入时间戳。

步骤 2:初始化 Signature 对象

创建负责所有签署操作的 Signature 对象:

Signature signature = new Signature(filePath);

内部原理: 该对象加载文档并准备进行操作。库会自动检测文档格式(PDF、DOCX、XLSX 等),并使用相应的签署方式。

重要提示: 使用 try‑with‑resources 或手动关闭 Signature 对象,以避免内存泄漏,尤其在循环处理多个文档时。

步骤 3:配置数字签名选项

在这里您可以指定签名的外观和行为:

import com.groupdocs.signature.options.sign.DigitalSignOptions;

DigitalSignOptions options = new DigitalSignOptions(CERTIFICATE_FILE_PATH) {
    @Override
    public void setImageFilePath(String value) {
        super.setImageFilePath(IMAGE_FILE_PATH);
    }
};

可定制项包括:

  • 证书路径 – 法律有效签名的必填项
  • 图片路径 – 可选的可视化签名(如扫描的手写签名)
  • 签名位置 – 也可以设置 X/Y 坐标、宽高(后文自定义章节会详细说明)
  • 密码保护 – 若 .pfx 文件受密码保护,请使用 options.setPassword("your_password") 设置

常见错误: 忘记为受密码保护的 .pfx 文件设置密码,会抛出难以理解的异常。务必按示例添加密码行。

步骤 4:执行签名并进行错误处理

下面执行签名并优雅地处理可能的异常:

try {
    signature.sign(outputFilePath, options);
    System.out.println("Document signed successfully: " + outputFilePath);
} catch (com.groupdocs.signature.exception.GroupDocsSignatureException ex) {
    System.out.println("GroupDocs Signature Exception: " + ex.getMessage());
    // Handle library-specific errors (e.g., invalid certificate, corrupted document)
} catch (Exception ex) {
    System.out.println("System Exception: " + ex.getMessage());
    // Handle general errors (e.g., file I/O issues, permission problems)
}

为何使用两个 catch 块? 第一个捕获 GroupDocs 特有的错误(如证书验证失败),第二个捕获所有其他异常(如文件系统权限问题),帮助您在开发阶段更快定位问题。

生产环境建议: 用 SLF4J 或 Log4j 替代 System.out.println(),以便更好地记录日志。

高级配置选项

想要更细粒度的控制?以下是常用的可自定义选项:

DigitalSignOptions options = new DigitalSignOptions(CERTIFICATE_FILE_PATH);

// Visual appearance
options.setImageFilePath(IMAGE_FILE_PATH);
options.setLeft(100);  // X position in pixels
options.setTop(100);   // Y position in pixels
options.setWidth(200); // Signature width
options.setHeight(100); // Signature height

// Certificate settings
options.setPassword("certificate_password"); // If .pfx is password-protected

// Signature metadata
options.setReason("Contract approval"); // Why this document is being signed
options.setContact("john@company.com"); // Signer's contact info
options.setLocation("New York Office"); // Where the signature occurred

实战技巧: 对于合同类文档,务必填写 Reason、Contact、Location 等字段,它们会出现在 PDF 签名属性中,审计时更具可信度。

常见陷阱与解决方案

下面列出最容易让开发者踩坑的问题及对应的解决办法,帮助您省去大量调试时间:

1. 证书无效错误

问题: 抛出 CertificateException 或 “Invalid certificate format”。

解决方案:

  • 确认 .pfx 文件未损坏:在 Windows 证书管理器中打开或使用 keytool -list -keystore certificate.pfx 检查。
  • 核实密码是否正确。
  • 检查证书是否已过期(常被忽视)。

预防措施: 在生产环境中实现证书到期监控,并在到期前 30 天发送告警。

2. 文件路径问题

问题: FileNotFoundException 或 “Access denied”。

解决方案:

  • 开发阶段使用绝对路径,例如 C:/projects/docs/sample.pdf。
  • 检查文件权限,确保 Java 进程拥有读取输入文件和写入输出目录的权限。
  • 在 Windows 上注意反斜杠与正斜杠的区别,推荐使用 File.separator 或统一使用正斜杠实现跨平台兼容。

3. 大文档内存问题

问题: 处理大于 50 MB 的 PDF 时应用崩溃或卡顿。

解决方案:

  • 增加 JVM 堆内存:例如在运行配置中加入 -Xmx2G。
  • 将文档分批处理,而非一次性全部加载。
  • 始终关闭 Signature 对象:使用 try‑with‑resources 或手动调用 dispose()。
// Good: automatic resource management
try (Signature signature = new Signature(filePath)) {
    signature.sign(outputFilePath, options);
}
// Signature is automatically closed here

4. PDF 签名位置错误

问题: 签名出现在错误位置或与已有内容重叠。

解决方案:

  • PDF 坐标系原点在左下角,而非大多数 UI 系统的左上角。
  • 先获取页面尺寸,再根据尺寸计算偏移量。
  • 在多个 PDF 查看器(Adobe Acrobat、浏览器内置查看器等)中进行测试,因为渲染可能略有差异。

安全最佳实践

数字签名的安全性取决于实现方式。请遵循以下生产级别的建议:

证书管理

切勿在源码中硬编码证书路径或密码。 推荐做法:

// Bad - hardcoded secrets
String certPath = "/home/user/cert.pfx";
String certPassword = "mypassword123";

// Good - environment variables or secure configuration
String certPath = System.getenv("CERT_PATH");
String certPassword = System.getenv("CERT_PASSWORD");

最佳实践:

  • 将证书存放在安全金库(AWS Secrets Manager、Azure Key Vault、HashiCorp Vault)中。
  • 对高价值签名操作使用硬件安全模块(HSM)。
  • 在证书到期前自动轮换,并实现自动续订。
  • 限制证书文件的文件系统权限,仅对运行应用的用户只读。

输入校验

在签署前始终对文档进行校验:

// Check file exists and is readable
File inputFile = new File(filePath);
if (!inputFile.exists() || !inputFile.canRead()) {
    throw new IllegalArgumentException("Cannot access input file: " + filePath);
}

// Verify file size is reasonable (prevent DoS attacks)
long maxFileSize = 100 * 1024 * 1024; // 100MB
if (inputFile.length() > maxFileSize) {
    throw new IllegalArgumentException("File too large for signing: " + inputFile.length());
}

// Validate file extension matches expected format
String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
if (!Arrays.asList("pdf", "docx", "xlsx").contains(extension)) {
    throw new IllegalArgumentException("Unsupported file format: " + extension);
}

审计日志

记录每一次签署操作,以满足合规和排错需求:

// Log signature operations with essential details
logger.info("Signing document: {} by user: {} with certificate: {}",
    fileName, userId, certificateThumbprint);

try {
    signature.sign(outputFilePath, options);
    logger.info("Successfully signed: {} to {}", fileName, outputFilePath);
} catch (Exception ex) {
    logger.error("Failed to sign document: {} - Error: {}", fileName, ex.getMessage());
    throw ex; // Re-throw after logging
}

日志内容建议: 文档名称及大小、发起签署的用户、证书指纹(不要记录完整证书)、时间戳、成功或失败状态以及错误信息(切勿记录密码或完整证书)。

何时使用不同的签名类型

GroupDocs.Signature 除数字签名外,还支持多种签名类型。以下是各自适用场景:

数字签名(本教程覆盖的)

最佳场景: 合同、财务文件、合规文档
提供: 加密验证、篡改检测、不可否认性
使用时机: 需要法律效力或需证明文档未被修改时

图片签名

最佳场景: 简单的视觉确认、内部审批
提供: 仅视觉呈现(无加密验证)
使用时机: 仅需签名外观且无法律要求的场合(如内部备忘录)

QR 码签名

最佳场景: 移动端验证、跨系统追踪
提供: 嵌入数据 + 易于扫描
使用时机: 需要快速扫描获取元数据(文档 ID、时间戳)时

条形码签名

最佳场景: 库存单据、运输标签、自动化处理
提供: 机器可读的标准化数据
使用时机: 文档将被条码扫描器批量处理时

我的建议: 对于任何具有法律意义的文档(合同、协议、发票),始终使用 数字签名。它是唯一能够提供加密真实性证明的方式。

实际应用案例

以下是企业在生产环境中使用 Java 文档签署的典型方案:

1. 合同管理系统

场景: 律所每日需签署 100+ 客户协议

实现思路:

  • 将未签署的合同存放在云存储(S3、Azure Blob)
  • 合同审批通过后通过 API 触发签署
  • 自动将已签署 PDF 邮件发送给所有相关方
  • 将签署后的文档连同审计日志归档

代码集成模式:

// Pseudo-code example
public void processApprovedContract(String contractId) {
    Contract contract = contractRepository.findById(contractId);
    String unsignedDoc = downloadFromCloudStorage(contract.getStorageKey());
    
    // Sign the document
    String signedDoc = signDocument(unsignedDoc, getLegalCertificate());
    
    // Store and notify
    uploadToCloudStorage(signedDoc, contract.getStorageKey() + "_signed");
    emailService.sendSignedContract(contract.getParties(), signedDoc);
    auditLog.recordSigning(contractId, getCurrentUser());
}

2. 发票处理自动化

场景: 财务部门自动签署外发发票

关键需求:

  • 发票生成后立即签署
  • 添加公司印章图片
  • 在签名元数据中写入发票编号、日期、金额

实现技巧: 使用 RabbitMQ、AWS SQS 等消息队列异步执行签署,避免阻塞发票生成流程。

3. 人力资源文档工作流

场景: 签署员工合同、Offer Letter、NDAs

安全考量:

  • 为不同文档类型使用不同证书(HR 与 Legal 各自独立)
  • 基于角色的访问控制决定谁可以触发签署
  • 对已签署文档进行加密备份

4. 与 CRM 系统集成

场景: 当交易关闭时,Salesforce 或 HubSpot 触发文档签署

集成模式:

  • CRM 发送 webhook 调用 Java 签署服务
  • 使用模板填充交易数据
  • 将签署后的文档上传回 CRM

Webhook 处理示例:

@PostMapping("/api/sign-sales-document")
public ResponseEntity<String> signSalesDocument(@RequestBody DealClosedEvent event) {
    // Generate document from template
    String document = documentGenerator.createFromTemplate(event.getDealId());
    
    // Sign it
    String signedDoc = documentSigner.sign(document, getSalesCertificate());
    
    // Upload to CRM
    crmClient.uploadDocument(event.getDealId(), signedDoc);
    
    return ResponseEntity.ok("Document signed and uploaded");
}

5. 电商订单确认

场景: 为 B2B 交易的采购订单和发货单签署

性能优化:

  • 为常用文档类型预生成已签名模板
  • 对同一证书的重复签署进行缓存
  • 对批量订单使用批处理签署

实际集成模式

微服务架构

如果您采用微服务,推荐如下结构:

[Order Service] --> [Signing Service] --> [Storage Service]
                         |
                         v
                  [Notification Service]

签署服务职责: 提供 REST API 接收签署请求,管理证书生命周期,处理高并发签署队列,并提供状态回调。

优势: 将签署逻辑解耦,便于证书轮换和独立水平扩展。

批处理模式

针对每日上千甚至上万文档的高吞吐场景:

public class BatchDocumentSigner {
    private final BlockingQueue<SigningTask> queue = new LinkedBlockingQueue<>();
    private final ExecutorService executorService = Executors.newFixedThreadPool(5);
    
    public void submitForSigning(String documentPath, String certificatePath) {
        queue.offer(new SigningTask(documentPath, certificatePath));
    }
    
    public void startProcessing() {
        for (int i = 0; i < 5; i++) {
            executorService.submit(() -> {
                while (true) {
                    try {
                        SigningTask task = queue.take();
                        processSigningTask(task);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            });
        }
    }
    
    private void processSigningTask(SigningTask task) {
        // Your signing logic here
    }
}

该模式可避免内存占用过高,并提升整体吞吐。

性能考量

签署性能优化

典型签署耗时:

  • 小型 PDF(1‑5 页):100‑300 ms
  • 中型 PDF(20‑50 页):500‑1000 ms
  • 大型 PDF(100+ 页):2‑5 s
  • Word 文档:通常比 PDF 更快

优化策略:

  1. 复用 Signature 对象(如可能)
// Bad - creates new object for each document
for (String doc : documents) {
    Signature sig = new Signature(doc);
    sig.sign(output, options);
}

// Good - reuse when signing multiple documents with same options
for (String doc : documents) {
    try (Signature sig = new Signature(doc)) {
        sig.sign(output, options);
    }
}
  1. 批量并行处理 – 使用 CompletableFuture 或 ParallelStream 对独立签署任务并行化:
List<CompletableFuture<Void>> futures = documents.stream()
    .map(doc -> CompletableFuture.runAsync(() -> signDocument(doc)))
    .collect(Collectors.toList());

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
  1. 监控与分析 – 使用 JProfiler、YourKit 等工具定位瓶颈。常见问题包括证书加载(可缓存证书)、图片处理(签名前压缩图片)以及文件 I/O(使用 SSD 或 RAM Disk 作为临时目录)。

资源使用指南

内存需求:

  • 基础库约 50 MB 堆
  • 每个文档约占 2 倍文档大小的内存(输入 + 输出)
  • 对于 100 MB 的 PDF,建议至少分配 -Xmx256m(建议 -Xmx1G 并监控实际使用情况)

生产建议: 启用 GC 日志,设置堆使用率 > 80% 时报警。

Java 内存管理最佳实践

// Always use try-with-resources
try (Signature signature = new Signature(filePath)) {
    signature.sign(outputPath, options);
} // Automatically calls signature.dispose()

// For custom resource management
Signature signature = null;
try {
    signature = new Signature(filePath);
    signature.sign(outputPath, options);
} finally {
    if (signature != null) {
        signature.dispose();
    }
}

生产监控指标: 堆内存使用趋势、GC 暂停时间、并发签署数、各文档类型的平均签署时长。

结论

您已经掌握了在 Java 中实现专业级数字签名的完整流程。下面回顾一下您现在可以做到的事:

✅ 在任意 Java 项目(Maven 或 Gradle)中配置 GroupDocs.Signature
✅ 使用合法的数字证书以编程方式签署文档
✅ 优雅地处理错误并排查常见问题
✅ 在生产环境中落实安全最佳实践
✅ 根据业务需求选择合适的签名类型
✅ 针对高并发文档处理进行性能优化

核心结论: 自动化数字签名能够每天为团队节省大量手工工作时间,同时提升安全性和合规性。无论是处理 10 份文档还是 10 000 份,本文提供的模式都具备可扩展性。

下一步

想进一步深化实现吗?以下方向值得探索:

  1. 签名验证工作流 – 学习如何以编程方式验证已签署文档。
  2. 自定义签名外观 – 使用公司徽标创建品牌化签名块。
  3. 多签名工作流 – 实现顺序审批链(签署 → 会签 → 最终批准)。
  4. 云集成 – 与 AWS S3、Google Drive、Dropbox 等存储服务无缝对接。

有疑问吗? GroupDocs 社区论坛活跃且乐于助人——搜索已有帖子或在 forum.groupdocs.com 发帖提问。

FAQ Section

1. 使用 GroupDocs.Signature 可以对哪些文件格式进行数字签名?

您可以签署 PDF、DOCX、XLSX、PPTX 以及超过 50 种其他格式,包括图片文件(PNG、JPG)和纯文本。PDF 是法律签署的首选,因为它在不同平台上能够保持布局不变,但库同样支持电子表格、演示文稿,甚至 CAD 文件,提供统一的 API。

2. 如何在批处理过程中签署多个文档?

使用线程池执行并行签署(参见“批处理模式”章节)。对于 1000+ 文档,建议使用消息队列(RabbitMQ、AWS SQS)将工作分发到多台服务器。务必监控内存使用并实现限流,以防资源耗尽。

3. 能否验证由 GroupDocs.Signature 创建的签名?

可以!调用 signature.verify() 并传入相应的验证选项即可。该方法会检查证书有效性、签名完整性以及文档是否被修改。还可以验证签署时间戳、撤销状态和信任链,以确保符合合规要求。

4. 数字签名和电子签名有什么区别?

数字签名 使用加密证书并提供防篡改验证(本教程所述)。电子签名 是更宽泛的概念,可能仅是键入姓名、点击 “我同意” 或使用数字签名。若需在多数司法管辖区获得法律效力,数字签名是首选。

5. 如何排查 “Invalid certificate” 错误?

首先确认 .pfx 文件能在 Windows 证书管理器或使用 keytool -list 正常打开。常见问题包括:

  1. .pfx 的密码错误
  2. 证书已过期(检查有效期)
  3. 证书文件损坏——重新从 CA 导出
  4. 文件系统权限不足——确保 Java 进程有读取权限

6. 能否将 GroupDocs.Signature 与 AWS S3 等云存储集成?

完全可以。将文档从 S3 下载到临时目录,完成签署后再上传回 S3。生产环境建议使用预签名 URL 实现安全直接上传,并为 S3 交互实现重试机制以应对瞬时故障。

7. 如何在生产环境管理证书过期?

实现每日检查证书到期日期的自动化任务,并在到期前 30 天发送告警。将证书的到期信息存入数据库,与证书元数据一起管理。部分团队使用企业证书管理系统自动拉取并部署新证书。

8. 能否在签名中加入除图片之外的自定义视觉元素?

可以。您可以自定义位置、尺寸、旋转角度、透明度和边框样式。高级场景下,可将图片签名与文本签名组合,创建复杂的签名块,还可以在签名区域内嵌入 QR 码或条形码以携带额外元数据。

9. 生产使用的许可证费用是多少?

GroupDocs 提供多种定价方案:面向小团队的 per‑developer 许可证、面向大型部署的 server‑based 许可证,以及包含高级支持的 enterprise 版。价格从每位开发者每年几百美元起,随开发者人数和支持级别递增。请联系销售获取基于实际使用量的精准报价。

10. 如何处理不同页面尺寸文档的签名定位?

先通过 signature.getDocumentInfo() 获取页面尺寸,然后以页面宽高的百分比计算签名位置,而不是固定像素。例如,距右边缘 10% 、距底部 5% 的位置可在不同纸张(A4、Letter 等)上保持一致。

Resources


最后更新: 2026-06-26
测试版本: GroupDocs.Signature 23.12 for Java
作者: GroupDocs