tweak layers

レイヤーパレットというものに正式な定義があるわけではないが、大体のイメージはPhotoshop 3.0から実装されたアレである。

アレ

これを整理してみるとこの中に存在するオブジェクトは

  • レイヤーのリスト(可視、リンク、サムネイル、タイトル等を含む)
  • 選択中のレイヤーの合成モード
  • 選択中のレイヤーの不透明度
  • 選択中のレイヤーの塗り潰しモード
  • 選択中のレイヤーの各種フラグ
  • 各種レイヤー操作のためのツールバー的なもの

とこんな感じになる。面白いのは合成モード云々が上にまとめられていることだ。これらは当然各レイヤーの属性なので、本来はレイヤーリスト中の各レイヤー項目内に配置されて然るべきものなのだが、おそらくパレットの面積の都合で上にまとめられている。

これに対して、レイヤーの可視状態とリンク状態はまとめられてない。この切り分けにどういう理由があるのかは分からない。可視・不可視の状態は全体を俯瞰できた方がよいということか。

そんなこんなを勘案しつつ、桃のレイヤーパレットはこんな感じにしてみたい。

上部にはチェックボックスひとつしか置いてないが、ここには可視・不可視の状態や透明部分の保護といった各種フラグ群を表示する。また、合成モードと不透明度のためのUIは画像の通りの場所に配置する。

画像の通りといえば見ての通り、各レイヤーを横に配置している。これはちょっとチャレンジングで、これが使いやすいかどうかは実際にドッグフーディングしてみないと分からない。もしかしたら何だこのクソUIは!!となるかもしれない。

The latest clipboard operation in javascript #2

貼り付けの動作について整理しておきたい。

Photoshopの場合、「ペースト」を行うと新規レイヤーが生成され、そこにクリップボード上の画像が配置される。また、「選択範囲へペースト」を行うと新規レイヤーが生成され、選択範囲がレイヤーマスクに設定された上でクリップボード上の画像が配置される。CSなんちゃらではもう少し貼り付けの仕方にバリエーションが増えるが、基本的な動作は割とシンプル。

一方gimpはなんかよく分からなくて、とにかくメニュー項目がたくさんあり:

  • 貼り付け
  • 同じ位置に貼り付け
  • 選択範囲に貼り付け
  • 選択範囲内の同じ位置に貼り付け
  • クリップボードから生成:レイヤー
  • クリップボードから生成:レイヤー(同じ位置)
  • クリップボードから生成:画像
  • クリップボードから生成:新しいパターン
  • クリップボードから生成:新しいブラシ

これ多分作った人も使い分けできないよね。貼り付けの動作自体も若干複雑で、レイヤーではなくフローティング選択範囲というものが生成される。その状態で新規レイヤーを生成すればそれに固定される。一方レイヤーの固定という機能を呼ぶとカレントのレイヤーに固定される。

ということでベースとしてはPhotoshopを参考にしたい。ただレイヤーマスクはまだ作るわけじゃないので「選択範囲へペースト」は後回し。

さて貼り付けを作る場合、桃にとって最も大きいインパクトは、従来はレイヤーが3枚に固定されていたのを基本的に制限なしに自由に増減できるようにしないとならないということだ。

内部的な機構についてはそのようにできるようにするためにいろいろ書き換えてきたので問題はないのだが、めんどくさいのはいわゆるレイヤーパレットというものを作らないといけないのである。つまり、UIの問題だ。

The latest clipboard operation in javascript

というわけでコピー処理を書く。

とりあえずこの辺を参考にする。というより、仕様がばんばん変わっていくのでここ以外はすぐ鮮度が落ちてしまう。強いて言えば、この辺りも手助けになるかもしれない。とは言えこのページにしても、例えば ClipboardItem とはなんぞやというところとかがいまいち説明不足だったりするのだがそこは引っかからなくていい。

気をつけるべき点として

  • クリップボード操作は https なページ上じゃないとできない

  • クリップボードへの書き込みは、現状の Chrome の実装では、パーミッションは特に必要ない

  • クリップボードへの画像の書き込みは、7月末にリリースされた Chrome 76 からやっとできるようになった。それ以外のブラウザでは「まだ」できない

  • クリップボード操作は対象のページがアクティブ、つまりカレントウィンドウのカレントタブじゃないとできない。論理的にその状態であると同時に実際にその状態じゃないとできない。どういうことかというと、クリップボード操作の行にブレイクポイントを貼ってそこからステップ実行とかすると操作は失敗するということ。対象のページがアクティブじゃないので

そんなこんなで

こんな感じで選択してメニューからコピーを選択すれば

こんな感じでクリップボード経由で他のアプリケーションとやり取りできる。うーん普通だ。

上記の通りクリップボードは https なページ上じゃないと動かないので、ローカルで試すには自己証明書を作らないといけない。とりあえずこの辺りを参考にした。

次は貼り付けを作る。

Menu bar

そんなわけでメニューバー的なものを書いた。

ただメニューバー的なものがメニューバー的に動作するだけなので、特に他に書くことがない。

桃に組み合わせるとこんな感じになる。次はクリップボード周りを書いてみよう。

Drawing into the selection

選択範囲がある時、描画がその中へ限定される処理を書いた。

さてこの選択範囲をどうこうするための、クリップボードに関するメニューというものが必要になるのだけど。どこへ追加したものだろうか。

桃の上部のパネルは、別に意識したわけではないのだけど、Microsoft 製アプリで言うところのリボンUIのように見えるので、クリップボード操作に関してもそれを模倣するという方法もあるが、リボンが優れたUIとはちょっと思えないのでそれは採らない。普通に「ファイル」「編集」云々の伝統的なメニューバーがほしい。

そういうものをちょちょいと出してくれる素敵なライブラリなんかないかな。

Ants march over the peach

選択範囲の表示をやってみた。

このトピックについてめんどくさい点は、Photoshop等に倣うなら、範囲表示の境界線がキャンバスの倍率によらず常に1ピクセルであるということだ。このための下準備がめんどくさい。蟻が行進するのは意外とめんどくさくない。

もう一つめんどくさいのは、選択範囲を決定する前段階の仮線の表示だ。何がめんどくさいかと言うと、やはりPhotoshopに倣うならばこの仮線はキャンバスの画像を反転した色で表示する必要があるのだ。

この反転表示と蟻の行進を組み合わせて表示するのが多少めんどくさい。ちなみにPhotoshopではなくgimpに倣えば、この手の仮線はxorではなく縁取りされた実線になるのだけど、これはどのピクセルを選択しているのかわかりづらいのでよくないと思う。

ともあれ、選択範囲の表示についての基礎の部分はできた。まだ実装してないけど選択範囲の集合論的な演算(範囲の追加、削除、インターセクションなど)も無理なく組み入れられると思う。

ということで次に考えるべきめんどくさいことは、この選択範囲をどうするかという点と、選択範囲に対する描画という点だ。前者はクリップボードとのやり取りという話に繋がるのでなかなか大掛かりにめんどくさい。また後者はつまり描画のクリッピングなのだが、おそらくcanvasの機能で一発ということにはならないのでこれまためんどくさい。

この記事めんどくさい言い過ぎだ。

Scan line

範囲選択機能を作る際、めんどくさいことは大まかに分けて2つあり:

  • 選択範囲の内部表現
  • 選択範囲の表示

まず内部表現から考えると選択範囲とは頂点の配列のことだ。それを結んで多角形とし、その内部に描画を限ることで範囲選択がなされる。

多角形によるクリッピングというのはキャンバスのネイティブの機能を用いて実現してもよいのだが、その場合アンチエイリアスが効いてしまう(アンチエイリアス自体はキャンバスの仕様に必要な要件ではなかったはずなのだが、どういうわけか全てのブラウザがそういうふうに動作する)ので自前でアンチエイリアスをかけない多角形塗りつぶし機能というのが必要だ。

というわけで書いた。

アンチエリアスをかけない描画メソッドというのはすでに線分と円についても作ってあるが、どれもなかなか面白く、グラフィックスの教科書をおさらいしてる気分になる。

* * *

ポリゴンの内部をキャンバスの機能で塗りつぶし、輪郭だけアンチエイリアスなしの線分描画関数で上書きすれば10倍くらい速くなることに気付いてしまった。ぐぬぬ…。

Have to press twice

Chrome 上で vi っぽいキーバインディングを再現するよ系の拡張としてcVIMを入れている。のだが、最近になって不思議な動作をするようになった。

:とかaとかtを押すと1行入力のプロンプトを求める状態になるはずが、なぜか2回左記のキーを押さないとプロンプトが出なくなってしまったのだ。不思議なことに従来通り1回押せば出るページもある。またそのページでも状態によって出たり出なかったりする。ランダム。

cVimのコミットもすっかり頻度が低くなってる今日この頃だけど、直るんだろうか。

All layers are independent in size

従来はすべてのレイヤーの大きさはキャンバスの大きさであり、また背景レイヤーの完全に直上にある構造だったがこれをやめ、レイヤーごとに大きさとオフセットを独立して持てるようにした。それに合わせて、いわゆるレイヤー移動ツールを実装した。

と文章で書くとこれだけなのだが描画のあらゆるところでオフセットを意識するように書き直すのは死ぬほど大変だった…。その割に見た目は何も変わっていないと言う。

次は矩形選択ツールを作る。

Curse of cursor

キャンバスに描かれるペンのサイズを事前に図示するために、カーソルの形状を CSS の cursor プロパティにより変更している。

が、Chrome ではこのプロパティにより設定できるカスタムカーソルの最大サイズに制限がかけられることになると言う。

https://www.chromestatus.com/feature/5825971391299584
https://bugs.chromium.org/p/chromium/issues/detail?id=880863

カーソルの形状の変更はおそらくネイティブなウィンドウシステムの機能に依存しているだろうから、最小公倍数的な仕様に揃えるということなのかな? と思ったらどうもカーソルの形状を変えることで誤クリックを誘導するような邪悪な広告対策のようだ。なんて世知辛い世の中だ。

というわけで桃缶でもそういう対応を入れることになったのであった。