From 86103e4c4daed84c4d9daf2e051150e06462f3cc Mon Sep 17 00:00:00 2001 From: hailin Date: Fri, 26 Dec 2025 05:35:58 -0800 Subject: [PATCH] =?UTF-8?q?fix(planting-service):=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E5=A4=96=E8=A7=82=E6=B5=81=E5=B5=8C?= =?UTF-8?q?=E5=85=A5=E7=AD=BE=E5=90=8D=E5=9B=BE=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - setImage 无法正确渲染签名到按钮字段 - 手动创建 XObject Form 外观流 - 计算图片缩放和居中位置 - 设置 widget 的 NormalAppearance 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../pdf/pdf-generator.service.ts | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/backend/services/planting-service/src/infrastructure/pdf/pdf-generator.service.ts b/backend/services/planting-service/src/infrastructure/pdf/pdf-generator.service.ts index f452e1bd..9a30f15c 100644 --- a/backend/services/planting-service/src/infrastructure/pdf/pdf-generator.service.ts +++ b/backend/services/planting-service/src/infrastructure/pdf/pdf-generator.service.ts @@ -381,11 +381,55 @@ export class PdfGeneratorService { try { const form = pdfDoc.getForm(); const signatureButton = form.getButton(FORM_FIELDS.SIGNATURE); - signatureButton.setImage(signatureImage); - this.logger.log('Signature embedded using form field'); - } catch { + + // 获取按钮的 widget 和尺寸 + const widgets = signatureButton.acroField.getWidgets(); + if (widgets.length > 0) { + const widget = widgets[0]; + const rect = widget.getRectangle(); + const { width: fieldWidth, height: fieldHeight } = rect; + + // 计算图片缩放尺寸(保持宽高比,适应字段大小) + const imgDims = signatureImage.scale(1); + let scale = Math.min(fieldWidth / imgDims.width, fieldHeight / imgDims.height); + const scaledWidth = imgDims.width * scale; + const scaledHeight = imgDims.height * scale; + + // 计算居中位置 + const x = (fieldWidth - scaledWidth) / 2; + const y = (fieldHeight - scaledHeight) / 2; + + // 创建外观流内容 + const appearanceStream = `q ${scaledWidth} 0 0 ${scaledHeight} ${x} ${y} cm /Img Do Q`; + + // 创建 XObject Form 作为外观 + const context = pdfDoc.context; + const imageXObjectName = 'Img'; + + const Resources = context.obj({ + XObject: { [imageXObjectName]: signatureImage.ref }, + }); + + const appearanceStreamRef = context.register( + context.stream(appearanceStream, { + Type: 'XObject', + Subtype: 'Form', + FormType: 1, + BBox: [0, 0, fieldWidth, fieldHeight], + Resources, + }), + ); + + // 设置外观到 widget + widget.setNormalAppearance(appearanceStreamRef); + + this.logger.log('Signature embedded using custom appearance stream'); + } else { + throw new Error('No widgets found for signature button'); + } + } catch (error) { // 如果没有签名按钮字段,回退到坐标方式 - this.logger.log('Signature button field not found, using coordinates'); + this.logger.log(`Signature button field error: ${error.message}, using coordinates`); this.embedSignatureByCoordinates(pdfDoc, signatureImage); } }