2012年10月25日木曜日

libtga

PNGもなんとかなったので今度はTGAに挑戦です。

TGAを扱うライブラリにはlibtgaとその改造版のlibtga-exがあります。

で、使い方を確認するために、とりあえずこんなのを書いてみました。
/* TARGA2BGR */
#include <stdio.h>
#include <stdlib.h>

#include "tga.h"

typedef struct {
    TGA *tga;
    unsigned char *buff;
} tga_read_t;

int close(const char *msg, tga_read_t *tr, int ret)
{
    fprintf(stderr, "%s\n", msg);
    if (tr->buff) {
        free(tr->buff);
    }

    if (tr->tga) {
        TGAClose(tr->tga);
    }

    return ret;
}

int main(int argc, char **argv)
{
    if (argc < 2) {
        return -1;
    }

    tga_read_t tr = {0};

    tr.tga = TGAOpen(argv[1], "rb");
    if (!tr.tga || tr.tga->last != TGA_OK) {
        return close("TGAOpen failed", &tr, -1);
    }

    if (TGAReadHeader(tr.tga) != TGA_OK) {
        return close("TGAReadHeader failed", &tr, -1);
    }

    fprintf(stderr, "width: %u\n", tr.tga->hdr.width);
    fprintf(stderr, "height: %u\n", tr.tga->hdr.height);
    fprintf(stderr, "depth: %d\n", tr.tga->hdr.depth);
    fprintf(stderr, "alpha: %d\n", tr.tga->hdr.alpha);

    size_t buf_size
         = tr.tga->hdr.width * tr.tga->hdr.height * tr.tga->hdr.depth >> 3;
    tr.buff = malloc(buf_size);
    if (!tr.buff) {
        return close("malloc failed", &tr, -1);
    }

    if (TGAReadScanlines(tr.tga, tr.buff, 0, tr.tga->hdr.height, TGA_BGR)
        != tr.tga->hdr.height) {
        return close("couldn't read all lines\n", &tr, -1);
    }

    char out_name[1024];
    sprintf(out_name, "%s.raw", argv[1]);
    FILE *out = fopen(out_name, "wb");
    if (!out) {
        return close("open output file failed", &tr, -1);
    }
    fwrite(tr.buff, 1, buf_size, out);
    fclose(out);

    return close("finish", &tr, 0);
}

こいつにtgaファイルを食わせてやればBGRなrawデータとして出力するわけですが、試しにtgaではないファイルを食わせるとなぜかクラッシュします。
いちおうTGAReadHeaderのところでチェックはしているみたいなんですが…はて?

で、TGAReadHeaderの部分のコードを読んでみると
int TGAReadHeader (TGA *tga)
{
    tbyte *tmp;

    if (!tga) return 0;
    __TGASeek(tga, 0, SEEK_SET);
    if (tga->off != 0) {
        TGA_ERROR(tga, TGA_SEEK_FAIL);
        return 0;
    }
    /* 中略 */
    return TGA_OK;
}
と問題なしならTGA_OKを返し、問題有りなら0を返すようになっています。
ではTGA_OKの中身は何かとtga.hのほうを読んでみると…
/* error codes */
enum {
    TGA_OK = 0,  /* success */
    TGA_ERROR,
    TGA_OOM,  /* out of memory */
    TGA_OPEN_FAIL,
    TGA_SEEK_FAIL,
    TGA_READ_FAIL,
    TGA_WRITE_FAIL,
    TGA_UNKNOWN_SUB_FORMAT  /* invalid bit depth */
};

TGA_OKが全然OKになってねえよ…そりゃクラッシュもするわ。

なんで誰もこれを直してないんだ?

0 件のコメント:

コメントを投稿