プログラム講座 中級編4
- オフスクリーンをPICT形式で保存する -
中級編4です。今回はオフスクリーン(仮想画面)に書かれた内容(画像)をPICT形式で保存してみましょう。
◆PICT形式とは
PICT形式(PICTフォーマット)はMacintoshの標準画像形式です。Windows ならばBMPといった画像形式があります。他にもTIFF, EPSなどがありますが、PICTはMac専用の画像形式と言ってもいいでしょう。そのため、他の機種でPICT画像を表示させようとすると、かなり苦労します。
PICT形式を説明すると長くなってしまいますし、中級編の範囲を超えてしまいますので、概略だけを説明します。
◆PICT形式の構造
PICT形式は先頭に512バイト、そしてその次に「オプコード」と呼ばれるデータ参照コードが続きます。オプコードが00FFHならばエンド、0001なら云々という具合に全て定義されていてインサイドマック、またはグラフィックファイルフォーマット(アスキー出版)などの本にそのコードが掲載されています。
問題は、そのオプコードで全部インサイドマックを見ながら、頭をかかえて書き出すような事をするのか、どうか?と言った部分でしょう。Mac以外の機種ではこのようにオプコードを解析して表示させたり保存するのですが、Macの場合は「PICTハンドル」さえあれば書き出す事ができます。
幸いにしてFuture BASICには、PICT形式で保存するサンプルプログラムが掲載されています。でも、よく見ると読み込んだPICTハンドルをそのまま書き出しているだけで、これでは画像にエフェクトをかけたりユーザーが描いた画像を保存するような事ができません。
PICTハンドルを取得するにはFuture BASICの命令にあるPICTURE ON, PICTURE OFFを使用するか、直接ToolBox(QuickDraw)を呼び出す方法があります。はっきり言って、どっちを使っても行数も変わりませんし手間も変わりません。せっかくですから、ToolBoxを使ってみましょう。
◆前回(その3)のプログラムに保存機能を付ける
1から作るのも面倒なので前回(その3)で使ったプログラムに保存機能を付けてみましょう。前回のプログラムは直接オフスクリーンに描画させているので、丁度よいサンプルですね。
まずは実際のプログラムを見てみましょう。
'--------------------------------------------------------
' "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)
COLOR _zWhite
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
色を変えてある部分が今回のポイントです。赤色がオフスクリーンからPICTハンドルを求めるところです。その中にある
savePicture& = FN OPENPICTURE(rect)
は、これ以降呼び出されるQuickDrawによる描画をsavePicture&ハンドルに記録して、という命令です。この命令が出されるとCALL CLOSEPICTURE命令が見つかるまでメモリの内部に描画方法(これがオプコード&データ)を記録していきます。
オフスクリーンの内容をそのままオフスクリーンに転送しています。こうするだけで自動的にオフスクリーンの内容が記録されます。やり方がわかれば簡単ですね。
◆PICT形式の書き出し
PICTハンドルが用意できれば後はFuture BASICのマニュアルにあるサンプルどおりにやるだけです。(ハンドブックの309ページに掲載されています)
まず、512バイトの空ヘッダーを書き出します。@header%(0)は配列header%の0番目(一番最初)のアドレス(@:アットです←という覚えやすい具合になってます^^;)を示します。そこから512バイトファイルに書き出します。
あとはbytes& = FN GETHANDLESIZE(savePicture&)で記録されたPICTのハンドルサイズを求めてファイルに書き出すだけです。
◆終わりに
やり方がわからなくてNiftyServeのホームパーティ上で質問し、快く回答して下さった後藤寿庵さんに感謝します。
PICT画像を解析して表示するプログラムならMZ-2861で作成したので原理は分かっていたのですが、こういう手軽なやり方があるとは知りませんでした。
PICT形式で保存できるようになりましたので、次回はPICT画像を読み込んで「白い部分だけ透過させて合成していく」プログラムを作成してみましょう。
◆今回のプログラムリスト
'-----------------------------------------------
' "仮想画面(オフスクリーン)の確保、表示"
'-----------------------------------------------
DIM offScreen&,cport&,rect;8
DIM header%(256)
END GLOBALS
' -----------------------------------------------
' "オフスクリーンを確保する"
' 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
'--------------------------------------------------------
' Display Character
'--------------------------------------------------------
LOCAL FN drawChar
c = RND(256)
x1 = RND(320)
y1 = RND(240)
x2 = RND(320)
y2 = RND(240)
CALL SETRECT(rect,x1,y1,x2,y2)
CALL SETGWORLD(offScreen&,0): ' "描画側をオフスクリーン側に"
COLOR c
CALL PAINTOVAL(rect)
CALL SETGWORLD(cport&,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,"/S保 存"
MENU 1,2,_enable,";"
MENU 1,3,_enable,"/Q終 了"
END FN
'---------------------------------------------
LOCAL FN doMenus
menuID = MENU(_menuID)
itemID = MENU(_itemID)
SELECT menuID
CASE 1 : ' File Menu
SELECT itemID
CASE 1:
FN savePict
CASE 3: ' Quit...
CALL DISPOSEGWORLD(offScreen&)
END
END SELECT
END SELECT
MENU
END FN
WINDOW OFF
WINDOW #1,"Main Screen",(16,45)-(16+320,45+240),_dialogMovable
CALL GETPORT(cport&): ' "ウィンドウのグラフポートを確保しておきます"
ON MENU FN doMenus
FN initMenu
FN setOffscreen
DO
HANDLEEVENTS
FN drawChar
FN transfer
UNTIL theProgramEnds
END