From 75652a86d1cd6e8bdd2967145fcd003415004219 Mon Sep 17 00:00:00 2001 From: dirk Date: Mon, 12 May 2014 19:05:56 +0000 Subject: [PATCH] Added support for writing RLE compressed TGA files. --- coders/tga.c | 327 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 195 insertions(+), 132 deletions(-) diff --git a/coders/tga.c b/coders/tga.c index cf4539609..414d349ce 100644 --- a/coders/tga.c +++ b/coders/tga.c @@ -64,6 +64,49 @@ #include "MagickCore/static.h" #include "MagickCore/string_.h" #include "MagickCore/module.h" + +/* + Enumerated declaractions. +*/ +typedef enum +{ + TGAColormap = 1, + TGARGB = 2, + TGAMonochrome = 3, + TGARLEColormap = 9, + TGARLERGB = 10, + TGARLEMonochrome = 11 +} TGAImageType; + +/* + Typedef declaractions. +*/ +typedef struct _TGAInfo +{ + TGAImageType + image_type; + + unsigned char + id_length, + colormap_type; + + unsigned short + colormap_index, + colormap_length; + + unsigned char + colormap_size; + + unsigned short + x_origin, + y_origin, + width, + height; + + unsigned char + bits_per_pixel, + attributes; +} TGAInfo; /* Forward declarations. @@ -97,40 +140,9 @@ static MagickBooleanType % o exception: return any errors or warnings in this structure. % */ -static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception) +static Image *ReadTGAImage(const ImageInfo *image_info, + ExceptionInfo *exception) { -#define TGAColormap 1 -#define TGARGB 2 -#define TGAMonochrome 3 -#define TGARLEColormap 9 -#define TGARLERGB 10 -#define TGARLEMonochrome 11 - - typedef struct _TGAInfo - { - unsigned char - id_length, - colormap_type, - image_type; - - unsigned short - colormap_index, - colormap_length; - - unsigned char - colormap_size; - - unsigned short - x_origin, - y_origin, - width, - height; - - unsigned char - bits_per_pixel, - attributes; - } TGAInfo; - Image *image; @@ -195,7 +207,7 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception) */ count=ReadBlob(image,1,&tga_info.id_length); tga_info.colormap_type=(unsigned char) ReadBlobByte(image); - tga_info.image_type=(unsigned char) ReadBlobByte(image); + tga_info.image_type=(TGAImageType) ReadBlobByte(image); if ((count != 1) || ((tga_info.image_type != TGAColormap) && (tga_info.image_type != TGARGB) && @@ -639,40 +651,35 @@ static inline size_t MagickMin(const size_t x,const size_t y) return(y); } +static inline void WriteTGAPixel(Image *image,TGAImageType image_type, + const Quantum *p) +{ + if (image_type == TGAColormap || image_type == TGARLEColormap) + (void) WriteBlobByte(image,(unsigned char) GetPixelIndex(image,p)); + else + { + if (image_type == TGAMonochrome || image_type == TGARLEMonochrome) + (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum( + GetPixelLuma(image,p)))); + else + { + (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelBlue(image, + p))); + (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelGreen(image, + p))); + (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelRed(image,p))); + if (image->alpha_trait == BlendPixelTrait) + (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelAlpha(image, + p))); + } + } +} + static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image, ExceptionInfo *exception) { -#define TargaColormap 1 -#define TargaRGB 2 -#define TargaMonochrome 3 -#define TargaRLEColormap 9 -#define TargaRLERGB 10 -#define TargaRLEMonochrome 11 - - typedef struct _TargaInfo - { - unsigned char - id_length, - colormap_type, - image_type; - - unsigned short - colormap_index, - colormap_length; - - unsigned char - colormap_size; - - unsigned short - x_origin, - y_origin, - width, - height; - - unsigned char - bits_per_pixel, - attributes; - } TargaInfo; + CompressionType + compression; const char *value; @@ -692,15 +699,15 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image, register unsigned char *q; + size_t + channels; + ssize_t count, y; - TargaInfo - targa_info; - - unsigned char - *targa_pixels; + TGAInfo + tga_info; /* Open output image file. @@ -722,38 +729,43 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image, if ((image->columns > 65535L) || (image->rows > 65535L)) ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); (void) TransformImageColorspace(image,sRGBColorspace,exception); - targa_info.id_length=0; + compression=image->compression; + if (image_info->compression != UndefinedCompression) + compression=image_info->compression; + tga_info.id_length=0; value=GetImageProperty(image,"comment",exception); if (value != (const char *) NULL) - targa_info.id_length=(unsigned char) MagickMin(strlen(value),255); - targa_info.colormap_type=0; - targa_info.colormap_index=0; - targa_info.colormap_length=0; - targa_info.colormap_size=0; - targa_info.x_origin=0; - targa_info.y_origin=0; - targa_info.width=(unsigned short) image->columns; - targa_info.height=(unsigned short) image->rows; - targa_info.bits_per_pixel=8; - targa_info.attributes=0; + tga_info.id_length=(unsigned char) MagickMin(strlen(value),255); + tga_info.colormap_type=0; + tga_info.colormap_index=0; + tga_info.colormap_length=0; + tga_info.colormap_size=0; + tga_info.x_origin=0; + tga_info.y_origin=0; + tga_info.width=(unsigned short) image->columns; + tga_info.height=(unsigned short) image->rows; + tga_info.bits_per_pixel=8; + tga_info.attributes=0; if ((image_info->type != TrueColorType) && (image_info->type != TrueColorMatteType) && (image_info->type != PaletteType) && (image->alpha_trait != BlendPixelTrait) && (IsImageGray(image,exception) != MagickFalse)) - targa_info.image_type=TargaMonochrome; + tga_info.image_type=compression == RLECompression ? TGARLEMonochrome : + TGAMonochrome; else if ((image->storage_class == DirectClass) || (image->colors > 256)) { /* Full color TGA raster. */ - targa_info.image_type=TargaRGB; - targa_info.bits_per_pixel=24; + tga_info.image_type=compression == RLECompression ? TGARLERGB : + TGARGB; + tga_info.bits_per_pixel=24; if (image->alpha_trait == BlendPixelTrait) { - targa_info.bits_per_pixel=32; - targa_info.attributes=8; /* # of alpha bits */ + tga_info.bits_per_pixel=32; + tga_info.attributes=8; /* # of alpha bits */ } } else @@ -761,30 +773,31 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image, /* Colormapped TGA raster. */ - targa_info.image_type=TargaColormap; - targa_info.colormap_type=1; - targa_info.colormap_length=(unsigned short) image->colors; - targa_info.colormap_size=24; + tga_info.image_type=compression == RLECompression ? TGARLEColormap : + TGAColormap; + tga_info.colormap_type=1; + tga_info.colormap_length=(unsigned short) image->colors; + tga_info.colormap_size=24; } /* Write TGA header. */ - (void) WriteBlobByte(image,targa_info.id_length); - (void) WriteBlobByte(image,targa_info.colormap_type); - (void) WriteBlobByte(image,targa_info.image_type); - (void) WriteBlobLSBShort(image,targa_info.colormap_index); - (void) WriteBlobLSBShort(image,targa_info.colormap_length); - (void) WriteBlobByte(image,targa_info.colormap_size); - (void) WriteBlobLSBShort(image,targa_info.x_origin); - (void) WriteBlobLSBShort(image,targa_info.y_origin); - (void) WriteBlobLSBShort(image,targa_info.width); - (void) WriteBlobLSBShort(image,targa_info.height); - (void) WriteBlobByte(image,targa_info.bits_per_pixel); - (void) WriteBlobByte(image,targa_info.attributes); - if (targa_info.id_length != 0) - (void) WriteBlob(image,targa_info.id_length,(unsigned char *) + (void) WriteBlobByte(image,tga_info.id_length); + (void) WriteBlobByte(image,tga_info.colormap_type); + (void) WriteBlobByte(image,tga_info.image_type); + (void) WriteBlobLSBShort(image,tga_info.colormap_index); + (void) WriteBlobLSBShort(image,tga_info.colormap_length); + (void) WriteBlobByte(image,tga_info.colormap_size); + (void) WriteBlobLSBShort(image,tga_info.x_origin); + (void) WriteBlobLSBShort(image,tga_info.y_origin); + (void) WriteBlobLSBShort(image,tga_info.width); + (void) WriteBlobLSBShort(image,tga_info.height); + (void) WriteBlobByte(image,tga_info.bits_per_pixel); + (void) WriteBlobByte(image,tga_info.attributes); + if (tga_info.id_length != 0) + (void) WriteBlob(image,tga_info.id_length,(unsigned char *) value); - if (targa_info.image_type == TargaColormap) + if (tga_info.colormap_type != 0) { unsigned char *targa_colormap; @@ -793,7 +806,7 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image, Dump colormap to file (blue, green, red byte order). */ targa_colormap=(unsigned char *) AcquireQuantumMemory((size_t) - targa_info.colormap_length,3UL*sizeof(*targa_colormap)); + tga_info.colormap_length,3UL*sizeof(*targa_colormap)); if (targa_colormap == (unsigned char *) NULL) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); q=targa_colormap; @@ -803,43 +816,94 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image, *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green)); *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red)); } - (void) WriteBlob(image,(size_t) (3*targa_info.colormap_length), + (void) WriteBlob(image,(size_t) (3*tga_info.colormap_length), targa_colormap); targa_colormap=(unsigned char *) RelinquishMagickMemory(targa_colormap); } /* Convert MIFF to TGA raster pixels. */ - count=(ssize_t) (targa_info.bits_per_pixel*targa_info.width)/8; - targa_pixels=(unsigned char *) AcquireQuantumMemory((size_t) count, - sizeof(*targa_pixels)); - if (targa_pixels == (unsigned char *) NULL) - ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); + channels=GetPixelChannels(image); for (y=(ssize_t) (image->rows-1); y >= 0; y--) { p=GetVirtualPixels(image,0,y,image->columns,1,exception); if (p == (const Quantum *) NULL) break; - q=targa_pixels; - for (x=0; x < (ssize_t) image->columns; x++) - { - if (targa_info.image_type == TargaColormap) - *q++=(unsigned char) GetPixelIndex(image,p); - else - if (targa_info.image_type == TargaMonochrome) - *q++=(unsigned char) ScaleQuantumToChar((ClampToQuantum( - GetPixelLuma(image,p)))); - else + if (compression == RLECompression) + { + x=0; + count=0; + while (x < (ssize_t) image->columns) + { + i=1; + while ((i < 128) && (count + i < 128) && + ((x + i) < (ssize_t) image->columns)) { - *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); - *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); - *q++=ScaleQuantumToChar(GetPixelRed(image,p)); - if (image->alpha_trait == BlendPixelTrait) - *q++=(unsigned char) ScaleQuantumToChar(GetPixelAlpha(image,p)); + if (tga_info.image_type == TGARLEColormap) + { + if (GetPixelIndex(image,p+(i*channels)) != + GetPixelIndex(image,p+((i-1)*channels))) + break; + } + else if (tga_info.image_type == TGARLEMonochrome) + { + if (GetPixelLuma(image,p+(i*channels)) != + GetPixelLuma(image,p+((i-1)*channels))) + break; + } + else + { + if ((GetPixelBlue(image,p+(i*channels)) != + GetPixelBlue(image,p+((i-1)*channels))) || + (GetPixelGreen(image,p+(i*channels)) != + GetPixelGreen(image,p+((i-1)*channels))) || + (GetPixelRed(image,p+(i*channels)) != + GetPixelRed(image,p+((i-1)*channels)))) + break; + if ((image->alpha_trait == BlendPixelTrait) && + (GetPixelAlpha(image,p+(i*channels)) != + GetPixelAlpha(image,p+(i-1)*channels))) + break; + } + i++; } - p+=GetPixelChannels(image); - } - (void) WriteBlob(image,(size_t) (q-targa_pixels),targa_pixels); + if (i < 3) + { + count+=i; + p+=(i*channels); + } + if ((i >= 3) || (count == 128) || + ((x + i) == (ssize_t) image->columns)) + { + if (count > 0) + { + WriteBlobByte(image,(unsigned char) (--count)); + while (count >= 0) + { + WriteTGAPixel(image,tga_info.image_type,p-((count+1)* + channels)); + count--; + } + count=0; + } + } + if (i >= 3) + { + WriteBlobByte(image,(unsigned char) (i-1 | 0x80)); + WriteTGAPixel(image,tga_info.image_type,p); + p+=(i*channels); + } + x+=i; + } + } + else + { + for (x=0; x < (ssize_t) image->columns; x++) + { + WriteTGAPixel(image,tga_info.image_type,p); + p+=channels; + } + } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, @@ -848,7 +912,6 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image, break; } } - targa_pixels=(unsigned char *) RelinquishMagickMemory(targa_pixels); (void) CloseBlob(image); return(MagickTrue); } -- 2.40.0