GDI+ 使ってみた

急遽、画像処理をしなくてはならなくなったので、GDI+を使ってみた。
自分用メモも兼ねて簡単な使い方の紹介。


GDI+を使ってみたのは、なるべくたくさんのフォーマットの画像を読み書きしたかったから。
最初はBMP限定でやろうかと思ったけど、パレットとか色数とか、結局考慮しなきゃいけない点が多くて面倒だったから、いいものないかなって探してたら、たまたま見つけてGDI+を使ってみることにした。


とりあえず、参考にしたリンクを貼っ付けとく。
http://aki.issp.u-tokyo.ac.jp/itoh/PukiWiki/pukiwiki.php?%B2%E8%C1%FC
http://lamoo.s53.xrea.com/develop/gdiplus/gdiplus.html
http://park17.wakwak.com/~dragoon/gdiplus1.htm
http://weblog.rukihena.com/archives/2005/02/gdi_vc.html
http://www.nilab.info/resource/bbslog/megabbs/1093051600.html
だいたいこの辺がさんこうになるかと。


では、簡単な使い方のサンプル。
ちなみに、これはVC++2005proでしか動作確認してません。
まずは、プロジェクトの作成ってことで、Visual Studio 2005を起動して、[ファイル]-[新規作成]-[プロジェクト]から、プロジェクトの種類は「Win32コンソールアプリケーション」を選択。
もちろん、ほかのプロジェクトの種類でもOK(たぶん)。
で、プログラムの雛形ができたら、stdafx.hの最後に

  #include <gdiplus.h>
  #pragma comment (lib, "Gdiplus.lib")
  using namespace Gdiplus;

を書き足す。
簡単に説明すると、1行目がヘッダファイルのインクルード、2行目がライブラリの追加、3行目で名前空間の追加といった感じ。
で、ここで注意しなきゃいけないのが、マイクロソフトのバグ。
実はこんな文書があって、
http://support.microsoft.com/kb/922323/
gdiplus.hをインクルードするとエラーが出るから、このページにも書いてあるけど、

  #define WIN32_LEAN_AND_MEAN

をコメントアウト。
これで準備は整った!
次は、メイン関数への変更。
説明を省いて書いちゃうと、

  GdiplusStartupInput gdiplusStartupInput;
  ULONG_PTR gdiplusToken;
  GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

これが初期化で、

  GdiplusShutdown(gdiplusToken);

こっちが終了処理。
これで、GDI+は使えちゃいます。

そんでもって、今回は画像処理をするのが目的だったので、とりあえず画像を読み込んで1ピクセルずつ取得する処理がこっち。

  DWORD *LoadImage( wstring filename, UINT &width, UINT &height )
  {
    Bitmap inputImage( filename.c_str() );
    width = inputImage.GetWidth();
    height = inputImage.GetHeight();
    DWORD *image = new DWORD[width*height];
    Color color;
    for (UINT y = 0; y < height; ++y) {
      for (UINT x = 0; x < width; ++x) {
        inputImage.GetPixel( x, y, &color );
        image[y*width+x] = color.ToCOLORREF();
      }
    }
    return image;
  }

これで、filenameって名前の画像から1ピクセルごとのデータと、幅と高さが取得できます。
で、保存はこっち。
といきたいんだけど、実はちょっと面倒な処理があるので、こちらこのライブラリを借用しちゃって、使い方はライブラリの中に書いてあるので、メイン関数はそっちに置き換えればだいたいOK。
で、実際の保存用関数はだいたいこんな感じ。

  int SaveImage( wstring filename, DWORD *image, UINT width, UINT height )
  {
    Bitmap *outputImage = new Bitmap( width, height, PixelFormat32bppARGB );
    Color color;
    for (UINT y = 0; y < height; ++y) {
      for (UINT x = 0; x < width; ++x) {
        color.SetFromCOLORREF( image[y*width+x] );
        outputImage->SetPixel( x, y, color );
      }
    }
    outputImage->Save( filename.c_str(), &theGdiplus.GetEncoderByExtension(filename.c_str())->Clsid );
    return 0;
  }

これで、filenameって名前で、幅がwidth、高さがheightの画像ができちゃいます。
まぁざっとこんな感じで、途中紆余曲折があったけど、いろんな画像を読み込んで、なんか処理して、保存するってとこまでできるようになりました。