
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 を実行ファイル内リソースから読み込むサンプルプログラムのソースコードをダウンロードできます。
