You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何将Adobe Illustrator贝塞尔坐标导入Processing的bezier()函数?

我之前做过类似的字体动画项目,刚好踩过这些坑,给你梳理几个靠谱的解决方案:

解决方案:从AI导出贝塞尔曲线数据到Processing实现动画

一、先搞定AI端的完整贝塞尔数据导出

Adobe Point Exporter确实只能导出锚点坐标,漏掉了关键的曲线控制点信息,咱们可以用AI的内置JavaScript脚本来导出完整数据,步骤如下:

  • 打开你的AI字体文件,选择文件 > 脚本 > 其他脚本,新建一个.jsx文件,粘贴下面的代码:
// AI脚本:导出路径的贝塞尔锚点及控制点数据
var doc = app.activeDocument;
var output = [];

for (var i = 0; i < doc.pathItems.length; i++) {
  var path = doc.pathItems[i];
  var pathData = {
    name: path.name,
    points: []
  };
  
  for (var j = 0; j < path.pathPoints.length; j++) {
    var pt = path.pathPoints[j];
    pathData.points.push({
      anchor: {x: pt.anchor[0], y: pt.anchor[1]},
      leftDir: {x: pt.leftDirection[0], y: pt.leftDirection[1]},
      rightDir: {x: pt.rightDirection[0], y: pt.rightDirection[1]},
      isSmooth: pt.smooth
    });
  }
  output.push(pathData);
}

// 将数据导出为JSON文件
var saveFile = File.saveDialog("保存贝塞尔数据", "JSON files (*.json)");
if (saveFile) {
  var writer = new File(saveFile);
  writer.open("w");
  writer.write(JSON.stringify(output));
  writer.close();
  alert("数据导出成功!");
}
  • 运行脚本后,会生成一个包含所有锚点、左右控制点的JSON文件,完美满足Processing的需求。

二、Processing中解析数据并使用bezier()绘制

拿到JSON文件后,咱们可以用Processing的JSONObject来读取数据,然后把AI的路径转换成bezier()需要的四段式坐标(起点、控制点1、控制点2、终点)。注意AI的y轴是向上的,Processing是向下的,记得做坐标翻转:

import processing.data.*;

JSONObject fontData;
ArrayList<BezierSegment> segments;

void setup() {
  size(800, 600);
  fontData = loadJSONObject("font_data.json");
  segments = new ArrayList<BezierSegment>();
  
  // 解析JSON中的路径点,转换为bezier段
  JSONArray paths = fontData.getJSONArray("output");
  for (int i = 0; i < paths.size(); i++) {
    JSONObject path = paths.getJSONObject(i);
    JSONArray points = path.getJSONArray("points");
    
    for (int j = 0; j < points.size() - 1; j++) {
      JSONObject currPt = points.getJSONObject(j);
      JSONObject nextPt = points.getJSONObject(j+1);
      
      // AI坐标转Processing坐标(翻转y轴)
      float startX = currPt.getJSONObject("anchor").getFloat("x");
      float startY = height - currPt.getJSONObject("anchor").getFloat("y");
      float ctrl1X = currPt.getJSONObject("rightDir").getFloat("x");
      float ctrl1Y = height - currPt.getJSONObject("rightDir").getFloat("y");
      float ctrl2X = nextPt.getJSONObject("leftDir").getFloat("x");
      float ctrl2Y = height - nextPt.getJSONObject("leftDir").getFloat("y");
      float endX = nextPt.getJSONObject("anchor").getFloat("x");
      float endY = height - nextPt.getJSONObject("anchor").getFloat("y");
      
      segments.add(new BezierSegment(startX, startY, ctrl1X, ctrl1Y, ctrl2X, ctrl2Y, endX, endY));
    }
  }
}

void draw() {
  background(255);
  stroke(0);
  noFill();
  
  // 遍历所有bezier段,绘制并做动画处理(这里示例是控制点偏移)
  for (BezierSegment seg : segments) {
    // 给控制点加个简单的正弦动画
    float animOffset = sin(frameCount * 0.02) * 10;
    bezier(seg.startX, seg.startY, 
           seg.ctrl1X + animOffset, seg.ctrl1Y + animOffset, 
           seg.ctrl2X - animOffset, seg.ctrl2Y - animOffset, 
           seg.endX, seg.endY);
  }
}

// 自定义类存储bezier段数据
class BezierSegment {
  float startX, startY;
  float ctrl1X, ctrl1Y;
  float ctrl2X, ctrl2Y;
  float endX, endY;
  
  BezierSegment(float sx, float sy, float c1x, float c1y, float c2x, float c2y, float ex, float ey) {
    startX = sx; startY = sy;
    ctrl1X = c1x; ctrl1Y = c1y;
    ctrl2X = c2x; ctrl2Y = c2y;
    endX = ex; endY = ey;
  }
}

三、用Geomerative库简化流程

如果你想用Geomerative,其实不需要手动导出坐标——直接把AI的字体路径导出为SVG格式(AI中选文件 > 导出 > SVG,注意选择SVG 1.1,不要勾选“压缩”),然后用Geomerative加载并获取贝塞尔数据:

import geomerative.*;

RShape shape;

void setup() {
  size(800, 600);
  RG.init(this);
  
  // 加载SVG文件(确保SVG和Processing sketch在同一文件夹)
  shape = RG.loadShape("font_path.svg");
  
  // 关闭自动绘制,方便手动操作每个贝塞尔段
  RG.setPolygonizer(RG.UNIFORM);
}

void draw() {
  background(255);
  stroke(0);
  noFill();
  
  // 遍历每个路径的贝塞尔段
  for (int i = 0; i < shape.countPaths(); i++) {
    RPath path = shape.getPath(i);
    for (int j = 0; j < path.countSegments(); j++) {
      RSegment seg = path.getSegment(j);
      if (seg.isBezier()) {
        RBezier bez = seg.toBezier();
        
        // 获取四个控制点,同样做坐标翻转
        float sx = bez.point1.x;
        float sy = height - bez.point1.y;
        float c1x = bez.point2.x;
        float c1y = height - bez.point2.y;
        float c2x = bez.point3.x;
        float c2y = height - bez.point3.y;
        float ex = bez.point4.x;
        float ey = height - bez.point4.y;
        
        // 动画处理示例:随机偏移锚点
        float anim = sin(frameCount * 0.01 + j) * 5;
        bezier(sx + anim, sy + anim, c1x, c1y, c2x, c2y, ex - anim, ey - anim);
      }
    }
  }
}

这个方法更省心,Geomerative会帮你解析SVG里的所有贝塞尔信息,你只需要专注于动画逻辑就行。

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

火山引擎 最新活动