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

如何编程修改PSD文件的文本与图片并导出生成自定义图片?

psd.js本身仅提供PSD文件的只读解析能力,不支持修改图层后重新编码PSD文件,因此无法直接通过修改psd.js解析出的图层对象生成新的图片,以下是3种可落地的实现方案:

方案1:前端侧基于Canvas重绘实现(轻量、无服务端依赖)

适合中小流量、模板样式相对简单的场景,不需要额外部署服务端资源:

  • 用psd.js解析PSD文件后,先提取所有图层的层级顺序、位置、尺寸、透明度、混合模式属性,将所有非文本图层单独导出为图片资源
  • 提取所有目标文本图层的字体、字号、颜色、字重、行高、对齐方式、坐标位置属性,将文本内容开放为用户可编辑项
  • 在React项目中引入Canvas API(可使用fabric.js等封装库降低开发成本),按照PSD的图层从下到上的顺序,先绘制所有非文本图层的图片,再根据当前用户输入的文本内容绘制文本图层
  • 最终导出图片直接调用Canvas的toDataURL()或toBlob()方法即可生成PNG/JPG格式的文件

注意:需要提前在前端项目中预加载PSD用到的所有字体,避免绘制文本时字体降级导致样式和原PSD不一致

核心代码示例(基于fabric.js):

import { useRef, useEffect, useState } from 'react';
import { fabric } from 'fabric';
import PSD from 'psd';

const PsdEditor = () => {
  const canvasRef = useRef(null);
  const [textLayers, setTextLayers] = useState([]);
  const [fabricCanvas, setFabricCanvas] = useState(null);

  useEffect(() => {
    // 初始化画布
    const canvas = new fabric.Canvas(canvasRef.current);
    setFabricCanvas(canvas);

    // 解析PSD文件
    PSD.fromURL('/template.psd').then(psd => {
      canvas.setWidth(psd.width);
      canvas.setHeight(psd.height);
      const tempTextLayers = [];

      // 倒序遍历图层(psd.layers返回的是从上到下的顺序,绘制需要从下到上)
      [...psd.layers].reverse().forEach(layer => {
        if (!layer.text) {
          // 绘制非文本图层
          const imgUrl = layer.toPng().src;
          fabric.Image.fromURL(imgUrl, img => {
            img.set({
              left: layer.left,
              top: layer.top,
              selectable: false,
              opacity: layer.opacity / 255
            });
            canvas.add(img);
          });
        } else {
          // 存储文本图层信息
          tempTextLayers.push({
            id: layer.id,
            originText: layer.text.value,
            left: layer.left,
            top: layer.top,
            fill: `rgb(${layer.text.font.color.join(',')})`,
            fontSize: layer.text.font.sizes[0],
            fontFamily: layer.text.font.name,
            lineHeight: layer.text.leading / layer.text.font.sizes[0],
            selectable: true
          });
        }
      });
      setTextLayers(tempTextLayers);
    });
  }, []);

  // 用户修改文本后更新画布
  const updateText = (layerId, newText) => {
    const targetLayer = textLayers.find(item => item.id === layerId);
    // 先删除旧的文本对象
    const oldText = fabricCanvas.getObjects().find(obj => obj.layerId === layerId);
    if (oldText) fabricCanvas.remove(oldText);
    // 添加新的文本对象
    const newTextObj = new fabric.Text(newText, {
      ...targetLayer,
      layerId: layerId
    });
    fabricCanvas.add(newTextObj);
    fabricCanvas.renderAll();
  };

  // 导出图片
  const exportImage = () => {
    const dataUrl = fabricCanvas.toDataURL({ format: 'png' });
    const link = document.createElement('a');
    link.href = dataUrl;
    link.download = 'custom-image.png';
    link.click();
  };

  return <div>
    <canvas ref={canvasRef} />
    {/* 文本编辑区域可根据textLayers渲染输入框 */}
    <button onClick={exportImage}>导出图片</button>
  </div>
};
方案2:前后端结合实现(样式还原度最高)

如果PSD模板包含渐变文字、图层特效、复杂混合模式等前端Canvas难以1:1还原的效果,可采用服务端处理方案:

  • 前端仅负责收集用户输入的自定义文本和对应图层的唯一标识,将参数传给服务端接口
  • 服务端使用psd-tools(Python)、GraphicsMagick配合PSD扩展,或是直接调用Photoshop官方脚本API修改PSD源文件的对应文本图层,修改完成后直接导出图片返回给前端
  • 该方案完全复用PSD的原始渲染能力,样式还原度100%,不需要处理前端字体加载、特效适配等兼容问题,适合商业级高要求的生成场景
方案3:替换为SVG模板(长期维护成本最低)

如果设计师可以配合调整输出格式,可直接将PSD模板导出为SVG格式:

  • SVG中的文本本身就是可编辑的DOM节点,不需要额外的解析库即可直接在React中修改文本内容
  • 修改完成后可直接将整个SVG转为Blob导出为图片,适配所有端的显示效果,加载速度远高于PSD模板,也不需要处理图层绘制的逻辑
  • 适合模板迭代频率高、需要支持多端适配的场景

内容的提问来源于stack exchange,提问作者Imad Ben Abdeslam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 10:06:04