(前日からの続き)
さて、マルチスクリーンにまつわるSimpleCapの問題はいくつかあるのだが、まずは範囲選択時の問題から取りかかろう。
範囲選択キャプチャではカスタムビューの点情報を CGWindow関数へ渡す。
キャプチャ範囲の開始点、大きさ
↓
CGWindow関数
単一スクリーンだけの利用の場合は前回掲載したように2つの座標系はまったく同じになるので問題は生じない。一方マルチスクリーンになると画面の配置によって原点の取り方が異る為に意図したキャプチャ結果が得られないケースが出てくる。そこで座標系間で変換が必要になってくる。具体的なケースを元に変換ロジックを考えてみよう。
(X-1)サブ画面がメイン画面の左にあるケース
カスタムビューの原点は全画面を包含する矩形の左端となる。一方、CGWindow関数はメイン画面の左端となる。キャプチャする場合にこの時原点の位置の違いを反映させる必要がある。例のケースではX軸方向に -1280 だけ移動させる必要がある。
この -1280 という数値はどこから取れば良いのだろうか?
これは CGWindowの原点であるメイン画面の左端から、全画面の左端までの距離と一致する。そして、この数値は NSScreen から得られるスクリーン座標系の情報から求められる。
NSScreenから全画面を包含する矩形が得られて、左下(-1280,0)-右上(1600,1024)となる。この左にはみ出た分 1280 がメイン画面の左端から、全画面の左端までの距離となる。これは画面がたくさんあっても変わらない。
数式化してみると次のようになる。
・スクリーン座標系上での全画面範囲(左下)-(右上):(sx1, sy1)-(sx2, xy2)
・ローカル座標系上でキャプチャした範囲選択の開始点(左上):(lx1, ly1)
・CGWindow関数へ渡す開始点(左上):(cx1,cy1)
cx1 = lx1 -sx1
(X-2)サブ画面がメイン画面の右にあるケース
このケースは原点移動が発生しないので補正の必要はない。ただ実装上は先ほどの数式に当てはめられると場合分けが不要で扱いやすい。スクリーン座標系の方を見てみよう。
先ほどの sx1 は 0となる。
cx1 = lx1 -sx1 = lx1 - 0 = lx1
つまり原点移動は起こらず先ほどの数式が使える。
X軸は片づいた。次はY軸を考えよう。
(Y-1)サブ画面がメイン画面の上にあるケース。
X-1のケースと同様、原点移動が必要。こちらも NSScreenの情報が使える。
ただしY軸の場合、ローカル座標系およびCGWindow座標系は FlipしているのでX軸のように単純に sy1 が使えない(sy1 = 0)。Y軸の場合はメイン画面の高さを考慮する必要がある。原点移動に必要な高さは、画面全体の左上からメイン画面の左上までの高さなので、これを NSScreen座標系で考えると次の数式となる。
・スクリーン座標系上での全画面範囲(左下)-(右上):(sx1, sy1)-(sx2, xy2)
・メイン画面のサイズ(幅・高さ):(sw, sh)
・ローカル座標系上でキャプチャした範囲選択の開始点(左上):(lx1, ly1)
・CGWindow関数へ渡す開始点(左上):(cx1,cy1)
cy1 = ly1 - (sy2 - sh)
例の場合、sy2=1878, sh=1024 だから sy2 - sh = 864 となり、原点移動に必要な高さが得られる。
(Y-2)サブ画面がメイン画面の下にあるケース。
こちらのケースは原点移動が必要ない。
NSScreen情報はこんな感じ。
さて先ほどの数式が使えるかどうか。
sy2 = 1024
sh = 1024
sy2 - sh = 1024 - 1024 = 0
0となった。つまり原点移動は不要。
これまでの考察をまとめてみると次のようになる。
・スクリーン座標系上での全画面範囲(左下)-(右上):(sx1, sy1)-(sx2, xy2)
・メイン画面のサイズ(幅・高さ):(sw, sh)
・ローカル座標系上でキャプチャした範囲選択の開始点(左上):(lx1, ly1)
・CGWindow関数へ渡す開始点(左上):(cx1,cy1)
cx1 = lx1 -sx1
cy1 = ly1 - (sy2 - sh)
なお画面が3つ4つそれ以上存在し、例えばメイン画面の上下にサブ画面が存在する場合でも(恐らく)数式は正しく働くはず。これはスクリーン座標系とローカル座標系間でメイン画面の(左上もしくは左下の)位置関係は画面の数によらず取得できるはずだから。
さて数式は出た。後は実装するのみ。
結果はいかに(続く。。)