投稿者 tel | 2010年11月8日

TGAファイルの読み込みと保存

TGAファイルの読み込みと保存のプログラムを書いた。保存処理は無圧縮でもよかったけどRLE圧縮するようにしてみた。

フッターとかあるらしいけどフォーマットの仕様がよくわからん。

#ifndef _TGA_H
#define _TGA_H

#include <stdio.h>
#include "../image.h"

#pragma pack(1)

struct TGAHeader {
char idLength;
char colorMapType;
char dataTypeCode;
short int colorMapOrigin;
short int colorMapLength;
char colorMapDepth;
short int xOrigin;
short int yOrigin;
short width;
short height;
char bitsPerPixel;
char imageDescriptor;
};

struct TGAFooter {
int filePosition;
int dirPosition;
char id[17];
char end;
};

#pragma pack()

template <typename T, typename U>
inline void ReadLine(U *dst, FILE *fp, int length)
{
T p;
for(int j = 0; j < length; j++) {
fread(&p, sizeof(T), 1, fp);
*dst++ = p;
}
}

template <>
inline void ReadLine<unsigned char>(unsigned char *dst, FILE *fp, int length)
{
fread(dst, length, 1, fp);
}

template <typename T>
inline void ReadLine8(T *dst, FILE *fp, int length)
{
unsigned char p;
for(int j = 0; j < length; j++) {
fread(&p, 1, 1, fp);
*dst = p;
dst++;
}
}

template <typename T>
inline void ReadLine16(T *dst, FILE *fp, int length)
{
unsigned short p;
for(int j = 0; j < length; j++) {
fread(p, 2, 1, fp);
dst->r = ((p & 0x7c00) >> 10) * 8;
dst->g = ((p & 0x03e0) >> 5) * 8;
dst->b = (p & 0x1f) * 8;
dst++;
}
}

inline void ReadLine24(RGBA *dst, FILE *fp, int length)
{
unsigned char p[3];
for(int j = 0; j < length; j++) {
fread(p, 3, 1, fp);
dst->r = p[2];
dst->g = p[1];
dst->b = p[0];
dst->a = 255;
dst++;
}
}

inline void ReadLine24(BGRA *dst, FILE *fp, int length)
{
for(int j = 0; j < length; j++) {
fread(dst, 3, 1, fp);
dst->a = 255;
dst++;
}
}

inline void ReadLine24(RGB *dst, FILE *fp, int length)
{
unsigned char p[3];
for(int j = 0; j < length; j++) {
fread(p, 3, 1, fp);
dst->r = p[2];
dst->g = p[1];
dst->b = p[0];
dst++;
}
}

inline void ReadLine24(BGR *dst, FILE *fp, int length)
{
fread(dst, length * 3, 1, fp);
}

inline void ReadLine32(BGR *dst, FILE *fp, int length)
{
for(int i = 0; i < length; i++) {
BGRA p;
fread(&p, 1, 1, fp);
dst->r = p.r;
dst->g = p.g;
dst->b = p.b;
dst++;
}
}

inline void ReadLine32(BGRA *dst, FILE *fp, int length)
{
fread(dst, sizeof(BGRA), length, fp);
}

inline void ReadLine32(RGBA *dst, FILE *fp, int length)
{
for(int i = 0; i < length; i++) {
fread(&dst[i].b, 1, 1, fp);
fread(&dst[i].g, 1, 1, fp);
fread(&dst[i].r, 1, 1, fp);
fread(&dst[i].a, 1, 1, fp);
}
}

template <typename T, typename U>
inline void ReadLineRLE(U *dst, FILE *fp, int length)
{
int j = 0;
while(j < length) {
unsigned char buf[1];
fread(buf, 1, 1, fp);
int n = (buf[0] & 127) + 1;
T p;
if(buf[0] & 128) {
fread(&p, sizeof(T), 1, fp);

for(int k = 0; k < n; k++) {
*dst = p;
dst++;
}
} else {
for(int k = 0; k < n; k++) {
fread(&p, sizeof(T), 1, fp);
*dst++ = p;
}
}
j += n;
}
}

template <typename T>
inline void ReadLineRLE8(T *dst, FILE *fp, int length)
{
int j = 0;
while(j < length) {
unsigned char buf[1];
fread(buf, 1, 1, fp);
int n = (buf[0] & 127) + 1;
if(buf[0] & 128) {
unsigned char p;

fread(&p, 1, 1, fp);

for(int k = 0; k < n; k++) {
*dst++ = p;
}
} else {
unsigned char p;
for(int k = 0; k < n; k++) {
fread(&p, 1, 1, fp);
*dst++ = p;
}
}
j += n;
}
}

inline void ReadLineRLE24(BGR *dst, FILE *fp, int length)
{
int j = 0;
while(j < length) {
unsigned char buf[1];
fread(buf, 1, 1, fp);
int n = (buf[0] & 127) + 1;
if(buf[0] & 128) {
BGR p;

fread(&p, 3, 1, fp);

for(int k = 0; k < n; k++) {
*dst = p;
dst++;
}
} else {
for(int k = 0; k < n; k++) {
fread(dst, 3, 1, fp);
dst++;
}
}
j += n;
}
}

inline void ReadLineRLE24(BGRA *dst, FILE *fp, int length)
{
int j = 0;
while(j < length) {
unsigned char buf[1];
fread(buf, 1, 1, fp);
int n = (buf[0] & 127) + 1;
if(buf[0] & 128) {
BGRA p;
p.a = 255;
fread(&p, 3, 1, fp);

for(int k = 0; k < n; k++) {
*dst++ = p;
}
} else {
for(int k = 0; k < n; k++) {
fread(dst, 3, 1, fp);
dst->a = 255;
dst++;
}
}
j += n;
}
}

inline void ReadLineRLE24(RGBA *dst, FILE *fp, int length)
{
int j = 0;
while(j < length) {
unsigned char buf[1];
fread(buf, 1, 1, fp);
int n = (buf[0] & 127) + 1;
if(buf[0] & 128) {
RGBA p;
p.a = 255;
fread(&p.b, 1, 1, fp);
fread(&p.g, 1, 1, fp);
fread(&p.r, 1, 1, fp);

for(int k = 0; k < n; k++) {
*dst++ = p;
}
} else {
for(int k = 0; k < n; k++) {
fread(&dst->b, 1, 1, fp);
fread(&dst->g, 1, 1, fp);
fread(&dst->r, 1, 1, fp);
dst->a = 255;
dst++;
}
}
j += n;
}
}

template <typename T>
void ConvertPixel32(const T &rhs, BGR &lhs)
{
lhs.r = rhs.r;
lhs.g = rhs.g;
lhs.b = rhs.b;
}

void ConvertPixel32(const BGRA &rhs, BGRA &lhs)
{
lhs = rhs;
}

template <typename T>
inline void ReadLineRLE32(T *dst, FILE *fp, int length)
{
int j = 0;
while(j < length) {
unsigned char buf[1];
fread(buf, 1, 1, fp);
int n = (buf[0] & 127) + 1;
if(buf[0] & 128) {
BGRA p;
fread(&p, 4, 1, fp);
T t = p;

for(int k = 0; k < n; k++) {
*dst++ = t;
}
} else {
BGRA p;
for(int k = 0; k < n; k++) {
fread(&p, 4, 1, fp);
ConvertPixel32(p, *dst);
dst++;
}
}
j += n;
}
}

inline void ReadLineRLE32(RGBA *dst, FILE *fp, int length)
{
int j = 0;
while(j < length) {
unsigned char buf[1];
fread(buf, 1, 1, fp);
int n = (buf[0] & 127) + 1;
if(buf[0] & 128) {
RGBA p;
fread(&p.b, 1, 1, fp);
fread(&p.g, 1, 1, fp);
fread(&p.r, 1, 1, fp);
fread(&p.a, 1, 1, fp);

for(int k = 0; k < n; k++) {
*dst++ = p;
}
} else {
for(int k = 0; k < n; k++) {
fread(&dst->b, 1, 1, fp);
fread(&dst->g, 1, 1, fp);
fread(&dst->r, 1, 1, fp);
fread(&dst->a, 1, 1, fp);
dst++;
}
}
j += n;
}
}

template <typename T, typename U>
void ReadLineIndex(T *dst, FILE *fp, int length, U *palette)
{
for(int i = 0; i < length; i++) {
fread(&j, 1, 1, fp);
*dst++ = palette[j];
}
}

inline void WriteLine32(const BGRA *src, FILE *fp, int length)
{
fwrite(src, sizeof(BGRA), length, fp);
}

inline void WriteLineRLE24(const BGR *src, FILE *fp, int length)
{

}

template <typename T>
int LoadTga(const char *fileName, Image<T> *dst)
{
FILE *fp = NULL;
if(fileName == NULL && dst == NULL) {
return 0;
}

if(fopen_s(&fp, fileName, "rb") || fp == NULL) {
return 0;
}

TGAHeader header;

fread(&header, sizeof(TGAHeader), 1, fp);
printf("id     :%d\n", header.idLength);
printf("color  :%d\n", header.colorMapType);
printf("type   :%d\n", header.dataTypeCode);
// 0: no image
// 1: index color
// 2: full color
// 3: gray
// 9: index color RLE
//10: full color RLE
//11: gray RLE
printf("orign  :%d\n", header.colorMapOrigin);
printf("length :%d\n", header.colorMapLength);
printf("clr dpt:%d\n", header.colorMapDepth);
printf("x org  :%d\n", header.xOrigin);
printf("y org  :%d\n", header.yOrigin);
printf("width  :%d\n", header.width);
printf("height :%d\n", header.height);
printf("depth  :%d\n", header.bitsPerPixel);
printf("desc   :%d\n", header.imageDescriptor);
//
// 4
// 5

// skip id field
if(header.idLength > 0) {
char buf[256];
fread(&buf, header.idLength, 1, fp);
printf("id %s\n", buf);
}

if(header.dataTypeCode == 0) {
fclose(fp);
printf("unsupport format\n");
return 0;
}

dst->Create(header.width, header.height);

for(int i = 0; i < header.height; i++) {
T *line;

if(header.imageDescriptor & 32) {
line = dst->lines[i];
} else {
line = dst->lines[header.height - i - 1];
}

switch(header.dataTypeCode) {
case 0x1:
// indexed color raw data
//ReadLineIndex(line, fp, header.width);
break;
case 0x2:
// full color raw data

switch(header.bitsPerPixel) {
case 16:
ReadLine<BGRA16>(line, fp, header.width);
break;
case 24:
ReadLine<BGR>(line, fp, header.width);
break;
case 32:
ReadLine<BGRA>(line, fp, header.width);
break;
}
break;
case 0x3:
// grayscale color raw data
ReadLine<unsigned char>(line, fp, header.width);
break;
case 0x9:
// indexed color RLE
//ReadLineIndexRLE(pallete, line, fp, header.width);
break;
case 0xA:
// full color RLE
switch(header.bitsPerPixel) {
case 16:
ReadLineRLE<BGRA16>(line, fp, header.width);
break;
case 24:
ReadLineRLE<BGR>(line, fp, header.width);
break;
case 32:
ReadLineRLE<BGRA>(line, fp, header.width);
break;
}
break;
case 0xB:
// grayscale color RLE
ReadLineRLE<unsigned char>(line, fp, header.width);
break;
}
}

TGAFooter footer;
int size = fread(&footer, sizeof(TGAFooter), 1, fp);

if(size > 0) {
printf("size:%d\n", size);
printf("file:%d\n", footer.filePosition);
printf("dir :%d\n", footer.dirPosition);
printf("id  :%s\n", footer.id);
}

fclose(fp);

return 1;
}

template <typename T>
int SaveTga(const char *fileName, const Image<T> *src)
{
FILE *fp = NULL;

if(fileName == NULL || src == NULL) {
return 0;
}

if(fopen_s(&fp, fileName, "wb") || fp == NULL) {
return 0;
}

TGAHeader header;

header.idLength        = 0;
header.colorMapType    = 0;
header.dataTypeCode    = 0xA;
header.colorMapOrigin  = 0;
header.colorMapLength  = 0;
header.colorMapDepth   = 0;
header.xOrigin         = 0;
header.yOrigin         = 0;
header.width           = src->width;
header.height          = src->height;
header.bitsPerPixel    = sizeof(T) * 8;
header.imageDescriptor = 0;

fwrite(&header, sizeof(TGAHeader), 1, fp);

/*
for(int i = 0; i < src->height; i++) {
const T *line = src->lines[src->height - i - 1];
//WriteLine32(line, fp, src->width);
fwrite(line, sizeof(T) * src->width, 1, fp);
}
*/


for(int i = 0; i < src->height; i++) {
const T *line = src->lines[src->height - i - 1];
int j = 0;

do {
const T *p = &line[j];
unsigned char length = 0;
bool r = *p == line[++j];
if(r) {
while(*p == line[j + 1] && j < src->width && length != 127) {
j++;
length++;
}
} else {
while(line[j] != line[j + 1] && j < src->width && length != 127) {
j++;
length++;
}
}
if(r) {
length |= 0x80;
fwrite(&length, 1, 1, fp);
fwrite(p, sizeof(T), 1, fp);
} else {
fwrite(&length, 1, 1, fp);
for(int k = 0; k < length + 1; k++) {
fwrite(p++, sizeof(T), 1, fp);
}
}
} while(j < src->width);
}

fclose(fp);

return 1;
}

#endif // _TGA_H

2012/04/23 いろいろ間違っていたので修正。


コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

カテゴリー

%d人のブロガーが「いいね」をつけました。