From 1ec86afa6a48ab0aaf3ca85224f797af9d7869c7 Mon Sep 17 00:00:00 2001 From: Arnar Mar Hrafnkelsson Date: Sun, 16 Sep 2001 09:01:54 +0000 Subject: [PATCH] Adds reading capabilities for certain variants of targa, writer code has not been done yet. --- Imager.pm | 24 +++- Imager.xs | 12 ++ MANIFEST | 1 + Makefile.PL | 2 +- feat.h | 1 + image.h | 5 +- tga.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 384 insertions(+), 5 deletions(-) create mode 100644 tga.c diff --git a/Imager.pm b/Imager.pm index dfa6bb70..3a85b127 100644 --- a/Imager.pm +++ b/Imager.pm @@ -809,7 +809,7 @@ sub read { $self->{ERRSTR}='format not supported'; return undef; } - my %iolready=(jpeg=>1, png=>1, tiff=>1, pnm=>1, raw=>1, bmp=>1); + my %iolready=(jpeg=>1, png=>1, tiff=>1, pnm=>1, raw=>1, bmp=>1, tga=>1); if ($iolready{$input{type}}) { # Setup data source @@ -860,6 +860,16 @@ sub read { $self->{DEBUG} && print "loading a bmp file\n"; } + if ( $input{type} eq 'tga' ) { + $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed + if ( !defined($self->{IMG}) ) { + $self->{ERRSTR}=$self->_error_as_msg(); +# $self->{ERRSTR}='unable to read tga image'; + return undef; + } + $self->{DEBUG} && print "loading a tga file\n"; + } + if ( $input{type} eq 'raw' ) { my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input); @@ -953,7 +963,7 @@ sub write { fax_fine=>1, @_); my ($fh, $rc, $fd, $IO); - my %iolready=( tiff=>1, raw=>1, png=>1, pnm=>1, bmp=>1, jpeg=>1 ); # this will be SO MUCH BETTER once they are all in there + my %iolready=( tiff=>1, raw=>1, png=>1, pnm=>1, bmp=>1, jpeg=>1, tga=>1 ); # this will be SO MUCH BETTER once they are all in there unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; } @@ -1021,6 +1031,13 @@ sub write { return undef; } $self->{DEBUG} && print "writing a bmp file\n"; + } elsif ( $input{type} eq 'tga' ) { + if ( !i_writetga_wiol($self->{IMG}, $IO) ) { + $self->{ERRSTR}=$self->_error_as_msg(); +# $self->{ERRSTR}='unable to write tga image'; + return undef; + } + $self->{DEBUG} && print "writing a tga file\n"; } if (exists $input{'data'}) { @@ -2020,6 +2037,7 @@ sub def_guess_type { return 'pnm' if ($ext =~ m/^p[pgb]m$/); return 'png' if ($ext eq "png"); return 'bmp' if ($ext eq "bmp" || $ext eq "dib"); + return 'tga' if ($ext eq "tga"); return 'gif' if ($ext eq "gif"); return (); } @@ -3814,7 +3832,7 @@ the i_aspect_only tag is non-zero. =back -The following tags are set when reading a Windows BMP file is read: +The following tags are set when a Windows BMP file is read: =over diff --git a/Imager.xs b/Imager.xs index 3299e07d..db3bc5d8 100644 --- a/Imager.xs +++ b/Imager.xs @@ -1746,6 +1746,18 @@ Imager::ImgRaw i_readbmp_wiol(ig) Imager::IO ig + +undef_int +i_writetga_wiol(im,ig) + Imager::ImgRaw im + Imager::IO ig + +Imager::ImgRaw +i_readtga_wiol(ig, length) + Imager::IO ig + int length + + Imager::ImgRaw i_scaleaxis(im,Value,Axis) Imager::ImgRaw im diff --git a/MANIFEST b/MANIFEST index 4121d7ab..33baea2f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -5,6 +5,7 @@ MANIFEST README Makefile.PL bmp.c Reading and writing Windows BMP files +tga.c Reading and writing Targa files color.c Color translation and handling conv.c convert.c diff --git a/Makefile.PL b/Makefile.PL index d144c6d0..b4d2817c 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -63,7 +63,7 @@ if (defined $Config{'d_dlsymun'}) { $OSDEF .= ' -DDLSYMUN'; } filters.o dynaload.o stackmach.o datatypes.o regmach.o trans2.o quant.o error.o convert.o map.o tags.o palimg.o maskimg.o img16.o rotate.o - bmp.o color.o fills.o); + bmp.o tga.o color.o fills.o); %opts=( 'NAME' => 'Imager', diff --git a/feat.h b/feat.h index c82f953f..ade7a928 100644 --- a/feat.h +++ b/feat.h @@ -28,5 +28,6 @@ static char *i_format_list[]={ "raw", "pnm", "bmp", + "tga", NULL}; diff --git a/image.h b/image.h index 16686c9f..c6236946 100644 --- a/image.h +++ b/image.h @@ -547,9 +547,12 @@ undef_int i_writeraw_wiol(i_img* im, io_glue *ig); i_img * i_readpnm_wiol(io_glue *ig, int length); undef_int i_writeppm_wiol(i_img *im, io_glue *ig); -extern int i_writebmp_wiol(i_img *im, io_glue *ig); +extern int i_writebmp_wiol(i_img *im, io_glue *ig); extern i_img *i_readbmp_wiol(io_glue *ig); +i_img * i_readtga_wiol(io_glue *ig, int length); +undef_int i_writetga_wiol(i_img *im, io_glue *ig); + i_img * i_scaleaxis(i_img *im, float Value, int Axis); i_img * i_scale_nn(i_img *im, float scx, float scy); i_img * i_haar(i_img *im); diff --git a/tga.c b/tga.c new file mode 100644 index 00000000..0f467ba4 --- /dev/null +++ b/tga.c @@ -0,0 +1,344 @@ +#include "image.h" +#include "io.h" +#include "log.h" +#include "iolayer.h" + +#include +#include + + +/* +=head1 NAME + +tga.c - implements reading and writing targa files, uses io layer. + +=head1 SYNOPSIS + + io_glue *ig = io_new_fd( fd ); + i_img *im = i_readtga_wiol(ig, -1); // no limit on how much is read + // or + io_glue *ig = io_new_fd( fd ); + return_code = i_writetga_wiol(im, ig); + +=head1 DESCRIPTION + +tga.c implements the basic functions to read and write portable targa +files. It uses the iolayer and needs either a seekable source or an +entire memory mapped buffer. + +=head1 FUNCTION REFERENCE + +Some of these functions are internal. + +=over 4 + +=cut +*/ + + +#define BSIZ 1024 + + + +typedef struct { + char idlength; + char colourmaptype; + char datatypecode; + short int colourmaporigin; + short int colourmaplength; + char colourmapdepth; + short int x_origin; + short int y_origin; + short width; + short height; + char bitsperpixel; + char imagedescriptor; +} tga_header; + + + +/* +=item i_readtga_wiol(ig, length) + +Retrieve an image and stores in the iolayer object. Returns NULL on fatal error. + + ig - io_glue object + length - maximum length to read from data source, before closing it -1 + signifies no limit. + +=cut +*/ + +i_img * +i_readtga_wiol(io_glue *ig, int length) { + i_img* img; + int type; + int y, i; + int width, height, channels; + char *idstring; + unsigned char *uc; + i_color val; + + tga_header header; + size_t palbsize; + unsigned char *palbuf; + unsigned char headbuf[18]; + unsigned char *linebuf; + + i_clear_error(); + + mm_log((1,"i_readtga(ig %p, length %d)\n", ig, length)); + + io_glue_commit_types(ig); + + if (ig->readcb(ig, &headbuf, 18) != 18) { + i_push_error(errno, "could not read targa header"); + return NULL; + } + + header.idlength = headbuf[0]; + header.colourmaptype = headbuf[1]; + header.datatypecode = headbuf[2]; + header.colourmaporigin = headbuf[4] << 8 + headbuf[3]; + header.colourmaplength = headbuf[6] << 8 + headbuf[5]; + header.colourmapdepth = headbuf[7]; + header.x_origin = headbuf[9] << 8 + headbuf[8]; + header.y_origin = headbuf[11] << 8 + headbuf[10]; + header.width = (headbuf[13] << 8) + headbuf[12]; + header.height = (headbuf[15] << 8) + headbuf[14]; + header.bitsperpixel = headbuf[16]; + header.imagedescriptor = headbuf[17]; + + mm_log((1,"Id length: %d\n",header.idlength)); + mm_log((1,"Colour map type: %d\n",header.colourmaptype)); + mm_log((1,"Image type: %d\n",header.datatypecode)); + mm_log((1,"Colour map offset: %d\n",header.colourmaporigin)); + mm_log((1,"Colour map length: %d\n",header.colourmaplength)); + mm_log((1,"Colour map depth: %d\n",header.colourmapdepth)); + mm_log((1,"X origin: %d\n",header.x_origin)); + mm_log((1,"Y origin: %d\n",header.y_origin)); + mm_log((1,"Width: %d\n",header.width)); + mm_log((1,"Height: %d\n",header.height)); + mm_log((1,"Bits per pixel: %d\n",header.bitsperpixel)); + mm_log((1,"Descriptor: %d\n",header.imagedescriptor)); + + + if (header.idlength) { + idstring = mymalloc(header.idlength+1); + if (ig->readcb(ig, idstring, header.idlength) != header.idlength) { + i_push_error(errno, "short read on targa idstring"); + return NULL; + } + myfree(idstring); /* Move this later, once this is stored in a tag */ + } + + width = header.width; + height = header.height; + + /* Set tags here */ + + /* Only RGB for now, eventually support all formats */ + switch (header.datatypecode) { + + case 0: /* No data in image */ + i_push_error(0, "Targa image contains no image data"); + return NULL; + break; + + case 1: /* Uncompressed, color-mapped images */ + if (header.imagedescriptor != 0) { + i_push_error(0, "Targa: Imagedescriptor not 0, not supported internal format"); + return NULL; + } + + if (header.bitsperpixel != 8) { + i_push_error(0, "Targa: bpp is not 8, unsupported."); + return NULL; + } + + mm_log((1, "Uncompressed color-mapped image\n")); + if (header.colourmapdepth != 24) { + i_push_error(0, "Colourmap is not 24 bit"); + return NULL; + } + channels = 3; + + img = i_img_pal_new(width, height, channels, 256); + + /* Read in the palette */ + + palbsize = header.colourmaplength*channels; + palbuf = mymalloc(palbsize); + + if (ig->readcb(ig, palbuf, palbsize) != palbsize) { + i_push_error(errno, "could not read targa colourmap"); + return NULL; + } + + /* populate the palette of the new image */ + for(i=0; i=0;y--) { + if (ig->readcb(ig, linebuf, width) != width) { + i_push_error(errno, "read for targa data failed"); + myfree(linebuf); + return NULL; + } + i_ppal(img, 0, width, y, linebuf); + } + + return img; + break; + + case 2: /* Uncompressed, RGB images */ + mm_log((1, "Uncompressed RGB image\n")); + channels = 3; + /* Do stuff */ + break; + case 3: /* Uncompressed, black and white images */ + i_push_error(0, "Targa black and white subformat is not supported"); + return NULL; + break; + case 9: /* Runlength encoded, color-mapped images */ + i_push_error(0, "Targa runlength coded colormapped subformat is not supported"); + return NULL; + break; + case 10: /* Runlength encoded, RGB images */ + channels = 3; + /* Do stuff */ + break; + case 11: /* Compressed, black and white images */ + i_push_error(0, "Targa compressed black and white subformat is not supported"); + return NULL; + break; + case 32: /* Compressed color-mapped, Huffman, Delta and runlength */ + i_push_error(0, "Targa Huffman/delta/rle subformat is not supported"); + return NULL; + break; + case 33: /* Compressed color-mapped, Huffman, Delta and runlength */ + i_push_error(0, "Targa Huffman/delta/rle/quadtree subformat is not supported"); + return NULL; + break; + default: /* All others which we don't know which might be */ + i_push_error(0, "Unknown targa format"); + return NULL; + break; + } + return NULL; +} + + + + + + + + + +undef_int +i_writetga_wiol(i_img *im, io_glue *ig) { + char header[255]; + int rc; + writep write_func; + + mm_log((1,"i_writeppm(im %p, ig %p)\n", im, ig)); + i_clear_error(); + + /* Add code to get the filename info from the iolayer */ + /* Also add code to check for mmapped code */ + + io_glue_commit_types(ig); + + if (im->channels == 3) { + sprintf(header,"P6\n#CREATOR: Imager\n%d %d\n255\n",im->xsize,im->ysize); + if (ig->writecb(ig,header,strlen(header))<0) { + i_push_error(errno, "could not write ppm header"); + mm_log((1,"i_writeppm: unable to write ppm header.\n")); + return(0); + } + + if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type) { + rc = ig->writecb(ig,im->idata,im->bytes); + } + else { + unsigned char *data = mymalloc(3 * im->xsize); + if (data != NULL) { + int y = 0; + int x, ch; + unsigned char *p; + static int rgb_chan[3] = { 0, 1, 2 }; + + rc = 0; + while (y < im->ysize && rc >= 0) { + i_gsamp(im, 0, im->xsize, y, data, rgb_chan, 3); + rc = ig->writecb(ig, data, im->xsize * 3); + } + myfree(data); + } + else { + i_push_error(0, "Out of memory"); + return 0; + } + } + if (rc<0) { + i_push_error(errno, "could not write ppm data"); + mm_log((1,"i_writeppm: unable to write ppm data.\n")); + return(0); + } + } + else if (im->channels == 1) { + sprintf(header, "P5\n#CREATOR: Imager\n%d %d\n255\n", + im->xsize, im->ysize); + if (ig->writecb(ig,header, strlen(header)) < 0) { + i_push_error(errno, "could not write pgm header"); + mm_log((1,"i_writeppm: unable to write pgm header.\n")); + return(0); + } + + if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type) { + rc=ig->writecb(ig,im->idata,im->bytes); + } + else { + unsigned char *data = mymalloc(im->xsize); + if (data != NULL) { + int y = 0; + int x, ch; + int chan = 0; + unsigned char *p; + + rc = 0; + while (y < im->ysize && rc >= 0) { + i_gsamp(im, 0, im->xsize, y, data, &chan, 1); + rc = ig->writecb(ig, data, im->xsize); + } + myfree(data); + } + else { + i_push_error(0, "Out of memory"); + return 0; + } + } + if (rc<0) { + i_push_error(errno, "could not write pgm data"); + mm_log((1,"i_writeppm: unable to write pgm data.\n")); + return(0); + } + } + else { + i_push_error(0, "can only save 1 or 3 channel images to pnm"); + mm_log((1,"i_writeppm: ppm/pgm is 1 or 3 channel only (current image is %d)\n",im->channels)); + return(0); + } + + return(1); +} -- 2.39.2