Cleaned up io.h, io.c which had functions not used any more, removed unused
[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
33=over 4
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
920aa4a5
AMH
78static
79int
80bpp_to_bytes(unsigned int bpp) {
81 switch (bpp) {
82 case 8:
83 return 1;
84 case 15:
85 case 16:
86 return 2;
87 case 24:
88 return 3;
89 case 32:
90 return 4;
91 }
92 return 0;
93}
94
95static
96int
97bpp_to_channels(unsigned int bpp) {
98 switch (bpp) {
99 case 8:
100 return 1;
101 case 15:
102 return 3;
103 case 16:
104 return 4;
105 case 24:
106 return 3;
107 case 32:
108 return 4;
109 }
110 return 0;
111}
112
113
114
76ff75b8
AMH
115/*
116 * Packing functions - used for (un)packing
117 * datastructures into raw bytes.
118*/
119
120
920aa4a5
AMH
121/* color_unpack
122
123Unpacks bytes into colours, for 2 byte type the first byte coming from
124the file will actually be GGGBBBBB, and the second will be ARRRRRGG.
125"A" represents an attribute bit. The 3 byte entry contains 1 byte
126each of blue, green, and red. The 4 byte entry contains 1 byte each
127of blue, green, red, and attribute.
128*/
129
130static
131void
132color_unpack(unsigned char *buf, int bytepp, i_color *val) {
133 switch (bytepp) {
134 case 1:
135 val->gray.gray_color = buf[0];
136 break;
137 case 2:
138 val->rgba.r = (buf[1] & 0x7c) << 1;
139 val->rgba.g = ((buf[1] & 0x03) << 6) | ((buf[0] & 0xe0) >> 2);
140 val->rgba.b = (buf[0] & 0x1f) << 3;
76ff75b8
AMH
141 val->rgba.a = (buf[1] & 0x80) ? 255 : 0;
142 val->rgba.r |= val->rgba.r >> 5;
143 val->rgba.g |= val->rgba.g >> 5;
144 val->rgba.b |= val->rgba.b >> 5;
920aa4a5
AMH
145 break;
146 case 3:
147 val->rgb.b = buf[0];
148 val->rgb.g = buf[1];
149 val->rgb.r = buf[2];
150 break;
151 case 4:
152 val->rgba.b = buf[0];
153 val->rgba.g = buf[1];
154 val->rgba.r = buf[2];
155 val->rgba.a = buf[3];
156 break;
157 default:
158 }
159}
160
76ff75b8
AMH
161
162
163/* color_pack
164
165Packs colous into bytes, for 2 byte type the first byte will be
166GGGBBBBB, and the second will be ARRRRRGG. "A" represents an
167attribute bit. The 3 byte entry contains 1 byte each of blue, green,
168and red. The 4 byte entry contains 1 byte each of blue, green, red,
169and attribute.
920aa4a5
AMH
170*/
171
76ff75b8
AMH
172static
173void
174color_pack(unsigned char *buf, int bitspp, i_color *val) {
175 switch (bitspp) {
176 case 8:
177 buf[0] = val->gray.gray_color;
178 break;
179 case 15:
180 buf[0] = (val->rgba.b >> 3);
181 buf[0] |= (val->rgba.g & 0x38) << 2;
182 buf[1] = (val->rgba.r & 0xf8)>> 1;
183 buf[1] |= (val->rgba.g >> 6);
184 case 16:
185 buf[1] |= val->rgba.a & 0x80;
186 break;
187 case 24:
188 buf[0] = val->rgb.b;
189 buf[1] = val->rgb.g;
190 buf[2] = val->rgb.r;
191 break;
192 case 32:
193 buf[0] = val->rgba.b;
194 buf[1] = val->rgba.g;
195 buf[2] = val->rgba.r;
196 buf[3] = val->rgba.a;
197 break;
198 default:
199 }
200 // printf("%d %3d %3d %3d\n", bitspp, val->rgb.r, val->rgb.g, val->rgb.b);
201}
202
203
204
205
206static
207int
208find_repeat(unsigned char *buf, int length, int bytepp) {
209 int i = 0;
210
211 while(i<length-1) {
212 if(memcmp(buf+i*bytepp, buf+(i+1)*bytepp, bytepp) == 0) {
213 if (i == length-2) return -1;
214 if (memcmp(buf+(i+1)*bytepp, buf+(i+2)*bytepp,bytepp) == 0)
215 return i;
216 else i++;
217 }
218 i++;
219 }
220 return -1;
221}
222
223
224static
225int
226find_span(unsigned char *buf, int length, int bytepp) {
227 int i = 0;
228 while(i<length) {
229 if(memcmp(buf, buf+(i*bytepp), bytepp) != 0) return i;
230 i++;
231 }
232 return length;
233}
234
235
236
237
238
920aa4a5
AMH
239static
240int
241tga_source_read(tga_source *s, unsigned char *buf, size_t pixels) {
242 int cp = 0, j, k;
243 if (!s->compressed) {
244 if (s->ig->readcb(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0;
245 return 1;
246 }
247
248 while(cp < pixels) {
249 int ml;
250 if (s->len == 0) s->state = NoInit;
251 switch (s->state) {
252 case NoInit:
253 if (s->ig->readcb(s->ig, &s->hdr, 1) != 1) return 0;
254
255 s->len = (s->hdr &~(1<<7))+1;
256 s->state = (s->hdr & (1<<7)) ? Rle : Raw;
257 if (s->state == Rle && s->ig->readcb(s->ig, s->cval, s->bytepp) != s->bytepp) return 0;
258
259 break;
260 case Rle:
261 ml = min(s->len, pixels-cp);
262 for(k=0; k<ml; k++) for(j=0; j<s->bytepp; j++)
263 buf[(cp+k)*s->bytepp+j] = s->cval[j];
264 // memset(buf+cp, s->cidx, ml);
265 cp += ml;
266 s->len -= ml;
267 break;
268 case Raw:
269 ml = min(s->len, pixels-cp);
270 if (s->ig->readcb(s->ig, buf+cp*s->bytepp, ml*s->bytepp) != ml*s->bytepp) return 0;
271 cp += ml;
272 s->len -= ml;
273 break;
274 }
275 }
276 return 1;
277}
278
76ff75b8
AMH
279
280
281/*
282 tga_dest_write
283
284 Note that it is possible for length to be more than 0 and the state
285 still be noinit. That just means that there isn't enough data yet to
286 determine the next packet type.
287
288*/
289
290static
291int
292tga_dest_write(tga_dest *s, unsigned char *buf, size_t pixels) {
293 int cp = 0, j, k;
294
295 if (!s->compressed) {
296 if (s->ig->writecb(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0;
297 return 1;
298 }
299
300 while(cp < pixels) {
301 int tlen;
302 int nxtrip = find_repeat(buf+cp*s->bytepp, pixels-cp, s->bytepp);
303 tlen = (nxtrip == -1) ? pixels-cp : nxtrip;
304 while(tlen) {
305 int clen = (tlen>128) ? 128 : tlen;
306 clen--;
307 if (s->ig->writecb(s->ig, &clen, 1) != 1) return 0;
308 clen++;
309 if (s->ig->writecb(s->ig, buf+cp*s->bytepp, clen*s->bytepp) != clen*s->bytepp) return 0;
310 tlen -= clen;
311 cp += clen;
312 }
313 if (cp >= pixels) break;
314 tlen = find_span(buf+cp*s->bytepp, pixels-cp, s->bytepp);
315 while (tlen) {
316 int clen = (tlen>128) ? 128 : tlen;
317 clen = (clen - 1) | 0x80;
318 if (s->ig->writecb(s->ig, &clen, 1) != 1) return 0;
319 clen = (clen & ~0x80) + 1;
320 if (s->ig->writecb(s->ig, buf+cp*s->bytepp, s->bytepp) != s->bytepp) return 0;
321 tlen -= clen;
322 cp += clen;
323 }
324 }
325 return 1;
326}
327
328
329
330
331
332
333
334
920aa4a5
AMH
335static
336int
337tga_palette_read(io_glue *ig, i_img *img, int bytepp, int colourmaplength) {
338 int i;
339 size_t palbsize;
340 unsigned char *palbuf;
341 i_color val;
342
343 palbsize = colourmaplength*bytepp;
344 palbuf = mymalloc(palbsize);
345
346 if (ig->readcb(ig, palbuf, palbsize) != palbsize) {
347 i_push_error(errno, "could not read targa colourmap");
348 return 0;
349 }
350
351 /* populate the palette of the new image */
352 for(i=0; i<colourmaplength; i++) {
353 color_unpack(palbuf+i*bytepp, bytepp, &val);
354 i_addcolors(img, &val, 1);
355 }
356 myfree(palbuf);
357 return 1;
358}
359
360
361
76ff75b8
AMH
362static
363int
364tga_palette_write(io_glue *ig, i_img *img, int bitspp, int colourmaplength) {
365 int i;
366 int bytepp = bpp_to_bytes(bitspp);
367 size_t palbsize = i_colorcount(img)*bytepp;
368 unsigned char *palbuf = mymalloc(palbsize);
369
370 for(i=0; i<colourmaplength; i++) {
371 i_color val;
372 i_getcolors(img, i, &val, 1);
373 color_pack(palbuf+i*bytepp, bitspp, &val);
374 }
375
376 if (ig->writecb(ig, palbuf, palbsize) != palbsize) {
377 i_push_error(errno, "could not write targa colourmap");
378 return 0;
379 }
380 myfree(palbuf);
381 return 1;
382}
383
384static
385void
386tga_header_unpack(tga_header *header, unsigned char headbuf[18]) {
387 header->idlength = headbuf[0];
388 header->colourmaptype = headbuf[1];
389 header->datatypecode = headbuf[2];
390 header->colourmaporigin = (headbuf[4] << 8) + headbuf[3];
391 header->colourmaplength = (headbuf[6] << 8) + headbuf[5];
392 header->colourmapdepth = headbuf[7];
393 header->x_origin = (headbuf[9] << 8) + headbuf[8];
394 header->y_origin = (headbuf[11] << 8) + headbuf[10];
395 header->width = (headbuf[13] << 8) + headbuf[12];
396 header->height = (headbuf[15] << 8) + headbuf[14];
397 header->bitsperpixel = headbuf[16];
398 header->imagedescriptor = headbuf[17];
399}
400
401
402static
403void
404tga_header_pack(tga_header *header, unsigned char headbuf[18]) {
405 headbuf[0] = header->idlength;
406 headbuf[1] = header->colourmaptype;
407 headbuf[2] = header->datatypecode;
408 headbuf[3] = header->colourmaporigin & 0xff;
409 headbuf[4] = header->colourmaporigin >> 8;
410 headbuf[5] = header->colourmaplength & 0xff;
411 headbuf[6] = header->colourmaplength >> 8;
412 headbuf[7] = header->colourmapdepth;
413 headbuf[8] = header->x_origin & 0xff;
414 headbuf[9] = header->x_origin >> 8;
415 headbuf[10] = header->y_origin & 0xff;
416 headbuf[11] = header->y_origin >> 8;
417 headbuf[12] = header->width & 0xff;
418 headbuf[13] = header->width >> 8;
419 headbuf[14] = header->height & 0xff;
420 headbuf[15] = header->height >> 8;
421 headbuf[16] = header->bitsperpixel;
422 headbuf[17] = header->imagedescriptor;
423}
424
920aa4a5 425
1ec86afa
AMH
426
427/*
428=item i_readtga_wiol(ig, length)
429
430Retrieve an image and stores in the iolayer object. Returns NULL on fatal error.
431
432 ig - io_glue object
433 length - maximum length to read from data source, before closing it -1
434 signifies no limit.
435
436=cut
437*/
438
439i_img *
440i_readtga_wiol(io_glue *ig, int length) {
441 i_img* img;
7c58edfc 442 int x, y, i;
1ec86afa 443 int width, height, channels;
920aa4a5 444 int mapped;
1ec86afa 445 char *idstring;
1ec86afa 446
920aa4a5 447 tga_source src;
1ec86afa 448 tga_header header;
1ec86afa 449 unsigned char headbuf[18];
7c58edfc 450 unsigned char *databuf;
920aa4a5
AMH
451 unsigned char *reorderbuf;
452
453 i_color *linebuf = NULL;
1ec86afa
AMH
454 i_clear_error();
455
456 mm_log((1,"i_readtga(ig %p, length %d)\n", ig, length));
457
458 io_glue_commit_types(ig);
459
460 if (ig->readcb(ig, &headbuf, 18) != 18) {
461 i_push_error(errno, "could not read targa header");
462 return NULL;
463 }
464
76ff75b8 465 tga_header_unpack(&header, headbuf);
1ec86afa
AMH
466
467 mm_log((1,"Id length: %d\n",header.idlength));
468 mm_log((1,"Colour map type: %d\n",header.colourmaptype));
469 mm_log((1,"Image type: %d\n",header.datatypecode));
470 mm_log((1,"Colour map offset: %d\n",header.colourmaporigin));
471 mm_log((1,"Colour map length: %d\n",header.colourmaplength));
472 mm_log((1,"Colour map depth: %d\n",header.colourmapdepth));
473 mm_log((1,"X origin: %d\n",header.x_origin));
474 mm_log((1,"Y origin: %d\n",header.y_origin));
475 mm_log((1,"Width: %d\n",header.width));
476 mm_log((1,"Height: %d\n",header.height));
477 mm_log((1,"Bits per pixel: %d\n",header.bitsperpixel));
478 mm_log((1,"Descriptor: %d\n",header.imagedescriptor));
479
1ec86afa
AMH
480 if (header.idlength) {
481 idstring = mymalloc(header.idlength+1);
482 if (ig->readcb(ig, idstring, header.idlength) != header.idlength) {
483 i_push_error(errno, "short read on targa idstring");
484 return NULL;
485 }
486 myfree(idstring); /* Move this later, once this is stored in a tag */
487 }
488
489 width = header.width;
490 height = header.height;
491
492 /* Set tags here */
920aa4a5 493
1ec86afa 494 switch (header.datatypecode) {
1ec86afa
AMH
495 case 0: /* No data in image */
496 i_push_error(0, "Targa image contains no image data");
497 return NULL;
498 break;
920aa4a5
AMH
499 case 1: /* Uncompressed, color-mapped images */
500 case 9: /* Compressed, color-mapped images */
501 case 3: /* Uncompressed, grayscale images */
502 case 11: /* Compressed, grayscale images */
1ec86afa 503 if (header.bitsperpixel != 8) {
920aa4a5 504 i_push_error(0, "Targa: mapped/grayscale image's bpp is not 8, unsupported.");
1ec86afa
AMH
505 return NULL;
506 }
920aa4a5 507 src.bytepp = 1;
1ec86afa 508 break;
920aa4a5
AMH
509 case 2: /* Uncompressed, rgb images */
510 case 10: /* Compressed, rgb images */
511 if ((src.bytepp = bpp_to_bytes(header.bitsperpixel)))
512 break;
513 i_push_error(0, "Targa: direct color image's bpp is not 15/16/24/32 - unsupported.");
1ec86afa
AMH
514 return NULL;
515 break;
516 case 32: /* Compressed color-mapped, Huffman, Delta and runlength */
1ec86afa 517 case 33: /* Compressed color-mapped, Huffman, Delta and runlength */
920aa4a5 518 i_push_error(0, "Unsupported Targa (Huffman/delta/rle/quadtree) subformat is not supported");
1ec86afa
AMH
519 return NULL;
520 break;
521 default: /* All others which we don't know which might be */
522 i_push_error(0, "Unknown targa format");
523 return NULL;
524 break;
525 }
920aa4a5
AMH
526
527 src.state = NoInit;
528 src.len = 0;
529 src.ig = ig;
530 src.compressed = !!(header.datatypecode & (1<<3));
531
532 /* Determine number of channels */
533
534 mapped = 1;
535 switch (header.datatypecode) {
536 int tbpp;
537 case 2: /* Uncompressed, rgb images */
538 case 10: /* Compressed, rgb images */
539 mapped = 0;
540 case 1: /* Uncompressed, color-mapped images */
541 case 9: /* Compressed, color-mapped images */
542 if ((channels = bpp_to_channels(mapped ?
543 header.colourmapdepth :
544 header.bitsperpixel))) break;
545 i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout");
546 return NULL;
547 break;
548 case 3: /* Uncompressed, grayscale images */
549 case 11: /* Compressed, grayscale images */
550 mapped = 0;
551 channels = 1;
552 break;
553 }
554
555 img = mapped ?
556 i_img_pal_new(width, height, channels, 256) :
557 i_img_empty_ch(NULL, width, height, channels);
558
559 if (mapped &&
560 !tga_palette_read(ig,
561 img,
562 bpp_to_bytes(header.colourmapdepth),
563 header.colourmaplength)
564 ) {
565 i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout");
566 return NULL;
567 }
568
569 /* Allocate buffers */
570 databuf = mymalloc(width*src.bytepp);
571 if (!mapped) linebuf = mymalloc(width*sizeof(i_color));
572
573 for(y=0; y<height; y++) {
574 if (!tga_source_read(&src, databuf, width)) {
575 i_push_error(errno, "read for targa data failed");
576 myfree(databuf);
577 return NULL;
578 }
7456c26c 579 if (mapped && header.colourmaporigin) for(x=0; x<width; x++) databuf[x] -= header.colourmaporigin;
920aa4a5
AMH
580 if (mapped) i_ppal(img, 0, width, header.imagedescriptor & (1<<5) ? y : height-1-y, databuf);
581 else {
582 for(x=0; x<width; x++) color_unpack(databuf+x*src.bytepp, src.bytepp, linebuf+x);
583 i_plin(img, 0, width, header.imagedescriptor & (1<<5) ? y : height-1-y, linebuf);
584 }
585 }
586 myfree(databuf);
587 if (linebuf) myfree(linebuf);
588 return img;
1ec86afa
AMH
589}
590
591
592
593
594
595
596
597
598
599undef_int
7456c26c 600i_writetga_wiol(i_img *img, io_glue *ig) {
7456c26c
AMH
601 static int rgb_chan[] = { 2, 1, 0, 3 };
602 tga_header header;
76ff75b8 603 tga_dest dest;
7456c26c 604 unsigned char headbuf[18];
76ff75b8
AMH
605 // unsigned char *data;
606 unsigned int bitspp;
607
608 int idlen;
609 int mapped;
1ec86afa 610
76ff75b8
AMH
611 /* parameters */
612 int compress = 1;
613 char *idstring = "testing";
614 int wierdpack = 0;
1ec86afa 615
76ff75b8
AMH
616 idlen = strlen(idstring);
617 mapped = img->type == i_palette_type;
1ec86afa 618
76ff75b8 619 mm_log((1,"i_writetga_wiol(img %p, ig %p)\n", img, ig));
7456c26c
AMH
620 mm_log((1, "virtual %d, paletted %d\n", img->virtual, mapped));
621 mm_log((1, "channels %d\n", img->channels));
76ff75b8
AMH
622
623 i_clear_error();
624
625 switch (img->channels) {
626 case 1:
627 bitspp = 8;
628 if (wierdpack) {
629 mm_log((1,"wierdpack option ignored for 1 channel images\n"));
630 wierdpack=0;
631 }
632 break;
633 case 2:
634 i_push_error(0, "Cannot store 2 channel image in targa format");
635 return 0;
636 break;
637 case 3:
638 bitspp = wierdpack ? 15 : 24;
639 break;
640 case 4:
641 bitspp = wierdpack ? 16 : 32;
642 break;
643 default:
644 i_push_error(0, "Targa only handles 1,3 and 4 channel images.");
645 return 0;
646 }
7456c26c 647
76ff75b8
AMH
648 io_glue_commit_types(ig);
649
7456c26c
AMH
650 header.idlength;
651 header.idlength = idlen;
652 header.colourmaptype = mapped ? 1 : 0;
653 header.datatypecode = mapped ? 1 : img->channels == 1 ? 3 : 2;
7456c26c 654 header.datatypecode += compress ? 8 : 0;
76ff75b8 655 mm_log((1, "datatypecode %d\n", header.datatypecode));
7456c26c
AMH
656 header.colourmaporigin = 0;
657 header.colourmaplength = mapped ? i_colorcount(img) : 0;
76ff75b8 658 header.colourmapdepth = mapped ? bitspp : 0;
7456c26c
AMH
659 header.x_origin = 0;
660 header.y_origin = 0;
661 header.width = img->xsize;
662 header.height = img->ysize;
76ff75b8 663 header.bitsperpixel = mapped ? 8 : bitspp;
7456c26c
AMH
664 header.imagedescriptor = (1<<5); /* normal order instead of upside down */
665
76ff75b8 666 tga_header_pack(&header, headbuf);
7456c26c
AMH
667
668 if (ig->writecb(ig, &headbuf, sizeof(headbuf)) != sizeof(headbuf)) {
669 i_push_error(errno, "could not write targa header");
670 return 0;
7c58edfc
AMH
671 }
672
7456c26c
AMH
673 if (idlen) {
674 if (ig->writecb(ig, idstring, idlen) != idlen) {
675 i_push_error(errno, "could not write targa idstring");
676 return 0;
1ec86afa
AMH
677 }
678 }
7456c26c 679
76ff75b8
AMH
680 /* Make this into a constructor? */
681 dest.compressed = compress;
682 dest.bytepp = mapped ? 1 : bpp_to_bytes(bitspp);
683 dest.ig = ig;
c95846c2 684
76ff75b8
AMH
685 mm_log((1, "dest.compressed = %d\n", dest.compressed));
686 mm_log((1, "dest.bytepp = %d\n", dest.bytepp));
c95846c2 687
76ff75b8
AMH
688 if (img->type == i_palette_type) {
689 int i;
690 int bytepp = bpp_to_bytes(bitspp);
691 if (!tga_palette_write(ig, img, bitspp, i_colorcount(img))) return 0;
692
693 if (!img->virtual && !dest.compressed) {
7456c26c
AMH
694 if (ig->writecb(ig, img->idata, img->bytes) != img->bytes) {
695 i_push_error(errno, "could not write targa image data");
696 return 0;
1ec86afa 697 }
7456c26c
AMH
698 } else {
699 int y;
700 i_palidx *vals = mymalloc(sizeof(i_palidx)*img->xsize);
701 for(y=0; y<img->ysize; y++) {
702 i_gpal(img, 0, img->xsize, y, vals);
76ff75b8 703 tga_dest_write(&dest, vals, img->xsize);
1ec86afa 704 }
7456c26c 705 myfree(vals);
1ec86afa 706 }
76ff75b8
AMH
707 } else { /* direct type */
708 int x, y;
709 int bytepp = wierdpack ? 2 : bpp_to_bytes(bitspp);
710 int lsize = bytepp * img->xsize;
711 i_color *vals = mymalloc(img->xsize*sizeof(i_color));
712 unsigned char *buf = mymalloc(lsize);
713
7456c26c 714 for(y=0; y<img->ysize; y++) {
76ff75b8
AMH
715 i_glin(img, 0, img->xsize, y, vals);
716 for(x=0; x<img->xsize; x++) color_pack(buf+x*bytepp, bitspp, vals+x);
717 tga_dest_write(&dest, buf, img->xsize);
1ec86afa 718 }
76ff75b8
AMH
719 myfree(buf);
720 myfree(vals);
1ec86afa 721 }
7456c26c 722 return 1;
1ec86afa 723}