841-biborokuWebフロントエンドの備忘録

角丸&エフェクトを簡単解除!Figmaエクスポート作業を快適にするプラグインを作ってみた

PureImage Export

作成したプラグインは下記のURLをご覧ください。

https://www.figma.com/community/plugin/1479843311486845733/pureimage-export

選択したレイヤーの角丸やエフェクトを解除することなく、プラグインを使用することで、それらを一時的に無効化した状態でエクスポート・保存できます。

また、複数のレイヤーを選択した場合は、ZIPファイルとしてまとめてダウンロードすることが可能です。

おすすめの方

  • FigmaからWebコーディング用に最適化された画像をエクスポートしたい方
  • Figmaから簡単に画像を取り込みたいWebデザイナーやフロントエンド開発者

PureImage Export の特徴

  • 🧹 角丸&エフェクトの解除
  • 🔍 プレビュー表示
  • 📁 複数レイヤーの一括ダウンロード

使い方

  1. 角丸やエフェクトが適用されたレイヤーを選択する。
  2. エクスポートの設定を行う(デフォルト設定のままでもOK)。
  3. PureImage Export を実行する。
  4. レイヤー1つ選択の場合、プレビューが表示される。
  5. 角丸やエフェクトを設定し、[Export as xxx] をクリック。
  6. 保存する。

なぜプラグインを作ろうと思ったか

画像を書き出すときの手間

Webサイトのデザインルールとして角丸が適用されている場合、ほとんどの写真や画像に角丸が適用された状態のFigmaデータになっています。

コーディングする際、書き出すたびに角丸を外したり、ページごとに複製してまとめて角丸を解除して書き出したり……。毎回手動で角丸やエフェクトを外さなければならないのが面倒でした。

他にいい方法はないのか🤔?

先日、選択したレイヤーやグループ内のネストされたレイヤーすべての角丸をリセットできる「Reset Corner Radius」を作成しました。

「角丸がリセットできるなら、角丸やエフェクトも解除できるのでは?」「さらに、デザインの設定を変えずにエクスポートだけできるのでは?」と思い、今回のプラグインを作成するに至りました。

📝コーディングで地味につらい...Figmaで画像・レイヤーの角丸を一括で解除するプラグインを作ってみた

画像・エクスポート関連のプラグインを調査

Figmaで使用できる画像・エクスポート関連のプラグインにはどのようなものがあるか調査しました。

WebP Exporter

選択したレイヤー画像の品質、スケール、ファイル名などまとめて設定できるWebpプラグインです。
"Exporting many freeze the UI. Try selecting fewer or smaller nodes."

ノード数が多いとUIがフリーズするため、少なくするよう警告が表示されており、適切に対策が取られているプラグインだと感じました。

Export Original Images

選択した画像をトリミングせずに元のサイズのままエクスポートできます。

Free Compressed PDF and Image Exporter

圧縮された画像やPDFを書き出すことができます。

Figma to HTML

ReactまたはHTML形式のファイルやCSS、画像をエクスポートできます。画像に角丸が設定されている場合は、角丸が解除された状態の画像が含まれます。

他のエクスポート系プラグインを試した結果

圧縮やフォーマット変更など、画像のエクスポート設定を調整できるプラグインは多数ありましたが、角丸やエフェクトを解除してエクスポートできるプラグインは見つけられませんでした。

※あるかもしれませんが、少なくとも自分の調査では見つかりませんでした。

使用したライブラリ・フレームワーク

  • @create-figma-plugin/ui, @create-figma-plugin/utilities (Figmaプラグイン開発用)
  • preact (軽量なUIライブラリ)
  • jszip (ZIP圧縮処理)
  • encoding-japanese (文字エンコーディング変換)

実行フロー

開発で取り組んだ最適化

Figmaプラグインを開発する中で直面した課題と、それをどう解決したかの備忘録として、以下の4つのポイントについてまとめました。

  1. レイヤーの幅・高さ制限を設けている
  2. 角丸とエフェクトを解除してリストアできるようにしている
  3. 文字化けしないように処理
  4. エクスポート処理を軽くするためチャンク処理をしている

1. レイヤーが大きすぎるとフリーズする問題の対策

Figmaでは、大きなサイズのレイヤーをエクスポートしようとすると処理が遅くなり、最悪の場合フリーズしてしまうことがあります。そのため、プラグインではエクスポートサイズの制限を設けました。

const MAX_EXPORT_SIZE = 5000;

function isExportSizeValid(node: BaseNode): boolean {
  const figmaNode = node as FrameNode | RectangleNode;
  const { width, height } = figmaNode;
  let scale = figmaNode.exportSettings[0]?.constraint?.value || 1;
  let exportWidth = width * scale;
  let exportHeight = height * scale;

  return exportWidth <= MAX_EXPORT_SIZE && exportHeight <= MAX_EXPORT_SIZE;
}

エクスポート時にこの関数を使用し、制限を超える場合は警告を出すようにしました。

2. 角丸とエフェクトを解除・リストアする処理

エクスポート時にエフェクトや角丸が影響を及ぼし、期待通りの出力にならないことがありました。そのため、一時的にこれらのスタイルを解除し、エクスポート後に元に戻す処理を実装しました。

function storeAndRemoveEffectsAndRadius(
  node: BaseNode,
  effects: boolean,
  radius: boolean
): { effects?: ReadonlyArray<Effect>; cornerRadius?: number[] } {
  const originalState: { effects?: ReadonlyArray<Effect>; cornerRadius?: number[] } = {};

  if (effects && "effects" in node) {
    originalState.effects = node.effects;
    node.effects = [];
  }

  if (radius && "topLeftRadius" in node) {
    originalState.cornerRadius = [
      node.topLeftRadius,
      node.topRightRadius,
      node.bottomLeftRadius,
      node.bottomRightRadius,
    ];
    node.topLeftRadius = 0;
    node.topRightRadius = 0;
    node.bottomLeftRadius = 0;
    node.bottomRightRadius = 0;
  }

  return originalState;
}

function restoreEffectsAndRadius(
  node: BaseNode,
  originalState: { effects?: ReadonlyArray<Effect>; cornerRadius?: number[] }
): void {
  if (originalState.cornerRadius) {
    Object.assign(node, {
      topLeftRadius: originalState.cornerRadius[0],
      topRightRadius: originalState.cornerRadius[1],
      bottomLeftRadius: originalState.cornerRadius[2],
      bottomRightRadius: originalState.cornerRadius[3],
    });
  }
  if (originalState.effects && "effects" in node) {
    node.effects = originalState.effects;
  }
}

このように、処理の前後でエフェクトと角丸を適切にリストアできるようにしました。

3. 文字化け防止のためのZIPファイル名エンコード処理

ZIPファイル内に格納するファイル名のエンコーディング処理を行うことで、解凍時の文字化けを防いでいます。特に、日本語などの特殊文字が含まれる場合、以下のようにSJIS(Shift-JIS)エンコーディングを使用することで、Windows環境での互換性を保ちます。

const blob = await zip.generateAsync({
  type: "blob",
  encodeFileName: (name) =>
    Encoding.codeToString(
      Encoding.convert(name, {
        to: "SJIS",
        from: "UNICODE",
        type: "array",
      })
    ),
});

function sanitizeFileName(name: string): string {
  return name.replace(/[^a-zA-Z0-9-_\.]/g, "_");
}

この関数を使って、エクスポート時にファイル名を安全な形式に変換しています。

4. エクスポート処理の軽量化(チャンク処理)

大量のファイルを一度にエクスポートしようとすると、処理が重くなり、ユーザーの操作が遅延してしまう可能性があります。そのため、エクスポートをチャンク処理で分割し、処理の負担を軽減しています。

const chunkSize = 10; // 一度に処理するファイル数

const addFilesInChunks = async (startIndex = 0): Promise<void> => {
  const endIndex = Math.min(startIndex + chunkSize, images.length);
  const chunk = images.slice(startIndex, endIndex);

  // チャンクに含まれるファイルを追加処理
  for (const image of chunk) {
    // ここでファイルをアーカイブに追加
  }

  // 次のチャンクを処理
  if (endIndex < images.length) {
    await addFilesInChunks(endIndex);
  }
};

まとめ

制作の途中で処理が重くなったり、文字化けが発生したりと、躓くポイントは多くありましたが、試行錯誤を重ねながらなんとか形にすることができました😌

AIを活用したコーディングの情報が増えている中、まだ従来の方法でコーディングを行っている部分も多く、少しでも手間を減らせればと考えています。効率化や作業の負担軽減につながるポイントはまだ多くあるはずなので、引き続き改善を進めていきたいと思います🎉

📝参考

シェア