尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

PDF入参以及模板对应签章图踩坑点 JAR版本为 iText5

PDF入参以及模板对应签章图踩坑点 JAR版本为 iText5
📅 发布时间:2026/6/19 22:32:41
模板PDF推荐使用万兴PDF工具破解版调整表单域和表单域名称,入参后的PDF需要设置入参字体和扁平化来保证PDF可以直接显示入参参数。可以防止出现打开PDF显示
文本域

// OSS上的PDF模板文件URL
private static final String OSS_PDF_TEMPLATE_URL = "";


@PostMapping("/oss/uploadSignedPdf")
public Result<String> uploadSignedPdfToOSS(@RequestBody JSONObject requestBody) {
try {
// 参数校验
String idCard = CommonUtils.processNullableValue(requestBody.getString("idCard"), "");
String email = CommonUtils.processNullableValue(requestBody.getString("email"), "");
String phone = CommonUtils.processNullableValue(requestBody.getString("phone"), "");
String signatureBase64 = CommonUtils.processNullableValue(requestBody.getString("signature"), "");

if (signatureBase64.isEmpty()) {
return Result.error("签名图片不能为空");
}

// 移除Base64字符串中的前缀(如果存在)
if (signatureBase64.startsWith("data:image/png;base64,")) {
signatureBase64 = signatureBase64.substring("data:image/png;base64,".length());
}
// Base64解码签名图片
byte[] signatureBytes = Base64.getDecoder().decode(signatureBase64);
File signatureFile = File.createTempFile("signature_", ".png");
Files.write(signatureFile.toPath(), signatureBytes);

// 创建带签名的PDF(使用PdfReader)
File tempPdf = generateSignedPdf(idCard, email, phone, signatureFile);

// 上传OSS
String relativePath = "contracts/" + phone+tempPdf.getName();
String ossUrl = OssBootUtil.upload(
new FileInputStream(tempPdf),
relativePath
);

// 清理临时文件
signatureFile.delete();
tempPdf.delete();

return Result.OK(ossUrl);
} catch (IOException | IllegalArgumentException | DocumentException e) {
return Result.error("文件处理失败: " + e.getMessage());
}
}

// 签名图片缩放比例常量
private static final float SIGNATURE_IMAGE_SCALE = 0.1f; // 将图片缩小到原来的10%
private static final String SIGNATURE_FORM_FIELD = "signature"; // 签名表单域名称

private File generateSignedPdf(String idCard, String email, String phone, File signature) throws IOException, DocumentException {
// 使用PdfReader读取模板
PdfReader reader = new PdfReader(OSS_PDF_TEMPLATE_URL);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("temp_contract.pdf"));
// 设置中文字体,使用更通用的字体配置以确保在各种设备上都能正常显示
BaseFont baseFont = null;
try {
// 尝试使用iText内置的中文字体
baseFont = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
} catch (Exception e1) {
try {
// 备选字体方案
baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
} catch (Exception e2) {
log.warn("无法加载中文字体,使用默认字体");
}
}

Font signatureFont = baseFont != null ? new Font(baseFont, 12, Font.NORMAL) : new Font();

Image signatureImage = Image.getInstance(signature.getAbsolutePath());

// 填充表单字段
AcroFields form = stamper.getAcroFields();

// 添加字体替代,确保中文正常显示
if (baseFont != null) {
form.addSubstitutionFont(baseFont);
}

// 填充表单字段,使用setValueAsString替代setField,可能在某些情况下更可靠
if (idCard != null && !idCard.isEmpty()) {
form.setField("idCard", idCard);
}
if (email != null && !email.isEmpty()) {
form.setField("email", email);
}
if (phone != null && !phone.isEmpty()) {
form.setField("phone", phone);
}


// 添加签名图片到PDF
List<AcroFields.FieldPosition> fieldPositions = form.getFieldPositions(SIGNATURE_FORM_FIELD);
if (fieldPositions != null && !fieldPositions.isEmpty()) {
for (AcroFields.FieldPosition fieldPosition : fieldPositions) {
int page = fieldPosition.page;
PdfContentByte canvas = stamper.getOverContent(page);

Rectangle signRect = fieldPosition.position;
float x = signRect.getLeft();
float y = signRect.getBottom();

// 调整签名图片大小 - 将图片缩小到原来的10%
float width = signatureImage.getWidth() * SIGNATURE_IMAGE_SCALE;
float height = signatureImage.getHeight() * SIGNATURE_IMAGE_SCALE;
signatureImage.scaleToFit(width, height);

// 设置图片位置
signatureImage.setAbsolutePosition(x, y);
canvas.addImage(signatureImage);
}
log.info("成功在{}个页面位置添加签名图片", fieldPositions.size());
} else {
log.warn("未找到签名表单域:{}", SIGNATURE_FORM_FIELD);
}


// 添加当前日期
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
String currentDate = dateFormat.format(new Date());
if (currentDate != null && !currentDate.isEmpty()) {
form.setField("signDate", currentDate);
}

// 设置表单扁平化,但不启用完全压缩,可能有助于移动设备兼容性
stamper.setFormFlattening(true);

stamper.close();
reader.close();
return new File("temp_contract.pdf");
}

相关新闻

  • 雷达系统杂波设计与仿真
  • 国标GB28181视频平台EasyCVR一体化加油站安防视频监控方案与实践
  • JavaScript 沙箱

最新新闻

  • 2026年当下上海诚信的硼化锆源头厂家选型全指南 - 品牌鉴赏官2026
  • MC68HC908GP32 SPI通信深度解析:双缓冲机制与OVRF/MODF错误处理实战
  • AI写作辅助平台8款AI论文平台榜单,毕业护航利器!
  • 【微积分】三角函数求导积分公式的图形化记忆法
  • Dify插件集合:AI应用开发中的标准化组件库架构实践
  • Cesium 曲线漫游教程 | 3D Tiles·Cesium Entity三维可视化源码

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号