Habit modulation #2

というわけでテストを書く。

テストは mocha に実行させる。一方、桃は esm の文法に基づいてモジュールを分けてある。ここで問題が出てくる。ググればたくさんその手の話が出てくるが、要するに mocha、ひいては node.js が今現在 cjs と esm の過渡期にあって、まだあんまり esm の対応が行き届いていない。

mocha においても、import/export を使ったソースを渡してもエラーになる。その辺をどうするかはまさに議論中のようだ。

で、いくつかのワークアラウンドが考えられて:

  • ブラウザ上でテストを実行する: cjs と esm の混乱はあくまで node.js の中の話である。ブラウザを起動してその上でテストを実行すれば普通に esm のコードがテスト対象になる、はず
  • esm のコードを babel でトランスパイルした上でそれをテストする
  • モジュールをダイナミックロードする

前2者はワークアラウンドにしては大掛かりになるので、最後の奴で行ってみよう。

const assert = require('assert'); let testfunc1, testfunc2; before(() => import('./path/to/module').then(module => { ({testfunc1, testfunc2} = module); }); describe('test', () => { it('works', () => { // test code with testfunc[12] }); });

どうでもいいが最近のこの wordpress のエディタが使いにくい。

Habit modulation

「レイヤーの複製」という機能を実装した。これも、処理の本体よりいろいろな周辺の事柄の方が面倒なパターンである。

Photoshopにも同じようなメニュー項目がある。こちらは「レイヤーの複製…」であり、後ろに点々があるというのはつまりダイアログを経由するということだ。といってもこのダイアログではそんなにできることは多くない。レイヤー名と、出力先を指定できるくらいだ。

この出力先としてPhotoshopで開いている別のドキュメントを選択できるのだが、これはなかなか重要なようなそうでないような微妙な位置づけだ。これがないとレイヤーがもともと属するドキュメント上で複製し、それをカットして、別のドキュメント上でペーストする手順を踏まなければならないのだが、ダイアログで出力先を指定できることでこの手順を飛ばせる。

一方で、PhotoshopをいわゆるMDIアプリケーションとして運用するならレイヤーパレットからドラッグを開始して目的の文書上でドロップすればだいたい同じことはできる。こちらのほうが分かりやすいし手っ取り早い。微妙というのはそういうことだ。

さて桃の場合、いまのところ同一ページで複数の画像を取り扱うことはないのですなわち「…」もこの微妙なダイアログもない。メニュー項目を選択したら即レイヤーが複製される。いいことだ。この時、複製されたレイヤー名は自動的に付けられるのだが、それがこの記事の主題だ。

この複製後のレイヤー名の自動生成がなかなかめんどくさい。複製元のレイヤーの名前が「のコピー」で終わっている、「のコピー #\d+」で終わっている、そうではない場合のそれぞれについてふさわしい名前を生成しないといけない。めんどくさい。

めんどくさいが、しかし入力と出力は決定的でユーザのインタラクティブな操作に左右されることもないので、むしろユニットテストに回しやすいネタだ。そうだテストを書こう。

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

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

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

xclip

割とどうでもいいことなのだけど一応メモ。

X Window System が持っているセレクションはたとえば xclip といったプログラムでアクセスできる。

このとき、例えばテキスト以外、例えば画像とかをやり取りするにはどうするんでしたっけ? そのような場合は target オプションに ATOM を指定する。ATOM ってなんだろう…。

ATOM はここで定義されている: https://tronche.com/gui/x/icccm/sec-2.html

X11 の用語自体に ATOM というものがあったようが気がしないでもないが、関係があるのかはよく分からない。さてこれを参考にした上で、画像はどれになるのかと言うと実はどれでもなく、mime タイプを指定する。

$ cat foo.png | xclip -i -selection clipboard -target image/png

ここで jpeg とかをコピーしてもアプリケーションによっては対応してないこともあるので、必要ならコピー前に png に変換するなどの処理が必要。

とここまで書いて思ったのですが X11 から Wayland へみたいなドラスティックな変更を行った場合この辺どうなるんだろう。ググってみると当然ながら Wayland が面倒を見ることになるようだ: https://wayland.freedesktop.org/docs/html/ch04.html#sect-Protocol-data-sharing

この辺を考えるとディスプレイサーバという名称がふさわしいのかどうかよく分からなくなってくるが、気にしないことにしたい。

The latest clipboard operation in javascript #3

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

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

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

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