gtkmm には画像を表示するためのウィジェット Gtk::Image があります。Gtk::Image はアニメーション GIF にも対応しているので、 アニメーション GIF ファイルを読み込むだけで簡単にアニメーションを実現することができます。
Gtk::Image にはいくつかのコンストラクタがあります。
Gtk::Image(const std::string& file)
Gtk::Image(const Glib::RefPtr<Gdk::Pixbuf>& pixbuf)
Gtk::Image(const Glib::RefPtr<Gdk::PixbufAnimation>& animation)
ファイルパス文字列を引数に取るコンストラクタの使い方は簡単です。このコンストラクタはアニメーションと非アニメーションの両方に対応しており、 指定されたファイルの中身に応じて自動的に、 非アニメーション (Gdk::Pixbuf) とアニメーション (Gdk::PixbufAnimation) を使い分けてくれます。画像を外部ファイルから読み込むのであればこのファイルパスを指定するコンストラクタで充分です。
しかし、 画像を外部ファイルから読み込むのではなく、 実行ファイル内のリソースとして画像を読み込みたいということもありますよね。そのときは、 Glib::RefPtr<Gdk::Pixbuf>
または Glib::RefPtr<Gdk::PixbufAnimation>
を引数に取るコンストラクタを使うことになります。
JPEG や PNG を使うときには Glib::RefPtr<Gdk::Pixbuf>
を引数にとるコンストラクタを使います。アニメーション GIF を使うときには Glib::RefPtr<Gdk::PixbufAnimation>
を引数にとるコンストラクタを使います。Gdk::Pixbuf
、 Gdk::PixbufAnimation
は自分で用意する必要があります。
Gdk::Pixbufの作り方
まず、 JPEG や PNG など非アニメーション画像を実行ファイル内部から読み込む方法を説明します。
Gdk::Pixbuf
には create_from_
で始まるスタティック関数がいくつかあります。
create_from_file(const std::string& filename)
create_from_inline(int data_length, const guint8* data, bool copy_pixels = false)
create_from_file
は外部ファイルを読み込んで Gdk::Pixbuf
を作成する関数です。create_from_inline
はバイト列 (unsigned char
の配列) から Gdk::Pixbuf
を作成する関数です。この create_from_inline
関数を使えば外部ファイルから読み取ることなく、 実行ファイル内のリソース (バイト配列) から画像を作成することができます。
Gdk::Pixbuf用のバイト配列の作り方
GTK+には gdk-pixbuf-csource
というコマンドが付属しています。この gdk-pixbuf-csouce
を使って画像ファイルを C 言語のソースコードに変換することができます。
たとえば、 sample.png
という画像ファイルを変換する場合は以下のようにします。
gdk-pixbuf-csource --raw --name=sample_png sample.png > sample.png.h
これで、 sample.png.h
というファイルが出力されます。拡張子は .h
ではなく .c
としてもいいかもしれません。このファイルの中身は以下のようになっています。
sample.png.h/* GdkPixbuf RGBA C-Source image dump */
#ifdef __SUNPRO_C
#pragma align 4 (sample_png)
#endif
#ifdef __GNUC__
static const guint8 sample_png[] __attribute__ ((__aligned__ (4))) =
#else
static const guint8 sample_png[] =
#endif
{ ""
/* Pixbuf magic (0x47646b50) */
"GdkP"
/* length: header (24) + pixel_data (262144) */
"¥0¥4¥0¥30"
/* pixdata_type (0x1010002) */
"¥1¥1¥0¥2"
/* rowstride (1024) */
"¥0¥0¥4¥0"
/* width (256) */
"¥0¥0¥1¥0"
/* height (256) */
"¥0¥0¥1¥0"
/* pixel_data: */
"¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377"
"¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377"
<div class="vspace" data-length="0" style="margin-block-start:-1px;height:1px"></div>
(途中省略)
"¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377"
"¥377¥377¥377¥377¥377¥377¥377¥377¥377¥377"};
ifdef
などの分岐があって複雑に見えますが、 static const guint8 sample_png[] = {...};
でバイト列を sample_png
という変数に設定しているだけです。
- 注意
gdk-pixbuf-csource
の変換結果は画像ファイルのバイト列そのままではなく、Glib::Pixbuf
として読み込むための専用形式になります。
バイト列をGdk::Pixbufに読み込む
gdk-pixbuf-csource
で作成したファイル sample.png.h
を #include
すると、 sample_png
変数を参照できます。この sample_png
変数を create_from_inline
関数に指定します。
sample.png.hを読み込む#include "img/sample.png.h"
Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_inline(-1, sample_png);
create_from_inline
関数の第 1 引数にはバイト配列の長さを指定しますが、 -1
を指定することもできます。
Glib::RefPtr<Gdk::Pixbuf>
が作成できたら、 あとは Gtk::Image
のコンストラクタ引数で指定するか、 もしくは set
関数で指定するだけです。
コンストラクタでGlib::RefPtrを指定する Gtk::Image image(pixbuf);
もしくは
set関数でGlib::RefPtrを指定する Gtk::Image image;
image.set(pixbuf);
非アニメーション画像を実行ファイル内のリソースとして保持して読み込む手順は以上です。
サンプルプログラム
PNG 画像を実行ファイル内リソースから読み込むサンプルプログラムのソースコードをダウンロードできます。
Gdk::PixbufAnimationの作り方
続いて、 アニメーション GIF を実行ファイル内にリソースとして保持する方法を説明します。
Gdk::Pixbuf
には create_from_inline
というバイト列を指定して読み込む関数がありましたが、 残念なことに Gdk::PixbufAnimation
には create_from_inline
関数がありません。(Gdk::PixbufAnimation
には create_from_file
関数しかありません。)
代わりに、 Gdk::PixbufLoader を使用してバイト列から Gdk::PixbufAnimation
を作成します。
Gdk::PixbufLoader
には write
というバイト列を読み込む関数があります。この関数に指定するバイト列は Gdk::Pixbuf::create_from_inline
とは形式が異なることに注意してください。create_from_inline
関数には gdk-pixbuf-csource
コマンドで作成したピクセルデータのバイト配列を指定しましたが、 Gdk::PixbufLoader
の write
関数には画像ファイルのバイト列そのものを指定する必要があります。
Gdk::PixbufAnimation用のバイト配列の作り方
Gdk::PixbufAnimation
をバイト列から作成するためにGdk::PixbufLoader
を使うGdk::PixbufLoader
はgdk-pixbuf-csource
で作成したバイト列を受け取れない
ということで、 Gdk::PixbufLoader
で処理できるバイト列 (画像ファイルのバイナリーそのもの) を作成します。
バイナリーファイルを C 言語のソースコードとして取り込むのに xxd コマンドが使えます。
- Windowsでxxdを使う
- xxd コマンドは MSYS2 の vim に含まれています。MSYS2 MinGW を使っている場合には、 vim パッケージをインストールすることで xxd コマンドが使えるようになります。
$pacman -S vim
たとえば、 sample.gif
というアニメーション GIF ファイルを変換する場合は以下のようにします。
xxd -i sample.gif > sample.gif.h
xxd
コマンドに -i
オプションを指定することで C 言語ソースコードにインクルード可能な形式になります。出力されたファイル sample.gif.h
の中身は以下のようになっています。
sample.gif.hunsigned char sample_gif[] = {
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x00, 0x01, 0x00, 0x01, 0xa5, 0x1f,
0x00, 0xff, 0xff, 0xff, 0xf7, 0xf7, 0xf7, 0xef, 0xef, 0xef, 0xe6, 0xe6,
0xe6, 0xde, 0xde, 0xde, 0xd6, 0xd6, 0xd6, 0xce, 0xce, 0xce, 0xc5, 0xc5,
(途中省略)
0x83, 0x7a, 0xe6, 0x09, 0xa7, 0x86, 0x25, 0xed, 0x89, 0xe6, 0xa0, 0x86,
0x34, 0x39, 0x8b, 0x87, 0x03, 0xe8, 0x68, 0xe7, 0x7f, 0xf7, 0x75, 0x79,
0xa6, 0x3c, 0x72, 0x4e, 0x3a, 0x06, 0x4a, 0x96, 0x66, 0x58, 0x4d, 0x10,
0x00, 0x3b
};
unsigned int sample_gif_len = 8942;
シンプルで分かりやすい内容です。ファイルのバイト列がそのまま sample_gif
という変数に設定されています。また、 sample_gif_len
という変数にバイト列の長さも設定してくれています。
- ヒント
xxd
はファイルの内容を C 言語のソースコードに取り込み可能なバイト列に変換するだけなので、 画像以外のリソースを実行ファイルに埋め込むのにも使えます。
バイト列をGdk::PixbufLoaderで読み込む
xxd
で作成したファイル sample.gif.h
を #include
すると、 sample_gif
変数と sample_gif_len
変数を参照できます。この sample_gif
変数と sample_gif_len
変数を Gdk::PixbufLoader
の write
関数に指定します。
sample.png.hを読み込む#include "img/sample.gif.h"
Glib::RefPtr<Gdk::PixbufLoader> loader = Gdk::PixbufLoader::create();
loader->write(sample_gif, sample_gif_len);
loader->close();
Glib::RefPtr<Gdk::PixbufAnimation> pixbuf = loader->get_animation();
Gdk::PixbufLoader
の get_animation
関数を呼び出すと Glib::RefPtr<Gdk::PixbufAnimation>
を取得することができます。
- ヒント
Gdk::PixbufLoader
にはget_animation
関数だけでなくget_pixbuf
関数もあります。この関数を使えば非アニメーション画像を読み込んでGlib::RefPtr<Gdk::Pixbuf>
を取得することができます。非アニメーション画像の読み込みにもxxd
+Gdk::PixbufLoader
を使用して共通化するのがいいかもしれませんね。
Glib::RefPtr<Gdk::PixbufAnimation>
が取得できたら、 あとは Gtk::Image
のコンストラクタ引数で指定するか、 もしくは set
関数で指定するだけです。
コンストラクタでGlib::RefPtrを指定する Gtk::Image image(pixbuf);
もしくは
set関数でGlib::RefPtrを指定する Gtk::Image image;
image.set(pixbuf);
アニメーション GIF を実行ファイルに埋め込む手順の説明は以上です。
サンプルプログラム
アニメーション GIF を実行ファイル内リソースから読み込むサンプルプログラムのソースコードをダウンロードできます。