+4
-4
.vscode/launch.json
+4
-4
.vscode/launch.json
···
7
7
{
8
8
"type": "lldb",
9
9
"request": "launch",
10
-
"name": "Inspect PBM",
10
+
"name": "Inspect TGA",
11
11
"program": "${workspaceFolder}/img-inspect",
12
-
"args": ["TestImages/j.pbm"],
12
+
"args": ["TestImages/kitty.tga"],
13
13
"cwd": "${workspaceFolder}"
14
14
},
15
15
{
16
16
"type": "lldb",
17
17
"request": "launch",
18
-
"name": "BMP2PPM",
18
+
"name": "TGA2PPM",
19
19
"program": "${workspaceFolder}/img2ppm",
20
-
"args": ["TestImages/monochrome.bmp", "TestImages/monochrome.bmp.ppm"],
20
+
"args": ["TestImages/rgby.tga", "TestImages/rgby.tga.ppm"],
21
21
"cwd": "${workspaceFolder}"
22
22
}
23
23
]
TestImages/KikiFlash.tga
TestImages/KikiFlash.tga
This is a binary file and will not be displayed.
TestImages/KikiGray.tga
TestImages/KikiGray.tga
This is a binary file and will not be displayed.
TestImages/cbw8.tga
TestImages/cbw8.tga
This is a binary file and will not be displayed.
TestImages/kitty.tga
TestImages/kitty.tga
This is a binary file and will not be displayed.
+51
img-inspect.c
+51
img-inspect.c
···
1
1
#include "img.h"
2
2
#include <stdio.h>
3
+
#include <string.h>
3
4
4
5
struct Ctx {
5
6
FILE *file;
···
33
34
if(argc < 2) {
34
35
printf("Usage: %s <file>\n", argv[0]);
35
36
return 1;
37
+
}
38
+
39
+
int dumpColorMap = 0;
40
+
for(int i = 2; i < argc; ++i) {
41
+
/* BMP Color Table, TGA Color Map */
42
+
if(strcmp(argv[i], "-colorMap") == 0
43
+
|| strcmp(argv[1], "-colorTable") == 0) {
44
+
dumpColorMap = 1;
45
+
}
36
46
}
37
47
38
48
FILE *file = fopen(argv[1], "rb");
···
94
104
img.bmp.xPPM,
95
105
img.bmp.yPPM,
96
106
img.bmp.colorTableSize);
107
+
if(dumpColorMap && img.bmp.colorTableSize) {
108
+
printf(" Color table:\n");
109
+
for(int i = 0; i < img.bmp.colorTableSize; ++i) {
110
+
const struct ImgBmpRGBQuad *color = &img.bmp.colorTable[i];
111
+
printf(" %u,%u,%u,%u\n",
112
+
color->red, color->green, color->blue, color->reserved);
113
+
}
114
+
}
115
+
break;
116
+
case ImgFormatTga:
117
+
printf(
118
+
"ID: %s\n"
119
+
"Color map type: %u\n"
120
+
"Image type: %u\n"
121
+
"Color map first index: %u\n"
122
+
"Color map length: %u\n"
123
+
"Color map entry size: %u\n"
124
+
"Origin X: %u\n"
125
+
"Origin Y: %u\n"
126
+
"Pixel Depth: %u\n"
127
+
"Image Origin: %u\n"
128
+
"Alpha Bits: %u\n",
129
+
img.tga.id,
130
+
img.tga.colorMapType,
131
+
img.tga.imageType,
132
+
img.tga.colorMapFirstIndex,
133
+
img.tga.colorMapLength,
134
+
img.tga.colorMapEntrySize,
135
+
img.tga.originX,
136
+
img.tga.originY,
137
+
img.tga.pixelDepth,
138
+
img.tga.imageOrigin,
139
+
img.tga.alphaBits);
140
+
if(dumpColorMap && img.tga.colorMapType) {
141
+
printf(" Color map:\n");
142
+
for(int i = 0; i < img.tga.colorMapLength; ++i) {
143
+
const struct ImgTgaColor *color = &img.tga.colorMap[i];
144
+
printf(" %u,%u,%u,%u\n",
145
+
color->red, color->green, color->blue, color->alpha);
146
+
}
147
+
}
97
148
break;
98
149
default:
99
150
break;
+414
-1
img.c
+414
-1
img.c
···
8
8
static ImgStatus readPbm(Img *img, ImgAny buf, ImgSz bufSz);
9
9
static ImgStatus openBmp(Img *img);
10
10
static ImgStatus readBmp(Img *img, ImgAny buf, ImgSz bufSz);
11
+
static ImgStatus openTga(Img *img);
12
+
static ImgStatus readTga(Img *img, ImgAny buf, ImgSz bufSz);
11
13
12
14
ImgStatus imgOpen(Img *img, const ImgFuncs *funcs)
13
15
{
···
23
25
return openPbm(img);
24
26
case ImgFormatBmp:
25
27
return openBmp(img);
28
+
case ImgFormatTga:
29
+
return openTga(img);
26
30
}
27
31
}
28
32
···
40
44
return readPbm(img, buf, bufSz);
41
45
case ImgFormatBmp:
42
46
return readBmp(img, buf, bufSz);
47
+
case ImgFormatTga:
48
+
return readTga(img, buf, bufSz);
43
49
}
44
50
}
45
51
···
66
72
return "PBM";
67
73
case ImgFormatBmp:
68
74
return "BMP";
75
+
case ImgFormatTga:
76
+
return "TGA";
69
77
}
70
78
}
71
79
···
102
110
return "BMP: Unsupported compression mode";
103
111
case ImgErrBmpUnsupportedBitDepth:
104
112
return "BMP: Unsupported bit depth";
113
+
case ImgErrTgaMissingColorMap:
114
+
return "TGA: Missing color map";
115
+
case ImgErrTgaColorMapTooLong:
116
+
return "TGA: Color map too long (>256 colors)";
117
+
case ImgErrTgaNoImageData:
118
+
return "TGA: Attempt to decode an image not containing image data";
119
+
case ImgErrTgaUnsupportedPixelDepth:
120
+
return "TGA: Unsupported pixel depth";
105
121
}
106
122
}
107
123
···
130
146
return ImgOK;
131
147
}
132
148
149
+
static ImgStatus readU24LE(Img *img, ImgU32 *out)
150
+
{
151
+
ImgU8 bytes[3];
152
+
ImgStatus status = img->funcs.read(img->funcs.user, bytes, 3);
153
+
if(status != ImgOK) { return status; }
154
+
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
155
+
*out = ((ImgU32)bytes[2] << 16) | ((ImgU32)bytes[1] << 8) | (ImgU32)bytes[0];
156
+
#else
157
+
*out = ((ImgU32)bytes[0] << 16) | ((ImgU32)bytes[1] << 8) | (ImgU32)bytes[2];
158
+
#endif
159
+
return ImgOK;
160
+
}
161
+
133
162
static ImgStatus readU32LE(Img *img, ImgU32 *out)
134
163
{
135
164
ImgStatus status = img->funcs.read(img->funcs.user, out, 4);
···
165
194
return img->funcs.seek(img->funcs.user, off);
166
195
}
167
196
197
+
static ImgStatus determineTga(Img *img);
198
+
168
199
static ImgStatus determineFormat(Img *img)
169
200
{
170
201
ImgStatus status;
···
189
220
img->format = ImgFormatQoi;
190
221
return ImgOK;
191
222
}
192
-
return ImgErrUnknownFormat;
223
+
status = determineTga(img);
224
+
if(status != ImgOK) { return status; }
225
+
if(img->format == ImgFormatUnknown) {
226
+
return ImgErrUnknownFormat;
227
+
}
228
+
return ImgOK;
193
229
}
194
230
195
231
struct RGBA {
···
1009
1045
1010
1046
return ImgOK;
1011
1047
}
1048
+
1049
+
#define TGA_NO_IMAGE_DATA 0
1050
+
#define TGA_COLOR_MAPPED 1
1051
+
#define TGA_TRUE_COLOR 2
1052
+
#define TGA_BLACK_AND_WHITE 3
1053
+
#define TGA_RLE_COLOR_MAPPED 9
1054
+
#define TGA_RLE_TRUE_COLOR 10
1055
+
#define TGA_RLE_BLACK_AND_WHITE 11
1056
+
1057
+
ImgStatus determineTga(Img *img)
1058
+
{
1059
+
ImgOff returnOff = 0;
1060
+
ImgStatus status;
1061
+
1062
+
status = read(img, &img->tga.idLength, 1);
1063
+
++returnOff;
1064
+
if(status != ImgOK) { return status; }
1065
+
1066
+
status = read(img, &img->tga.colorMapType, 1);
1067
+
++returnOff;
1068
+
if(status != ImgOK) { return status; }
1069
+
1070
+
/* invalid color map type, likely not TGA */
1071
+
if(img->tga.colorMapType != 0 && img->tga.colorMapType != 1) {
1072
+
return seek(img, -returnOff);
1073
+
}
1074
+
1075
+
status = read(img, &img->tga.imageType, 1);
1076
+
++returnOff;
1077
+
if(status != ImgOK) { return status; }
1078
+
1079
+
switch(img->tga.imageType) {
1080
+
case TGA_NO_IMAGE_DATA:
1081
+
case TGA_COLOR_MAPPED:
1082
+
case TGA_TRUE_COLOR:
1083
+
case TGA_BLACK_AND_WHITE:
1084
+
case TGA_RLE_COLOR_MAPPED:
1085
+
case TGA_RLE_TRUE_COLOR:
1086
+
case TGA_RLE_BLACK_AND_WHITE:
1087
+
break;
1088
+
/* invalid image type, likely not TGA */
1089
+
default:
1090
+
return seek(img, -returnOff);
1091
+
}
1092
+
1093
+
status = readU16LE(img, &img->tga.colorMapFirstIndex);
1094
+
returnOff += 2;
1095
+
if(status != ImgOK) { return status; }
1096
+
1097
+
if(!img->tga.colorMapType && img->tga.colorMapFirstIndex != 0) {
1098
+
return seek(img, -returnOff);
1099
+
}
1100
+
1101
+
status = readU16LE(img, &img->tga.colorMapLength);
1102
+
returnOff += 2;
1103
+
if(status != ImgOK) { return status; }
1104
+
1105
+
if(!img->tga.colorMapType && img->tga.colorMapLength != 0) {
1106
+
return seek(img, -returnOff);
1107
+
}
1108
+
if(img->tga.colorMapType && img->tga.colorMapLength == 0) {
1109
+
return seek(img, -returnOff);
1110
+
}
1111
+
1112
+
status = read(img, &img->tga.colorMapEntrySize, 1);
1113
+
++returnOff;
1114
+
if(status != ImgOK) { return status; }
1115
+
1116
+
if(!img->tga.colorMapType && img->tga.colorMapEntrySize != 0) {
1117
+
return seek(img, -returnOff);
1118
+
}
1119
+
1120
+
status = readU16LE(img, &img->tga.originX);
1121
+
returnOff += 2;
1122
+
if(status != ImgOK) { return status; }
1123
+
1124
+
status = readU16LE(img, &img->tga.originY);
1125
+
returnOff += 2;
1126
+
if(status != ImgOK) { return status; }
1127
+
1128
+
status = readU16LE(img, &img->tga.width);
1129
+
returnOff += 2;
1130
+
if(status != ImgOK) { return status; }
1131
+
1132
+
status = readU16LE(img, &img->tga.height);
1133
+
returnOff += 2;
1134
+
if(status != ImgOK) { return status; }
1135
+
1136
+
status = read(img, &img->tga.pixelDepth, 1);
1137
+
returnOff += 1;
1138
+
if(status != ImgOK) { return status; }
1139
+
1140
+
ImgU8 imageDescriptor;
1141
+
status = read(img, &imageDescriptor, 1);
1142
+
++returnOff;
1143
+
if(status != ImgOK) { return status; }
1144
+
1145
+
/* unused bits must be 0 */
1146
+
if((imageDescriptor >> 6) != 0) {
1147
+
return seek(img, -returnOff);
1148
+
}
1149
+
1150
+
img->tga.alphaBits = imageDescriptor & 15;
1151
+
img->tga.imageOrigin = (imageDescriptor >> 4) & 3;
1152
+
1153
+
img->format = ImgFormatTga;
1154
+
return ImgOK;
1155
+
}
1156
+
1157
+
/* Number of bytes needed to store the given amount of bits */
1158
+
#define BITS_TO_BYTES(bits) (((bits) + 7) >> 3)
1159
+
1160
+
ImgStatus openTga(Img *img)
1161
+
{
1162
+
ImgStatus status;
1163
+
1164
+
if(img->tga.colorMapType) {
1165
+
if(img->tga.colorMapLength > IMG_TGA_MAX_COLOR_MAP_SIZE) {
1166
+
return ImgErrTgaColorMapTooLong;
1167
+
}
1168
+
} else if(img->tga.imageType == TGA_COLOR_MAPPED || img->tga.imageType == TGA_RLE_COLOR_MAPPED) {
1169
+
return ImgErrTgaMissingColorMap;
1170
+
}
1171
+
1172
+
/* the header was already read in by determineTga() */
1173
+
if(img->tga.idLength) {
1174
+
status = read(img, img->tga.id, img->tga.idLength);
1175
+
if(status != ImgOK) { return status; }
1176
+
}
1177
+
/* NUL-terminate for convenience */
1178
+
img->tga.id[img->tga.idLength] = '\0';
1179
+
1180
+
/* set this here in case there is no color map */
1181
+
if(img->tga.alphaBits) {
1182
+
img->channelCount = 4;
1183
+
} else {
1184
+
img->channelCount = 3;
1185
+
}
1186
+
img->width = img->tga.width;
1187
+
img->height = img->tga.height;
1188
+
1189
+
/* image data follows color map and we'll read that in readTga() */
1190
+
/* so if we don't have a color map, we just return early here */
1191
+
if(!img->tga.colorMapType) {
1192
+
return ImgOK;
1193
+
}
1194
+
1195
+
/* bits in a color field */
1196
+
ImgU32 fieldBits = img->tga.colorMapEntrySize / 3;
1197
+
/* spec requires fields be at most 8 bits each */
1198
+
if(fieldBits > 8) {
1199
+
fieldBits = 8;
1200
+
}
1201
+
/* mask of a field's bits */
1202
+
ImgU32 fieldMask = (1 << fieldBits) - 1;
1203
+
/* bits in a full color entry (3 fields) */
1204
+
ImgU32 entryBits = fieldBits * 3;
1205
+
/* total bits needed to store the entry (round up to 8) */
1206
+
ImgU32 totalBits = BITS_TO_BYTES(img->tga.colorMapEntrySize) << 3;
1207
+
/* bits not used by entry */
1208
+
ImgU32 alphaBits = totalBits - entryBits;
1209
+
/* alpha bit mask */
1210
+
ImgU32 alphaMask = (1 << alphaBits) - 1;
1211
+
if(alphaBits != 0) {
1212
+
img->channelCount = 4;
1213
+
} else {
1214
+
img->channelCount = 3;
1215
+
}
1216
+
1217
+
ImgU8 entry8;
1218
+
ImgU16 entry16;
1219
+
ImgU32 entry32;
1220
+
for(ImgU16 i = img->tga.colorMapFirstIndex; i < img->tga.colorMapLength; ++i) {
1221
+
struct ImgTgaColor *color = &img->tga.colorMap[i];
1222
+
1223
+
switch(totalBits) {
1224
+
case 8:
1225
+
status = read(img, &entry8, 1);
1226
+
if(status != ImgOK) { return status; }
1227
+
entry32 = entry8;
1228
+
break;
1229
+
case 16:
1230
+
status = readU16LE(img, &entry16);
1231
+
if(status != ImgOK) { return status; }
1232
+
entry32 = entry16;
1233
+
break;
1234
+
case 32:
1235
+
status = readU32LE(img, &entry32);
1236
+
if(status != ImgOK) { return status; }
1237
+
break;
1238
+
}
1239
+
1240
+
color->red = (entry32 >> (fieldBits * 2)) & fieldMask;
1241
+
color->green = (entry32 >> fieldBits) & fieldMask;
1242
+
color->blue = entry32 & fieldMask;
1243
+
if(alphaBits > 0) {
1244
+
color->alpha = (entry32 >> (fieldBits * 3)) & alphaMask;
1245
+
}
1246
+
}
1247
+
1248
+
return ImgOK;
1249
+
}
1250
+
1251
+
static ImgStatus readTgaColorMapped(Img *img, ImgAny buf, ImgSz bufSz);
1252
+
static ImgStatus readTgaTrueColor(Img *img, ImgAny buf, ImgSz bufSz);
1253
+
static ImgStatus readTgaBlackAndWhite(Img *img, ImgAny buf, ImgSz bufSz);
1254
+
static ImgStatus readTgaRleColorMapped(Img *img, ImgAny buf, ImgSz bufSz);
1255
+
static ImgStatus readTgaRleTrueColor(Img *img, ImgAny buf, ImgSz bufSz);
1256
+
static ImgStatus readTgaRleBlackAndWhite(Img *img, ImgAny buf, ImgSz bufSz);
1257
+
1258
+
/* TODO: Implement RLE */
1259
+
ImgStatus readTga(Img *img, ImgAny buf, ImgSz bufSz)
1260
+
{
1261
+
ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount;
1262
+
if(bufSz < expectedSize) {
1263
+
return ImgErrBufferTooSmall;
1264
+
}
1265
+
1266
+
switch(img->tga.imageType) {
1267
+
case TGA_NO_IMAGE_DATA:
1268
+
return ImgErrTgaNoImageData;
1269
+
case TGA_COLOR_MAPPED:
1270
+
return readTgaColorMapped(img, buf, bufSz);
1271
+
case TGA_TRUE_COLOR:
1272
+
return readTgaTrueColor(img, buf, bufSz);
1273
+
case TGA_BLACK_AND_WHITE:
1274
+
return readTgaBlackAndWhite(img, buf, bufSz);
1275
+
case TGA_RLE_COLOR_MAPPED:
1276
+
return readTgaRleColorMapped(img, buf, bufSz);
1277
+
case TGA_RLE_TRUE_COLOR:
1278
+
return readTgaRleTrueColor(img, buf, bufSz);
1279
+
case TGA_RLE_BLACK_AND_WHITE:
1280
+
return readTgaRleBlackAndWhite(img, buf, bufSz);
1281
+
}
1282
+
return ImgErrUnimplemented;
1283
+
}
1284
+
1285
+
ImgStatus readTgaColorMapped(Img *img, ImgAny buf, ImgSz bufSz)
1286
+
{
1287
+
ImgStatus status;
1288
+
ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount;
1289
+
ImgU8 *cur = buf;
1290
+
ImgU8 *end = cur + expectedSize;
1291
+
1292
+
/* above 8 not supported, also enforced by IMG_TGA_MAX_COLOR_MAP_LENGTH */
1293
+
if(img->tga.pixelDepth > 8) {
1294
+
return ImgErrTgaUnsupportedPixelDepth;
1295
+
}
1296
+
1297
+
ImgU8 pixel;
1298
+
while(cur < end) {
1299
+
status = read(img, &pixel, 1);
1300
+
if(status != ImgOK) { return status; }
1301
+
1302
+
const struct ImgTgaColor *color = &img->tga.colorMap[pixel];
1303
+
*cur++ = color->red;
1304
+
*cur++ = color->green;
1305
+
*cur++ = color->blue;
1306
+
if(img->channelCount == 4) {
1307
+
*cur++ = color->alpha;
1308
+
}
1309
+
}
1310
+
1311
+
return ImgOK;
1312
+
}
1313
+
1314
+
ImgStatus readTgaTrueColor(Img *img, ImgAny buf, ImgSz bufSz)
1315
+
{
1316
+
ImgStatus status;
1317
+
ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount;
1318
+
ImgU8 *curr = buf;
1319
+
ImgU8 *end = curr + expectedSize;
1320
+
1321
+
ImgU32 pixelSize = BITS_TO_BYTES(img->tga.pixelDepth);
1322
+
ImgU32 alphaMask = (1 << img->tga.alphaBits) - 1;
1323
+
ImgU32 fieldBits = (img->tga.pixelDepth - img->tga.alphaBits) / 3;
1324
+
ImgU32 fieldMask = (1 << fieldBits) - 1;
1325
+
1326
+
ImgU8 pixel8;
1327
+
ImgU16 pixel16;
1328
+
ImgU32 pixel32;
1329
+
while(curr < end) {
1330
+
switch(pixelSize) {
1331
+
case 1:
1332
+
status = read(img, &pixel8, 1);
1333
+
if(status != ImgOK) { return status; }
1334
+
pixel32 = pixel8;
1335
+
break;
1336
+
case 2:
1337
+
status = readU16LE(img, &pixel16);
1338
+
if(status != ImgOK) { return status; }
1339
+
pixel32 = pixel16;
1340
+
break;
1341
+
case 3:
1342
+
status = readU24LE(img, &pixel32);
1343
+
if(status != ImgOK) { return status; };
1344
+
break;
1345
+
case 4:
1346
+
status = readU32LE(img, &pixel32);
1347
+
if(status != ImgOK) { return status; }
1348
+
break;
1349
+
default:
1350
+
return ImgErrTgaUnsupportedPixelDepth;
1351
+
}
1352
+
1353
+
*curr++ = (pixel32 >> (2 * fieldBits)) & fieldMask;
1354
+
*curr++ = (pixel32 >> fieldBits) & fieldMask;
1355
+
*curr++ = pixel32 & fieldMask;
1356
+
if(img->channelCount > 3) {
1357
+
*curr++ = (pixel32 >> (3 * fieldBits)) & alphaMask;
1358
+
}
1359
+
}
1360
+
1361
+
return ImgOK;
1362
+
}
1363
+
1364
+
ImgStatus readTgaBlackAndWhite(Img *img, ImgAny buf, ImgSz bufSz)
1365
+
{
1366
+
ImgStatus status;
1367
+
ImgSz expectedSize = (ImgSz)img->width * img->height * img->channelCount;
1368
+
ImgU8 *curr = buf;
1369
+
ImgU8 *end = curr + expectedSize;
1370
+
1371
+
ImgU32 pixelSize = BITS_TO_BYTES(img->tga.pixelDepth);
1372
+
ImgU8 pixel8;
1373
+
ImgU16 pixel16;
1374
+
ImgU32 pixel32;
1375
+
while(curr < end) {
1376
+
switch(pixelSize) {
1377
+
case 1:
1378
+
status = read(img, &pixel8, 1);
1379
+
if(status != ImgOK) { return status; }
1380
+
break;
1381
+
case 2:
1382
+
status = readU16LE(img, &pixel16);
1383
+
if(status != ImgOK) { return status; }
1384
+
pixel8 = pixel16 >> 8;
1385
+
break;
1386
+
case 3:
1387
+
status = readU24LE(img, &pixel32);
1388
+
if(status != ImgOK) { return status; }
1389
+
pixel8 = pixel32 >> 16;
1390
+
break;
1391
+
case 4:
1392
+
status = readU32LE(img, &pixel32);
1393
+
if(status != ImgOK) { return status; }
1394
+
pixel8 = pixel32 >> 24;
1395
+
break;
1396
+
default:
1397
+
return ImgErrTgaUnsupportedPixelDepth;
1398
+
}
1399
+
1400
+
*curr++ = pixel8;
1401
+
*curr++ = pixel8;
1402
+
*curr++ = pixel8;
1403
+
if(img->channelCount > 3) {
1404
+
*curr++ = 255;
1405
+
}
1406
+
}
1407
+
1408
+
return ImgOK;
1409
+
}
1410
+
1411
+
ImgStatus readTgaRleColorMapped(Img *img, ImgAny buf, ImgSz bufSz)
1412
+
{
1413
+
return ImgErrUnimplemented;
1414
+
}
1415
+
1416
+
ImgStatus readTgaRleTrueColor(Img *img, ImgAny buf, ImgSz bufSz)
1417
+
{
1418
+
return ImgErrUnimplemented;
1419
+
}
1420
+
1421
+
ImgStatus readTgaRleBlackAndWhite(Img *img, ImgAny buf, ImgSz bufSz)
1422
+
{
1423
+
return ImgErrUnimplemented;
1424
+
}
+45
-8
img.h
+45
-8
img.h
···
24
24
ImgErrBmpUnsupportedVariant,
25
25
ImgErrBmpPlaneCount,
26
26
ImgErrBmpUnsupportedCompression,
27
-
ImgErrBmpUnsupportedBitDepth
27
+
ImgErrBmpUnsupportedBitDepth,
28
+
ImgErrTgaMissingColorMap,
29
+
ImgErrTgaColorMapTooLong,
30
+
ImgErrTgaNoImageData,
31
+
ImgErrTgaUnsupportedPixelDepth,
28
32
};
29
33
30
34
typedef enum ImgStatusE ImgStatus;
···
46
50
ImgFormatUnknown,
47
51
ImgFormatQoi,
48
52
ImgFormatPbm,
49
-
ImgFormatBmp
53
+
ImgFormatBmp,
54
+
ImgFormatTga
50
55
};
51
56
52
57
typedef enum ImgFormatE ImgFormat;
53
58
54
-
struct ImgQoiInfoS {
59
+
struct ImgQoi {
55
60
ImgU8 colorSpace;
56
61
};
57
62
58
-
struct ImgPbmInfoS {
63
+
struct ImgPbm {
59
64
char variant;
60
65
ImgU16 max;
61
66
};
···
67
72
ImgU8 reserved;
68
73
};
69
74
70
-
struct ImgBmpInfoS {
75
+
struct ImgBmp {
71
76
ImgU32 bitmapOffset;
72
77
ImgS32 width;
73
78
ImgS32 height;
···
81
86
struct ImgBmpRGBQuad colorTable[256];
82
87
};
83
88
89
+
/* for color map, converted to RGBA32 for convenience */
90
+
struct ImgTgaColor {
91
+
ImgU8 red;
92
+
ImgU8 green;
93
+
ImgU8 blue;
94
+
ImgU8 alpha;
95
+
};
96
+
97
+
/* just use true-color at that point */
98
+
#define IMG_TGA_MAX_COLOR_MAP_SIZE 256
99
+
100
+
struct ImgTga {
101
+
ImgU8 idLength;
102
+
/* 1 extra for null byte */
103
+
char id[256];
104
+
/* 1 if has color map, 0 otherwise */
105
+
ImgU8 colorMapType;
106
+
ImgU8 imageType;
107
+
ImgU16 colorMapFirstIndex;
108
+
ImgU16 colorMapLength;
109
+
ImgU8 colorMapEntrySize;
110
+
ImgU16 originX;
111
+
ImgU16 originY;
112
+
ImgU16 width;
113
+
ImgU16 height;
114
+
ImgU8 imageOrigin;
115
+
ImgU8 pixelDepth;
116
+
ImgU8 alphaBits;
117
+
struct ImgTgaColor colorMap[IMG_TGA_MAX_COLOR_MAP_SIZE];
118
+
};
119
+
84
120
struct ImgS {
85
121
ImgFormat format;
86
122
ImgU32 width;
···
88
124
ImgU8 channelCount;
89
125
ImgFuncs funcs;
90
126
union {
91
-
struct ImgQoiInfoS qoi;
92
-
struct ImgPbmInfoS pbm;
93
-
struct ImgBmpInfoS bmp;
127
+
struct ImgQoi qoi;
128
+
struct ImgPbm pbm;
129
+
struct ImgBmp bmp;
130
+
struct ImgTga tga;
94
131
};
95
132
};
96
133