タイトル【SnapXShot制作記】アイコン設定は簡単、マウスポインタ挿入にハマるカテゴリーグラフィックス, ProjectBuilder/Interface Builder, SnapXShot制作記
作成日2000/12/6 1:57:39作成者新居雅行
Mac OS Xの画面撮影ツール「SnapXShot」だが、Mac OS XでStuffIt Delux 6.0を使って圧縮した。何にも考えずにリリースしたが、利用者の方より御連絡をいただき、Mac OS X Public Betaに付属しているStuffIt Expanderでは解凍できても起動ができないとのことだ。CodeWarriorのデバッグの経験を生かし、同じように解凍結果を見てみると、案の定ファイルの実行権限が設定されていない。Public Betaに付属するStuffIt Expander Ver.6.0a5にはバグがあってファイルの情報が完全に復元されないのである。現在、フリーで配付されているStuffIt Expander Ver.6.0はそのバグが直っている。つまり、Ver.6.0の方が新しいわけで、そちらを使って解凍をしてもらいたい。

さて、アイコンについては思った通り、Project Builderを使っているためか、非常に簡単に済んだ。小池さんのプログラマー日記では「ジャイアントアイコン」と呼んでいたのがMac OS Xでのごっついアイコンである。以前なら最大で32ドット四方なので、ビットをマウスでいじって下手なデザインもしたが、128ドット四方をちまちまクリックして描く気にはなれない。もう、これは写真を使うしかない。カメラの写真を撮影しようかと思ったけど、意匠権に觝触しそうだし、なかなかいい題材がない。結局、我が家の家族だったネコのルイくんの顔写真にした(去年に、14歳で他界している)。128ドットの画像ファイルを作り、周辺をぼかすなど、Photoshopでちょっとした画像処理を行なって、TIFFファイルにしておいた。アイコンは、/Developer/ApplicationsフォルダにあるIconComposerを使う。Project Builderとの統合がいまいちなのだが、MOSAのセミナーでアップルの人が使うところを見ていたので迷うところはない。まず、IconComposerをダブルクリックして起動する。そして、128ドットの画像(なぜかいちばん大きな画像がThumbnail)に、写真画像を入れる。あとは、他のサイズの画像の枠、そしてマスクの枠に、ドラッグして埋めていけばいい。いちいちスケーリングするかをダイアログボックスで聞いてくる。そして、プロジェクトのあるフォルダに保存する。

◇IconComposerでアイコンを作成した
 

Project Builderでは、そのアイコンファイルをプロジェクトに登録する。Resourcesのグループに入れるのが順当だろう。そして、プロジェクトの設定を変更するのだが、いちばん説明しやすい方法として、ProjectメニューのEdit Active Target(Command+option+E)を紹介しておこう。すると、プロジェクトの設定ウインドウが出てくるので、Application Settingsのタブを選択し、Icon fileにアイコンファイルのファイル名を入れておく。これはファイル名だけでよく、余計なパスなどは不要なようだ。そして、ウインドウ左上の刷毛のアイコンをクリックして、いちどクリアし、再度トンカチアイコンでビルドをすれば、あっさりアイコンが出てきた。

◇Icon fileのファイル名はキータイプする
 

◇写真をアイコンに持つアプリケーションが出来上がった
 

ここまでできたから、いっそのこと、マウスポインタを入れてやろう!と思ったまではよかったのだが、かなりはまってしまった。もともと、グラフィックス系をバリバリやっているわけではなく、しかも、QuickDrawは最近はすっかりごぶさただったので、道は茨だった。紆余曲折あったのだが、方針編と実装編に分けて説明しよう。
まずは方針だ。理想は、「現在のマウスポインタの形状」がビットマップで得られれば文句はない。だが、結果的にはできないことが分かった。まず、淡い記憶でQuickDrawグローバルがあったはずだと思った。LowMem.hを探すと、あったあった…LMGetTheCursorだ(昔は違うシンボルだったような…)。Appleのサイトで検索…うーん、CarbonはUnsupportedになっている。残念、しかも、Carbonアプリケーションはカーソル画像を取得できないとまで丁寧に書いてある。GDeviceのメンバーにも現在のマウスポインタ画像を取得するものはあったはずだけど、試してみたが、やっぱり何もデータは得られない。データが0になっている。マウスポインタはもっぱら設定するものとしかAPIは用意されていないようだ。Mac OS Xに付属のGrabもマウスポインタはいくつかの形状から選択するようになっている。仕方ないから、常に矢印のポインタをGetQDGlobalsArrowで得ることにした。
得られるデータは、Corsor形データであり、Bit16というシンプルだがやっかいな形式のデータだ。結果的には、そこからPixMap型データを得て、CopyMaskで画面ショットにマウスポインタを上書きするという手はずを踏まないといけない。いろいろサボリを考えてやってはみたが、急がば回れとはよく行ったものだ。最終的には、マジメな方針での実装になった。Technoteの記述もあったので、マウスの形状のPixMap、そしてマスクパターンのPixMapを作った。いずれも、1ビットのデプスのGWorldを作り用意したのである。ただ、Bit16と言っても単なる1ビットの集まりなので、いろいろうまい方法はあるのだろうけど、結局はGWorldにSetCPixcelでドットごとに記述するという方法でビットマップデータを作成した。
余談だが、階乗を取るための演算子は、すっかり^であると思い込んでしまっていた。Visual Basicとかのマクロ系の頭になっていたのである。Cには階乗の演算子はなかった。これで、けっこうはまってしまったのである。
さて、こうした方針で実装を行なうわけだが、短いプログラムながらかなりいじってやっと動くようになった。Bit16のデータからGWorldを作ったのだが、最初はそこで作ったGWorldのPixMapだけを取り出してGWorldは捨てていた。でも、そうしたら、実はPixMapも壊されることに気付き、GWorldを温存してPixMapを使ってからまとめて破棄するようにした。こう書けば簡単な話だが、これに気付くまでに何度も試行錯誤をすることになってしまった。
矢印カーソルのマスクや矢印がきちんとPixMapで得られることが確認できた後は、それを画面ショットに合成する必要がある。座標はGetMouseで得られるので、あとはCopyMaskだということになる。PICTのレコーディングを開始して、CopyBitsで画面の内容を転送し、さらにマウスポインタをCopyMaskで描いても、なぜかマウスポインタが記録されない。さんざん悩み、思い出した…CopyMaskはPICTには記録されないのである。結果的に、画面ショットのデータのPixMapに、マウスポインタのPixMapをCopyMaskで書き込んで、ビットマップを作った。
ところで、PixMapは使い終わるとDisposePixMapするものとばかり思っていたが、なぜか、そこで落ちるのである。しかも、何度か画面ショットを撮影した後で、DisposePixMapで落ちる。落ちた時には、なぜかすでにPixMapのデータが破棄されていて、ハンドルの先には何もない。デバッガで調べたがDisposePixMap直前はハンドルの先にはデータがある。これも悩んだが、Inside Macintoshを見ると、「普通はDisposePixMapを呼ぶことはないよ」と書いてある。同じことがNewPixMapにも書いてある。うーん、確かに、普通のアプリケーションはこの構造体をいじることはないだろうけど、私はある。さんざん悩んだのだが、単にDisposePixMapを使わないで、そのままにしておくことで、きちんと動き始めた。落ちたりはしない。理由をこじつければ、PixMap自体の解放は自動的に行なわれるのではないかということだ。パージ可能なようになっていて、あるタイミングで勝手に解放されるのだろう。だから、PixMapを使うときにはLockPixelsでメモリをロックするのだと言えば、話の辻褄が合いそうだ。だけど、疲れた…。

そんなこんなで、Project BuilderでMach-Oを生成し、アイコンもついてマウスポインタも矢印固定だが出てくるようになった。ちょっとは進歩はしたわけだが、そろそろ次は、WaitNextEventによるぐるぐる回しをやめて、Carbon Event Managerを使う番ば回ってきそうだ。
関連リンクSnapXShot