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

如何将PSD矢量路径转换为SVG路径数据?

PSD路径记录转SVG路径数据解决方案

一、RecordType与SVG路径命令映射

先过滤无关的RecordType(如6、8、7),仅处理核心路径记录:

  • RecordType 0/3:仅标记后续贝塞尔点数量,转换时直接跳过,仅作计数参考
  • RecordType 1/2/4/5:贝塞尔路径点,是转换核心,对应SVG路径命令规则如下:
    1. 闭合属性:recordType为1/2时路径闭合,转换完成后需追加Z命令;4/5为开放路径,无需添加
    2. 关联属性(linked):
      • linked: true:当前点的前控制点与上一个点的后控制点对称关联(平滑贝塞尔点),对应SVG的S(平滑三次贝塞尔)命令
      • linked: false:当前点为角点,前/后控制点独立,对应SVG的C(三次贝塞尔)命令
    3. 直线段判断:若前控制点与锚点坐标完全重合,说明是直线段,对应SVG的L(直线)命令

二、坐标值转换

PSD解析出的坐标是相对文档尺寸的比例值(范围0~1),需转换为SVG可用的绝对坐标,同时修正坐标系差异:

  1. 获取PSD文档实际宽度docWidth和高度docHeight
  2. 坐标转换公式:
    svgX = psdHoriz * docWidth
    svgY = docHeight - (psdVert * docHeight)
    
    (PSD坐标系以左上角为原点,y轴向下;SVG以左上角为原点,y轴向上,因此需翻转y坐标)

三、转换实现示例(JavaScript)

function convertPsdPathsToSvg(psdPathRecords, docWidth, docHeight) {
  const svgPathParts = [];
  let prevAnchor = null;
  let prevLeaving = null;

  // 过滤出贝塞尔点记录
  const bezierPoints = psdPathRecords.filter(record => [1,2,4,5].includes(record.recordType));

  if (bezierPoints.length === 0) return '';

  // 第一个点:移动到锚点
  const firstPoint = bezierPoints[0];
  const firstAnchorX = firstPoint.anchor.horiz * docWidth;
  const firstAnchorY = docHeight - (firstPoint.anchor.vert * docHeight);
  svgPathParts.push(`M ${firstAnchorX} ${firstAnchorY}`);
  prevAnchor = {x: firstAnchorX, y: firstAnchorY};

  // 处理后续点
  for (let i = 1; i < bezierPoints.length; i++) {
    const point = bezierPoints[i];
    const currPrecedingX = point.preceding.horiz * docWidth;
    const currPrecedingY = docHeight - (point.preceding.vert * docHeight);
    const currAnchorX = point.anchor.horiz * docWidth;
    const currAnchorY = docHeight - (point.anchor.vert * docHeight);
    const currLeavingX = point.leaving.horiz * docWidth;
    const currLeavingY = docHeight - (point.leaving.vert * docHeight);

    // 判断是否为直线段(前控制点与锚点重合)
    const isLine = Math.abs(currPrecedingX - currAnchorX) < 0.001 && Math.abs(currPrecedingY - currAnchorY) < 0.001;

    if (isLine) {
      svgPathParts.push(`L ${currAnchorX} ${currAnchorY}`);
    } else if (point.linked) {
      // 平滑贝塞尔:用上一个点的后控制点镜像出当前前控制点
      const mirroredPrecedingX = 2 * prevAnchor.x - prevLeaving.x;
      const mirroredPrecedingY = 2 * prevAnchor.y - prevLeaving.y;
      svgPathParts.push(`S ${mirroredPrecedingX} ${mirroredPrecedingY} ${currAnchorX} ${currAnchorY}`);
    } else {
      // 普通三次贝塞尔
      svgPathParts.push(`C ${currPrecedingX} ${currPrecedingY} ${currLeavingX} ${currLeavingY} ${currAnchorX} ${currAnchorY}`);
    }

    prevAnchor = {x: currAnchorX, y: currAnchorY};
    prevLeaving = {x: currLeavingX, y: currLeavingY};
  }

  // 闭合路径
  const isClosed = [1,2].includes(bezierPoints[0].recordType);
  if (isClosed) {
    svgPathParts.push('Z');
  }

  return svgPathParts.join(' ');
}

四、注意事项

  • 非贝塞尔点记录(如RecordType 6、8、7)是PSD元数据,不影响SVG路径形状,转换时直接忽略
  • 坐标转换必须使用PSD文档的实际像素尺寸,比例值乘以对应尺寸才能得到正确的绝对坐标
  • 浮点运算可能存在精度误差,可通过toFixed(2)等方法保留合适的小数位数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:37:06