😎

psdのdiffをvimから見やすくしてみた

2024/06/07に公開

はじめに

プログラミングとかをしていると、gitを使って差分が見られるのはとっても便利ですよね!?
そんな便利なgitですが、psdファイル等のバイナリっぽいファイル差分を見るにはちょっと難しいです。

自分は趣味でお絵描きをすることがあり、普段使っているgitのdiffのように差分管理できればいいなと思いました。
そうはいっても、通常のお絵描きソフトではgitの連携はおろか差分の確認すらできません。
最終的にはpsdの差分管理を内蔵したお絵描きソフトでも作ろうかなぁとか思っていますが、
まずは簡単に実現できる用にvimのプラグインとして作ってみました。

実用とは程遠いですが、psdファイルの差分をvimdiff形式で見ることができるようになります。

https://github.com/kamecha/psd_diff

これを作る過程で得た知見を紹介します。

使用例

何はともあれ、使用している様子を見てみましょう。
まずは上記のプラグインをvimプラグインとして、お好きな方法でインストールします。
このプラグインはdenops.vimに依存しているので、Deno・denops.vim両方をインストールしておいてください。
ここではインストールの方法は省略します。

そして、お絵描きソフトでそれぞれの状態を保存、gitにコミットします。

git管理された事を表現するlog

  1. はじまりのverとしてコミット
    初期の絵

  2. 編集を加えた後に、ツヤとか諸々描き足したよ~としてコミット
    編集を加えた絵

  3. git difftool --extcmd "nvim -c 'autocmd User DenopsPluginPost:psd_diff ++once PsdDiffArgs'" 89a2a8d 187347d を実行
    プラグイン導入後のdiff

編集したpsdファイルの差分がvimdiff形式で表示されました。
バイナリファイルをそれぞれ目grepするよりは、かなり見やすくなったのではないでしょうか。

psdファイル

お絵描きソフトで良く使われるpsdファイルですが、お絵描きしない人には馴染みが無いと思うので、ちょっとだけ説明します。
ありがたい事に、psdファイルの仕様はAdobeが公開しているので、それを参考にします。
いやぁ仕様が公開されてるのってありがたいですね~

https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/

pngやjpegといった画像ファイルとは違い、レイヤーという概念が登場します。
透明な板に絵を描いて、それを重ね、上から見るように表示しているといった感じです。

今回差分表示を試みるのは、このレイヤー情報です。

git

https://git-scm.com/
gitは版管理ツールです。
プログラミング等に利用される事が多いですが、お絵描きにも適用できないかなぁ
と個人的に考えています。
特に好きな機能としては以下のものがあります。

  • commitがスナップショットである
  • diffを取ることができる
  • mergeができる

これらの機能を有効活用できるお絵描きソフトがあれば便利そうですよねぇ

今回はこのうちdiffに着目して、vim上で再現しようとています。

git difftool

https://git-scm.com/docs/git-difftool
diffを取る際にはgit diffを使いますが、diff用のツールを指定する方法がgit difftoolです。
今回はこのコマンドを使ってvimを呼び出し、psdファイルの差分を見ることにします。

詳細はリンク先を見て欲しいのですが、--extcmdオプションを使うことで、外部コマンドを実行することができるので、これを利用します。

使用例で紹介したコマンドを分解すると以下のように解釈できます。
git difftool --extcmd "nvim -c 'autocmd User DenopsPluginPost:psd_diff ++once PsdDiffArgs'" 89a2a8d 187347d

  • git difftool --extcmd <command> 89a2a8d 187347d
    • commandとしてnvimを使用し、nvim $LOCAL $REMOTEを実行する
    • $LOCAL$REMOTEにはそれぞれ比較対象の(スナップショットから復元された)ファイルが渡される
  • nvim -c 'autocmd User DenopsPluginPost:psd_diff ++once PsdDiffArgs'
    • nvimを起動し、autocmd User DenopsPluginPost:psd_diff ++once PsdDiffArgsを実行する
    • denops.vimがプラグインであるpsd_diffを読み込んだ後に、一度だけPsdDiffArgsコマンドを実行するautocmdを登録する

つまり作成するプラグインの機能としては、2つのpsdファイルを受取り、そのdiffを表示するコマンドを提供すれば良いことになります。

vimdiff

https://vim-jp.org/vimdoc-ja/diff.html
そもそもvimにはdiff表示機能があります。

vimからgitを使用するプラグインもこの機能を使う事が多いので、使い慣れておくとなにかと便利です。
差分間移動(]c[c)や、差分を適用する(dpdo)などの機能があります。

この差分機能はファイルの差分を見るだけでなく、vimのバッファに表示されさえすれば、よしなに差分を計算して表示してくれます。そのため、今回はpsdファイルを解釈してその内容をそのままバッファに表示すれば、diff機能でそのまま差分を計算・表示できます。

denopsを用いたプラグイン開発

https://github.com/vim-denops/denops.vim
今回のプラグインはdenops.vimを使って作ってみました。
denops.vimのおかげで、Denoで使用できるライブラリをvimから使うことができ、とても簡単に実装できました。
psdのパースライブラリがnpmに転がっているので、それをDeno経由で呼び出す事で、レイヤー情報を簡単に取得することができました。
ここではdenopsプラグインを作る際にそれぞれ意識した点を実際のコードを例に紹介します。

ディレクトリ構成

  • doc
    • ヘルプファイルを配置するディレクトリ
  • plugin
    • プラグインロード時に読み込まれるファイルを配置するディレクトリ
    • プラグイン用のコマンドをここでvimに登録する
  • autoload
    • 必要になった時に自動的に読み込まれるファイルを配置するディレクトリ
    • 処理の大本はここに配置する
  • denops
    • denopsプラグインを配置するディレクトリ
    • main関数をexportするファイルを配置する

plugin

https://github.com/kamecha/psd_diff/blob/main/plugin/psd_diff.vim
それぞれのコマンドを定義しています

  • PsdPrint
    引数としてpsdファイルのPathを受け取り、現在のバッファにその内容を表示します
  • PsdDiff
    引数として2つのpsdファイルのPathを受け取り、そのdiffを表示します
  • PsdDiffArgs
    PsdDiffコマンドの引数に、$LOCAL$REMOTEを渡して実行するのと同じ動作をします
    argv()等は起動時に与えられた引数を取り扱います

autoload

https://github.com/kamecha/psd_diff/blob/main/autoload/psd_diff.vim
それぞれの関数を定義しています
こちらのファイルはpluginで定義したコマンドから呼び出されるまでは、読み込まれません

  • psd_diff#print_psd
    引数としてpsdファイルのPathを受け取り、denopsプラグインで該当Pathのpsdファイルをテキスト変換したものを表示します
  • psd_diff#diff_psd
    引数として2つのpsdファイルのPathを受け取り、そのdiffを表示します
    ここでvimdiff形式で表示します(:help diffthisでチェック)

denops

https://github.com/kamecha/psd_diff/blob/0b0dd793ea812c920b7f1d26fe010421f2cc3156/denops/psd_diff/main.ts#L1-L18
denopsプラグインのエントリーポイントです

  • main
    denopsプラグインのエントリーポイントです
    Pathを受け取り、psdファイルをパースしてテキストに変換する処理を登録しています。
    パースの箇所でnpmライブラリを使用しています。

おわりに

お絵描きにもgitを使いたい!との思いから、その足がかりとしてpsdファイルのdiffをvimで見やすく表示するプラグインを作ってみました。
diffを表示するために必要な事の確認、連携する方法等を簡単におためしするために、denops.vimを使用したvimプラグイン作成はとても楽しかったです。

テキストを編集するために便利な機能のほとんどはvimにすでに実装されているので、それを使うだけで済んでしまうのはとても楽ですね。
今回はパースが面倒で、npmライブラリを使用するためdenops.vimに依存していますが、時間があればvimscriptで自前パースでもしてみようかなぁとか思っています。

GitHubで編集を提案
traP

Discussion