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