You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React-PDF编辑器与签名后PDF的字段垂直错位问题(逐字段下移一个字段高度)

React-PDF编辑器与签名后PDF的字段垂直错位问题(逐字段下移一个字段高度)

一、编辑器内字段逐次下移的问题修复

从你描述的现象和代码来看,核心问题出在字段位置计算的依赖监听和坐标更新逻辑上,我帮你梳理两个关键修复点:

1. 修复useEffect的依赖监听错误

你的PlacedFieldComponent里的useEffect依赖了canvasRef.current,但useRefcurrent属性是可变引用,不会触发useEffect重新执行,导致字段位置计算不及时或错误。

修改步骤:

  • 在父组件PdfEditor中,监听PDF页面加载完成事件,获取并保存canvas的尺寸到state:
    // 在PdfEditor组件内添加
    const [canvasSize, setCanvasSize] = useState<{ width: number; height: number } | null>(null);
    
    useEffect(() => {
      const canvas = canvasRef.current;
      if (canvas) {
        setCanvasSize({ width: canvas.width, height: canvas.height });
      }
    }, [currentPage]); // 切换页面时重新获取尺寸
    
  • canvasSize作为props传递给PlacedFieldComponent,然后在子组件的useEffect中依赖canvasSize而非canvasRef.current
    // PlacedFieldComponent的useEffect修改
    useEffect(() => {
      if (!canvasSize) return;
      const dpr = window.devicePixelRatio || 1;
      const canvasWidth = canvasSize.width / dpr;
      const canvasHeight = canvasSize.height / dpr;
      const px = (field.position?.x ?? 0) * canvasWidth - FIELD_WIDTH / 2;
      const py = (field.virtualY ?? 0) * canvasHeight - FIELD_HEIGHT / 2;
      // 移除之前的条件判断,直接更新位置,避免累积偏移
      setPos({ x: px, y: py });
    }, [field.position, field.virtualY, field.page, canvasSize]);
    

2. 移除位置更新的条件判断

你之前的代码里,只有当位置差异大于1px时才更新pos,这会导致后续字段的位置无法正确重置到点击位置,累积偏移。直接移除这个条件,每次字段属性变化时强制更新位置即可。

二、签名后PDF字段错位的问题修复

这个问题的核心是PDF坐标系统和浏览器坐标系统的差异

  • 浏览器(react-pdf)的坐标原点在页面左上角,y轴向下递增
  • pdf-lib的坐标原点在页面左下角,y轴向上递增

你之前手动减40px是临时补丁,正确的做法是做坐标转换:

修复代码示例(pdf-lib绘制时的坐标转换)

async function embedFieldsToPdf(originalPdf: Uint8Array, placedFields: PlacedField[]) {
  const pdfDoc = await PDFDocument.load(originalPdf);
  const pages = pdfDoc.getPages();

  placedFields.forEach(field => {
    const targetPage = pages[field.page - 1]; // 注意:pdf-lib的页面索引从0开始
    const pageWidth = targetPage.getWidth();
    const pageHeight = targetPage.getHeight();

    // 转换编辑器的比例坐标到pdf-lib的实际坐标
    const editorXRatio = field.position?.x ?? 0;
    const editorYRatio = field.virtualY ?? 0;

    // X坐标:直接按比例转换(左右方向一致)
    const pdfX = editorXRatio * pageWidth - FIELD_WIDTH / 2;

    // Y坐标:关键转换,从浏览器的顶部基准转为pdf的底部基准
    const editorYFromTop = editorYRatio * pageHeight;
    const pdfY = pageHeight - editorYFromTop - FIELD_HEIGHT;

    // 示例:绘制文本字段和边框
    if (field.type === 'Text') {
      // 绘制边框
      targetPage.drawRectangle({
        x: pdfX,
        y: pdfY,
        width: FIELD_WIDTH,
        height: FIELD_HEIGHT,
        borderColor: rgb(0, 0, 1),
        borderWidth: 1,
      });
      // 绘制文本
      targetPage.drawText(field.value ?? '', {
        x: pdfX + 4,
        y: pdfY + 10,
        size: 12,
        color: rgb(0, 0, 0),
      });
    }
    // 其他字段类型(如签名图片)同理转换坐标
  });

  return await pdfDoc.save();
}

三、额外验证点

  1. 确保添加字段时的初始坐标计算正确:在PdfEditor的点击事件中,计算virtualY时直接用(e.clientY - rect.top) / rect.height,不要添加额外的偏移量。
  2. 检查所有字段是否使用absolute定位,且父容器设置了position: relative,避免定位基准错误。

按照这些步骤修复后,编辑器内的字段漂移和最终PDF的错位问题应该都能解决,不需要再依赖临时的40px调整啦。

火山引擎 最新活动