May 12, 2024

ExportX Figma插件使用说明[中文]


快速开始

我们的插件支持 「设计模式」和「Dev模式」, 查看下面视频,快速了解插件使用方式~

导出格式支持与压缩率

我们支持同时压缩多种格式和倍率的图片,但是规则限制在5条以内,图片格式支持:

格式支持节省空间
AVIF≈92%
WEBP≈88%
JPG≈85%
PNG≈68%
SVG≈8%
ico🚧 开发中-
💡

压缩效果根据统计得出,实际效果可能有所不同,此表格将持续更新。

历史记录

插件压缩的图片我们会在您的电脑上永久的存储起来,直到您清空缓存或者清除历史纪录。

受限于客户端存储限制,我们仅保存15条历史纪录。

免费图床服务

ExportX为您提供了能够快速上传的免费图床,服务建立在Cloudflare的免费CDN上,我们保证不删除您的图片。方便您0配置即可获得上传体验。

打开插件右上角的开关,即可使用我们的免费图床服务。

此时,点击”ExportX”按钮,一键完成压缩、上传操作。在历史记录中,点击复制按钮,即可获得图片链接。

使用我们的免费图床需要遵守我们的相关协议。

当然,我们更推荐您使用自定义上传服务。

自定义上传服务

如果您有自己的对象存储服务,您可以通过替换成自己的上传接口。 首先,点击左上角的[设置],在上传设置中,选择”自定义”方式。

ImageImage

上传接口规范

开启自定义上传后,图片会通过POST请求上传到您的接口。接口需要遵守以下规范:

Request内容

Header: 您可以通过自定义header来传递token等信息。

Content-Type: multipart/form-data;

Body: 插件通过form-data的方式上传文件,下面的参数是插件提供的,同时,您可以通过自定义Body来传递额外的信息。

参数名类型说明
fileFile二进制文件
fileNameString文件名,如image92.avif
formatString图片格式,如png
figmaNameStringFigma用户名,用户可以在Figma中修改,不是唯一的,但具有可读性。
figmaIdStringFigma用户ID ,19位的数字,参考Figma User
xidString组合字段,格式为figmaName@figmaId

Response内容

您需要给插件返回一个json对象,包含图片的url,url用于复制到剪贴板,如果没有返回url,复制按钮将不可用。

{
  "url": "https://dev.cdn.abfree.com/images/6FjJoXmt34ox0Fu1.png"
}

Cloudflare R2+Worker

示例代码,此处使用hono来演示

import { Hono } from "hono";

type Bindings = {
  MY_BUCKET: R2Bucket;
  CDN_URL: string;
};

const app = new Hono<{
  Bindings: Bindings;
}>();

app.post("/upload", async (c) => {
  const key = genFileKey();
  const formData = await c.req.parseBody();
  const file = formData["file"];

  if (file instanceof File) {
    const fileBuffer = await file.arrayBuffer();
    const fullName = file.name;
    const ext = fullName.split(".").pop();
    const path = `images/${key}.${ext}`;

    let contentType = file.type;

    if (contentType === "image/svg") {
      contentType = "image/svg+xml";
    }

    console.log(file.type);
    await c.env.MY_BUCKET.put(path, fileBuffer, {
      httpMetadata: {
        contentType: contentType,
        contentDisposition: `inline`,
      },
    });
    return c.json({
      url: `${c.env.CDN_URL}/${path}`,
    });
  } else {
    return c.text("Invalid file", 400);
  }
});

Amazon S3 或兼容S3

大多数对象存储都兼容S3协议,比如

  • AWS S3
  • Cloudflare R2
  • Google Cloud Storage
  • 阿里云OSS
  • 腾讯云COS

示例代码

// api.ts
import { Hono } from "hono";
import { uploadToS3 } from "./s3";

type Bindings = {
  CDN_URL: string;
};

const app = new Hono<{
  Bindings: Bindings;
}>();

app.post("/uploadS3", async (c) => {
  const key = genFileKey();
  const formData = await c.req.parseBody();
  const file = formData["file"];
  if (file instanceof File) {
    const fileBuffer = await file.arrayBuffer();
    const fullName = file.name;
    const ext = fullName.split(".").pop();
    const path = `images/${key}.${ext}`;
    let contentType = file.type;
    if (contentType === "image/svg") {
      contentType = "image/svg+xml";
    }
    const uint8Array = new Uint8Array(fileBuffer);
    await uploadToS3(c, {
      file: uint8Array,
      contentType,
      key: key,
    });
    return c.json({
      url: `${c.env.CDN_URL}/${path}`,
    });
  } else {
    return c.text("Invalid file", 400);
  }
});
// s3.ts
import { S3 } from "@aws-sdk/client-s3";
import { Context } from "hono";

let s3Client: S3;
interface UploadParams {
  file: Uint8Array;
  contentType: string;
  key: string;
}
export async function uploadToS3(c: Context, params: UploadParams) {
  const client = getClient(c);
  await client.putObject({
    Body: params.file,
    Bucket: c.env.S3_BUCKET,
    Key: params.key,
    ContentType: params.contentType,
  });
}
function getClient(c: Context) {
  if (s3Client) return s3Client;
  const { S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, S3_REGION } =
    c.env;
  s3Client = new S3({
    credentials: {
      accessKeyId: S3_ACCESS_KEY_ID,
      secretAccessKey: S3_SECRET_ACCESS_KEY,
    },
    endpoint: S3_ENDPOINT,
    region: S3_REGION,
  });
  return s3Client;
}

QA

上传是如何发起的

为了保护您图片的隐私性,上传行为是由前端发起,因此您可能需要处理跨域问题。

如何避免服务不被滥用

一般情况下,您填入的上传服务接口是公网可访问的,如果接口泄露,这样可能会导致匿名访问甚至滥用。因此,我们建议您使用xid+secret白名单的方式来限制访问。

什么是xid?

xid是figmaId和figmaName的组合字段,格式为figmaName@figmaId。它包含在上传的body当中,您可以在接口中校验这个字段是否在白名单中。

  • figmaName,是Figma登录信息中用户的名字,用户可以在Figma中修改,不是唯一的,但具有可读性。
  • figmaId,19位的数字,是Figma登录信息中用户的唯一标识.

具体可以参阅[Figma User]

xid难以被伪造,已经足够安全,但是如果您需要更高的安全性,我们建议您增加一个secret字段。

什么是secret?

secret是您自己设置的密码,您可以自己生成并颁发给用户,用户在使用插件时需要在Body中填入这个密码。

💡

当然这只是一种建议,具体的安全策略需要根据您的实际情况来制定。

如何排查上传错误

如果您在浏览器中使用Figma,可以在开发者工具中查看Network或Console面板,查看上传的请求和返回。

如果您使用的Figma客户端,您可以按下面提示打开控制台获取错误信息。

如何获取我的xid

在插件首页,点击右上角的用户按钮,您可以看到您的xid。