如何将PSD矢量路径转换为SVG路径数据?
PSD路径记录转SVG路径数据解决方案
一、RecordType与SVG路径命令映射
先过滤无关的RecordType(如6、8、7),仅处理核心路径记录:
- RecordType 0/3:仅标记后续贝塞尔点数量,转换时直接跳过,仅作计数参考
- RecordType 1/2/4/5:贝塞尔路径点,是转换核心,对应SVG路径命令规则如下:
- 闭合属性:
recordType为1/2时路径闭合,转换完成后需追加Z命令;4/5为开放路径,无需添加 - 关联属性(linked):
linked: true:当前点的前控制点与上一个点的后控制点对称关联(平滑贝塞尔点),对应SVG的S(平滑三次贝塞尔)命令linked: false:当前点为角点,前/后控制点独立,对应SVG的C(三次贝塞尔)命令
- 直线段判断:若前控制点与锚点坐标完全重合,说明是直线段,对应SVG的L(直线)命令
- 闭合属性:
二、坐标值转换
PSD解析出的坐标是相对文档尺寸的比例值(范围0~1),需转换为SVG可用的绝对坐标,同时修正坐标系差异:
- 获取PSD文档实际宽度
docWidth和高度docHeight - 坐标转换公式:
(PSD坐标系以左上角为原点,y轴向下;SVG以左上角为原点,y轴向上,因此需翻转y坐标)svgX = psdHoriz * docWidth svgY = docHeight - (psdVert * docHeight)
三、转换实现示例(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
相关产品推荐
相关产品推荐

