sketch文件转fabric.js画布模板json的实现原理

最近研究了下 sketch 转 fabric.js 画布模板 json

搞定是把文件传给接口进行解析, github 上能解析 sketch 的仓库有sketch-to-htmlsketch2json, 不过都有利弊

sketch-to-html

缺点

  • 仅支持在 node 环境下解析, 解析的数据是通过读取文件的形式获取. 而在浏览器环境中, 不支持执行 node 命令、创建文件和读取文件
js 复制代码
exec(`rm -rf output/*;unzip -o ${source} -d output;`, (err, stdout, stderr) => {
  // 复制图片到结果文件夹
  fse.copySync("./output/images", "./output/html/images");
  // 复制模板资源文件夹
  fse.copySync("./template/assets", "./output/html/assets");
  // 复制首页
  fse.copySync("./template/index.html", "./output/html/index.html");
  // 读取每个 page 的信息
  let files = fs.readdirSync("./output/pages");
  let fileStore = {};
  files.forEach((f) => {
    fileStore[f] = JSON.parse(fs.readFileSync("./output/pages/" + f).toString());
  });
});
  • 其中对文本元素处理上使用到了bplist-parser 二进制列表解析器。 该库也只支持在 node 环境中使用.
js 复制代码
const bplistParser = require("bplist-parser");
function parseArchive(base64String) {
  const buf2 = Buffer.from(base64String, "base64");
  const obj = bplistParser.parseBuffer(buf2);
  const parser = new NSArchiveParser();
  return parser.parse(obj);
}
  • 图片是通过 node 解析到单独文件夹中, 图片解析不了

优点

解析 sketch 文件的原始数据进行了处理

如 解析了元素的位置, 宽高, 路径, 类型等属性, 后面可以直接复用解析逻辑

js 复制代码
const handleItem = function (item) {
  let result = {};
  result.id = item.do_objectID;
  result.frame = item.frame || {};
  result.style = styleParser(item.style, item.attributedString, item);
  result.path = pathParser(item);
  result.isVisible = item.isVisible;
  let name = item.name ? item.name : "未命名";
  name = name
    .replace(/[\u4e00-\u9fa5]*/, function (m) {
      return pinyin(m, {
        style: "normal",
      });
    })
    .replace(/^([^a-z_A-Z])/, "_$1")
    .replace(/[^a-z_A-Z0-9-]/g, "_");
  result.name = rename(name);
  nameStore.push(result.name);
  result.type = item._class;
  if (item._class === "oval") {
    result.isCircle = util.isCircle(item);
    if (result.isCircle) {
      const p1 = util.toPoint(item.path.points[0].point, item);
      const p2 = util.toPoint(item.path.points[1].point, item);
      const p3 = util.toPoint(item.path.points[2].point, item);
      const p4 = util.toPoint(item.path.points[3].point, item);
      result.style.borderRadius = (p1.y - p3.y) / 2;
    }
  }
  result.isMask = !!item.hasClippingMask;
  if (item._class === "rectangle") {
    result.isRect = util.isRect(item);
  }
  if (item._class === "text") {
    result.text = result.style.text || item.name;
  }
  if (item._class === "bitmap") {
    result.image = item.image._ref + ".png";
  }
  if (item._class === "artboard") {
    result.frame.x = null;
    result.frame.y = null;
  }
  if (item.symbolID) {
    result.symbolID = item.symbolID;
  }
  return result;
};

sketch2json

缺点

  • 解析后的数据较原始, 和 psd.js 解析出来的数据比较像
  • 不能解析图片

优点

  • 支持在浏览器端进行解析
  • 处理逻辑较简单

原理分析

通过阅读以上两个库的源码, 发现都使用了 jszip 对 sketch 进行解压, 然后就直接获取到数据

为什么以上两个库不约而同的使用相同方法?

在 sketch 官方仓库里能得到解答

Sketch documents are stored as ZIP archives containing JSON encoded data. The file format was originally introduced in Sketch 43 and allows for better third-party integration. Generate Sketch documents dynamically, read or modify them without opening them in Sketch.

Sketch 以包含 JSON 编码数据的 ZIP 存档形式存储。该文件格式最初是在 Sketch 43 中引入的,它允许更好的第三方集成。动态生成 Sketch 文档,无需在 Sketch 中打开即可读取或修改它们。

所以直接解压后就能得到 json 编码数据

developer.sketch.com/file-format...

以上两个仓库都有官方文档的影子, 如果要解析市面上还没有支持的文件, 也可以去官网寻求思路

解析

综合以上两个仓库, 我们可以利用其中对优缺点进行开发

图片解析

首先需要改造 sketch2json 仓库, 使其支持图片解析

通过阅读源码可知, sketch2json 只解析 json 文件, 其他文件都会过滤掉

js 复制代码
const listOfJSONFiles = (zip) => List(Object.keys(zip.files).filter((path) => path.slice(-5) === ".json"));

单独区分 json, 非 json 数据进行 base64 转换

js 复制代码
async function getFileFromZip(zip, path) {
  if (path.indexOf("json") != -1) {
    return new Promise((resolve, reject) =>
      zip
        .file(path)
        .async("string")
        .then(function (content) {
          resolve([path, JSON.parse(content)]);
        })
        .catch(function (error) {
          reject(error);
        })
    );
  } else {
    return new Promise((resolve, reject) =>
      zip
        .file(path)
        .async("arraybuffer")
        .then(function (res) {
          try {
            var binary = "";
            var bytes = new Uint8Array(res);
            let ext = "";
            // 找出签名列表中定义好的类型,并返回
            for (let i = 0, len = signatureList.length; i < len; i++) {
              if (check(bytes, signatureList[i])) {
                ext = signatureList[i];
              }
            }
            var len = bytes.byteLength;
            for (var i = 0; i < len; i++) {
              binary += String.fromCharCode(bytes[i]);
            }
            const base64 = "data:" + ext.mime + ";base64," + window.btoa(binary);
            resolve([path, base64]);
          } catch (e) {
            reject(e);
          }
        })
        .catch(function (error) {
          reject(error);
        })
    );
  }
}

数据转换

通过以上方法可以获取到 sketch 转 json 的原始数据, 然后利用 sketch-to-html 相关逻辑来解析字段

以下 layer 字段代表当前图层元素

形状元素圆角

js 复制代码
const radius = layer.fixedRadius;

水平翻转

js 复制代码
if (layer.isFlippedHorizontal) {
  const flipX = layer.isFlippedHorizontal;
}

垂直翻转

js 复制代码
if (layer.isFlippedVertical) {
  const flipX = layer.isFlippedVertical;
}

旋转

js 复制代码
const angle = layer.rotation;

透明度

js 复制代码
const opacity = layer.style.contextSettings.opacity;

边框

js 复制代码
if (layer.style.borders) {
  layer.style.borders.forEach((_border) => {
    if (_border.isEnabled) {
      if (layer._class == "text") {
        result.strokeWidth = _border.thickness;
        result.fill = colorParser(_border.color);
      } else {
        result.fill = colorParser(_border.color);
        result.strokeWidth = _border.thickness;
      }
    }
  });
}

具体参数详解可以通过 github 查看, 转化为 fabric 支持画布渲染的 json 格式和上一篇文章差不多, 可以了解一下

psd文件转fabric.js画布模板json的实现原理

使用

为了方便大家使用,所以通过发布到npm上大家可以直接下载安装

js 复制代码
npm i -S sketchtojson

import toJson from 'sketchtojson';
async function parse(file){
  const result = await toJson(file);
  console.log(result)
}

tojson.js仓库

github.com/haixin-fang...

支持psd、sketch转json

简介

vue-design-editor 是仿搞定设计的一款开源图片编辑器, 支持多种格式的导入,包括png、jpg、gif、mp4, 也可以一键psd转模板(后续开发)

github地址 预览

上个开源库是 starfish-vue3-lowcode

github地址 预览

相关推荐
M ? A3 分钟前
Vue 迁移 React 实战:VuReact 一键自动化转换方案
前端·vue.js·经验分享·react.js·开源·自动化·vureact
yuki_uix4 分钟前
重排、重绘与合成——浏览器渲染性能的底层逻辑
前端·javascript·面试
止观止30 分钟前
拥抱 ESNext:从 TC39 提案到生产环境中的现代 JS
开发语言·javascript·ecmascript·esnext
沃尔威武33 分钟前
调试黑科技:Chrome DevTools时间旅行调试实战
前端·科技·chrome devtools
yuki_uix41 分钟前
虚拟 DOM 与 Diff 算法——React 性能优化的底层逻辑
前端·react.js·面试
时寒的笔记41 分钟前
js逆向7_案例惠nong网
android·开发语言·javascript
yuki_uix42 分钟前
从输入 URL 到页面显示——浏览器工作原理全解析
前端·面试
果汁华1 小时前
GitHub Trending 热门仓库整理 (2026年4月10日)
github
weixin_408099671 小时前
【完整教程】天诺脚本如何调用 OCR 文字识别 API?自动识别屏幕文字实战(附代码)
前端·人工智能·后端·ocr·api·天诺脚本·自动识别文字脚本
吴声子夜歌1 小时前
ES6——Generator函数详解
前端·javascript·es6