]> git.imager.perl.org - imager.git/blob - tga.c
split Imager's typemap into internal, public and old perl bugfixes
[imager.git] / tga.c
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
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
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
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
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
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
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
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
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
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
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
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
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 colourmap");
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
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 colourmap");
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 *
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          */
727   case 10: /* Compressed,   rgb images          */
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    */
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     i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout");
777     if (idstring) myfree(idstring);
778     if (img) i_img_destroy(img);
779     return NULL;
780   }
781   
782   /* Allocate buffers */
783   /* width is max 0xffff, src.bytepp is max 4, so this is safe */
784   databuf = mymalloc(width*src.bytepp);
785   /* similarly here */
786   if (!mapped) linebuf = mymalloc(width*sizeof(i_color));
787   
788   for(y=0; y<height; y++) {
789     if (!tga_source_read(&src, databuf, width)) {
790       i_push_error(errno, "read for targa data failed");
791       if (linebuf) myfree(linebuf);
792       myfree(databuf);
793       if (img) i_img_destroy(img);
794       return NULL;
795     }
796     if (mapped && header.colourmaporigin) for(x=0; x<width; x++) databuf[x] -= header.colourmaporigin;
797     if (mapped) i_ppal(img, 0, width, header.imagedescriptor & (1<<5) ? y : height-1-y, databuf);
798     else {
799       for(x=0; x<width; x++) color_unpack(databuf+x*src.bytepp, src.bytepp, linebuf+x);
800       i_plin(img, 0, width, header.imagedescriptor & (1<<5) ? y : height-1-y, linebuf);
801     }
802   }
803   myfree(databuf);
804   if (linebuf) myfree(linebuf);
805   
806   i_tags_add(&img->tags, "i_format", 0, "tga", -1, 0);
807   i_tags_addn(&img->tags, "tga_bitspp", 0, mapped?header.colourmapdepth:header.bitsperpixel);
808   if (src.compressed) i_tags_addn(&img->tags, "compressed", 0, 1);
809   return img;
810 }
811
812
813
814 /*
815 =item i_writetga_wiol(img, ig)
816
817 Writes an image in targa format.  Returns 0 on error.
818
819    img    - image to store
820    ig     - io_glue object
821
822 =cut
823 */
824
825 undef_int
826 i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen) {
827   tga_header header;
828   tga_dest dest;
829   unsigned char headbuf[18];
830   unsigned int bitspp;
831   unsigned int attr_bits = 0;
832   
833   int mapped;
834
835   /* parameters */
836
837   /*
838     int compress = 1;
839     char *idstring = "testing";
840     int wierdpack = 0;
841   */
842
843   idlen = strlen(idstring);
844   mapped = img->type == i_palette_type;
845
846   mm_log((1,"i_writetga_wiol(img %p, ig %p, idstring %p, idlen %ld, wierdpack %d, compress %d)\n",
847           img, ig, idstring, (long)idlen, wierdpack, compress));
848   mm_log((1, "virtual %d, paletted %d\n", img->virtual, mapped));
849   mm_log((1, "channels %d\n", img->channels));
850   
851   i_clear_error();
852
853   if (img->xsize > TGA_MAX_DIM || img->ysize > TGA_MAX_DIM) {
854     i_push_error(0, "image too large for TGA");
855     return 0;
856   }
857
858   switch (img->channels) {
859   case 1:
860     bitspp = 8;
861     if (wierdpack) {
862       mm_log((1,"wierdpack option ignored for 1 channel images\n"));
863       wierdpack=0;
864     }
865     break;
866   case 2:
867     i_push_error(0, "Cannot store 2 channel image in targa format");
868     return 0;
869     break;
870   case 3:
871     bitspp = wierdpack ? 15 : 24;
872     break;
873   case 4:
874     bitspp = wierdpack ? 16 : 32;
875     attr_bits = wierdpack ? 1 : 8;
876     break;
877   default:
878     i_push_error(0, "Targa only handles 1,3 and 4 channel images.");
879     return 0;
880   }
881
882   header.idlength = idlen;
883   header.colourmaptype   = mapped ? 1 : 0;
884   header.datatypecode    = mapped ? 1 : img->channels == 1 ? 3 : 2;
885   header.datatypecode   += compress ? 8 : 0;
886   mm_log((1, "datatypecode %d\n", header.datatypecode));
887   header.colourmaporigin = 0;
888   header.colourmaplength = mapped ? i_colorcount(img) : 0;
889   header.colourmapdepth  = mapped ? bitspp : 0;
890   header.x_origin        = 0;
891   header.y_origin        = 0;
892   header.width           = img->xsize;
893   header.height          = img->ysize;
894   header.bitsperpixel    = mapped ? 8 : bitspp;
895   header.imagedescriptor = (1<<5) | attr_bits; /* normal order instead of upside down */
896
897   tga_header_pack(&header, headbuf);
898
899   if (i_io_write(ig, &headbuf, sizeof(headbuf)) != sizeof(headbuf)) {
900     i_push_error(errno, "could not write targa header");
901     return 0;
902   }
903
904   if (idlen) {
905     if (i_io_write(ig, idstring, idlen) != idlen) {
906       i_push_error(errno, "could not write targa idstring");
907       return 0;
908     }
909   }
910   
911   /* Make this into a constructor? */
912   dest.compressed = compress;
913   dest.bytepp     = mapped ? 1 : bpp_to_bytes(bitspp);
914   dest.ig         = ig;
915
916   mm_log((1, "dest.compressed = %d\n", dest.compressed));
917   mm_log((1, "dest.bytepp = %d\n", dest.bytepp));
918
919   if (img->type == i_palette_type) {
920     if (!tga_palette_write(ig, img, bitspp, i_colorcount(img))) return 0;
921     
922     if (!img->virtual && !dest.compressed) {
923       if (i_io_write(ig, img->idata, img->bytes) != img->bytes) {
924         i_push_error(errno, "could not write targa image data");
925         return 0;
926       }
927     } else {
928       int y;
929       i_palidx *vals = mymalloc(sizeof(i_palidx)*img->xsize);
930       for(y=0; y<img->ysize; y++) {
931         i_gpal(img, 0, img->xsize, y, vals);
932         tga_dest_write(&dest, vals, img->xsize);
933       }
934       myfree(vals);
935     }
936   } else { /* direct type */
937     int x, y;
938     size_t bytepp = wierdpack ? 2 : bpp_to_bytes(bitspp);
939     size_t lsize = bytepp * img->xsize;
940     i_color *vals = mymalloc(img->xsize*sizeof(i_color));
941     unsigned char *buf = mymalloc(lsize);
942     
943     for(y=0; y<img->ysize; y++) {
944       i_glin(img, 0, img->xsize, y, vals);
945       for(x=0; x<img->xsize; x++) color_pack(buf+x*bytepp, bitspp, vals+x);
946       tga_dest_write(&dest, buf, img->xsize);
947     }
948     myfree(buf);
949     myfree(vals);
950   }
951
952   if (i_io_close(ig))
953     return 0;
954
955   return 1;
956 }
957
958 /*
959 =back
960
961 =head1 AUTHOR
962
963 Arnar M. Hrafnkelsson <addi@umich.edu>
964
965 =head1 SEE ALSO
966
967 Imager(3)
968
969 =cut
970 */