1 #include "imageri.h"
2 #include "log.h"
3 #include "iolayer.h"
4
5 #include <stdlib.h>
6 #include <errno.h>
7
8
9 /*
10 =head1 NAME
11
12 tga.c - implements reading and writing targa files, uses io layer.
13
14 =head1 SYNOPSIS
15
16 io_glue *ig = io_new_fd( fd );
17 i_img *im = i_readtga_wiol(ig, -1); // no limit on how much is read
18 // or
19 io_glue *ig = io_new_fd( fd );
20 return_code = i_writetga_wiol(im, ig);
21
22 =head1 DESCRIPTION
23
24 tga.c implements the basic functions to read and write portable targa
25 files. It uses the iolayer and needs either a seekable source or an
26 entire memory mapped buffer.
27
28 =head1 FUNCTION REFERENCE
29
30 Some of these functions are internal.
31
32 =over
33
34 =cut
35 */
36
37
38
39
40 typedef struct {
41 unsigned char idlength;
42 char colourmaptype;
43 char datatypecode;
44 short int colourmaporigin;
45 short int colourmaplength;
46 char colourmapdepth;
47 short int x_origin;
48 short int y_origin;
49 int width;
50 int height;
51 char bitsperpixel;
52 char imagedescriptor;
53 } tga_header;
54
55
56 typedef enum { NoInit, Raw, Rle } rle_state;
57
58 typedef struct {
59 int compressed;
60 size_t bytepp;
61 rle_state state;
62 unsigned char cval[4];
63 int len;
64 unsigned char hdr;
65 io_glue *ig;
66 } tga_source;
67
68
69 typedef struct {
70 int compressed;
71 int bytepp;
72 io_glue *ig;
73 } tga_dest;
74
75 #define TGA_MAX_DIM 0xFFFF
76
77 /*
78 =item bpp_to_bytes(bpp)
79
80 Convert bits per pixel into bytes per pixel
81
82 bpp - bits per pixel
83
84 =cut
85 */
86
87
88 static
89 size_t
bpp_to_bytes(unsigned int bpp)90 bpp_to_bytes(unsigned int bpp) {
91 switch (bpp) {
92 case 8:
93 return 1;
94 case 15:
95 case 16:
96 return 2;
97 case 24:
98 return 3;
99 case 32:
100 return 4;
101 }
102 return 0;
103 }
104
105
106
107 /*
108 =item bpp_to_channels(bpp)
109
110 Convert bits per pixel and the number of attribute bits into channels
111 in the image
112
113 bpp - bits per pixel
114 attr_bit_count - number of attribute bits
115
116 =cut
117 */
118
119 static
120 int
bpp_to_channels(unsigned int bpp,int attr_bit_count)121 bpp_to_channels(unsigned int bpp, int attr_bit_count) {
122 switch (bpp) {
123 case 8:
124 return 1;
125 case 16:
126 if (attr_bit_count == 1)
127 return 4;
128 case 15:
129 return 3;
130 case 32:
131 if (attr_bit_count == 8)
132 return 4;
133 case 24:
134 return 3;
135 }
136 return 0;
137 }
138
139
140
141 /*
142 * Packing functions - used for (un)packing
143 * datastructures into raw bytes.
144 */
145
146
147 /*
148 =item color_unpack(buf, bytepp, val)
149
150 Unpacks bytes into colour structures, for 2 byte type the first byte
151 coming from the file will actually be GGGBBBBB, and the second will be
152 ARRRRRGG. "A" represents an attribute bit. The 3 byte entry contains
153 1 byte each of blue, green, and red. The 4 byte entry contains 1 byte
154 each of blue, green, red, and attribute.
155
156 buf - pointer to data
157 bytepp - bytes per pixel
158 val - pointer to color to store to
159
160 =cut
161 */
162
163 static
164 void
color_unpack(unsigned char * buf,int bytepp,i_color * val)165 color_unpack(unsigned char *buf, int bytepp, i_color *val) {
166 switch (bytepp) {
167 case 1:
168 val->gray.gray_color = buf[0];
169 break;
170 case 2:
171 val->rgba.r = (buf[1] & 0x7c) << 1;
172 val->rgba.g = ((buf[1] & 0x03) << 6) | ((buf[0] & 0xe0) >> 2);
173 val->rgba.b = (buf[0] & 0x1f) << 3;
174 val->rgba.a = (buf[1] & 0x80) ? 0 : 255;
175 val->rgba.r |= val->rgba.r >> 5;
176 val->rgba.g |= val->rgba.g >> 5;
177 val->rgba.b |= val->rgba.b >> 5;
178 break;
179 case 3:
180 val->rgb.b = buf[0];
181 val->rgb.g = buf[1];
182 val->rgb.r = buf[2];
183 break;
184 case 4:
185 val->rgba.b = buf[0];
186 val->rgba.g = buf[1];
187 val->rgba.r = buf[2];
188 val->rgba.a = buf[3];
189 break;
190 }
191 }
192
193
194
195 /*
196 =item color_pack
197
198 Packs a colour into an array of bytes, for 2 byte type the first byte
199 will be GGGBBBBB, and the second will be ARRRRRGG. "A" represents an
200 attribute bit. The 3 byte entry contains 1 byte each of blue, green,
201 and red. The 4 byte entry contains 1 byte each of blue, green, red,
202 and attribute.
203
204 buf - destination buffer
205 bitspp - bits per pixel
206 val - color to pack
207
208 =cut
209 */
210
211 static
212 void
color_pack(unsigned char * buf,int bitspp,i_color * val)213 color_pack(unsigned char *buf, int bitspp, i_color *val) {
214 switch (bitspp) {
215 case 8:
216 buf[0] = val->gray.gray_color;
217 break;
218 case 16:
219 buf[0] = (val->rgba.b >> 3);
220 buf[0] |= (val->rgba.g & 0x38) << 2;
221 buf[1] = (val->rgba.r & 0xf8)>> 1;
222 buf[1] |= (val->rgba.g >> 6);
223 buf[1] |= val->rgba.a > 0x7f ? 0 : 0x80;
224 break;
225 case 15:
226 buf[0] = (val->rgba.b >> 3);
227 buf[0] |= (val->rgba.g & 0x38) << 2;
228 buf[1] = (val->rgba.r & 0xf8)>> 1;
229 buf[1] |= (val->rgba.g >> 6);
230 break;
231 case 24:
232 buf[0] = val->rgb.b;
233 buf[1] = val->rgb.g;
234 buf[2] = val->rgb.r;
235 break;
236 case 32:
237 buf[0] = val->rgba.b;
238 buf[1] = val->rgba.g;
239 buf[2] = val->rgba.r;
240 buf[3] = val->rgba.a;
241 break;
242 }
243 }
244
245
246 /*
247 =item find_repeat
248
249 Helper function for rle compressor to find the next triple repeat of the
250 same pixel value in buffer.
251
252 buf - buffer
253 length - number of pixel values in buffer
254 bytepp - number of bytes in a pixel value
255
256 =cut
257 */
258
259 static
260 int
find_repeat(unsigned char * buf,int length,int bytepp)261 find_repeat(unsigned char *buf, int length, int bytepp) {
262 int i = 0;
263
264 while(i<length-1) {
265 if(memcmp(buf+i*bytepp, buf+(i+1)*bytepp, bytepp) == 0) {
266 if (i == length-2) return -1;
267 if (memcmp(buf+(i+1)*bytepp, buf+(i+2)*bytepp,bytepp) == 0)
268 return i;
269 else i++;
270 }
271 i++;
272 }
273 return -1;
274 }
275
276
277 /*
278 =item find_span
279
280 Helper function for rle compressor to find the length of a span where
281 the same pixel value is in the buffer.
282
283 buf - buffer
284 length - number of pixel values in buffer
285 bytepp - number of bytes in a pixel value
286
287 =cut
288 */
289
290 static
291 int
find_span(unsigned char * buf,int length,int bytepp)292 find_span(unsigned char *buf, int length, int bytepp) {
293 int i = 0;
294 while(i<length) {
295 if(memcmp(buf, buf+(i*bytepp), bytepp) != 0) return i;
296 i++;
297 }
298 return length;
299 }
300
301
302 /*
303 =item tga_header_unpack(header, headbuf)
304
305 Unpacks the header structure into from buffer and stores
306 in the header structure.
307
308 header - header structure
309 headbuf - buffer to unpack from
310
311 =cut
312 */
313
314 static
315 void
tga_header_unpack(tga_header * header,unsigned char headbuf[18])316 tga_header_unpack(tga_header *header, unsigned char headbuf[18]) {
317 header->idlength = headbuf[0];
318 header->colourmaptype = headbuf[1];
319 header->datatypecode = headbuf[2];
320 header->colourmaporigin = (headbuf[4] << 8) + headbuf[3];
321 header->colourmaplength = (headbuf[6] << 8) + headbuf[5];
322 header->colourmapdepth = headbuf[7];
323 header->x_origin = (headbuf[9] << 8) + headbuf[8];
324 header->y_origin = (headbuf[11] << 8) + headbuf[10];
325 header->width = (headbuf[13] << 8) + headbuf[12];
326 header->height = (headbuf[15] << 8) + headbuf[14];
327 header->bitsperpixel = headbuf[16];
328 header->imagedescriptor = headbuf[17];
329 }
330
331
332 /* this function should never produce diagnostics to stdout, maybe to the logfile */
333 int
tga_header_verify(unsigned char headbuf[18])334 tga_header_verify(unsigned char headbuf[18]) {
335 tga_header header;
336 tga_header_unpack(&header, headbuf);
337 switch (header.datatypecode) {
338 default:
339 /*printf("bad typecode!\n");*/
340 return 0;
341 case 1: /* Uncompressed, color-mapped images */
342 case 3: /* Uncompressed, grayscale images */
343 case 9: /* Compressed, color-mapped images */
344 case 11: /* Compressed, grayscale images */
345 if (header.bitsperpixel != 8)
346 return 0;
347 break;
348 case 0:
349 case 2: /* Uncompressed, rgb images */
350 case 10: /* Compressed, rgb images */
351 if (header.bitsperpixel != 15 && header.bitsperpixel != 16
352 && header.bitsperpixel != 24 && header.bitsperpixel != 32)
353 return 0;
354 break;
355 }
356
357 switch (header.colourmaptype) {
358 default:
359 /*printf("bad colourmaptype!\n");*/
360 return 0;
361 case 1:
362 if (header.datatypecode != 1 && header.datatypecode != 9)
363 return 0; /* only get a color map on a color mapped image */
364 case 0:
365 break;
366 }
367
368 switch (header.colourmapdepth) {
369 default:
370 return 0;
371 case 0: /* can be 0 if no colour map */
372 case 15:
373 case 16:
374 case 24:
375 case 32:
376 break;
377 }
378
379 return 1;
380 }
381
382
383 /*
384 =item tga_header_pack(header, headbuf)
385
386 Packs header structure into buffer for writing.
387
388 header - header structure
389 headbuf - buffer to pack into
390
391 =cut
392 */
393
394 static
395 void
tga_header_pack(tga_header * header,unsigned char headbuf[18])396 tga_header_pack(tga_header *header, unsigned char headbuf[18]) {
397 headbuf[0] = header->idlength;
398 headbuf[1] = header->colourmaptype;
399 headbuf[2] = header->datatypecode;
400 headbuf[3] = header->colourmaporigin & 0xff;
401 headbuf[4] = header->colourmaporigin >> 8;
402 headbuf[5] = header->colourmaplength & 0xff;
403 headbuf[6] = header->colourmaplength >> 8;
404 headbuf[7] = header->colourmapdepth;
405 headbuf[8] = header->x_origin & 0xff;
406 headbuf[9] = header->x_origin >> 8;
407 headbuf[10] = header->y_origin & 0xff;
408 headbuf[11] = header->y_origin >> 8;
409 headbuf[12] = header->width & 0xff;
410 headbuf[13] = header->width >> 8;
411 headbuf[14] = header->height & 0xff;
412 headbuf[15] = header->height >> 8;
413 headbuf[16] = header->bitsperpixel;
414 headbuf[17] = header->imagedescriptor;
415 }
416
417
418 /*
419 =item tga_source_read(s, buf, pixels)
420
421 Reads pixel number of pixels from source s into buffer buf. Takes
422 care of decompressing the stream if needed.
423
424 s - data source
425 buf - destination buffer
426 pixels - number of pixels to put into buffer
427
428 =cut
429 */
430
431 static
432 int
tga_source_read(tga_source * s,unsigned char * buf,size_t pixels)433 tga_source_read(tga_source *s, unsigned char *buf, size_t pixels) {
434 int cp = 0, j, k;
435 if (!s->compressed) {
436 if (i_io_read(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0;
437 return 1;
438 }
439
440 while(cp < pixels) {
441 int ml;
442 if (s->len == 0) s->state = NoInit;
443 switch (s->state) {
444 case NoInit:
445 if (i_io_read(s->ig, &s->hdr, 1) != 1) return 0;
446
447 s->len = (s->hdr &~(1<<7))+1;
448 s->state = (s->hdr & (1<<7)) ? Rle : Raw;
449 {
450 /*
451 static cnt = 0;
452 printf("%04d %s: %d\n", cnt++, s->state==Rle?"RLE":"RAW", s->len);
453 */
454 }
455 if (s->state == Rle && i_io_read(s->ig, s->cval, s->bytepp) != s->bytepp) return 0;
456
457 break;
458 case Rle:
459 ml = i_min(s->len, pixels-cp);
460 for(k=0; k<ml; k++) for(j=0; j<s->bytepp; j++)
461 buf[(cp+k)*s->bytepp+j] = s->cval[j];
462 cp += ml;
463 s->len -= ml;
464 break;
465 case Raw:
466 ml = i_min(s->len, pixels-cp);
467 if (i_io_read(s->ig, buf+cp*s->bytepp, ml*s->bytepp) != ml*s->bytepp) return 0;
468 cp += ml;
469 s->len -= ml;
470 break;
471 }
472 }
473 return 1;
474 }
475
476
477
478
479 /*
480 =item tga_dest_write(s, buf, pixels)
481
482 Writes pixels from buf to destination s. Takes care of compressing if the
483 destination is compressed.
484
485 s - data destination
486 buf - source buffer
487 pixels - number of pixels to put write to destination
488
489 =cut
490 */
491
492 static
493 int
tga_dest_write(tga_dest * s,unsigned char * buf,size_t pixels)494 tga_dest_write(tga_dest *s, unsigned char *buf, size_t pixels) {
495 int cp = 0;
496
497 if (!s->compressed) {
498 if (i_io_write(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0;
499 return 1;
500 }
501
502 while(cp < pixels) {
503 int tlen;
504 int nxtrip = find_repeat(buf+cp*s->bytepp, pixels-cp, s->bytepp);
505 tlen = (nxtrip == -1) ? pixels-cp : nxtrip;
506 while(tlen) {
507 unsigned char clen = (tlen>128) ? 128 : tlen;
508 clen--;
509 if (i_io_write(s->ig, &clen, 1) != 1) return 0;
510 clen++;
511 if (i_io_write(s->ig, buf+cp*s->bytepp, clen*s->bytepp) != clen*s->bytepp) return 0;
512 tlen -= clen;
513 cp += clen;
514 }
515 if (cp >= pixels) break;
516 tlen = find_span(buf+cp*s->bytepp, pixels-cp, s->bytepp);
517 if (tlen <3) continue;
518 while (tlen) {
519 unsigned char clen = (tlen>128) ? 128 : tlen;
520 clen = (clen - 1) | 0x80;
521 if (i_io_write(s->ig, &clen, 1) != 1) return 0;
522 clen = (clen & ~0x80) + 1;
523 if (i_io_write(s->ig, buf+cp*s->bytepp, s->bytepp) != s->bytepp) return 0;
524 tlen -= clen;
525 cp += clen;
526 }
527 }
528 return 1;
529 }
530
531
532
533
534
535
536 /*
537 =item tga_palette_read(ig, img, bytepp, colourmaplength)
538
539 Reads the colormap from a tga file and stores in the paletted image
540 structure.
541
542 ig - iolayer data source
543 img - image structure
544 bytepp - bytes per pixel
545 colourmaplength - number of colours in colourmap
546
547 =cut
548 */
549
550 static
551 int
tga_palette_read(io_glue * ig,i_img * img,int bytepp,int colourmaplength)552 tga_palette_read(io_glue *ig, i_img *img, int bytepp, int colourmaplength) {
553 int i;
554 size_t palbsize;
555 unsigned char *palbuf;
556 i_color val;
557
558 palbsize = colourmaplength*bytepp;
559 palbuf = mymalloc(palbsize);
560
561 if (i_io_read(ig, palbuf, palbsize) != palbsize) {
562 i_push_error(errno, "could not read targa colormap");
563 return 0;
564 }
565
566 /* populate the palette of the new image */
567 for(i=0; i<colourmaplength; i++) {
568 color_unpack(palbuf+i*bytepp, bytepp, &val);
569 i_addcolors(img, &val, 1);
570 }
571 myfree(palbuf);
572 return 1;
573 }
574
575
576 /*
577 =item tga_palette_write(ig, img, bitspp, colourmaplength)
578
579 Stores the colormap of an image in the destination ig.
580
581 ig - iolayer data source
582 img - image structure
583 bitspp - bits per pixel in colourmap
584 colourmaplength - number of colours in colourmap
585
586 =cut
587 */
588
589 static
590 int
tga_palette_write(io_glue * ig,i_img * img,int bitspp,int colourmaplength)591 tga_palette_write(io_glue *ig, i_img *img, int bitspp, int colourmaplength) {
592 int i;
593 size_t bytepp = bpp_to_bytes(bitspp);
594 size_t palbsize = i_colorcount(img)*bytepp;
595 unsigned char *palbuf = mymalloc(palbsize);
596
597 for(i=0; i<colourmaplength; i++) {
598 i_color val;
599 i_getcolors(img, i, &val, 1);
600 color_pack(palbuf+i*bytepp, bitspp, &val);
601 }
602
603 if (i_io_write(ig, palbuf, palbsize) != palbsize) {
604 i_push_error(errno, "could not write targa colormap");
605 return 0;
606 }
607 myfree(palbuf);
608 return 1;
609 }
610
611
612
613 /*
614 =item i_readtga_wiol(ig, length)
615
616 Read in an image from the iolayer data source and return the image structure to it.
617 Returns NULL on error.
618
619 ig - io_glue object
620 length - maximum length to read from data source, before closing it -1
621 signifies no limit.
622
623 =cut
624 */
625
626 i_img *
i_readtga_wiol(io_glue * ig,int length)627 i_readtga_wiol(io_glue *ig, int length) {
628 i_img* img = NULL;
629 int x, y;
630 int width, height, channels;
631 int mapped;
632 char *idstring = NULL;
633
634 tga_source src;
635 tga_header header;
636 unsigned char headbuf[18];
637 unsigned char *databuf;
638
639 i_color *linebuf = NULL;
640 i_clear_error();
641
642 mm_log((1,"i_readtga(ig %p, length %d)\n", ig, length));
643
644 if (i_io_read(ig, &headbuf, 18) != 18) {
645 i_push_error(errno, "could not read targa header");
646 return NULL;
647 }
648
649 tga_header_unpack(&header, headbuf);
650
651 mm_log((1,"Id length: %d\n",header.idlength));
652 mm_log((1,"Colour map type: %d\n",header.colourmaptype));
653 mm_log((1,"Image type: %d\n",header.datatypecode));
654 mm_log((1,"Colour map offset: %d\n",header.colourmaporigin));
655 mm_log((1,"Colour map length: %d\n",header.colourmaplength));
656 mm_log((1,"Colour map depth: %d\n",header.colourmapdepth));
657 mm_log((1,"X origin: %d\n",header.x_origin));
658 mm_log((1,"Y origin: %d\n",header.y_origin));
659 mm_log((1,"Width: %d\n",header.width));
660 mm_log((1,"Height: %d\n",header.height));
661 mm_log((1,"Bits per pixel: %d\n",header.bitsperpixel));
662 mm_log((1,"Descriptor: %d\n",header.imagedescriptor));
663
664 if (header.idlength) {
665 /* max of 256, so this is safe */
666 idstring = mymalloc(header.idlength+1);
667 if (i_io_read(ig, idstring, header.idlength) != header.idlength) {
668 i_push_error(errno, "short read on targa idstring");
669 return NULL;
670 }
671 }
672
673 width = header.width;
674 height = header.height;
675
676
677 /* Set tags here */
678
679 switch (header.datatypecode) {
680 case 0: /* No data in image */
681 i_push_error(0, "Targa image contains no image data");
682 if (idstring) myfree(idstring);
683 return NULL;
684 break;
685 case 1: /* Uncompressed, color-mapped images */
686 case 9: /* Compressed, color-mapped images */
687 case 3: /* Uncompressed, grayscale images */
688 case 11: /* Compressed, grayscale images */
689 if (header.bitsperpixel != 8) {
690 i_push_error(0, "Targa: mapped/grayscale image's bpp is not 8, unsupported.");
691 if (idstring) myfree(idstring);
692 return NULL;
693 }
694 src.bytepp = 1;
695 break;
696 case 2: /* Uncompressed, rgb images */
697 case 10: /* Compressed, rgb images */
698 if ((src.bytepp = bpp_to_bytes(header.bitsperpixel)))
699 break;
700 i_push_error(0, "Targa: direct color image's bpp is not 15/16/24/32 - unsupported.");
701 if (idstring) myfree(idstring);
702 return NULL;
703 break;
704 case 32: /* Compressed color-mapped, Huffman, Delta and runlength */
705 case 33: /* Compressed color-mapped, Huffman, Delta and runlength */
706 i_push_error(0, "Unsupported Targa (Huffman/delta/rle/quadtree) subformat is not supported");
707 if (idstring) myfree(idstring);
708 return NULL;
709 break;
710 default: /* All others which we don't know which might be */
711 i_push_error(0, "Unknown targa format");
712 if (idstring) myfree(idstring);
713 return NULL;
714 break;
715 }
716
717 src.state = NoInit;
718 src.len = 0;
719 src.ig = ig;
720 src.compressed = !!(header.datatypecode & (1<<3));
721
722 /* Determine number of channels */
723
724 mapped = 1;
725 switch (header.datatypecode) {
726 case 2: /* Uncompressed, rgb images */ /* FALLTHROUGH */
727 case 10: /* Compressed, rgb images */ /* FALLTHROUGH */
728 mapped = 0;
729 case 1: /* Uncompressed, color-mapped images */
730 case 9: /* Compressed, color-mapped images */
731 if ((channels = bpp_to_channels(mapped ?
732 header.colourmapdepth :
733 header.bitsperpixel,
734 header.imagedescriptor & 0xF))) break;
735 i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout");
736 if (idstring) myfree(idstring);
737 return NULL;
738 break;
739 case 3: /* Uncompressed, grayscale images */ /* FALLTHROUGH */
740 case 11: /* Compressed, grayscale images */
741 mapped = 0;
742 channels = 1;
743 break;
744 default:
745 i_push_error(0, "invalid or unsupported datatype code");
746 return NULL;
747 }
748
749 if (!i_int_check_image_file_limits(width, height, channels,
750 sizeof(i_sample_t))) {
751 mm_log((1, "i_readtga_wiol: image size exceeds limits\n"));
752 return NULL;
753 }
754
755 img = mapped ?
756 i_img_pal_new(width, height, channels, 256) :
757 i_img_empty_ch(NULL, width, height, channels);
758
759 if (!img) {
760 if (idstring)
761 myfree(idstring);
762 return NULL;
763 }
764
765 if (idstring) {
766 i_tags_add(&img->tags, "tga_idstring", 0, idstring, header.idlength, 0);
767 myfree(idstring);
768 }
769
770 if (mapped &&
771 !tga_palette_read(ig,
772 img,
773 bpp_to_bytes(header.colourmapdepth),
774 header.colourmaplength)
775 ) {
776 /* tga_palette_read() sets a message */
777 if (img) i_img_destroy(img);
778 return NULL;
779 }
780
781 /* Allocate buffers */
782 /* width is max 0xffff, src.bytepp is max 4, so this is safe */
783 databuf = mymalloc(width*src.bytepp);
784 /* similarly here */
785 if (!mapped) linebuf = mymalloc(width*sizeof(i_color));
786
787 for(y=0; y<height; y++) {
788 if (!tga_source_read(&src, databuf, width)) {
789 i_push_error(errno, "read for targa data failed");
790 if (linebuf) myfree(linebuf);
791 myfree(databuf);
792 if (img) i_img_destroy(img);
793 return NULL;
794 }
795 if (mapped && header.colourmaporigin) for(x=0; x<width; x++) databuf[x] -= header.colourmaporigin;
796 if (mapped) i_ppal(img, 0, width, header.imagedescriptor & (1<<5) ? y : height-1-y, databuf);
797 else {
798 for(x=0; x<width; x++) color_unpack(databuf+x*src.bytepp, src.bytepp, linebuf+x);
799 i_plin(img, 0, width, header.imagedescriptor & (1<<5) ? y : height-1-y, linebuf);
800 }
801 }
802 myfree(databuf);
803 if (linebuf) myfree(linebuf);
804
805 i_tags_add(&img->tags, "i_format", 0, "tga", -1, 0);
806 i_tags_addn(&img->tags, "tga_bitspp", 0, mapped?header.colourmapdepth:header.bitsperpixel);
807 if (src.compressed) i_tags_addn(&img->tags, "compressed", 0, 1);
808 return img;
809 }
810
811
812
813 /*
814 =item i_writetga_wiol(img, ig)
815
816 Writes an image in targa format. Returns 0 on error.
817
818 img - image to store
819 ig - io_glue object
820
821 =cut
822 */
823
824 undef_int
i_writetga_wiol(i_img * img,io_glue * ig,int wierdpack,int compress,char * idstring,size_t idlen)825 i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen) {
826 tga_header header;
827 tga_dest dest;
828 unsigned char headbuf[18];
829 unsigned int bitspp;
830 unsigned int attr_bits = 0;
831
832 int mapped;
833
834 /* parameters */
835
836 /*
837 int compress = 1;
838 char *idstring = "testing";
839 int wierdpack = 0;
840 */
841
842 idlen = strlen(idstring);
843 mapped = img->type == i_palette_type;
844
845 mm_log((1,"i_writetga_wiol(img %p, ig %p, idstring %p, idlen %ld, wierdpack %d, compress %d)\n",
846 img, ig, idstring, (long)idlen, wierdpack, compress));
847 mm_log((1, "virtual %d, paletted %d\n", img->virtual, mapped));
848 mm_log((1, "channels %d\n", img->channels));
849
850 i_clear_error();
851
852 if (img->xsize > TGA_MAX_DIM || img->ysize > TGA_MAX_DIM) {
853 i_push_error(0, "image too large for TGA");
854 return 0;
855 }
856
857 switch (img->channels) {
858 case 1:
859 bitspp = 8;
860 if (wierdpack) {
861 mm_log((1,"wierdpack option ignored for 1 channel images\n"));
862 wierdpack=0;
863 }
864 break;
865 case 2:
866 i_push_error(0, "Cannot store 2 channel image in targa format");
867 return 0;
868 break;
869 case 3:
870 bitspp = wierdpack ? 15 : 24;
871 break;
872 case 4:
873 bitspp = wierdpack ? 16 : 32;
874 attr_bits = wierdpack ? 1 : 8;
875 break;
876 default:
877 i_push_error(0, "Targa only handles 1,3 and 4 channel images.");
878 return 0;
879 }
880
881 header.idlength = idlen;
882 header.colourmaptype = mapped ? 1 : 0;
883 header.datatypecode = mapped ? 1 : img->channels == 1 ? 3 : 2;
884 header.datatypecode += compress ? 8 : 0;
885 mm_log((1, "datatypecode %d\n", header.datatypecode));
886 header.colourmaporigin = 0;
887 header.colourmaplength = mapped ? i_colorcount(img) : 0;
888 header.colourmapdepth = mapped ? bitspp : 0;
889 header.x_origin = 0;
890 header.y_origin = 0;
891 header.width = img->xsize;
892 header.height = img->ysize;
893 header.bitsperpixel = mapped ? 8 : bitspp;
894 header.imagedescriptor = (1<<5) | attr_bits; /* normal order instead of upside down */
895
896 tga_header_pack(&header, headbuf);
897
898 if (i_io_write(ig, &headbuf, sizeof(headbuf)) != sizeof(headbuf)) {
899 i_push_error(errno, "could not write targa header");
900 return 0;
901 }
902
903 if (idlen) {
904 if (i_io_write(ig, idstring, idlen) != idlen) {
905 i_push_error(errno, "could not write targa idstring");
906 return 0;
907 }
908 }
909
910 /* Make this into a constructor? */
911 dest.compressed = compress;
912 dest.bytepp = mapped ? 1 : bpp_to_bytes(bitspp);
913 dest.ig = ig;
914
915 mm_log((1, "dest.compressed = %d\n", dest.compressed));
916 mm_log((1, "dest.bytepp = %d\n", dest.bytepp));
917
918 if (img->type == i_palette_type) {
919 if (!tga_palette_write(ig, img, bitspp, i_colorcount(img))) return 0;
920
921 if (!img->virtual && !dest.compressed) {
922 if (i_io_write(ig, img->idata, img->bytes) != img->bytes) {
923 i_push_error(errno, "could not write targa image data");
924 return 0;
925 }
926 } else {
927 int y;
928 i_palidx *vals = mymalloc(sizeof(i_palidx)*img->xsize);
929 for(y=0; y<img->ysize; y++) {
930 i_gpal(img, 0, img->xsize, y, vals);
931 tga_dest_write(&dest, vals, img->xsize);
932 }
933 myfree(vals);
934 }
935 } else { /* direct type */
936 int x, y;
937 size_t bytepp = wierdpack ? 2 : bpp_to_bytes(bitspp);
938 size_t lsize = bytepp * img->xsize;
939 i_color *vals = mymalloc(img->xsize*sizeof(i_color));
940 unsigned char *buf = mymalloc(lsize);
941
942 for(y=0; y<img->ysize; y++) {
943 i_glin(img, 0, img->xsize, y, vals);
944 for(x=0; x<img->xsize; x++) color_pack(buf+x*bytepp, bitspp, vals+x);
945 tga_dest_write(&dest, buf, img->xsize);
946 }
947 myfree(buf);
948 myfree(vals);
949 }
950
951 if (i_io_close(ig))
952 return 0;
953
954 return 1;
955 }
956
957 /*
958 =back
959
960 =head1 AUTHOR
961
962 Arnar M. Hrafnkelsson <addi@umich.edu>
963
964 =head1 SEE ALSO
965
966 Imager(3)
967
968 =cut
969 */
970