tuedaの日記

2011-07-02

[] C/C++でもっとも簡単にPNG/JPEG/BMP/その他の画像をread/writeするには?

例えばPNG画像ならlibpngを使うのがスタンダードなやり方だが、このlibpngライブラリ実はかなり使いずらい。

しかもlibpngが最初から用意されている環境ならともかく、自分でソースを取ってきてコンパイルして使えるようにするのは結構大変なことが多い。

品質・速度はどうでもいいからとにかくread/writeだけ手軽にしたい時にはこれらを使うのはいい選択肢ではない。

そこでSean Barrettさんの1ファイルでPNGもJPEGもBMPもその他いろいろ読めてしまう夢のライブラリが役に立つ。

(1ファイルと言っても4500行もあるけど)

上記HPの、

public domain JPEG decompression
public domain PNG decompression
public domain BMP, TGA, PSD loading
public domain ZLIB decompression - stb_image.c   // こっちが読み込み
public domain very-limited image writers for PNG, BMP, TGA   // こっちが書き込み

読み込みがstb_image.c(ヘッダーファイルはこの中に入っているので適当にコピペして自作する)、

書き込みがstb_image_write.h(ソースファイルはこの中に入っているので適当にコピペして自作する)。

(もう少し整理して欲しいのだが...)

使い方はこんな感じ。恐らく解説の必要はないだろう。画像フォーマットは自動判別。stbi_loadの4番目の引数はコンポーネント数を強制するときに使う。

つまり4を指定するとフォーマットにかかわらず必ずデータがRGBAで返ってくる。

#include <iostream>
#include "stb_image.hpp"        // 自分で切り出して作った
#include "stb_image_write.hpp"  // 自分で切り出して作った
using namespace std;

const char* FILE_NAME     = "../test.png";
const char* OUT_FILE_NAME = "out.png";

/**
 *
 */
int main (int argc, char** argv) 
{
    unsigned char* pixels ;
    int width;
    int height;
    int bpp;
    int ret;

    cout << "reading ...\n";
    pixels = stbi_load (FILE_NAME, &width, &height, &bpp, 0);
    
    cout << "FILE_NAME = " << FILE_NAME     << "\n";
    cout << "pixels    = " << (void*)pixels << "\n";
    cout << "width     = " << width         << "\n";
    cout << "height    = " << height        << "\n";
    cout << "bpp       = " << bpp           << "\n";

    cout << "writing ...\n";
    ret = stbi_write_png (OUT_FILE_NAME, width, height, bpp, pixels, width*bpp);
    
    cout << "ret = " << ret << "\n";

    stbi_image_free (pixels);

    return 0;
}

.cしか配布されていなく.hは自分で.cの一部をコピって使ってね、とか変な癖もあるが非常にお手軽に画像ファイルをread/writeできる。

何のライブラリにも依存していない(!)のでたいがいの環境でコンパイルできるはず。