9.3 画像の拡大・縮小(その2)

今回は画像の拡大/縮小ができるもう1つのメソッドを使ってみることにするね。
そーいえば前回画像の拡大/縮小ができるメソッドは stretchCopy メソッド以外にもう1つあるって言ってたよね。
それってどんなメソッドなの?
operateStretch っていうメソッドで、 画像を拡大/縮小して重ね合わせたい時に使うメソッドなんだ。
画像を重ね合わせるって?
レイヤに元々画像が表示されてて、その上に別の画像を拡大/縮小して重ね合わせるってことだよ。
それって stretchCopy メソッドでも出来るんじゃないの?
ううん、stretchCopy メソッドで画像を拡大/縮小コピーすると、 コピーした場所に元々表示されてた画像は消えちゃうんだ。
あ、そーなんだ。
でも、元々表示されてる画像を消さずに、別の画像を拡大/縮小して重ね合わせたい時もあるでしょ。
そういう時に operateStretch メソッドを使うの。
なるほどね〜。
んじゃまずは operateStretch メソッドの引数から見ていくね。

operateStretch メソッドの引数>
引数名引数の意味デフォルト値
第1引数dleftコピー先の四角形の左端の位置
第2引数dtopコピー先の四角形の上端の位置
第3引数dwidthコピー先の四角形の幅
第4引数dheightコピー先の四角形の高さ
第5引数srcコピー元のレイヤ
第6引数sleftコピー元の四角形の左端の位置
第7引数stopコピー元の四角形の上端の位置
第8引数swidthコピー元の四角形の幅
第9引数sheightコピー元の四角形の高さ
第10引数mode演算のモードomAuto(自動決定)
第11引数opa演算の強度(不透明度)255
第12引数type拡大縮小(補間)のタイプstNearest(最近傍補間)

うわ、引数多いね…
えーっと…ほとんど stretchCopy メソッドの引数とおんなじみたいだけど、違ってるのは…
第10引数の mode っていうのと、 第11引数の opa っていうのが増えたとこかな?
ん、そうだね。
これってどーいう引数なの?
じゃまず第10引数の mode から見ていくね。
はーい。
mode はコピー元とコピー先の画像を重ね合わせる方法を指定するための引数で、 指定できるのはこの4つの値のどれかなんだ。

operateStretch メソッドの mode に指定できる値>
値の意味
omOpaque不透明合成(アルファ値無視)
omAlphaアルファ合成
omAddAlpha加算アルファ合成
omAuto合成法自動選択
※この他にも値が定義されていますが、吉里吉里2 version 2.30 RC 1 現在で未実装となっています。

えっと、これってどーゆー意味なの?
ん〜、確かに表を見ただけじゃわかりにくいと思うから、実際にやってみるね。

<各合成法で画像を拡大して重ね合わせた結果>

上の図は 吉里吉里のアイコン画像 を拡大して2つ重ね合わせた時の画像なんだ。
左から順に mode の値を omOpaque(不透明合成)、 omAlpha(アルファ合成)、 omAddAlpha(加算アルファ合成)にした時の画像だよ。
なんか左のだけ背景が黒くなってるね。
左の画像は modeomOpaque にした時の画像で、 吉里吉里のアイコン画像 のアルファ値を無視して合成してるからこんなふうに表示されるんだ。
アルファ値を無視して合成してるって?
今表示してる 吉里吉里のアイコン画像 はこんなふうにメイン画像とマスク画像に分解できるよね。

<メイン画像とマスク画像>

メイン画像の方が表示される画像で、マスク画像の方は不透明度を表してるんだよね。
そうそう。
で、modeomOpaque を指定すると、 アルファ値の情報を持ってるマスク画像の方を無視して、メイン画像の方だけをコピーするの。
※厳密にはメイン画像を完全に不透明な画像であるとみなしてコピーします。
あ、だから背景が黒くなってたんだ。
そ。ちなみに omAlpha(真ん中の画像)と omAddAlpha(右側の画像)はマスク画像も含めて拡大コピーできるよ。
真ん中のと右のっておんなじに見えるんだけど。
見た目にはわからないと思うけど、一応ちょっとだけ違ってるんだ。
また線形補間の時みたいにビミョーに違ってるんだね…
§9.2 参照。
んー、線形補間と低精度線形補間は大体どんな画像でもほぼ同じに見えると思うけど、 omAlphaomAddAlpha はコピー元とコピー先のレイヤの画像によっては全然違ったコピー結果になることもあるよ。
この例だとたまたま違いがほとんど出てないだけ。
そーなの?
omAlphaomAddAlpha の合成法は全然違うからね。
ここでは詳しく説明しないけど、「吉里吉里2 リファレンス」の「グラフィックシステム」の項目とかに詳しいことが載ってるから、 興味があったら見てみてね。
はーい。
あ、そーいえばあともう1つ omAuto っていうのがあったよね?  あれはどうなっちゃったの?
omAuto を指定すると、 3種類の合成法のどれを使うかをコピー元レイヤの状態に応じて自動的に決めてくれるんだ。
へぇ、そうなんだ。便利だね。
ん、だから大抵の場合は omAuto にしててもいいかもね。
デフォルト値も omAuto になってるし。
そだね。
んじゃ次は第11引数の opa だね。
これはどんな引数か大体わかるんじゃない?
opa ってなんか opacity っぽいよね?
ん、そのとーり。
opa は画像をコピーする時の不透明度、 つまり opacity を指定するための引数だよ。
あ、やっぱりそーなんだ。
opa の値を変えると、例えばこんな感じに画像を半透明にして重ね合わせられるんだ。

opa128 に設定して右下の画像を拡大コピーした結果>

右下にある 吉里吉里のアイコン画像 が半透明になってるね。
ん。operateStretch メソッドについては大体こんなとこなんだけど…
だけど?
実は operateStretch メソッドには、 画像を拡大/縮小コピーする時に制約がついちゃうんだよね。
制約って?
stretchCopy メソッドの時は4種類の補間ができたよね。
stNearest(最近傍補間)と stFastLinear(低精度線形補間)と stLinear(線形補間)と stCubic(3次元補間)の4種類だったよね。
§9.2 参照。
そうそう。
これが operateStretch メソッドだと、 基本的に stNearest しか使えないんだ。
※吉里吉里2 version 2.30 RC 1 現在で stFastLinear は特定の条件を満たした場合のみ使用可能で、stLinear, stCubic は未実装(使用不可能)となっています。 詳細は「吉里吉里2リファレンス」の「Layerクラス−operateStretchメソッド」の項目を参照してください。
えっ、そーなの?
それじゃあ画像をキレイに拡大/縮小して重ね合わせることって出来ないの?
んーん、やろうと思えばできるよ。
え、できるの? どーやって?
ちょっとこのスクリプトを first.ks に書き込んで実行してみて。

<線形補間(stLinear)を使って画像を拡大して重ね合わせるスクリプト(first.ksの中身)>

; メッセージレイヤを非表示にします
[position page=fore layer=message0 visible=false]
; 表画面の 0 番の前景レイヤに画像を読み込みます
[image page=fore layer=0 storage="krkr" visible=true]

[iscript]
// 画像を見やすくするため背景レイヤを白色で塗りつぶします
kag.fore.base.fillRect(0, 0, kag.fore.base.width, kag.fore.base.height, 0xFFFFFF);

// 0 番の前景レイヤへの参照を変数 layer0 に代入します
var layer0 = kag.fore.layers[0];

// 拡大後の幅(newWidth)と高さ(newHeight)を計算します
var newWidth = int (layer0.imageWidth * 1.5);
var newHeight = int (layer0.imageHeight * 1.5);

// 親レイヤを 0 番の前景レイヤとして一時レイヤを作ります
var tempLayer = new Layer(kag, layer0);
// 一時レイヤに 0 番の前景レイヤの画像を線形補間を使って拡大コピーします
tempLayer.setImageSize(newWidth, newHeight);
tempLayer.stretchCopy(0, 0, newWidth, newHeight, layer0, 0, 0, layer0.imageWidth, layer0.imageHeight, stLinear);

// 0 番の前景レイヤの幅と高さを調整します
layer0.setImageSize(int (newWidth * 1.5), int (newHeight * 1.5));
layer0.setSizeToImageSize();

// 0 番の前景レイヤを透明色で塗りつぶします
layer0.fillRect(0, 0, layer0.width, layer0.height, 0x00000000);

// 一時レイヤの画像を 0 番の前景レイヤに重ね合わせます
// 1.まず左上に表示する画像を重ね合わせます
layer0.operateRect(0, 0, tempLayer, 0, 0, newWidth, newHeight);
// 2.次に右下に表示する画像を重ね合わせます
layer0.operateRect(int (newWidth * 0.5), int (newHeight * 0.5), tempLayer, 0, 0, newWidth, newHeight);

// 一時レイヤは必要なくなったので無効化します
invalidate tempLayer;
[endscript]

えっと、じゃあとりあえず実行してみるね。
うん。

<実行結果>

ホントだ、キレイに拡大して重ね合わせられてるね!
実はこれ operateStretch メソッドは使ってないんだ。
え、使ってないの?
じゃどうやってるかスクリプトを見ながら説明してくね。
うん。
まず最初の position タグのとこから layer0 に 0 番の前景レイヤへの参照を代入してるとこまでは前回とおんなじだから問題ないよね。
うん、だいじょぶだよ。
あと、その次の newWidthnewHeight を計算してるとこも、 倍率を1.5倍にしてるだけで基本的に前回と同じだから、これも OK だよね?
うん、おっけー。
じゃ次いくね。
ここで一時レイヤ(tempLayer)を作ってるんだけど、 今回は assignImages メソッドじゃなくって、 stretchCopy メソッドを使って 0 番の前景レイヤの画像(拡大前の画像ね)を一時レイヤに拡大コピーしてるんだ。
ホントだ。
これって 0 番の前景レイヤの画像を拡大して、 線形補間(stLinear)を使って一時レイヤにコピーしてるんだよね?
そうそう。
だから前回 stretchCopy メソッドを呼び出した時とは layer0tempLayer が逆になってるわけね。
前回は一時レイヤの画像を 0 番の前景レイヤに拡大コピーしたもんね。
んじゃ次ね。
次は 0 番の前景レイヤのサイズを設定してるんだけど…
幅と高さが newWidthnewHeight の1.5倍になってるね。
これって何で1.5倍になってるの?
こんなふうに、コピー先のレイヤの幅と高さがコピーする画像の幅と高さの1.5倍になるように 吉里吉里のアイコン画像 を2つ重ねて表示してるからだよ。

<画像の重ね合わせ>

上の図で 緑色の四角形 の部分が 0 番の前景レイヤ、つまりコピー先のレイヤを表してて、 まず最初にコピー先のレイヤの左上に1つ目の 吉里吉里のアイコン画像 をコピーして、 それから右下(座標で言うと(0.5*newWidth, 0.5*newHeight) のとこね)に2つ目の 吉里吉里のアイコン画像 をコピーしてるから、コピー先のレイヤの幅と高さはそれぞれ newWidthnewHeight の1.5倍になるワケ。
なるほど、確かにこうやって重ね合わせると幅も高さも1.5倍必要になるね。
これで 0 番の前景レイヤのサイズも設定できたから、 次に画像をコピーしたいとこなんだけど、その前に fillRect メソッドを呼び出してレイヤを透明色で塗りつぶしとかないとね。
fillRect メソッドについては §3.2§3.10 参照。
fillRect メソッド…ってレイヤを塗りつぶすメソッドだよね?
何でここでレイヤを塗りつぶさなくちゃいけないの?
最初に image タグで 0 番の前景レイヤに画像を読み込んだよね。
うん。
最初に読み込んだ画像はまだ 0 番の前景レイヤに残ってるから、 このまま画像を重ね合わせたらマズイでしょ?
え、そーなの?
レイヤを透明色で塗りつぶさずにこのまま画像を重ね合わせたら、 こんなふうに元々あった画像が残ったままになっちゃうからね。

<レイヤを透明色で塗りつぶさずに画像を重ね合わせた結果>

あの左上の方にちょっとだけ見えてるのが元々あった画像?
そ。だからまず画像を消して、それから operateRect メソッドを呼び出して画像を重ね合わせるの。
operateRect メソッド?
operateRect メソッドは画像をそのままの大きさで重ね合わせるメソッドなんだ。
へぇ、そーいうメソッドもあるんだね。
まぁ operateRect メソッドが基本のメソッドで operateStretch メソッドの方が拡張版、みたいな感じだけどね。
あ、そー言われればそーだね。
なんかスクリプトも operateRect メソッドの方がシンプルみたいだし。
ん、operateRect メソッドの方が引数の数も少ないしね。
ちなみにこれが operateRect メソッドの引数だよ。

operateRect メソッドの引数>
引数名引数の意味デフォルト値
第1引数dleftコピー先の四角形の左端の位置
第2引数dtopコピー先の四角形の上端の位置
第3引数srcコピー元のレイヤ
第4引数sleftコピー元の四角形の左端の位置
第5引数stopコピー元の四角形の上端の位置
第6引数swidthコピー元の四角形の幅
第7引数sheightコピー元の四角形の高さ
第8引数mode演算のモードomAuto(自動決定)
第9引数opa演算の強度(不透明度)255

operateRect メソッドの引数は全部 operateStretch メソッドにもあるからわかりやすいんじゃないかな。
ホントだ。
引数の意味も operateStretch メソッドの時とおんなじなの?
ん、全部同じ意味だよ。
operateRect メソッドの mode には前述の4種類の値以外にも様々な値が指定できます。
 詳細は「吉里吉里2リファレンス」の「Layer クラス−operateRect メソッド」の項目を参照してください。
dwidthdheight が無いけど、 コピー先の四角形の幅と高さって……あ、画像をそのままコピーするから dwidthswidth とおんなじで、 dheightsheight とおんなじになるんだ。
ん。あと画像を補間する必要はないから、type も必要ないよね。
だね。
じゃスクリプトの方に戻るけど、 operateRect メソッドを呼び出してるとこは大体わかる?
え〜っと…operateRect メソッドを2回呼び出してるのって、 吉里吉里のアイコン画像 を2つ重ねて表示するからなんだよね?
そだよ。
最初の operateRect メソッドdleftdtop がどっちも 0 になってるから、 0 番の前景レイヤの左上に一時レイヤの画像をコピーしてるのかな?
画像を重ね合わせた結果を見ると、 左上の 吉里吉里のアイコン画像 の方が奥に表示されてて、 右下の 吉里吉里のアイコン画像 は手前に表示されてるよね。
うん、そだね。
2つの画像を重ね合わせると、最初にコピーした画像が奥に表示されて、 2番目にコピーした画像が手前に表示されるから…
そっか、奥にある左上の 吉里吉里のアイコン画像 の方を先にコピーしてて、 手前にある右上の 吉里吉里のアイコン画像 を後からコピーしてるってことになるんだね。
そういうこと。
第3引数〜第9引数までは大丈夫?
えっと、第3引数(src)tempLayer だから一時レイヤの画像をコピーするってことだね。
うんうん。
あと、第4引数(sleft)と第5引数(stop)はどっちも 0 になってて、 第6引数(swidth)と第7引数(sheight)はそれぞれ newWidth, newHeight になってるから、 一時レイヤの画像全体をコピーするってことだよね。
ん、そうだね。
引数が全部で7つしか指定されてないんだけど…?
第8引数と第9引数は省略してるの。
あ、確かに第8引数と第9引数にはデフォルトの値があるね。
第8引数の modeomAuto で、 第9引数の opa255 になってるね。
それぞれどういう意味だったか覚えてる?
modeomAuto だと画像を重ね合わせる方法が自動的に決まって、 opa255 だと不透明度 255 で画像を重ね合わせるってことでしょ。
さすがにこれは覚えてたね。
そりゃさっき聞いたばっかりだもん。
まぁそうだよね。
じゃ次は2つ目の 吉里吉里のアイコン画像 をコピーしてるとこね。
今度は右下にコピーするから第1引数(dleft)と第2引数(dtop)最初にコピーした時と違ってるけど、 これって何で newWidthnewHeight の0.5倍になるの?
この図を見ればわかると思うけど、右下の 吉里吉里のアイコン画像 は 0 番の前景レイヤの左上の点から見ると(newWidth * 0.5, newHeight * 0.5)の位置にあるでしょ。
あ、ホントだ。
つまり、operateRect メソッドを2回呼び出すことでこんなふうに画像をコピーしてるわけね。

operateRect メソッドによる画像のコピー>

これで拡大コピーができたから、あとは必要なくなった一時レイヤを無効化すれば OK。
どう、大体解った?
うーん、operateStretch メソッドを使う時よりちょっとややこしくなってる感じだけど、 やってることは大体理解できたかな。
ん、じゃ今回はこの辺にしとこっか。
は〜い!
それじゃ、また次回ね!


前へ | TOP | 次へ