mieki256's diary



2024/02/04() [n年前の日記]

#1 [basic] FreeBASICでexeに画像バイナリを含めたい。その2

_昨日、 の実験の続き。FreeBASICで生成した実行形式ファイル(exeファイル)の中に、画像のバイナリデータを含めてしまって、それをウインドウに描画したい。

環境は Windows10 x64 22H2 + FreeBASIC 1.10.1 32bit。

調べた範囲では、方法は4つある。昨日メモした内容を再度メモ。
リソースファイル利用、bin2bas利用、asm記述の利用については昨日試した。asm記述の利用だけは上手く行かなかったけど…。

今回は、バイナリファイルをオブジェクトファイルに変換してリンカで結合する方法を試してみた。

オブジェクトファイル化して結合する方法 :

以下で詳しく説明されてた。ありがたや。

_How to embed any binary file into your FB executable - freebasic.net

まずは、バイナリファイルのオブジェクトファイル化。MinGW や MSYS2 についてくる ld.exe、または、objcopy.exe を利用して、バイナリファイル、 _image_png.png を、オブジェクトファイル image_png.o に変換する。
ld -r -b binary -o image_png.o image_png.png

or

objcopy -I binary -O elf32-i386 -B i386 image_png.png image_png.o


これを、.bas と一緒にして、FreeBASIC でコンパイルする。
fbc loadpngld.bas image_png.o


.bas のソースは以下。

_loadpngld.bas
' 画像読み込み用ライブラリ FBImage を使う
#include once "FBImage.bi"

' カレントディレクトリを exeファイルのある場所にする
chdir exepath()

' リンクしたバイナリオブジェクトの先頭アドレスと終了アドレス
#If defined( __FB_WIN32__ ) And Not defined( __FB_64BIT__ )
' Windows 32bit
extern image_png_png_start alias "binary_image_png_png_start" as byte
extern image_png_png_end alias "binary_image_png_png_end" as byte
#Else
' Windows 64bit and other
extern image_png_png_start alias "_binary_image_png_png_start" as byte
extern image_png_png_end alias "_binary_image_png_png_end" as byte
#endif

' デスクトップ解像度を指定
Dim As Integer scrw = 512
Dim As Integer scrh = 288

' ウインドウサイズと色深度(bpp)を指定
screenres scrw, scrh, 32

' バイナリデータの先頭アドレスとサイズを取得
dim as byte ptr imgdata = @image_png_png_start
dim as Integer imgdata_length = @image_png_png_end - @image_png_png_start

' メモリ上にある画像データを FBImage で読み込む。ポインタとバイト数を渡す
var img = LoadRGBAMemory(imgdata, imgdata_length)

' 画像を描画。RGB=(255, 0, 255) のピクセルは透明色として扱う
Put (16, 16), img, TRANS

' キー入力があるまで待ち続ける
sleep

' 画像を使い終わったので破棄
ImageDestroy img


生成された loadpngld.exe を実行したら、ウインドウ内にpng画像が描画された。

loadpngld_ss.png


ということで、この方法でも画像データを exe に内包して利用できると分かった。

ただ、この方法は、ld か objcopy が必要になる点がちょっと厳しいかもしれない。MinGW や MSYS2 をインストールしてある環境なら、 _GNU Binutils パッケージ をインストールして ld や objcopy を使えるけれど、FreeBASIC しかインストールしてない環境ではオブジェクトファイル化が難しいだろうなと…。


少し解説。

ld もしくは objcopy を使って、バイナリファイルをオブジェクトファイル化すると、そのオブジェクトファイルにはいくつかのシンボルが入ってる。objdump -t hoge.o でシンボルを確認できる。
> objdump -t image_png.o

image_png.o:     file format pe-i386

 SYMBOL TABLE:
[  0](sec  1)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 _binary_image_png_png_start
[  1](sec -1)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x0000c4a8 _binary_image_png_png_size
[  2](sec  1)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x0000c4a8 _binary_image_png_png_end

hoge.png というファイルをオブジェクト化したなら、以下のようなシンボルになる。
  • 開始アドレスを示すシンボルは _binary_hoge_png_start に。
  • 終了アドレスを示すシンボルは _binary_hoge_png_end に。
この2つのシンボルを頼りにして(?)、FreeBASIC側からアクセスすればいい。

注意点。FreeBASIC が32bitか、64bitかで、FreeBASICからアクセスする際のシンボル名が微妙に変わるらしい。32bit版は、先頭の「_」が無くなるのだとか。
32bit:
binary_image_png_png_start
binary_image_png_png_end

64bit:
_binary_image_png_png_start
_binary_image_png_png_end


FreeBASIC側の仕様についてもメモ。

  • __FB_WIN32__ は、Windows上でコンパイルする際に定義されるシンボル。
  • __FB_64BIT__ は、64bitアプリとしてコンパイルする際に定義されるシンボル。
___FB_WIN32__
___FB_64BIT__

#ifdef - #else - #endif を使えば、Windowsとそれ以外、64bitとそれ以外、といった具合に条件を分けてコンパイルできる。

_条件付きコンパイル


FreeBASICでは、シンボル?の前に「@」がつくと、アドレスを示す値になるらしい。あちこちのソースに出現していて、これは一体何だろうと思ってた…。また、ptr はポインタ変数であることを示してる。

_演算子 @ (のアドレス)
_POINTER | PTR

以上です。

過去ログ表示

Prev - 2024/02 - Next
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project