tweak layers #7

ドラッグ&ドロップのついでに、画像ファイルを桃にドロップした場合レイヤーとして読み込むようにした。また、Alt+[、Alt+] でアクティブなレイヤーを前後に切り替えられるようにした(Photoshopと同じ)。

その他、Ctrl+Shift+[、Ctrl+Shift+] などアクティブなレイヤー自体を前後に動かす系のショートカットも実装したのだがこれがとても難しい。

処理自体が難しいのではなく、ショートカットの扱いが難しい。キー入力は keydown イベントで受け、KeyboardEvent#key で判断することになる。一方、Shift を押しているか否かでマッピングが変わる系のキーというものがある。こういったキーを keydown イベントで取得すると例えば Shift+[ というストロークは Shift+{ という扱いになる。これが正しいのか間違っているのかよく分からない。入力された文字と押されたキーの混同が起こっている。はて。

tweak layers #6

大量にレイヤーを追加した場合、当然ながらレイヤーパレットの最大表示幅を超えるレイヤーサムネイルが生成されることになり、隠れているサムネイルの表示の制御はユーザーのスクロール操作によって行われる。

さて、レイヤーを並べ替えるためにドラッグを開始して、スクロール領域から隠れている場所にドロップしたい場合、スクロール領域の端っこにポインタを持っていくと自動的にスクロールするような機能が必要になるのでそれを作らないといけない。

ところが驚くことに。そういう機能作らないとだなーめんどくさいなーなどと思いながらドロップを試してみた所、すでにそういう動作をするではありませんか。んん〜? ブラウザの標準の機能なの?

Chromium ではだいたい想定したとおりの動作をし、Firefox ではスクロール領域の端っこでポインタをちょこちょこ動かした時に限り自動スクロールするようだ。ふーんじゃあ別にコードを書かなくてもいいのかな。

だいたい、というのはスクロール領域内部の端っこだけではなく領域の外側も自動スクロールのトリガーになっててほしいのだけど、まあ、いいかな。

tweak layers #5

さてレイヤーパレットができたことでヘッダ部分のレイヤー周りは不要になったので、色々と整理した。また、描画ツールのオプションはポップアップ形式をやめ、ヘッダの下部に表示するようにした。

レイヤーパレットの実装がもうちょっと続く。ドラッグ&ドロップによるレイヤーの並べ替えが必要。

The latest clipboard operation in javascript #3

ということでクリップボードからのペーストができるようになった。

貼り付ける画像のサイズは無制限でいいんだろうか? 制限をかけるとすると、閾値を越えたときはエラーにする? 適当にリサイズして貼り付ける? どちらも良くない感じがする。制限はかけず、32768×32768ピクセルの画像をペーストしてブラウザがぶっ飛んでもまあそういう日もあるかもね的精神でいきたい。

ちなみにレイヤーの枚数には制限があり、とりあえず100枚を限度にしている。

ところで navigator.clipboard.read() で画像を読み込む場合、それで得たクリップボードアイテムをblobに変換し、そこからオブジェクトURLを生成し、img要素に読み込ませ、それをcanvasに描画という手順が一般的なのだが、最近はImageBitmapというものがあるそうなのでそれを使った。javascriptの世界は日に日に新しい機能が追加されて困っちゃう。ImageBitmapはblobから生成できて、そのままcanvasへの描画ソースになれる。

tweak layers #2

レイヤーパレット上のツールバー的なものをどこに配置したものだろうか。

もっとも、ツールバーと言っても、とりあえず実装するのはカレントレイヤーの削除と新規レイヤーの追加くらいである。前者は対象がカレントレイヤーであるのだから、そのためのボタンをパレット上のカレントレイヤー領域のどこかに配置するのが当然、自然だろう。

一方で後者が難しい。新規レイヤーが常に最前面への追加なら、カレントレイヤーは関係ないのでツールバー的な領域を新設してそこへボタンを置けばいいが、カレントレイヤーの手前に追加と言った動作ならこれもパレット内のカレントレイヤー領域内に置くのが多少は自然に思える。

多少はというのは、確かに動作の起点はカレントレイヤーなのだが、動作の対象は別の新規レイヤーなのでそこに若干のズレを感じないこともないということだ。

難しい。どうしたものか。

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 なページ上じゃないと動かないので、ローカルで試すには自己証明書を作らないといけない。とりあえずこの辺りを参考にした。

次は貼り付けを作る。