プログラム講座 中級編5

- PICT画像の白抜きを行う -

 中級編5です。今回は読み込まれたPICT形式(画像)で白の部分を透過させる、つまり背景と合成させるプログラムを作成します。PICT形式の読み込みは初級編2のものを、PICT画像の保存およびオフスクリーンの確保については、中級編3、4を参考にして下さい。ここで使用しているプログラムは初級編2と中級編4で使用したものに手を加えました。このように、後で何回も使い回しができるようにしておくと便利ですしバグも少なく開発効率も良くなります。



◆COPYBITSの転送形式
 ToolBoxの関数COPYBITSにはいくつかの転送モードがあります。以下に転送モードを示します。

都合の良いことに_transparentを指定すると背景色(ここでは白、特に設定しなければ白になります)のピクセルだけ転送しなくなります。つまり背景色以外転送されるので、簡単に白抜きの合成ができるという事です。

 さて、合成するためにはもう一枚余計にオフスクリーンが必要です。今回はoffScreen2&という変数を用意しここに読み込んだPICT画像を表示します。次にoffScreen&の方にCOPYBITSで転送します。これだけで処理はおしまいです。簡単ですね。



◆アップデートイベント
 今回は中級編3、4と違い定期的に画像を書き換えません。ウィンドウを他のウィンドウの下になるように重ね合わせた後に、一番手前に持ってくると、せっかく表示してあった画像が消えてしまっています。
 このようになってしまうとシステムは「ウィンドウリフレッシュ(再描画:通常アップデートイベント)」を要求してきます。このイベントが来たらウィンドウの内容を書き直してやらなければなりません。
 この処理を行っているのが関数doDialogです。アップデートイベントが来たらオフスクリーンからウィンドウに描画してやります。これだけですので、特に複雑なことはありません。ただし、ウィンドウが複数枚ある場合やエディットフィールドがある場合は、処理が複雑になります。ウィンドウを複数枚使用する場合は、ちゃんとした設計をしておいた方がいいでしょう。というかしておくべきです。



◆終わりに
 初級編からこの中級編までで最低限の事は学んだと思います。C言語とかでプログラムすれば面倒なものもFuture BASICではかなり簡単にできるというのが、わかってもらえれば幸いです。本当は本にしてFuture BASIC入門とか書けばいいんですが、それにはまだまだ時間が必要ですね。
 あと、今までの所で「ここがわからない」という所がありましたら、すみませんがメールをいただけると幸いです。
 次回は直接オフスクリーンを操作してみましょう。



◆今回のプログラムリスト
'----------------------------------------------- ' "仮想画面(オフスクリーン)の確保、表示" '----------------------------------------------- DIM offScreen&,offScreen2&,cport&,rect;8 DIM header%(256) END GLOBALS '------------------------------------------------------------- ' "PICTファイルをオープンしてオフスクリーンに描画する" ' "描画する時に白抜きをして以前の画像と合成する" '------------------------------------------------------------- LOCAL FN openPictFile DIM rectPICT;8 f$ = FILES$(_fOpen,"PICT",,vRefNum%) LONG IF f$<>"" OPEN "I",#1, f$,,vRefNum% fileSize& = LOF(1,1) pictHandle& = FN NEWHANDLE(fileSize&+4) LONG IF pictHandle& err = FN HLOCK(pictHandle&) LONG IF err = 0 READ FILE#1, [pictHandle&], fileSize& BLOCKMOVE [pictHandle&]+512,[pictHandle&],fileSize& - 512 err = FN HUNLOCK(pictHandle&) err = FN SETHANDLESIZE(pictHandle&, fileSize&-512) err = FN HLOCK(pictHandle&) rectPICT;8 = [pictHandle&]+_picFrame '---------------------------------------------------- err% = FN NEWGWORLD(offScreen2&,8,rectPICT,0,0,0) LONG IF err% BEEP XELSE CALL SETGWORLD(offScreen2&,0): '"オフスクリーン2に切り替える" CALL DRAWPICTURE(pictHandle&,rectPICT) CALL COPYBITS(#offScreen2&+2,#offScreen&+2,rectPICT,rectPICT,_transparent,0) CALL SETGWORLD(cport&,0): '"ウィンドウに切り替える" CALL DISPOSEGWORLD(offScreen2&): '"使用済みなので廃棄する" END IF '---------------------------------------------------- err = FN HUNLOCK(pictHandle&) END IF err = FN DISPOSHANDLE(pictHandle&) XELSE BEEP END IF CLOSE #1 END IF END FN ' ----------------------------------------------- ' "オフスクリーンを確保する" ' offScreen& = "オフスクリーンのアドレス" ' ----------------------------------------------- CLEAR LOCAL LOCAL FN setOffscreen CALL SETRECT(rect,0,0,320,240): '"320x240の画面を作成" err% = FN NEWGWORLD(offScreen&,8,rect,0,0,0) LONG IF err% BEEP END: ' "多くの場合、メモリ不足" END IF END FN '-------------------------------- ' Copy Offscreen -> Window '-------------------------------- CLEAR LOCAL LOCAL FN transfer CALL SETRECT(rect,0,0,320,240) CALL COPYBITS(#offScreen&+2,#cport&+2,rect,rect,_srcCopy,0) END FN '-------------------------------------------------------- ' "Pict画像の保存" '-------------------------------------------------------- LOCAL FN savePict DEF OPEN "PICT": ' "ファイルタイプをPICTにする" CALL SETRECT(rect,0,0,320,240) saveFile$ = FILES$(_fSave,"保存ファイル名:","名称未設定",volRefNum%) LONG IF LEN(saveFile$) OPEN "O",#1,saveFile$,,volRefNum% CALL SETGWORLD(offScreen&,0): ' "描画側をオフスクリーン側に" savePicture& = FN OPENPICTURE(rect) CALL COPYBITS(#offScreen&+2,#offScreen&+2,rect,rect,_srcCopy,0) CALL CLOSEPICTURE CALL SETGWORLD(cport&,0): ' "描画側を元に戻す" WRITE FILE #1,@header%(0),512: ' "Header Write" bytes& = FN GETHANDLESIZE(savePicture&) err% = FN HLOCK(savePicture&) WRITE FILE #1,[savePicture&],bytes& CLOSE #1 CALL KILLPICTURE(savePicture&) END IF END FN '-------------------------------------------------------- ' "メニューの構築" '-------------------------------------------------------- LOCAL FN initMenu 'File Menu MENU 1,0,_enable,"ファイル" MENU 1,1,_enable,"/Opictファイルを開く..." MENU 1,2,_enable,"/S保 存" MENU 1,3,_enable,";" MENU 1,4,_enable,"/Q終 了" END FN '--------------------------------------------- LOCAL FN doMenus menuID = MENU(_menuID) itemID = MENU(_itemID) SELECT menuID CASE 1 : ' File Menu SELECT itemID CASE 1: FN openPictFile FN transfer CASE 2: FN savePict CASE 4: ' Quit... CALL DISPOSEGWORLD(offScreen&) END END SELECT END SELECT MENU END FN '-------------------------------------------------------- ' "アップデートなどのイベントを取得する" '-------------------------------------------------------- LOCAL FN doDialog evnt = DIALOG(0) id = DIALOG(evnt) SELECT evnt CASE _wndRefresh FN transfer: '"アップデートイベントなので画面を再描画がする" END SELECT END FN WINDOW OFF WINDOW #1,"Main Screen",(16,45)-(16+320,45+240),_dialogMovable CALL GETPORT(cport&): ' "ウィンドウのグラフポートを確保しておきます" ON MENU FN doMenus ON DIALOG FN doDialog FN initMenu FN setOffscreen DO HANDLEEVENTS UNTIL theProgramEnds END