ページ

2009年3月7日土曜日

β版バグ修正 - マルチスクリーン(その3)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

昨日考えたロジックの実装に入る。

まず範囲選択キャプチャを行うメソッドに手を入れる。

NSRect s_rect = _rect;
s_rect.origin = [self convertFromLocalToCGWindowPoint:_rect.origin];
CGImageRef cgimage = CGWindowListCreateImage(NSRectToCGRect(s_rect), option,
[_capture_controller windowID],
kCGWindowImageDefault);

以前はローカル座標系の範囲 _rect を直接 CGWindowListCreateImage へ渡していたが、#convertFromLocalToCGWindowPoint: を使い CGWindow関数の座標系へ変換をかける。#convertFromLocalToCGWindowPoint のコードは次の通り。
- (NSPoint)convertFromLocalToCGWindowPoint:(NSPoint)from_p
{
CGFloat cx1, cy1, lx1, ly1, sx1, sy2;
NSRect frame = [Screen frame];
NSRect m_frame = [[NSScreen mainScreen] frame];

CGFloat sh = m_frame.size.height;
lx1 = from_p.x;
ly1 = from_p.y;
sx1 = frame.origin.x;
sy2 = frame.origin.y + frame.size.height;

cx1 = lx1 - sx1;
cy1 = ly1 - (sy2 - sh);

return NSMakePoint(cx1, cy1);
}

昨日の数式をそのまま実装しただけ。Screen#frame は全画面の範囲を返す。

さて実行してみよう、といきたいところだが、あいにく今はマルチスクリーンを試せる環境が無い。とりあえずシングルスクリーンで動作確認を取っておく。


大丈夫そうだ。

- - - -
マルチスクリーン環境は職場でないと試せないので月曜日に出社した時に試してみる。


(6/11追記)数式に一部誤りあり。下記を参照のこと。
β版バグ修正 - マルチスクリーン(検証) CommentsAdd Star

2009年3月6日金曜日

β版バグ修正 - マルチスクリーン(その2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

(前日からの続き)
さて、マルチスクリーンにまつわる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つそれ以上存在し、例えばメイン画面の上下にサブ画面が存在する場合でも(恐らく)数式は正しく働くはず。これはスクリーン座標系とローカル座標系間でメイン画面の(左上もしくは左下の)位置関係は画面の数によらず取得できるはずだから。


さて数式は出た。後は実装するのみ。
結果はいかに(続く。。)

2009年3月5日木曜日

β版バグ修正 - マルチスクリーン

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

マルチスクリーン利用時にモニタの配置状況によっては範囲選択がうまく働かないとの報告をもらった。

例えば、サブ画面(メニューバーの無い方)が左に来ている場合。


サブ画面が右側にある場合は問題ない。同様にサブ画面が上にあるケースも問題が出る。
これに関連してスクリーン全体のキャプチャ時の点滅する点線の描画もおかしいようだ(キャプチャ自体は問題ない)。


何が起こっているか調査して整理してみよう。
まずは考慮すべき座標系について。SimpleCapでは次の3つを考える必要がある。

a. スクリーン座標系
b. SimpleCapのメインビューのローカル座標系
c. CGWindow系関数(キャプチャ関数)の座標系


それぞれは次のような独自の座標系を持っている。

a. スクリーン座標系
Cocoa(そしてQuartz)標準の座標系。左下が原点(0,0)となる。NSScreen で取得できる各種座標もこの座標系。


b. SimpleCapのメインビューのローカル座標系
filip(Y軸がスクリーン座標系と反転)させた座標系を使っている。左上が原点(0,0)になる。


c. CGWindow系関数(キャプチャ関数)の座標系
これも左上が原点(0,0)となる。



a,b,c共に異なる座標系を構成している。これらはスクリーンが一つの場合は特に支障をきたさないのだが、マルチスクリーンになると違いが出てくる。特に b.とc.は座標系は同じなのだがマルチスクリーンにした時の原点の取り方が異なっている。

これらを少し丁寧に調べてみよう。
検証にあたっては PowerBookG4(1280x854)とシネマディスプレイ(1600x1024)を使う。



スクリーンの位置関係は色々な組み合わせがあるが、整理しやすいようにX軸、Y軸方向で別々に考えてみる。

まずはY軸方向から。メインとサブ画面の上下関係は2種類ある。

(Y-1) サブ画面がメイン画面の上にあるケース


スクリーン座標系は、メイン画面の左下を原点として積み上げているのがわかる。一方、ローカル座標は2つのスクリーンを包含する矩形の左上を原点としている。最後の CGWindow系はメイン画面の左上を原点として、サブ画面は負の領域に配置されている。範囲選択では、ローカル座標をそのまま CGWindow系へ渡してキャプチャしている為、ここで座標系の不一致が起こり問題となっている。

(Y-2) サブ画面がメイン画面の下にあるケース

こちらはローカル座標とCGWindow系の座標系が一致しているのでキャプチャ自体は問題ない。ただしスクリーン系とは違っているので別の部分(ボタンの位置が変)に問題が出ている。


続いてX座標方向。Y軸方向と違ってFlipしていないのでこちらは原点の取り方だけが違う。

(X-1) サブ画面がメイン画面の左にあるケース

これもローカル座標系とCGWindow系で原点の取り方で違いが大きく出ている。

(X-2) サブ画面がメイン画面の右にあるケース

X軸だけ見ればこのケースはすべて同じに扱える。

- - - -
なるほど。マルチスクリーンになったとたん3つともてんでバラバラの座標系になっている。これは正常に動作しないわけだ。

さてどうするか。

2009年3月4日水曜日

メニューのアイコン作り直し

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

メニューアイコンの作り直し中。

以前はこんな感じ。


ドット絵もいいのだがちょっとレトロな感じ?が強すぎるので作り直してみた。

2009年3月3日火曜日

マウスカーソルの画像

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

マウスカーソルの画像をアイコンで使えないか試行錯誤中。
またちょっとしたツールを作った。

実行形態:CursorImage.app.zip
ソース:CursorImage.zip

実行すると次の画面が現れる。上のエリアへ画像をドラッグ&ドロップするとマウスカーソルと合成した画像を作る。


save ボタンを押すとデスクトップに PNG画像を生成する。

2009年3月2日月曜日

β版バグ修正 - ファイル名変更でドットで始まるファイル他

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

今日もバグ取り。ユーザに指摘されたバグを直す。

ドットで始まるファイルに変更できてしまう件と、名称変更中にファイル切り替えを行うと拡張子が重なってしまう(例:abc.png.png)を直した。

ファイル変更中に、ファイル切り替えや次のキャプチャなどの操作に入った場合は直前のファイル名変更を終わらせてから操作を実行するように修正した。これも初歩的なミスだな。


今日はこれだけ。

- - - -
ファイル名の形式をカスタマイズしたいとの要望を受けた(例:YmdHisなど)。これは当初切り捨てた機能だが今後要望が多ければ付けていこうと思う。

それとftpなどを使った各種Webサイトへのアップロード機能があると便利との意見ももらった。これは同感。
ただ SimpleCap自体に実装することは考えていない。この用途の為に SimpleViewerへアプリ起動機能を持たせてある。何らかのアップローダソフトをここから呼出して連携できれば良いと考えている。ファイル名をコマンドライン引数で渡す仕様になっているので、それを受け取って所定のサイトへアップロードできるソフトがあれば簡単に連携できる。適当なソフトを知っていれば是非情報を教えてください。そのようなソフトを開発してくれる人があれば歓迎します。後日立ち上げる公式サイトでも紹介させてもらいます。

2009年3月1日日曜日

β版バグ修正 - SimpleViewerの数値が変

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

SimpleViewerで画像を削除した時にインデックス値と総数がおかしいとの指摘を受けた。


調べてみると初歩的なミスで削除時にこれらの数値を更新していなかった。修正はすぐに完了。
修正版の公開は後日のリリースにて。

- - - -
他の人に使ってもらうとこういう問題の発見が早くて助かる。
β版を公開する意義はこういう所にあるのかと実感。