SDL_image を用いて画像ファイルを読み込むサンプルプログラム(Ubuntu 上)

SDL_image は,BMP, JPEG, PNG, PNM などの画像ファイルを読み書きする機能を持ったライブラリ.現在の版は SDL2 用の SDL2_image である. このページでは,SDL2_image を用いて画像ファイルを読み込み,各画素の R, G, B 値を表示するプログラムを示す.

前準備

Ubuntu のシステム更新

Ubuntu で OS のシステム更新を行うときは, 端末で,次のコマンドを実行する。これは、パッケージ情報を最新の状態に保ち、インストール済みのパッケージをセキュリティアップデートやバグ修正を含めて更新するためである。

Ubuntu のインストールはこちらの別ページで説明する。
# パッケージリストの情報を更新
sudo apt update
# インストール済みのパッケージを包括的に更新 (依存関係も考慮)
sudo apt full-upgrade
# カーネル更新等で実際に再起動が必要な場合のみ実行を推奨
# sudo shutdown -r now

C/C++ コンパイラー,pkg-config のインストール

端末で,次のコマンドを実行する.

# パッケージリストの情報を更新
sudo apt update
sudo apt -y install build-essential pkg-config

SDL2, SDL2_image のインストール(Ubuntu 上)

端末で,次のコマンドを実行する. -dev の付いたパッケージには,コンパイルに必要なヘッダファイルと pkg-config 用の設定ファイルが含まれる.

# パッケージリストの情報を更新
sudo apt update
sudo apt -y install libsdl2-dev libsdl2-image-dev

プログラム例

画像ファイルにはヘッダが付いており,圧縮されていることも多い.また,画像ファイルの形式は複数ある. SDL2_image の IMG_Load を使うと,ファイル形式の判別,ヘッダの解析,展開の処理を自分で書く必要がない

IMG_Load が返す SDL_Surface の画素形式は,読み込んだファイルによって異なる(パレット形式,1画素4バイト,B, G, R の順など). そこで,次のプログラムでは SDL_ConvertSurfaceFormat により SDL_PIXELFORMAT_RGB24(1画素3バイト,R, G, B の順)へ変換し,画素の並びを一定にしている.

1行分のデータの後ろには詰め物(パディング)が入ることがあるため,行の先頭アドレスは幅 w ではなく pitch(1行あたりのバイト数)を用いて求める.

/* SDL2, SDL2_image を用いた画像ファイル読み込みのサンプルプログラム */

#include <stdio.h>
#include <stdlib.h>

#include <SDL.h>
#include <SDL_image.h>

int main(int argc, char *argv[])
{
  SDL_Surface *image;
  SDL_Surface *rgb;
  int i, j;

  /* コマンドラインの確認 */
  if (argc < 2) {
    fprintf(stderr, "Usage: %s <image_file>\n", argv[0]);
    return 1;
  }

  /* 画像ファイルの読み込み.ファイル形式は内容から判別される */
  image = IMG_Load(argv[1]);
  if (image == NULL) {
    fprintf(stderr, "Couldn't load %s: %s\n", argv[1], SDL_GetError());
    return 1;
  }

  /* 1画素3バイト,R, G, B の順の形式に変換 */
  rgb = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_RGB24, 0);
  SDL_FreeSurface(image);
  if (rgb == NULL) {
    fprintf(stderr, "SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError());
    return 1;
  }

  fprintf(stderr, "w = %d, h = %d, pitch = %d, BytesPerPixel = %d\n",
          rgb->w, rgb->h, rgb->pitch, rgb->format->BytesPerPixel);

  for (i = 0; i < rgb->h; i++) {
    /* 行の先頭アドレスは pitch (1行のバイト数) から求める */
    unsigned char *row = (unsigned char *)rgb->pixels + (size_t)i * rgb->pitch;
    for (j = 0; j < rgb->w; j++) {
      int r = row[j * 3];
      int g = row[j * 3 + 1];
      int b = row[j * 3 + 2];
      printf("%d, %d = (%d, %d, %d)\n", i, j, r, g, b);
    }
  }

  SDL_FreeSurface(rgb);
  SDL_Quit();
  return 0;
}

ビルド手順

view.c のところは実際のファイル名に読み替えること. コンパイルオプションとリンクするライブラリは pkg-config で取得する.

gcc -o view view.c $(pkg-config --cflags --libs sdl2 SDL2_image)

実行

画素ごとに1行を出力するため,出力行数は「幅×高さ」になる. 出力を確認するときは,ファイルへリダイレクトするか head と組み合わせる.

./view sample.png | head -n 20