13 tga.c - implements reading and writing targa files, uses io layer.
17 io_glue *ig = io_new_fd( fd );
18 i_img *im = i_readtga_wiol(ig, -1); // no limit on how much is read
20 io_glue *ig = io_new_fd( fd );
21 return_code = i_writetga_wiol(im, ig);
25 tga.c implements the basic functions to read and write portable targa
26 files. It uses the iolayer and needs either a seekable source or an
27 entire memory mapped buffer.
29 =head1 FUNCTION REFERENCE
31 Some of these functions are internal.
45 short int colourmaporigin;
46 short int colourmaplength;
60 enum { NoInit, Raw, Rle } state;
61 unsigned char cval[4];
70 bpp_to_bytes(unsigned int bpp) {
87 bpp_to_channels(unsigned int bpp) {
107 Unpacks bytes into colours, for 2 byte type the first byte coming from
108 the file will actually be GGGBBBBB, and the second will be ARRRRRGG.
109 "A" represents an attribute bit. The 3 byte entry contains 1 byte
110 each of blue, green, and red. The 4 byte entry contains 1 byte each
111 of blue, green, red, and attribute.
116 color_unpack(unsigned char *buf, int bytepp, i_color *val) {
119 val->gray.gray_color = buf[0];
122 val->rgba.r = (buf[1] & 0x7c) << 1;
123 val->rgba.g = ((buf[1] & 0x03) << 6) | ((buf[0] & 0xe0) >> 2);
124 val->rgba.b = (buf[0] & 0x1f) << 3;
125 val->rgba.a = (buf[1] & 0x80);
133 val->rgba.b = buf[0];
134 val->rgba.g = buf[1];
135 val->rgba.r = buf[2];
136 val->rgba.a = buf[3];
145 Does not byte reorder, returns true on success, 0 otherwise
150 tga_source_read(tga_source *s, unsigned char *buf, size_t pixels) {
152 if (!s->compressed) {
153 if (s->ig->readcb(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0;
159 if (s->len == 0) s->state = NoInit;
162 if (s->ig->readcb(s->ig, &s->hdr, 1) != 1) return 0;
164 s->len = (s->hdr &~(1<<7))+1;
165 s->state = (s->hdr & (1<<7)) ? Rle : Raw;
166 if (s->state == Rle && s->ig->readcb(s->ig, s->cval, s->bytepp) != s->bytepp) return 0;
170 ml = min(s->len, pixels-cp);
171 for(k=0; k<ml; k++) for(j=0; j<s->bytepp; j++)
172 buf[(cp+k)*s->bytepp+j] = s->cval[j];
173 // memset(buf+cp, s->cidx, ml);
178 ml = min(s->len, pixels-cp);
179 if (s->ig->readcb(s->ig, buf+cp*s->bytepp, ml*s->bytepp) != ml*s->bytepp) return 0;
190 tga_palette_read(io_glue *ig, i_img *img, int bytepp, int colourmaplength) {
193 unsigned char *palbuf;
196 palbsize = colourmaplength*bytepp;
197 palbuf = mymalloc(palbsize);
199 if (ig->readcb(ig, palbuf, palbsize) != palbsize) {
200 i_push_error(errno, "could not read targa colourmap");
204 /* populate the palette of the new image */
205 for(i=0; i<colourmaplength; i++) {
206 color_unpack(palbuf+i*bytepp, bytepp, &val);
207 i_addcolors(img, &val, 1);
218 =item i_readtga_wiol(ig, length)
220 Retrieve an image and stores in the iolayer object. Returns NULL on fatal error.
223 length - maximum length to read from data source, before closing it -1
230 i_readtga_wiol(io_glue *ig, int length) {
233 int width, height, channels;
239 unsigned char headbuf[18];
240 unsigned char *databuf;
241 unsigned char *reorderbuf;
243 i_color *linebuf = NULL;
246 mm_log((1,"i_readtga(ig %p, length %d)\n", ig, length));
248 io_glue_commit_types(ig);
250 if (ig->readcb(ig, &headbuf, 18) != 18) {
251 i_push_error(errno, "could not read targa header");
255 header.idlength = headbuf[0];
256 header.colourmaptype = headbuf[1];
257 header.datatypecode = headbuf[2];
258 header.colourmaporigin = (headbuf[4] << 8) + headbuf[3];
259 header.colourmaplength = (headbuf[6] << 8) + headbuf[5];
260 header.colourmapdepth = headbuf[7];
261 header.x_origin = (headbuf[9] << 8) + headbuf[8];
262 header.y_origin = (headbuf[11] << 8) + headbuf[10];
263 header.width = (headbuf[13] << 8) + headbuf[12];
264 header.height = (headbuf[15] << 8) + headbuf[14];
265 header.bitsperpixel = headbuf[16];
266 header.imagedescriptor = headbuf[17];
268 mm_log((1,"Id length: %d\n",header.idlength));
269 mm_log((1,"Colour map type: %d\n",header.colourmaptype));
270 mm_log((1,"Image type: %d\n",header.datatypecode));
271 mm_log((1,"Colour map offset: %d\n",header.colourmaporigin));
272 mm_log((1,"Colour map length: %d\n",header.colourmaplength));
273 mm_log((1,"Colour map depth: %d\n",header.colourmapdepth));
274 mm_log((1,"X origin: %d\n",header.x_origin));
275 mm_log((1,"Y origin: %d\n",header.y_origin));
276 mm_log((1,"Width: %d\n",header.width));
277 mm_log((1,"Height: %d\n",header.height));
278 mm_log((1,"Bits per pixel: %d\n",header.bitsperpixel));
279 mm_log((1,"Descriptor: %d\n",header.imagedescriptor));
282 if (header.idlength) {
283 idstring = mymalloc(header.idlength+1);
284 if (ig->readcb(ig, idstring, header.idlength) != header.idlength) {
285 i_push_error(errno, "short read on targa idstring");
288 myfree(idstring); /* Move this later, once this is stored in a tag */
291 width = header.width;
292 height = header.height;
296 switch (header.datatypecode) {
297 case 0: /* No data in image */
298 i_push_error(0, "Targa image contains no image data");
301 case 1: /* Uncompressed, color-mapped images */
302 case 9: /* Compressed, color-mapped images */
303 case 3: /* Uncompressed, grayscale images */
304 case 11: /* Compressed, grayscale images */
305 if (header.bitsperpixel != 8) {
306 i_push_error(0, "Targa: mapped/grayscale image's bpp is not 8, unsupported.");
311 case 2: /* Uncompressed, rgb images */
312 case 10: /* Compressed, rgb images */
313 if ((src.bytepp = bpp_to_bytes(header.bitsperpixel)))
315 i_push_error(0, "Targa: direct color image's bpp is not 15/16/24/32 - unsupported.");
318 case 32: /* Compressed color-mapped, Huffman, Delta and runlength */
319 case 33: /* Compressed color-mapped, Huffman, Delta and runlength */
320 i_push_error(0, "Unsupported Targa (Huffman/delta/rle/quadtree) subformat is not supported");
323 default: /* All others which we don't know which might be */
324 i_push_error(0, "Unknown targa format");
332 src.compressed = !!(header.datatypecode & (1<<3));
334 /* Determine number of channels */
337 switch (header.datatypecode) {
339 case 2: /* Uncompressed, rgb images */
340 case 10: /* Compressed, rgb images */
342 case 1: /* Uncompressed, color-mapped images */
343 case 9: /* Compressed, color-mapped images */
344 if ((channels = bpp_to_channels(mapped ?
345 header.colourmapdepth :
346 header.bitsperpixel))) break;
347 i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout");
350 case 3: /* Uncompressed, grayscale images */
351 case 11: /* Compressed, grayscale images */
358 i_img_pal_new(width, height, channels, 256) :
359 i_img_empty_ch(NULL, width, height, channels);
362 !tga_palette_read(ig,
364 bpp_to_bytes(header.colourmapdepth),
365 header.colourmaplength)
367 i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout");
371 /* Allocate buffers */
372 databuf = mymalloc(width*src.bytepp);
373 if (!mapped) linebuf = mymalloc(width*sizeof(i_color));
375 for(y=0; y<height; y++) {
376 if (!tga_source_read(&src, databuf, width)) {
377 i_push_error(errno, "read for targa data failed");
381 if (mapped) i_ppal(img, 0, width, header.imagedescriptor & (1<<5) ? y : height-1-y, databuf);
383 for(x=0; x<width; x++) color_unpack(databuf+x*src.bytepp, src.bytepp, linebuf+x);
384 i_plin(img, 0, width, header.imagedescriptor & (1<<5) ? y : height-1-y, linebuf);
388 if (linebuf) myfree(linebuf);
401 i_writetga_wiol(i_img *im, io_glue *ig) {
406 mm_log((1,"i_writetga_wiol(im %p, ig %p)\n", im, ig));
409 /* Add code to get the filename info from the iolayer */
410 /* Also add code to check for mmapped code */
412 io_glue_commit_types(ig);
414 if (im->type == i_palette_type) {
428 if (im->channels == 3) {
429 sprintf(header,"P6\n#CREATOR: Imager\n%d %d\n255\n",im->xsize,im->ysize);
430 if (ig->writecb(ig,header,strlen(header))<0) {
431 i_push_error(errno, "could not write ppm header");
432 mm_log((1,"i_writeppm: unable to write ppm header.\n"));
436 if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type) {
437 rc = ig->writecb(ig,im->idata,im->bytes);
440 unsigned char *data = mymalloc(3 * im->xsize);
445 static int rgb_chan[3] = { 0, 1, 2 };
448 while (y < im->ysize && rc >= 0) {
449 i_gsamp(im, 0, im->xsize, y, data, rgb_chan, 3);
450 rc = ig->writecb(ig, data, im->xsize * 3);
455 i_push_error(0, "Out of memory");
460 i_push_error(errno, "could not write ppm data");
461 mm_log((1,"i_writeppm: unable to write ppm data.\n"));
465 else if (im->channels == 1) {
466 sprintf(header, "P5\n#CREATOR: Imager\n%d %d\n255\n",
467 im->xsize, im->ysize);
468 if (ig->writecb(ig,header, strlen(header)) < 0) {
469 i_push_error(errno, "could not write pgm header");
470 mm_log((1,"i_writeppm: unable to write pgm header.\n"));
474 if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type) {
475 rc=ig->writecb(ig,im->idata,im->bytes);
478 unsigned char *data = mymalloc(im->xsize);
486 while (y < im->ysize && rc >= 0) {
487 i_gsamp(im, 0, im->xsize, y, data, &chan, 1);
488 rc = ig->writecb(ig, data, im->xsize);
493 i_push_error(0, "Out of memory");
498 i_push_error(errno, "could not write pgm data");
499 mm_log((1,"i_writeppm: unable to write pgm data.\n"));
504 i_push_error(0, "can only save 1 or 3 channel images to pnm");
505 mm_log((1,"i_writeppm: ppm/pgm is 1 or 3 channel only (current image is %d)\n",im->channels));