ページ

2008年2月28日木曜日

スクリーンショットを撮る

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

以前からこのブログの画像はプレビュー(Preview.app)のグラブ機能を使って作成している。が、イマイチ使いづらい。以前利用していたスクリーンショットを撮るツールが Leopardになってから使えなくなったので仕方なくプレビューを使っているが、いっそのこと自分でツールを作ろうかと考えて少し前から調べ始めている。

今回画面全体のスクリーンショットを撮る簡単な方法が見つかったのでサンプルを作ってみた。



ソースコード:ScreenshotSample.zip


実行すると何も表示されないウィンドウが表示される。ここで "Capture"ボタンを押すと画面全体のスクリーンショットが表示される。

ソースコードは十数行だけ。
MyController.m

@implementation MyController

-(IBAction)capture:(id)sender
{
CGWindowID window_id = [window windowNumber];

CGImageRef cgimage = CGWindowListCreateImage(CGRectInfinite, kCGWindowListOptionOnScreenBelowWindow,window_id, kCGWindowImageDefault);

NSBitmapImageRep *bitmap_rep = [[NSBitmapImageRep alloc] initWithCGImage:cgimage];
NSImage *image = [[[NSImage alloc] init] autorelease];
[image addRepresentation:bitmap_rep];
[bitmap_rep release];
[view setImage:image];

CGImageRelease(cgimage);
}

@end


MacOSX 10.5 から使えるようになった各種の関数を使うと表示中のウィンドウを簡単にキャプチャできるようになる。


ADCからサンプルコードが出ていて、こちらは表示中のウィンドウ一覧を表示・選択できて様々なオプションを試すことができる。
Son Of Grab



- - - -
なお ADCのサンプルでは CGWindowID の取り方が出ていなかった。この為、最初は下記のように kCGNullWindowID を使っていたのだが、そうするとサンプルアプリのウィンドウまでキャプチャされてしまう。

CGWindowID window_id = kCGNullWindowID;




そこで NSWindow#windowNumber を使ってみたところ(そして kCGWindowListOptionOnScreenBelowWindowオプション)アプリのウィンドウを省くことができるようになった。

参照:Leopard CGWindowList* APIs
http://shiftedbits.org/2007/11/08/leopard-cgwindowlist-apis/

CGWindowID と NSWindow#windowNumberは同じではないとのことだが、今回はうまくいっていった。Carbonには HIWindowGetCGWindowID (MacWindows.h) が新しく用意されているので、こちらを使っても良い。

CGWindowID window_id = HIWindowGetCGWindowID( [window windowRef] );


試したところうまくいった。


その他参照情報:
CocoaDev: ScreenShotCode
http://www.cocoadev.com/index.pl?ScreenShotCode
MacOSXでのスクリーンショット取得方法の遷移を時系列で見るようでちょっと面白い。