HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2012
0901
GrapeColor(DION)PNGの画像の様に合成29解決


GrapeColor(DION)

リンク

2012/9/1(Sat) 15:29:48|NO.48990

PNGやGIFは透明部分と画像の部分の境がギザギザにならないように半透明なドットを使って処理されていますよね。
HSPにそのような画像を合成したい場合、picloadでいちいちPNGを合成していては非効率です。
PNGのような綺麗な合成を一回の読み込みで、その後何回も合成するにはどうすればいいでしょうか?



この記事に返信する


774

リンク

2012/9/1(Sat) 20:58:48|NO.48998

>一回の読み込みで、その後何回も合成する
ご自身で答えを出してます。
bufferで作成した画面に画像を保持して置けば可能です。
非効率だと感じられる恐らく99%以上はファイルからの読み込み処理です。

使用中でない画像を保持する事を非効率と感じられるかも知れませんが
通常のソフトでも表示画面の数倍程度の画像バッファは普通に扱います。
音声に比べれば微々たる物です。

アルファブレンド合成に関してですが、gmode7を利用するのであれば
予め画像を加工しておく・αチャンネルを取り出せるプラグインの導入等が必要になると思います。
Dishなら32bitPNGも扱えるそうですので、そのままできるのかも知れませんが…



FunnyMaker

リンク

2012/9/1(Sat) 23:52:24|NO.49002

PNGファイルから色の情報とアルファ値の情報を別々に読み込んでどこか(適当なバッファ
ウィンドウ?)へストックしておき、必要に応じてそれらからgmode7辺りを使って合成する
ということがしたいということでしょうか?

もしそうであればプラグインとかを使うことになのではないでしょうか?
といいながら、すみませんが私も見当がつきません。(アドバイスになっていませんねこれはw)



匿名希望

リンク

2012/9/2(Sun) 00:45:33|NO.49003

・artlet2dを利用する
・ゲーム等、速度が必要であればDirectXを利用する(HGIMG3等)



FunnyMaker

リンク

2012/9/2(Sun) 10:52:27|NO.49008

上手くいったので投稿します。これでどうですかね。

まず、Wikipediaで「PNG」を検索し、サイコロのPNG画像ファイル(2枚
見えると思いますが、背景が市松模様になっていない方です)をDLします。
この画像は800x600になっています。ファイル名はそのままでOKです。
そして、何か適当な画像(私は自分のDesktopのスクショを使いました)
を800x600で用意し、「無題.bmp」で保存してください。

それら2枚の画像を同じディレクトリに保存し、その中にhspのスクリプト
ファイルを作成し、以下のコードを貼り付けて実行してみてください。
「picload」命令でPNGを読み込んだときと同様に合成されるはずです。

私はファイルをインターネット上にアップロードする方法が分からないので
あなたにこのような手間をかけるようなことになってしまいました。
申し訳ありません。



*start screen 0,1600,600,0 color 0,0,0 : boxf 0,0,799,599 color 255,255,255 : boxf 800,0,1599,599 pos 0,0 : picload "PNG_transparency_demonstration_2.png",1 pos 800,0 : picload "PNG_transparency_demonstration_2.png",1 screen 1,800,600,0 gmode 0,800,600 : pos 0,0 : gcopy 0,800,0 gmode 6,800,600,256 : pos 0,0 : gcopy 0,0,0 screen 2,1600,600,0 color 255,255,255 : boxf 800,0,1599,599 gmode 6,800,600,256 : pos 800,0 : gcopy 1,0,0 color 0,0,0 : boxf 0,0,799,599;ここのcolorは黒が良い。 pos 0,0 : picload "PNG_transparency_demonstration_2.png",1 screen 3,800,600,0 pos 0,0 : picload "無題.bmp",1 gmode 7,800,600 : pos 0,0 : gcopy 2,0,0 ;picloadの場合と比べてみよう wait 400 pos 0,0 : picload "無題.bmp",1 pos 0,0 : picload "PNG_transparency_demonstration_2.png",1


何が起こっているか分かるようにあえて可視ウィンドウで行いました。

原理を説明します。

と言っても私には数学的に厳密な説明は出来ませんのでご了承を。
結論から言うと、PNG画像ファイルから色の情報とアルファ値の情報を
別々に取得することになります。が、すべて標準命令でいけます。
まず、ターゲットのPNG画像を「画像A」とし、これを、黒を背景とした場合と、
白を背景とした場合の2つの場合でpicloadでロードします。
この時の描画結果の違いから各ピクセルの元のアルファ値を求めるのです。
2枚の画像が用意できたら、白を背景とした方の画像から、gmode6のブレンド率256
で色減算コピーを使って、黒を背景にした画像の方を貼り付けます。
こうすることで、画像Aのアルファ値のマップが、アルファ値が大きい部分ほど
黒に近くなって出来上がります。
これを新たな真っ白なスペースにgmode 6のブレンド率256で色減算コピーすることで
色の反転が起き、黒白が入れ替わります。つまりgmode7で利用する形式のアルファブ
レンド成分になります。
この画像の左側に目的のPNG画像ファイルをもう一度読み込みます。この時背景色は何でも
かまいません。
こうすると、gmode7用のセットが完成するわけです!
あとはこれをバッファウィンドウ上に保存しておけばいいのです。



FunnyMaker

リンク

2012/9/2(Sun) 10:55:50|NO.49009

間違いに気づきました。
記事49008の最後から4〜3行目にある「この時背景色は何でもかまいません。」は誤りです。
背景色は黒でなくてはなりません。



GrapeColor(DION)

リンク

2012/9/2(Sun) 14:15:14|NO.49013

>>FunnyMakerさん
FunnyMakerさんに貼って頂いたスプリクトを試してみました。
普通にpicloadして合成した場合と、FunnyMakerさんの方法で合成した場合ですが、
比べてみると若干色が違います。
picloadで合成した場合、元の画像に忠実な色で合成されますが、FunnyMakerさんの方法の場合、元の画像より若干濃い目の色で合成されてしまいます。
これは何故なのでしょうか。



GENKI

リンク

2012/9/2(Sun) 14:31:44|NO.49014

このモジュール使ってgmonde 7で合成ってのはどうでしょうか?
http://d.hatena.ne.jp/As_hsp/20091213/1260714763



FunnyMaker

リンク

2012/9/2(Sun) 16:37:18|NO.49015

>FunnyMakerさんに貼って頂いたスプリクトを試してみました。
>普通にpicloadして合成した場合と、FunnyMakerさんの方法で合成した場合ですが、
>比べてみると若干色が違います。
>picloadで合成した場合、元の画像に忠実な色で合成されますが、FunnyMakerさんの方法の場合、元の画像より若干濃い目の色で合成されてしまいます。
>これは何故なのでしょうか。

すみません。作った本人である私が気づいていませんでした。
あなたの言う通り確かに若干色黒になりました。
ちなみに、合成される時に、下地の画像については色が黒に近い部分ほど合成結果がpicloadの時と近くなるようです。
原因を調べてみます。



FunnyMaker

リンク

2012/9/2(Sun) 16:53:19|NO.49016

原因がわかりました。
前回のスクリプト15行目のcolor 0,0,0 をcolor 128,128,128に変えたところ、完璧になったように思えます。
前回と同じ要領で以下のスクリプトを実行してみてください。


改善できたとはいえ、私には理論的には原因がわかりません。128 が 0〜256 の中間の値であるからでしょうか。


*start screen 0,1600,600,0 color 0,0,0 : boxf 0,0,799,599 color 255,255,255 : boxf 800,0,1599,599 pos 0,0 : picload "PNG_transparency_demonstration_2.png",1 pos 800,0 : picload "PNG_transparency_demonstration_2.png",1 screen 1,800,600,0 gmode 0,800,600 : pos 0,0 : gcopy 0,800,0 gmode 6,800,600,256 : pos 0,0 : gcopy 0,0,0 screen 2,1600,600,0 color 255,255,255 : boxf 800,0,1599,599 gmode 6,800,600,256 : pos 800,0 : gcopy 1,0,0 color 128,128,128 : boxf 0,0,799,599;ここのcolorは128,128,128が良い。 pos 0,0 : picload "PNG_transparency_demonstration_2.png",1 screen 3,800,600,0 pos 0,0 : picload "無題.bmp",1 gmode 7,800,600 : pos 0,0 : gcopy 2,0,0 ;picloadの場合と比べてみよう screen 4,800,600,0 pos 0,0 : picload "無題.bmp",1 pos 0,0 : picload "PNG_transparency_demonstration_2.png",1



FunnyMaker

リンク

2012/9/2(Sun) 16:56:02|NO.49017

すみません。上記スクリプトの

「PNG_transparency_demonstration_2.png」

という記述をすべて

「PNG_transparency_demonstration_1.png

に書き換えてください。



GrapeColor(DION)

リンク

2012/9/2(Sun) 17:57:02|NO.49018

>>FunnyMakerさん
私の環境ではcolor 64, 64, 64でちょうど同じ感じになりました。
しかし、画像の端のグラデーションの部分の色が微妙に違います。
色々試して頂いているにも関わらずケチをつけてしまい、申し訳ありません。



osakana

リンク

2012/9/2(Sun) 18:32:01|NO.49023

HSPの標準命令だけでやるなら
memfile を使うのが手軽だと思います。

dialog "", 16 if stat = 0 :end pngfile = refstr exist pngfile if strsize = -1 :end alloc pngdata, strsize bload pngfile, pngdata, strsize memfile pngdata pos 0, 0 picload "MEM:dummy.png", 1
picloadを使っているので表示結果も同じはずです



GrapeColor(DION)

リンク

2012/9/2(Sun) 19:11:31|NO.49025

>>osakanaさん
そんな方法があったんですね!
ところでその方法でpicloadした場合、ファイルから直接読み込むより2回以降のpicloadの処理は軽いのですか?



てれてれ

リンク

2012/9/2(Sun) 19:14:33|NO.49026

そのくらい自分で確めればいいのに・・・



GrapeColor(DION)

リンク

2012/9/2(Sun) 20:07:48|NO.49028

>>てれてれさん
自分で計測した結果、メモリーにストックしてもしなくても速度が全く同じだったので一応聞いてみたのです・・・。
誤解を招いてしまい本当に申し訳ありませんでした。



osakana

リンク

2012/9/2(Sun) 21:11:51|NO.49035

自分の環境ではmemfileを使った方が2倍強ほど高速でしたが
環境によって変わってくるんですかね。

>picloadでいちいちPNGを合成していては非効率です。
>PNGのような綺麗な合成を一回の読み込みで、その後何回も合成するにはどうすればいいでしょうか?

それでも一応この条件を満たすと思ったのですが、
ただ単にもっと表示を早くしたいと言う事だったのでしょうか?
ちなみに自分の環境では
gmode 7 + gcopy を使ったほうが、
memfile + picload よりも20倍程高速でした。



GrapeColor(DION)

リンク

2012/9/2(Sun) 21:43:10|NO.49037

そういえばgmode 7の使い方がイマイチ理解できないのですが、
bufferに合成したい画像を用意し(背景を黒にして(?))、その隣に背景画像を色反転させたものを用意して、
合成したい画面に背景を貼って、gcopyすんですよね?
もしよければ解説してください。
gmode 7のサンプルは一応確認しましたが理解できませんでした。



てれてれ

リンク

2012/9/2(Sun) 21:51:49|NO.49039

>49028
あら、それは失礼しました!



てれてれ

リンク

2012/9/2(Sun) 21:53:29|NO.49040

少し逸れますが、先ほど更新されたコンテスト作品に面白いものが・・・
http://dev.onionsoft.net/seed/info.ax?id=122



GrapeColor(DION)

リンク

2012/9/2(Sun) 21:55:54|NO.49041

>>てれてれさん
これは興味深い!
ちょっと試してみます



GrapeColor(DION)

リンク

2012/9/2(Sun) 22:20:44|NO.49048

紹介していただいたソフトを使用したのですが、FunnyMakerさんに作って頂いたプログラムと同じ結果になってしまいました。
もしかしてバグなんですかねこれって。



FunnyMaker

リンク

2012/9/2(Sun) 23:03:27|NO.49051

ご存じかと思いますが、「PNG2Gmode7」は私、「FunnyMaker」が作成いたしました。
GrapeColor(DION)さんのおっしゃる通り、このソフトは完全ではありません。
その旨をソフトに表記し忘れていましたので、誤解を招かぬよう、追記したいと思います。
迷惑を掛けてしまいました。すみません。



GrapeColor(DION)

リンク

2012/9/2(Sun) 23:20:26|NO.49053

>>FunnyMakerさん
いえ、私は別にFunnyMakerさんのソフトに対して言ったのではなく、gmodeに対してです。
誤解を招いてしまい本当に申し訳ないです。



osakana

リンク

2012/9/2(Sun) 23:37:49|NO.49054

こっちで用意した小さいpngファイルだと2倍ほど早かったんですが
サイコロの画像をダウンロードして測ってみたら1.05倍早くなるだけでした。
どうやらpicloadでpngを表示する処理自体が遅い様?

FunnyMakerさんのNO.49016でのスクリプトでも、
NO.49014でGENKIさんが紹介しているAsさんのモジュールでも、
ダイスの画像で試してみるとpicloadで表示した結果とは
若干色が変わってしまう見たいです。

プラグインを使って良いのなら
imgctl.dllでアルファ値を取得出来たと思います。
それで良いならスクリプト出しましょうか?



FunnyMaker

リンク

2012/9/2(Sun) 23:46:54|NO.49055

>GrapeColor(DION)さん

実は、gmodeにはバグ(または仕様か?)あります。

画像Aがあります。これらを重ならないように2枚ロードして用意します。
一方をA1,他方をA2とします。
A1に対してA2をgmode4で半透明コピーすると、理論上変化がないはずなのですが、(「ブレンド」ですからね)実際は
僅かに暗くなります。(R,G,Bで言えばそれぞれ-2ずつくらい。画像によってまちまち。法則性を見いだせなかった)

これはgmode5,6,7すべてにおいて同様です。私としては原因はRGB値の計算過程で循環小数をうまく扱えてい
ないからではないかと勝手に考えております。

但し、例外があって ブレンド率が 0 または 256 の時のみ正常にコピーされます。当然ですが。
(前者はコピーを実行しないことと同値で、後者はgmode0と同値ですから。 )
gmode7の場合ですとアルファブレンド成分が (R,G,B) = (0,0,0),(255,255,255)の時は正常にコピーされます。
上と同じ理由です。

従ってgmode7は白黒はっきりしている場合はたとえるならクッキーとかの「型抜き」の型としてはまともに使えます。



GrapeColor(DION)

リンク

2012/9/3(Mon) 00:05:53|NO.49057

>>osakanaさん
試してみたいのでお願いします。



osakana

リンク

2012/9/3(Mon) 00:38:48|NO.49058

>GrapeColorさん

今日はもう遅いので明日(3日)
書き込みます。



osakana

リンク

2012/9/3(Mon) 21:46:42|NO.49087

アルファチャンネル付きの png ファイルを imgctl を使って読み込み
gmode 7 + gcopy のピクセルアルファブレンドコピーで表示するスクリプトです。
実行するには imgctl の dll 版をダウンロードして
スクリプトと imgctl.dll を同じフォルダに入れて実行してください。
ダウンロードはルーチェさんのページから:http://www.ruche-home.net/

#uselib "imgctl.dll" #cfunc PNGtoDIB "PNGtoDIB" str #cfunc PNGAtoDIB "PNGAtoDIB" str #func DIBtoDC "DIBtoDC" int, int, int, int, int, int, int, int, int #func HeadDIB "HeadDIB" int, var #func DeleteDIB "DeleteDIB" int #define SRCCOPY $00CC0020 dialog "", 16 if stat = 0 :end filepath = refstr ; PNG画像オンリー hdib_main = PNGtoDIB(filepath) hdib_alpha = PNGAtoDIB(filepath) if hdib_alpha = 0 :dialog "アルファ値無し" :end HeadDIB hdib_main, pbmih dupptr biWidth, varptr(pbmih) + 4, 4, 4 dupptr biHeight, varptr(pbmih) + 8, 4, 4 screen 1, biWidth * 2, biHeight DIBtoDC hdc, 0, 0, biWidth, biHeight, hdib_main, 0, 0, SRCCOPY ; 0, 0 の位置にメイン画像を表示 DIBtoDC hdc, biWidth, 0, biWidth, biHeight, hdib_alpha, 0, 0, SRCCOPY ; biWidth, 0 の位置にαチャンネルのマスクを表示 DeleteDIB hdib_main DeleteDIB hdib_alpha redraw 1 screen 0, biWidth, biHeight gmode 7, biWidth, biHeight gcopy 1, 0, 0, biWidth, biHeight
作っている物によりますが
これだけのためにプラグインを使うなら
色が若干変わっても妥協するという選択肢もあると思います。



GrapeColor(DION)

リンク

2012/9/3(Mon) 22:45:12|NO.49093

>>osakanaさん
これは!
まさに完璧です。
速度も申し分ないです!
これにて解決とさせていただきます。



ONION software Copyright 1997-2023(c) All rights reserved.