ホーム > 諸々

QuickDraw Region について

QuickDraw Picture (いわゆる Macintosh PICT) を解析するのに必要ながら誰も書かないので、しばらく前に Computer History Museum で公開されたQuickDrawのソースを調べてみました。

まずRegionとは何かというと、Classic Mac OS のQuickDraw上で、任意の形状の範囲を指定するためのものです。ウインドウが移動された際の再描画の必要な領域とか、マウスポインタの形状を変化させる領域とかいうような、長方形で表すにはちょっとキツい形を表現する際に利用されます。

こいつをどう表現するか。機能的には白黒2値のビットマスクで全く問題ないのですが、QuickDrawではビットマップが

TYPE BitMap = RECORD
	baseAddr: Ptr;
	rowBytes: Integer;
	bounds: Rect;
END;
であるのに対し、Regionは
TYPE Region = RECORD
	rgnSize: Integer;
	rgnBBox: Rect;
	{more data}
END;

で定義されており、全く別の構造となっています。Regionでは長方形の組み合わせのような割と単純な図形を表すことが多いので、そういう場合に容量を削減できるようになっています。コンセプト的にはこちらの方がかかれている通りです。=> http://sinn246.wordpress.com/2011/10/26/ビル・アトキンソンとquickdraw リージョンについて思/

そして、実際はどうなっているかというと、

  1. Regionにしたい領域をビットマップとして用意(選択したい部分が黒として以下話を進めます)
  2. 用意したビットマップをぴったり取り囲む長方形を求め、rgnBBox に代入(4辺全てに接しなければだめです)
  3. 領域が完全な長方形の場合、このままrgnSizeに10 (= sizeof(rgnSize) + sizeof(rgnBBox)) を代入して終了
  4. 領域が長方形ではない場合、用意したビットマップをスキャンラインに分割
  5. 分割したそれぞれの行で、黒い部分の開始点と終了点のX座標を配列として取り出す
  6. 取り出した開始・終了点の座標を上の行と比較、上の行のいずれかの開始点もしくは終了点と被っているものを取り除く(一行目の場合、前の行は全て白と考える)
  7. 行のY座標、および残った点の座標を16-bit 整数の配列として出力し、最後に終了マーカーとして$7FFFを付け加える
  8. これを全ての行について行う
  9. 最終行まて終わった後、最終行の次の行を全て白と考え、この行についても改めて出力を行う
  10. 最後に、もう一度終了マーカー$7FFFを出力する
  11. 出力した全データのサイズを求め、rgnSize, rgnBBox の分も合わせた値を rgnSize に書き込む

以上が基本的な流れです。

具体的にはこんな具合です。

たとえばこんな領域を表したいとしましょう。

座標を書き入れるとこんな具合になります。

まず、この領域をとり囲む長方形は次のようになるので、

rgnBBoxは {1, 1, 6, 7} になります。(QuickDrawのRectは左上と右下の座標で表し、縦座標を先に書きます)

これをスキャンラインで分割し、黒い部分の開始点と終了点を書き入れると

のようになります。

最初の行 (y = 1) は x = 1 から x = 4 までが黒なので、y = 1 と x = 1, 4 を記録し、最後に $7FFF を付け加えて

$0001, $0001, $0004, $7FFF

となります。

次の行 (y = 2) もおなじく x = 1, 4 ですが、x = 1, x = 4 ともに上の行と同じなため、記録しません。よって y = 2 では記録すべき点がありませんので、この行はスルーします。

y = 3 では黒い範囲が x = 1..4 に加えて x = 5..7 が増えているので、x = 1, 4, 5, 7 になります。このうち x = 1, 4 は y = 2 の時と共通であるため、x = 5, 7 のみを記録します。したがって、

$0003, $0005, $0007, $7FFF

が追記されます。

y = 4 では、x = 1, 7 となり、y = 3 の時と比べ x = 1, 7 は共通ですが 4, 5 が無くなっています。ですので、この行では x = 4, 5 を記録し、

$0004, $0004, $0005, $7FFF

となります。

y = 5 では x = 1, 7 で、y = 4 と完全に一緒です。よってこの行はスルーです。

最後に y = 6 の分もやります。y = 5 では x = 1, 7 でしたが、その下は黒い部分はありません。よって x = 1, 7 が消えると考え、これを記録します。

$0006, $0001, $0007, $7FFF

そして終端にもう一度

$7FFF

を加え、データが終了となります。

結局、Regionのサイズはデータ部分だけで34バイトとなり、ヘッダの rgnSize 2バイトと rgnBBox 8バイトをあわせると44バイトとなります。この値がrgnSizeに入るので、今回の全データは

$002C, $0001, $0001, $0006, $0007,  ; rgnSize = 44, rgnBBox = {1, 1, 6, 7}
$0001, $0001, $0004, $7FFF,         ; 以下 rgnData
$0003, $0005, $0007, $7FFF,
$0004, $0004, $0005, $7FFF,
$0006, $0001, $0007, $7FFF,
$7FFF

になります。なおバイトオーダはビッグエンディアンです。

同様にして、

だと

$002C, $0001, $0001, $0005, $0007,  ; rgnSize = 44, rgnBBox = {1, 1, 5, 7}
$0001, $0001, $0005, $7FFF,
$0002, $0005, $0007, $7FFF,
$0004, $0001, $0002, $7FFF,
$0005, $0002, $0007, $7FFF,
$7FFF

となり、

$0030, $0001, $0001, $0005, $0007,  ; rgnSize = 48, rgnBBox = {1, 1, 5, 7}
$0001, $0001, $0005, $7FFF,
$0002, $0002, $0007, $7FFF,
$0004, $0001, $0005, $0006, $0007, $7FFF,
$0005, $0002, $0006, $7FFF,
$7FFF

のようになります。

2013.06.29

戻る