1 | /*
|
---|
2 |
|
---|
3 | gbmtga.c - Truevision Targa/Vista support
|
---|
4 |
|
---|
5 | Reads any uncompressed or runlength compresed type as 8 bit or 24 bit.
|
---|
6 | Writes out only as 8 bit or 24 bit.
|
---|
7 | Output options: 16,24,32, ydown,yup (default: 24 yup)
|
---|
8 |
|
---|
9 | */
|
---|
10 |
|
---|
11 | /*...sincludes:0:*/
|
---|
12 | #include <stdio.h>
|
---|
13 | #include <ctype.h>
|
---|
14 | #include <stddef.h>
|
---|
15 | #include <stdlib.h>
|
---|
16 | #include <string.h>
|
---|
17 | #include "gbm.h"
|
---|
18 | #include "gbmhelp.h"
|
---|
19 |
|
---|
20 | /*...vgbm\46\h:0:*/
|
---|
21 | /*...vgbmhelp\46\h:0:*/
|
---|
22 | /*...e*/
|
---|
23 |
|
---|
24 | /*...suseful:0:*/
|
---|
25 | #define low_byte(w) ((byte) ( (w)&0x00ff) )
|
---|
26 | #define high_byte(w) ((byte) (((unsigned)(w)&0xff00)>>8))
|
---|
27 | #define make_word(a,b) (((word)a) + (((word)b) << 8))
|
---|
28 | /*...e*/
|
---|
29 |
|
---|
30 | static GBMFT tga_gbmft =
|
---|
31 | {
|
---|
32 | "Targa",
|
---|
33 | "Truevision Targa/Vista bitmap",
|
---|
34 | "TGA VST AFI",
|
---|
35 | GBM_FT_R8|GBM_FT_R24|
|
---|
36 | GBM_FT_W8|GBM_FT_W24,
|
---|
37 | };
|
---|
38 |
|
---|
39 | #define GBM_ERR_TGA_BAD_BPP ((GBM_ERR) 400)
|
---|
40 | #define GBM_ERR_TGA_BAD_TYPE ((GBM_ERR) 401)
|
---|
41 | #define GBM_ERR_TGA_BAD_PAL ((GBM_ERR) 402)
|
---|
42 |
|
---|
43 | /*...starga file header definition:0:*/
|
---|
44 | /*
|
---|
45 |
|
---|
46 | A Targa file is a header, followed by an identification string, followed by
|
---|
47 | a color map, followed by the data for the image. Both the identification
|
---|
48 | string and the color-map can be of zero length.
|
---|
49 |
|
---|
50 | */
|
---|
51 |
|
---|
52 | #define TGA_NO_IMAGE 0 /* No image data included in file */
|
---|
53 | #define TGA_UNCOMP_CM 1 /* Uncompressed, Color-Mapped (VDA/D */
|
---|
54 | /* and Targa M-8 images) */
|
---|
55 | #define TGA_UNCOMP_RGB 2 /* Uncompressed, RGB images (eg: ICB */
|
---|
56 | /* Targa 16, 24 and 32) */
|
---|
57 | #define TGA_UNCOMP_BW 3 /* Uncompressed, B/W images (eg: */
|
---|
58 | /* Targa 8 and Targa M-8 images) */
|
---|
59 | #define TGA_RL_CM 9 /* Run-length, Color-Mapped (VDA/D */
|
---|
60 | /* and Targa M-8 images) */
|
---|
61 | #define TGA_RL_RGB 10 /* Run-length, RGB images (eg: ICB */
|
---|
62 | /* Targa 16, 24 and 32) */
|
---|
63 | #define TGA_RL_BW 11 /* Run-length, B/W images (eg: Targa */
|
---|
64 | /* 8 and Targa M-8) */
|
---|
65 | #define TGA_COMP_CM 32 /* Compressed Color-Mapped (VDA/D) */
|
---|
66 | /* data using Huffman, Delta, and */
|
---|
67 | /* run length encoding */
|
---|
68 | #define TGA_COMP_CM_4 33 /* Compressed Color-Mapped (VDA/D) */
|
---|
69 | /* data using Huffman, Delta, and */
|
---|
70 | /* run length encoding in 4 passes */
|
---|
71 |
|
---|
72 | #define IDB_ATTRIBUTES 0x0f /* How many attrib bits per pixel */
|
---|
73 | /* ie: 1 for T16, 8 for T32 */
|
---|
74 | #define IDB_ORIGIN 0x20 /* Origin in top left corner bit */
|
---|
75 | /* else its in bottom left corner */
|
---|
76 | #define IDB_INTERLEAVE 0xc0 /* Interleave bits as defined below */
|
---|
77 | #define IDB_NON_INT 0x00 /* Non-Interlaced */
|
---|
78 | #define IDB_2_WAY 0x40 /* 2 way (even/odd) interleaving */
|
---|
79 | #define IDB_4_WAY 0x80 /* 4 way interleaving (eg: AT&T PC) */
|
---|
80 |
|
---|
81 | typedef struct
|
---|
82 | {
|
---|
83 | byte n_chars_in_id; /* Length of identification text */
|
---|
84 | byte color_map_present; /* 0 means no, 1 yes */
|
---|
85 | byte image_type; /* Type of image file, one of TGA_ */
|
---|
86 | byte color_map_start_low; /* These 5 bytes are only valid if */
|
---|
87 | byte color_map_start_high; /* color_map_present is 1. They */
|
---|
88 | byte color_map_length_low; /* Specify the size of the color map */
|
---|
89 | byte color_map_length_high; /* and where it starts from */
|
---|
90 | byte color_map_entry_bits; /* Bits per color map entry */
|
---|
91 | /* Typically 15, 16, 24 or 32 */
|
---|
92 | byte x_origin_low;
|
---|
93 | byte x_origin_high;
|
---|
94 | byte y_origin_low;
|
---|
95 | byte y_origin_high;
|
---|
96 | byte width_low;
|
---|
97 | byte width_high;
|
---|
98 | byte height_low;
|
---|
99 | byte height_high;
|
---|
100 | byte bpp; /* Typically 16, 24 or 32 */
|
---|
101 | byte image_descriptor; /* Split into IDB_ bits */
|
---|
102 | } TGA_HEADER;
|
---|
103 |
|
---|
104 | #define SIZEOF_TGA_HEADER 18
|
---|
105 | /*...e*/
|
---|
106 | /*...sconverters:0:*/
|
---|
107 | /*...st24_t32:0:*/
|
---|
108 | static void t24_t32(byte *dest, const byte *src, int n)
|
---|
109 | {
|
---|
110 | while ( n-- )
|
---|
111 | {
|
---|
112 | *dest++ = *src++;
|
---|
113 | *dest++ = *src++;
|
---|
114 | *dest++ = *src++;
|
---|
115 | dest++;
|
---|
116 | }
|
---|
117 | }
|
---|
118 | /*...e*/
|
---|
119 | /*...st32_t24:0:*/
|
---|
120 | static void t32_t24(byte *dest, const byte *src, int n)
|
---|
121 | {
|
---|
122 | while ( n-- )
|
---|
123 | {
|
---|
124 | *dest++ = *src++;
|
---|
125 | *dest++ = *src++;
|
---|
126 | *dest++ = *src++;
|
---|
127 | src++;
|
---|
128 | }
|
---|
129 | }
|
---|
130 | /*...e*/
|
---|
131 | /*...st24_t16:0:*/
|
---|
132 | static void t24_t16(byte *dest, const byte *src, int n)
|
---|
133 | {
|
---|
134 | while ( n-- )
|
---|
135 | {
|
---|
136 | word b = (word) (*src++ & 0xf8);
|
---|
137 | word g = (word) (*src++ & 0xf8);
|
---|
138 | word r = (word) (*src++ & 0xf8);
|
---|
139 | word w;
|
---|
140 |
|
---|
141 | w = ((r << 7) | (g << 2) | (b >> 3));
|
---|
142 |
|
---|
143 | *dest++ = (byte) w;
|
---|
144 | *dest++ = (byte) (w >> 8);
|
---|
145 | }
|
---|
146 | }
|
---|
147 | /*...e*/
|
---|
148 | /*...st16_t24:0:*/
|
---|
149 | static void t16_t24(byte *dest, const byte *src, int n)
|
---|
150 | {
|
---|
151 | while ( n-- )
|
---|
152 | {
|
---|
153 | word l = *src++;
|
---|
154 | word h = *src++;
|
---|
155 | word w = l + (h << 8);
|
---|
156 |
|
---|
157 | *dest++ = (byte) ((w & 0x001fU) << 3);
|
---|
158 | *dest++ = (byte) ((w & 0x03e0U) >> 2);
|
---|
159 | *dest++ = (byte) ((w & 0x7c00U) >> 7);
|
---|
160 | }
|
---|
161 | }
|
---|
162 | /*...e*/
|
---|
163 | /*...e*/
|
---|
164 | typedef struct
|
---|
165 | {
|
---|
166 | TGA_HEADER header;
|
---|
167 | } TGA_PRIV;
|
---|
168 |
|
---|
169 | /*...stga_qft:0:*/
|
---|
170 | GBM_ERR tga_qft(GBMFT *gbmft)
|
---|
171 | {
|
---|
172 | *gbmft = tga_gbmft;
|
---|
173 | return GBM_ERR_OK;
|
---|
174 | }
|
---|
175 | /*...e*/
|
---|
176 | /*...stga_rhdr:0:*/
|
---|
177 | GBM_ERR tga_rhdr(const char *fn, int fd, GBM *gbm, const char *opt)
|
---|
178 | {
|
---|
179 | TGA_PRIV *priv = (TGA_PRIV *) gbm->priv;
|
---|
180 |
|
---|
181 | fn=fn; opt=opt; /* Suppress 'unref arg' compiler warnings */
|
---|
182 |
|
---|
183 | gbm_file_read(fd, (char *) &(priv->header), SIZEOF_TGA_HEADER);
|
---|
184 |
|
---|
185 | switch ( priv->header.image_type )
|
---|
186 | {
|
---|
187 | case TGA_RL_BW:
|
---|
188 | case TGA_UNCOMP_BW:
|
---|
189 | if ( priv->header.bpp != 8 )
|
---|
190 | return GBM_ERR_TGA_BAD_BPP;
|
---|
191 | break;
|
---|
192 | case TGA_RL_CM:
|
---|
193 | case TGA_UNCOMP_CM:
|
---|
194 | if ( priv->header.bpp != 8 )
|
---|
195 | return GBM_ERR_TGA_BAD_BPP;
|
---|
196 | if ( priv->header.color_map_entry_bits != 24 )
|
---|
197 | return GBM_ERR_TGA_BAD_PAL;
|
---|
198 | break;
|
---|
199 | case TGA_RL_RGB:
|
---|
200 | case TGA_UNCOMP_RGB:
|
---|
201 | if ( priv->header.bpp != 16 &&
|
---|
202 | priv->header.bpp != 24 &&
|
---|
203 | priv->header.bpp != 32 )
|
---|
204 | return GBM_ERR_TGA_BAD_BPP;
|
---|
205 | break;
|
---|
206 | default:
|
---|
207 | return GBM_ERR_TGA_BAD_TYPE;
|
---|
208 | }
|
---|
209 |
|
---|
210 | gbm->w = make_word(priv->header.width_low , priv->header.width_high );
|
---|
211 | gbm->h = make_word(priv->header.height_low, priv->header.height_high);
|
---|
212 |
|
---|
213 | if ( gbm->w <= 0 || gbm->h <= 0 )
|
---|
214 | return GBM_ERR_BAD_SIZE;
|
---|
215 |
|
---|
216 | gbm->bpp = ( priv->header.bpp == 8 ) ? 8 : 24;
|
---|
217 |
|
---|
218 | return GBM_ERR_OK;
|
---|
219 | }
|
---|
220 | /*...e*/
|
---|
221 | /*...stga_rpal:0:*/
|
---|
222 | GBM_ERR tga_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
|
---|
223 | {
|
---|
224 | TGA_PRIV *priv = (TGA_PRIV *) gbm->priv;
|
---|
225 |
|
---|
226 | switch ( priv->header.image_type )
|
---|
227 | {
|
---|
228 | /*...sTGA_UNCOMP_BW\44\ TGA_RL_BW:16:*/
|
---|
229 | case TGA_UNCOMP_BW:
|
---|
230 | case TGA_RL_BW:
|
---|
231 | {
|
---|
232 | int i;
|
---|
233 | for ( i = 0; i < 0x100; i++ )
|
---|
234 | gbmrgb[i].b =
|
---|
235 | gbmrgb[i].g =
|
---|
236 | gbmrgb[i].r = (byte) i;
|
---|
237 | }
|
---|
238 | break;
|
---|
239 | /*...e*/
|
---|
240 | /*...sTGA_UNCOMP_CM\44\ TGA_RL_CM:16:*/
|
---|
241 | case TGA_UNCOMP_CM:
|
---|
242 | case TGA_RL_CM:
|
---|
243 | {
|
---|
244 | int color_map_start, color_map_length, i;
|
---|
245 |
|
---|
246 | gbm_file_lseek(fd, (long) (SIZEOF_TGA_HEADER+priv->header.n_chars_in_id), SEEK_SET);
|
---|
247 |
|
---|
248 | color_map_start = make_word(priv->header.color_map_start_low , priv->header.color_map_start_high );
|
---|
249 | color_map_length = make_word(priv->header.color_map_length_low, priv->header.color_map_length_high);
|
---|
250 |
|
---|
251 | memset(gbmrgb, 0, 0x100 * sizeof(GBMRGB));
|
---|
252 | for ( i = color_map_start; i < color_map_start + color_map_length; i++ )
|
---|
253 | {
|
---|
254 | byte b[3];
|
---|
255 |
|
---|
256 | if ( gbm_file_read(fd, (char *) b, 3) != 3 )
|
---|
257 | return GBM_ERR_READ;
|
---|
258 | gbmrgb[i].b = b[0];
|
---|
259 | gbmrgb[i].g = b[1];
|
---|
260 | gbmrgb[i].r = b[2];
|
---|
261 | }
|
---|
262 | }
|
---|
263 | break;
|
---|
264 | /*...e*/
|
---|
265 | }
|
---|
266 |
|
---|
267 | return GBM_ERR_OK;
|
---|
268 | }
|
---|
269 | /*...e*/
|
---|
270 | /*...stga_rdata:0:*/
|
---|
271 | GBM_ERR tga_rdata(int fd, GBM *gbm, byte *data)
|
---|
272 | {
|
---|
273 | TGA_PRIV *priv = (TGA_PRIV *) gbm->priv;
|
---|
274 | byte *p;
|
---|
275 | int i, stride;
|
---|
276 |
|
---|
277 | gbm_file_lseek(fd, (long) (SIZEOF_TGA_HEADER + priv->header.n_chars_in_id), SEEK_SET);
|
---|
278 |
|
---|
279 | if ( priv->header.color_map_present )
|
---|
280 | {
|
---|
281 | int color_map_length;
|
---|
282 | int bpp_pal = priv->header.color_map_entry_bits;
|
---|
283 | /* Valid values are 32, 24, 16 and sometimes 15 */
|
---|
284 |
|
---|
285 | if ( bpp_pal == 15 ) bpp_pal = 16;
|
---|
286 |
|
---|
287 | color_map_length = make_word(priv->header.color_map_length_low, priv->header.color_map_length_high);
|
---|
288 | gbm_file_lseek(fd, (long) ((color_map_length * bpp_pal) / 8L), SEEK_CUR);
|
---|
289 | }
|
---|
290 |
|
---|
291 | stride = ((gbm->w*gbm->bpp + 31) / 32) * 4;
|
---|
292 | p = data;
|
---|
293 | if ( (priv->header.image_descriptor & IDB_ORIGIN) != 0 )
|
---|
294 | {
|
---|
295 | p += (gbm->h-1) * stride;
|
---|
296 | stride = -stride;
|
---|
297 | }
|
---|
298 |
|
---|
299 | switch ( priv->header.image_type )
|
---|
300 | {
|
---|
301 | /*...sTGA_RL_BW\44\ TGA_RL_CM\44\ TGA_RL_RGB:16:*/
|
---|
302 | case TGA_RL_CM:
|
---|
303 | case TGA_RL_BW:
|
---|
304 | case TGA_RL_RGB:
|
---|
305 | {
|
---|
306 | AHEAD *ahead;
|
---|
307 | int x = 0, y = 0;
|
---|
308 | if ( (ahead = gbm_create_ahead(fd)) == NULL )
|
---|
309 | return GBM_ERR_MEM;
|
---|
310 | switch ( priv->header.bpp )
|
---|
311 | {
|
---|
312 | /*...s8:32:*/
|
---|
313 | case 8:
|
---|
314 | while ( y < gbm->h )
|
---|
315 | {
|
---|
316 | int i, cnt = gbm_read_ahead(ahead);
|
---|
317 | if ( cnt == -1 )
|
---|
318 | {
|
---|
319 | gbm_destroy_ahead(ahead);
|
---|
320 | return GBM_ERR_READ;
|
---|
321 | }
|
---|
322 | if ( cnt & 0x80 )
|
---|
323 | {
|
---|
324 | byte v = (byte) gbm_read_ahead(ahead);
|
---|
325 | for ( i = 0x80; i <= cnt; i++ )
|
---|
326 | {
|
---|
327 | data[x++] = v;
|
---|
328 | if ( x == gbm->w )
|
---|
329 | { x = 0; y++; data += stride; }
|
---|
330 | }
|
---|
331 | }
|
---|
332 | else
|
---|
333 | for ( i = 0; i <= cnt; i++ )
|
---|
334 | {
|
---|
335 | data[x++] = (byte) gbm_read_ahead(ahead);
|
---|
336 | if ( x == gbm->w )
|
---|
337 | { x = 0; y++; data += stride; }
|
---|
338 | }
|
---|
339 | }
|
---|
340 | break;
|
---|
341 | /*...e*/
|
---|
342 | /*...s16:32:*/
|
---|
343 | /*
|
---|
344 | We have 3 bytes per pixel in the data array, indexed by p.
|
---|
345 | We will read 2 bytes per pixel into the right hand 2/3 of each line.
|
---|
346 | Then we will expand leftwards to fill the full width afterwards.
|
---|
347 | */
|
---|
348 |
|
---|
349 | case 16:
|
---|
350 |
|
---|
351 | p += gbm->w;
|
---|
352 |
|
---|
353 | while ( y < gbm->h )
|
---|
354 | {
|
---|
355 | int i, cnt = gbm_read_ahead(ahead);
|
---|
356 | if ( cnt == -1 )
|
---|
357 | {
|
---|
358 | gbm_destroy_ahead(ahead);
|
---|
359 | return GBM_ERR_READ;
|
---|
360 | }
|
---|
361 | if ( cnt & 0x80 )
|
---|
362 | {
|
---|
363 | byte v1 = (byte) gbm_read_ahead(ahead);
|
---|
364 | byte v2 = (byte) gbm_read_ahead(ahead);
|
---|
365 | for ( i = 0x80; i <= cnt; i++ )
|
---|
366 | {
|
---|
367 | p[x++] = v1;
|
---|
368 | p[x++] = v2;
|
---|
369 | if ( x == gbm->w*2 )
|
---|
370 | { x = 0; y++; p += stride; }
|
---|
371 | }
|
---|
372 | }
|
---|
373 | else
|
---|
374 | for ( i = 0; i <= cnt; i++ )
|
---|
375 | {
|
---|
376 | p[x++] = (byte) gbm_read_ahead(ahead);
|
---|
377 | p[x++] = (byte) gbm_read_ahead(ahead);
|
---|
378 | if ( x == gbm->w*2 )
|
---|
379 | { x = 0; y++; p += stride; }
|
---|
380 | }
|
---|
381 | }
|
---|
382 |
|
---|
383 | if ( stride < 0 )
|
---|
384 | stride = -stride;
|
---|
385 | for ( y = 0, p = data; y < gbm->h; y++, p += stride )
|
---|
386 | t16_t24(p, p+gbm->w, gbm->w);
|
---|
387 |
|
---|
388 | break;
|
---|
389 | /*...e*/
|
---|
390 | /*...s24:32:*/
|
---|
391 | case 24:
|
---|
392 | while ( y < gbm->h )
|
---|
393 | {
|
---|
394 | int i, cnt = gbm_read_ahead(ahead);
|
---|
395 | if ( cnt == -1 )
|
---|
396 | {
|
---|
397 | gbm_destroy_ahead(ahead);
|
---|
398 | return GBM_ERR_READ;
|
---|
399 | }
|
---|
400 | if ( cnt & 0x80 )
|
---|
401 | {
|
---|
402 | byte v1 = (byte) gbm_read_ahead(ahead);
|
---|
403 | byte v2 = (byte) gbm_read_ahead(ahead);
|
---|
404 | byte v3 = (byte) gbm_read_ahead(ahead);
|
---|
405 | for ( i = 0x80; i <= cnt; i++ )
|
---|
406 | {
|
---|
407 | p[x++] = v1;
|
---|
408 | p[x++] = v2;
|
---|
409 | p[x++] = v3;
|
---|
410 | if ( x == gbm->w*3 )
|
---|
411 | { x = 0; y++; p += stride; }
|
---|
412 | }
|
---|
413 | }
|
---|
414 | else
|
---|
415 | for ( i = 0; i <= cnt; i++ )
|
---|
416 | {
|
---|
417 | p[x++] = (byte) gbm_read_ahead(ahead);
|
---|
418 | p[x++] = (byte) gbm_read_ahead(ahead);
|
---|
419 | p[x++] = (byte) gbm_read_ahead(ahead);
|
---|
420 | if ( x == gbm->w*3 )
|
---|
421 | { x = 0; y++; p += stride; }
|
---|
422 | }
|
---|
423 | }
|
---|
424 | break;
|
---|
425 | /*...e*/
|
---|
426 | /*...s32:32:*/
|
---|
427 | case 32:
|
---|
428 | while ( y < gbm->h )
|
---|
429 | {
|
---|
430 | int i, cnt = gbm_read_ahead(ahead);
|
---|
431 | if ( cnt == -1 )
|
---|
432 | {
|
---|
433 | gbm_destroy_ahead(ahead);
|
---|
434 | return GBM_ERR_READ;
|
---|
435 | }
|
---|
436 | if ( cnt & 0x80 )
|
---|
437 | {
|
---|
438 | byte v1 = (byte) gbm_read_ahead(ahead);
|
---|
439 | byte v2 = (byte) gbm_read_ahead(ahead);
|
---|
440 | byte v3 = (byte) gbm_read_ahead(ahead);
|
---|
441 | gbm_read_ahead(ahead); /* Discard alpha channel */
|
---|
442 | for ( i = 0x80; i <= cnt; i++ )
|
---|
443 | {
|
---|
444 | p[x++] = v1;
|
---|
445 | p[x++] = v2;
|
---|
446 | p[x++] = v3;
|
---|
447 | if ( x == gbm->w*3 )
|
---|
448 | { x = 0; y++; p += stride; }
|
---|
449 | }
|
---|
450 | }
|
---|
451 | else
|
---|
452 | for ( i = 0; i <= cnt; i++ )
|
---|
453 | {
|
---|
454 | p[x++] = (byte) gbm_read_ahead(ahead);
|
---|
455 | p[x++] = (byte) gbm_read_ahead(ahead);
|
---|
456 | p[x++] = (byte) gbm_read_ahead(ahead);
|
---|
457 | gbm_read_ahead(ahead); /* Discard alpha channel */
|
---|
458 | if ( x == gbm->w*3 )
|
---|
459 | { x = 0; y++; p += stride; }
|
---|
460 | }
|
---|
461 | }
|
---|
462 | break;
|
---|
463 | /*...e*/
|
---|
464 | }
|
---|
465 | gbm_destroy_ahead(ahead);
|
---|
466 | }
|
---|
467 | break;
|
---|
468 | /*...e*/
|
---|
469 | /*...sTGA_UNCOMP_BW\44\ TGA_UNCOMP_CM\44\ TGA_UNCOMP_RGB:16:*/
|
---|
470 | case TGA_UNCOMP_BW:
|
---|
471 | case TGA_UNCOMP_CM:
|
---|
472 | case TGA_UNCOMP_RGB:
|
---|
473 | switch ( priv->header.bpp )
|
---|
474 | {
|
---|
475 | /*...s8:32:*/
|
---|
476 | case 8:
|
---|
477 | for ( i = 0; i < gbm->h; i++, p += stride )
|
---|
478 | if ( gbm_file_read(fd, p, gbm->w) != gbm->w )
|
---|
479 | return GBM_ERR_READ;
|
---|
480 | break;
|
---|
481 | /*...e*/
|
---|
482 | /*...s16:32:*/
|
---|
483 | case 16:
|
---|
484 | for ( i = 0; i < gbm->h; i++, p += stride )
|
---|
485 | {
|
---|
486 | if ( gbm_file_read(fd, p+gbm->w, gbm->w * 2) != gbm->w * 2 )
|
---|
487 | return GBM_ERR_READ;
|
---|
488 | t16_t24(p, p+gbm->w, gbm->w);
|
---|
489 | }
|
---|
490 | break;
|
---|
491 | /*...e*/
|
---|
492 | /*...s24:32:*/
|
---|
493 | case 24:
|
---|
494 | for ( i = 0; i < gbm->h; i++, p += stride )
|
---|
495 | if ( gbm_file_read(fd, p, gbm->w * 3) != gbm->w * 3 )
|
---|
496 | return GBM_ERR_READ;
|
---|
497 | break;
|
---|
498 | /*...e*/
|
---|
499 | /*...s32:32:*/
|
---|
500 | case 32:
|
---|
501 | {
|
---|
502 | byte *linebuf;
|
---|
503 | if ( (linebuf = malloc((size_t) (gbm->w * 4))) == NULL )
|
---|
504 | return GBM_ERR_MEM;
|
---|
505 |
|
---|
506 | for ( i = 0; i < gbm->h; i++, p += stride )
|
---|
507 | {
|
---|
508 | if ( gbm_file_read(fd, linebuf, gbm->w * 4) != gbm->w * 4 )
|
---|
509 | {
|
---|
510 | free(linebuf);
|
---|
511 | return GBM_ERR_READ;
|
---|
512 | }
|
---|
513 | t32_t24(p, linebuf, gbm->w);
|
---|
514 | }
|
---|
515 |
|
---|
516 | free(linebuf);
|
---|
517 | }
|
---|
518 | break;
|
---|
519 | /*...e*/
|
---|
520 | }
|
---|
521 | break;
|
---|
522 | /*...e*/
|
---|
523 | }
|
---|
524 |
|
---|
525 | return GBM_ERR_OK;
|
---|
526 | }
|
---|
527 | /*...e*/
|
---|
528 | /*...stga_w:0:*/
|
---|
529 | #define SW3(a,b,c) ((a)*4+(b)*2+(c))
|
---|
530 |
|
---|
531 | GBM_ERR tga_w(const char *fn, int fd, const GBM *gbm, const GBMRGB *gbmrgb, const byte *data, const char *opt)
|
---|
532 | {
|
---|
533 | TGA_HEADER tga_header;
|
---|
534 | int i, stride, obpp;
|
---|
535 | const byte *p;
|
---|
536 | BOOLEAN o16 = ( gbm_find_word(opt, "16" ) != NULL );
|
---|
537 | BOOLEAN o24 = ( gbm_find_word(opt, "24" ) != NULL );
|
---|
538 | BOOLEAN o32 = ( gbm_find_word(opt, "32" ) != NULL );
|
---|
539 | BOOLEAN yup = ( gbm_find_word(opt, "yup" ) != NULL );
|
---|
540 | BOOLEAN ydown = ( gbm_find_word(opt, "ydown") != NULL );
|
---|
541 |
|
---|
542 | fn=fn; /* Suppress 'unref arg' compiler warning */
|
---|
543 |
|
---|
544 | if ( gbm->bpp == 24 )
|
---|
545 | switch ( SW3(o16,o24,o32) )
|
---|
546 | {
|
---|
547 | case SW3(1,0,0): obpp = 16; break;
|
---|
548 | case SW3(0,0,0):
|
---|
549 | case SW3(0,1,0): obpp = 24; break;
|
---|
550 | case SW3(0,0,1): obpp = 32; break;
|
---|
551 | default: return GBM_ERR_BAD_OPTION;
|
---|
552 | }
|
---|
553 | else
|
---|
554 | {
|
---|
555 | if ( o16 || o24 || o32 )
|
---|
556 | return GBM_ERR_BAD_OPTION;
|
---|
557 | obpp = 8;
|
---|
558 | }
|
---|
559 |
|
---|
560 | if ( yup && ydown )
|
---|
561 | return GBM_ERR_BAD_OPTION;
|
---|
562 |
|
---|
563 | tga_header.n_chars_in_id = 0;
|
---|
564 | tga_header.image_type = ( obpp == 8 ) ? TGA_UNCOMP_CM : TGA_UNCOMP_RGB;
|
---|
565 | tga_header.x_origin_low = low_byte(0);
|
---|
566 | tga_header.x_origin_high = high_byte(0);
|
---|
567 | tga_header.y_origin_low = low_byte(0);
|
---|
568 | tga_header.y_origin_high = high_byte(0);
|
---|
569 | tga_header.color_map_start_low = low_byte(0);
|
---|
570 | tga_header.color_map_start_high = high_byte(0);
|
---|
571 | if ( gbm->bpp == 8 )
|
---|
572 | {
|
---|
573 | tga_header.color_map_present = (byte) 1;
|
---|
574 | tga_header.color_map_length_low = low_byte(0x100);
|
---|
575 | tga_header.color_map_length_high = high_byte(0x100);
|
---|
576 | tga_header.color_map_entry_bits = 24;
|
---|
577 | }
|
---|
578 | else
|
---|
579 | {
|
---|
580 | tga_header.color_map_present = (byte) 0;
|
---|
581 | tga_header.color_map_length_low = low_byte(0);
|
---|
582 | tga_header.color_map_length_high = high_byte(0);
|
---|
583 | tga_header.color_map_entry_bits = 0;
|
---|
584 | }
|
---|
585 | tga_header.width_low = low_byte(gbm->w);
|
---|
586 | tga_header.width_high = high_byte(gbm->w);
|
---|
587 | tga_header.height_low = low_byte(gbm->h);
|
---|
588 | tga_header.height_high = high_byte(gbm->h);
|
---|
589 | tga_header.bpp = (byte) obpp;
|
---|
590 | tga_header.image_descriptor = IDB_NON_INT;
|
---|
591 |
|
---|
592 | if ( ydown )
|
---|
593 | tga_header.image_descriptor |= IDB_ORIGIN;
|
---|
594 |
|
---|
595 | gbm_file_write(fd, (char *) &tga_header, SIZEOF_TGA_HEADER);
|
---|
596 |
|
---|
597 | switch ( obpp )
|
---|
598 | {
|
---|
599 | /*...s8:16:*/
|
---|
600 | case 8:
|
---|
601 | for ( i = 0; i < 0x100; i++ )
|
---|
602 | {
|
---|
603 | byte b[3];
|
---|
604 |
|
---|
605 | b[0] = gbmrgb[i].b;
|
---|
606 | b[1] = gbmrgb[i].g;
|
---|
607 | b[2] = gbmrgb[i].r;
|
---|
608 | gbm_file_write(fd, b, 3);
|
---|
609 | }
|
---|
610 |
|
---|
611 | stride = ((gbm->w + 3) & ~3);
|
---|
612 | p = data;
|
---|
613 |
|
---|
614 | if ( ydown )
|
---|
615 | {
|
---|
616 | p += ((gbm->h - 1) * stride);
|
---|
617 | stride = -stride;
|
---|
618 | }
|
---|
619 |
|
---|
620 | for ( i = 0; i < gbm->h; i++ )
|
---|
621 | {
|
---|
622 | gbm_file_write(fd, p, gbm->w);
|
---|
623 | p += stride;
|
---|
624 | }
|
---|
625 | break;
|
---|
626 | /*...e*/
|
---|
627 | /*...s16:16:*/
|
---|
628 | case 16:
|
---|
629 | {
|
---|
630 | byte *linebuf;
|
---|
631 |
|
---|
632 | if ( (linebuf = malloc((size_t) (gbm->w * 2))) == NULL )
|
---|
633 | return GBM_ERR_MEM;
|
---|
634 |
|
---|
635 | stride = ((gbm->w * 3 + 3) & ~3);
|
---|
636 | p = data;
|
---|
637 |
|
---|
638 | if ( ydown )
|
---|
639 | {
|
---|
640 | p += ((gbm->h - 1) * stride);
|
---|
641 | stride = -stride;
|
---|
642 | }
|
---|
643 |
|
---|
644 | for ( i = 0; i < gbm->h; i++ )
|
---|
645 | {
|
---|
646 | t24_t16(linebuf, p, gbm->w);
|
---|
647 | gbm_file_write(fd, linebuf, gbm->w * 2);
|
---|
648 | p += stride;
|
---|
649 | }
|
---|
650 |
|
---|
651 | free(linebuf);
|
---|
652 | }
|
---|
653 | break;
|
---|
654 | /*...e*/
|
---|
655 | /*...s24:16:*/
|
---|
656 | case 24:
|
---|
657 | stride = ((gbm->w * 3 + 3) & ~3);
|
---|
658 | p = data;
|
---|
659 |
|
---|
660 | if ( ydown )
|
---|
661 | {
|
---|
662 | p += ((gbm->h - 1) * stride);
|
---|
663 | stride = -stride;
|
---|
664 | }
|
---|
665 |
|
---|
666 | for ( i = 0; i < gbm->h; i++ )
|
---|
667 | {
|
---|
668 | gbm_file_write(fd, p, gbm->w * 3);
|
---|
669 | p += stride;
|
---|
670 | }
|
---|
671 | break;
|
---|
672 | /*...e*/
|
---|
673 | /*...s32:16:*/
|
---|
674 | case 32:
|
---|
675 | {
|
---|
676 | byte *linebuf;
|
---|
677 |
|
---|
678 | if ( (linebuf = malloc((size_t) (gbm->w * 4))) == NULL )
|
---|
679 | return GBM_ERR_MEM;
|
---|
680 |
|
---|
681 | stride = ((gbm->w * 3 + 3) & ~3);
|
---|
682 | p = data;
|
---|
683 |
|
---|
684 | if ( ydown )
|
---|
685 | {
|
---|
686 | p += ((gbm->h - 1) * stride);
|
---|
687 | stride = -stride;
|
---|
688 | }
|
---|
689 |
|
---|
690 | for ( i = 0; i < gbm->h; i++ )
|
---|
691 | {
|
---|
692 | t24_t32(linebuf, p, gbm->w);
|
---|
693 | gbm_file_write(fd, linebuf, gbm->w * 4);
|
---|
694 | p += stride;
|
---|
695 | }
|
---|
696 |
|
---|
697 | free(linebuf);
|
---|
698 | }
|
---|
699 | break;
|
---|
700 | /*...e*/
|
---|
701 | }
|
---|
702 |
|
---|
703 | return GBM_ERR_OK;
|
---|
704 | }
|
---|
705 | /*...e*/
|
---|
706 | /*...stga_err:0:*/
|
---|
707 | const char *tga_err(GBM_ERR rc)
|
---|
708 | {
|
---|
709 | switch ( (int) rc )
|
---|
710 | {
|
---|
711 | case GBM_ERR_TGA_BAD_BPP:
|
---|
712 | return "bits per pixel not 8, 16, 24 or 32";
|
---|
713 | case GBM_ERR_TGA_BAD_TYPE:
|
---|
714 | return "unsupported compression type for bits per pixel";
|
---|
715 | case GBM_ERR_TGA_BAD_PAL:
|
---|
716 | return "color map entry size not 24 bits per pixel";
|
---|
717 | }
|
---|
718 | return NULL;
|
---|
719 | }
|
---|
720 | /*...e*/
|
---|