はじめてのMorphicチュートリアル(第12回)「画像の表示」

今回は画像ファイルをモーフに表示する方法について学ぶ。
はじめてのMorphicチュートリアル(番外編)「ScratchCatをダウンロードする」でダウンロードしたScratch Catをモーフの表面に表示させる。Scratchのメディアサイトから画像ファイルをダウンロードしておいてもよい。いずれにせよ、ダウンロードしたファイルが展開され、画像ファイルが適当なフォルダに格納されている前提で話を進める。
ファイルに保存された画像を表示するには、画像ファイルを読み込んでFormオブジェクトを作り、それを表示するという流れで処理を行う。
画像ファイルを読み込むには以下のようにする。(ファイル名はフルパスで指定してもよい)

f1 := PNGReadWriter formFromFileNamed: 'Cat_1_Bitmap.png'.

PNGReadWriterはPNG形式のファイルの読み書きを行うためのクラスである。他にもBMPReadWriterやGIFReadWriter、AnimatedGIFReadWriter、JPEGReadWriterがある。各クラスに対し、ファイル名の引数を付けてformFromFileNamed:というキーワードメッセージを送れば、指定した画像ファイルを読み込んでFormオブジェクトを生成する。
生成して得られたFormオブジェクトから大きさやビット深度などの情報を得ることができる。

f1 extent. "(184@200)"
f1 depth. "32"

MyMorphで色のついた四角形の変わりにScratch Catを表示するなら、事前に画像を読み込んでおいてモーフ表示の際に描画する必要がある。そのため、画像ファイルを読み込んで得たFormオブジェクトは、formという名前のインスタンス変数で覚えておくことにする。
新たなインスタンス変数を追加するには、MyMorphのクラス定義を以下のように変える必要がある。

Morph subclass: #MyMorph
    instanceVariableNames: 'vec form'
    classVariableNames: ''
    category: 'Hajimeteno Morphic Tutorial'

System BrowserでMyMorphクラスを変更してAcceptするか、適当な場所で上記をDo itする。
画像ファイルはinitializeメソッドの中で(つまりモーフ生成時に)読み込むことにする。モーフ生成のたびに同じ画像ファイルを読み込むのは効率が悪いが、ここでは単純化のためにそうする。また、元のMyMorphは16×16ピクセルの大きさなので、Scratch Catを表示できない。そこで、モーフの大きさを画像の大きさに設定している。また、少し早めに動作するよう10ピクセルずつの移動とした。

initialize
    super initialize.
    vec := 10 @ 0.
    form := PNGReadWriter formFromFileNamed: 'Cat_1_Bitmap.png'.
    self extent: form extent

モーフはdrawOn:メッセージが送られると引数に与えられたキャンバスへ自分自身を描画するようになっており、現状ではモーフの大きさの色の付いた四角形を表示している。そこで、読み込んだFormオブジェクトを表示するために以下のようなdrawOn:メソッドを実装する。

drawOn: aCanvas
    aCanvas drawImage: form at: self topLeft

drawImage:at:というキーワードメッセージは2つの引数を持ち、最初に表示させたいFormオブジェクト、次に画面上の位置を指定する。
以上のような変更を加えた上で、MyMorph new openInWorldをDo itしてみると、以下のように表示される。
Scratch Cat bug
ご覧の通り、Scratch Catが表示されるものの、モーフが動くたびに分身が残って表示されてしまう。このような現象は、今回のように透明部分を含む画像を描画したり、全ての表示範囲を使わずに描画したモーフを動かす際に発生してしまう。
これを回避するには数カ所を変更する必要がある。まず必要なことは、先ほど実装したdrawOn:で、drawImage:at:の代わりにtranslucentImage:at:を用いて、透明部分の描画に対応することである。

drawOn: aCanvas
    aCanvas translucentImage: form at: self topLeft

更にモーフ自身の色が透明であるように設定する。

initialize
    super initialize.
    vec := 10 @ 0.
    self color: Color transparent.
    form := PNGReadWriter formFromFileNamed: 'Cat_1_Bitmap.png'.
    self extent: form extent

中央の行で透明色に設定している。
通常はこれだけで良いのだが、MyMorphではstepのたびに色を変えるようにしていたので、色を変えないようにstepメソッドを修正する。

step
    self topLeft: (self topLeft + vec)

以上で画像ファイルを表示させることができた。
2枚の画像を交互に表示させるのは今までの延長線上でできるので演習にしておこう。
(第12回おわり)