summaryrefslogtreecommitdiff
path: root/coders/tga.c
diff options
context:
space:
mode:
Diffstat (limited to 'coders/tga.c')
-rw-r--r--coders/tga.c632
1 files changed, 428 insertions, 204 deletions
diff --git a/coders/tga.c b/coders/tga.c
index 0bc67e9..eaf2420 100644
--- a/coders/tga.c
+++ b/coders/tga.c
@@ -1,6 +1,6 @@
/*
-% Copyright (C) 2003 - 2020 GraphicsMagick Group
-% Copyright (C) 2002 ImageMagick Studio
+% Copyright (C) 2003 - 2023 GraphicsMagick Group
+% Copyright (C) 2002 - 2022 ImageMagick Studio
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
%
% This program is covered by multiple licenses, which are described in
@@ -24,6 +24,8 @@
% Software Design %
% John Cristy %
% July 1992 %
+% Jaroslav Fojtik %
+% 2022 %
% %
% %
% %
@@ -40,6 +42,7 @@
#include "magick/attribute.h"
#include "magick/blob.h"
#include "magick/colormap.h"
+#include "magick/enum_strings.h"
#include "magick/log.h"
#include "magick/magick.h"
#include "magick/monitor.h"
@@ -53,42 +56,122 @@ static unsigned int
WriteTGAImage(const ImageInfo *,Image *);
-#define TGAColormap 1 /* Colormapped image data */
-#define TGARGB 2 /* Truecolor image data */
-#define TGAMonochrome 3 /* Monochrome image data */
-#define TGARLEColormap 9 /* Colormapped image data (encoded) */
-#define TGARLERGB 10 /* Truecolor image data (encoded) */
-#define TGARLEMonochrome 11 /* Monochrome image data (encoded) */
+#define TGAColormap 1U /* Colormapped image data */
+#define TGARGB 2U /* Truecolor image data */
+#define TGAMonochrome 3U /* Monochrome image data */
+#define TGARLEColormap 9U /* Colormapped image data (encoded) */
+#define TGARLERGB 10U /* Truecolor image data (encoded) */
+#define TGARLEMonochrome 11U /* Monochrome image data (encoded) */
typedef struct _TGAInfo
{
- unsigned char
- id_length, /* Size of Image ID field */
- colormap_type, /* Color map type */
- image_type; /* Image type code */
+ unsigned int
+ id_length, /* (U8) Size of Image ID field (starting after header) */
+ colormap_type, /* (U8) Color map type */
+ image_type; /* (U8) Image type code */
- unsigned short
- colormap_index, /* Color map origin */
- colormap_length; /* Color map length */
+ unsigned int
+ colormap_index, /* (U16) Color map origin */
+ colormap_length; /* (U16) Color map length */
- unsigned char
- colormap_size; /* Color map entry depth */
+ unsigned int
+ colormap_size; /* (U8) Color map entry depth */
- unsigned short
- x_origin, /* X origin of image */
- y_origin, /* Y orgin of image */
- width, /* Width of image */
- height; /* Height of image */
+ unsigned int
+ x_origin, /* (U16) X origin of image */
+ y_origin, /* (U16) Y orgin of image */
+ width, /* (U16) Width of image */
+ height; /* (U16) Height of image */
- unsigned char
- bits_per_pixel, /* Image pixel size */
- attributes; /* Image descriptor byte */
+ unsigned int
+ bits_per_pixel, /* (U8) Image pixel size */
+ attributes; /* (U8) Image descriptor byte (see below) */
} TGAInfo;
-
+/*
+ Image descriptor byte decode:
+
+ Bits 0 through 3 specify the number of attribute bits per pixel.
+
+ Bits 5 and 4 contain the image origin location. These bits are used
+ to indicate the order in which pixel data is transferred from the
+ file to the screen. Bit 4 is for left-to-right ordering, and bit 5
+ is for top-to-bottom ordering as shown below:
+
+ 00 (0) - Bottom Left
+ 10 (2) - Top Left
+ 01 (1) - Bottom Right
+ 11 (3) - Top Right
+
+ Screen destination | Image Origin
+ of first pixel | Bit 5 | Bit 4
+ --------------------+-------+------
+ Bottom left | 0 | 0
+ Bottom right | 0 | 1
+ Top left | 1 | 0
+ Top right | 1 | 1
+*/
+
+
+typedef struct _TGAFooter
+{
+ magick_uint32_t ExtensionOffset;
+ magick_uint32_t DeveloperDirOffset;
+ char Signature[16+1]; /* 16 official bytes + zero terminator. */
+ char Dot;
+ char Terminator;
+} TGAFooter;
+
+
+typedef struct _TGADevel
+{
+ magick_uint16_t ExtensionSize;
+ char Author[41];
+ char Comments[324+1];
+ magick_uint16_t TimeStamp[6];
+ magick_uint16_t JobTime[3];
+ char JobNameID[41+1]; /* The last byte must be a binary zero. */
+ char SoftwareID[41];
+ magick_uint16_t VersionNumber;
+ unsigned char VersionLetter;
+ unsigned char KeyColor[4]; /* A:R:G:B */
+ magick_uint16_t AspectRatio[2];
+ magick_uint16_t Gamma[2];
+ magick_uint32_t ColorCorrectionOffset;
+ magick_uint32_t PostageStampOffset;
+ magick_uint32_t ScanLineOffset;
+ unsigned char AttributesType; /* 0: no Alpha; 1 undefined useless data in the Alpha;
+ 2: undefined data in the Alpha might be retained;
+ 3 useful Alpha channel; 4: pre-multiplied Alpha */
+ /* Scan Line Table - Field 25 (Variable) */
+ /* Postage Stamp Image - Field 26 (Variable) */
+ /* Color Correction Table - Field 27 (2K Bytes) */
+} TGADevel;
+
static void LogTGAInfo(const TGAInfo *tga_info)
{
+ OrientationType orientation = UndefinedOrientation;
+ unsigned int attribute_bits;
+
+ attribute_bits = tga_info->attributes & 0xf;
+
+ switch((tga_info->attributes >> 4) & 3)
+ {
+ case 0:
+ orientation=BottomLeftOrientation;
+ break;
+ case 1:
+ orientation=BottomRightOrientation;
+ break;
+ case 2:
+ orientation=TopLeftOrientation;
+ break;
+ case 3:
+ orientation=TopRightOrientation;
+ break;
+ }
+
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"Targa Header:\n"
" ImageType : %s\n"
@@ -101,7 +184,7 @@ static void LogTGAInfo(const TGAInfo *tga_info)
" Width : %u\n"
" Height : %u\n"
" PixelDepth : %u\n"
- " Attributes : 0x%.2x",
+ " Attributes : 0x%.2x (AttributeBits: %u, Orientation: %s)",
((tga_info->image_type == TGAColormap) ? "Colormapped" :
(tga_info->image_type == TGARGB) ? "TrueColor" :
(tga_info->image_type == TGAMonochrome) ? "Monochrome" :
@@ -116,32 +199,96 @@ static void LogTGAInfo(const TGAInfo *tga_info)
tga_info->x_origin, tga_info->y_origin,
tga_info->width, tga_info->height,
(unsigned int) tga_info->bits_per_pixel,
- tga_info->attributes);
-
+ tga_info->attributes,attribute_bits,OrientationTypeToString(orientation));
}
-static magick_uint16_t ReadBlobLSBShortFromBuffer(unsigned char* buffer, size_t* readerpos)
+
+static void LogTGAFooter(const TGAFooter *ptga_footer)
{
- magick_uint16_t
- value;
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Targa Footer:\n"
+ " ExtensionOffset : %u\n"
+ " DeveloperDirOffset : %u\n"
+ " Signature : %s",
+ ptga_footer->ExtensionOffset,
+ ptga_footer->DeveloperDirOffset,
+ ptga_footer->Signature);
+}
+
- value=buffer[(*readerpos)+1] << 8;
- value|=buffer[*readerpos];
- *readerpos = *readerpos+2;
- return(value);
+static void LogTGADevel(const TGADevel *ptga_devel)
+{
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Targa Extension Area:\n"
+ " Extension Size : %u\n"
+ " Author Name : %s\n"
+ " Author Comments : %s\n"
+ " Date/Time Stamp : %u/%u/%u %u:%u:%u\n"
+ " Job Name/ID : %s\n"
+ " Job Time : %u:%u:%u\n"
+ " Software ID : %s\n"
+ " Software Version : %u.%u\n"
+ " Key Color : A=%u R=%u G=%u B=%u\n"
+ " Pixel Aspect Ratio : %u x %u\n"
+ " Gamma : %u x %u\n"
+ " Color Correction Offset: %u\n"
+ " Postage Stamp Offset: %u\n"
+ " Scan Line Offset : %u\n"
+ " Attributes Type : %u",
+ ptga_devel->ExtensionSize,
+ ptga_devel->Author,
+ ptga_devel->Comments,
+ ptga_devel->TimeStamp[0], ptga_devel->TimeStamp[1], ptga_devel->TimeStamp[2],
+ ptga_devel->TimeStamp[3], ptga_devel->TimeStamp[4], ptga_devel->TimeStamp[5],
+ ptga_devel->JobNameID,
+ ptga_devel->JobTime[0], ptga_devel->JobTime[1], ptga_devel->JobTime[2],
+ ptga_devel->SoftwareID,
+ ptga_devel->VersionNumber, (unsigned)ptga_devel->VersionLetter,
+ ptga_devel->KeyColor[0], ptga_devel->KeyColor[1], ptga_devel->KeyColor[2], ptga_devel->KeyColor[3],
+ ptga_devel->AspectRatio[0], ptga_devel->AspectRatio[1],
+ ptga_devel->Gamma[0], ptga_devel->Gamma[1],
+ ptga_devel->ColorCorrectionOffset,
+ ptga_devel->PostageStampOffset,
+ ptga_devel->ScanLineOffset,
+ (unsigned)ptga_devel->AttributesType);
}
-static int ReadBlobByteFromBuffer(unsigned char* buffer, size_t* readerpos)
+static int LoadHeaderTGA(TGAInfo *tga_info, Image *image)
{
- int
- value;
+ tga_info->id_length = ReadBlobByte(image);
+ tga_info->colormap_type = ReadBlobByte(image);
+ tga_info->image_type = ReadBlobByte(image);
+
+ tga_info->colormap_index = ReadBlobLSBShort(image);
+ tga_info->colormap_length = ReadBlobLSBShort(image) & 0xFFFF;
+ tga_info->colormap_size = ReadBlobByte(image);
+ tga_info->x_origin = ReadBlobLSBShort(image);
+ tga_info->y_origin = ReadBlobLSBShort(image);
+ tga_info->width = ReadBlobLSBShort(image) & 0xFFFF;
+ tga_info->height = ReadBlobLSBShort(image) & 0xFFFF;
+ tga_info->bits_per_pixel = ReadBlobByte(image);
+ tga_info->attributes = ReadBlobByte(image);
+ return 0;
+}
- value=(int)(buffer[*readerpos]);
- *readerpos = *readerpos + 1;
- return(value);
+
+
+static int ValidateHeaderTGA(const TGAInfo *tga_info)
+{
+ if (((tga_info->image_type != TGAColormap) &&
+ (tga_info->image_type != TGARGB) &&
+ (tga_info->image_type != TGAMonochrome) &&
+ (tga_info->image_type != TGARLEColormap) &&
+ (tga_info->image_type != TGARLERGB) &&
+ (tga_info->image_type != TGARLEMonochrome)) ||
+ (((tga_info->image_type == TGAColormap) ||
+ (tga_info->image_type == TGARLEColormap)) &&
+ (tga_info->colormap_type == 0))) return -1;
+ return 0;
}
+
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
@@ -171,9 +318,8 @@ static int ReadBlobByteFromBuffer(unsigned char* buffer, size_t* readerpos)
%
% 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)
{
Image
*image;
@@ -200,6 +346,12 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
TGAInfo
tga_info;
+ TGAFooter
+ tga_footer;
+
+ TGADevel
+ tga_devel;
+
unsigned char
runlength;
@@ -217,12 +369,11 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
unsigned int
is_grayscale=MagickFalse;
- const size_t headersize = 15;
- unsigned char readbuffer[15];
- const size_t commentsize = 256;
- char commentbuffer[256];
- size_t readbufferpos = 0;
+ unsigned char
+ readbuffer[4];
+ char
+ CommentAndBuffer[256];
/*
Open image file.
@@ -231,67 +382,162 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
assert(image_info->signature == MagickSignature);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickSignature);
- image=AllocateImage(image_info);
- status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
+ image = AllocateImage(image_info);
+ status = OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
if (status == MagickFalse)
ThrowReaderException(FileOpenError,UnableToOpenFile,image);
+
+ /*
+ Read TGA footer - if exists.
+ */
+ memset(&tga_footer, 0, sizeof(tga_footer));
+ memset(&tga_devel, 0, sizeof(tga_devel));
+ if (BlobIsSeekable(image))
+ {
+ if (SeekBlob(image,-26, SEEK_END) >= 3+15)
+ {
+ status = MagickTrue;
+ tga_footer.ExtensionOffset = ReadBlobLSBLong(image);
+ tga_footer.DeveloperDirOffset = ReadBlobLSBLong(image);
+ if (ReadBlob(image, 16, tga_footer.Signature) != 16)
+ status=MagickFail;
+ else
+ {
+ if ((tga_footer.Dot=ReadBlobByte(image)) != '.')
+ status=MagickFail;
+ if ((tga_footer.Terminator=ReadBlobByte(image)) != 0)
+ status=MagickFail;
+ }
+
+ if (status == MagickTrue)
+ {
+ if (image->logging)
+ LogTGAFooter(&tga_footer);
+ if (strncmp(tga_footer.Signature,"TRUEVISION-XFILE",16))
+ status=MagickFail;
+ }
+ if (status != MagickTrue) /* Footer is invalid. */
+ {
+ memset(&tga_footer, 0, sizeof(tga_footer));
+ }
+
+ if (tga_footer.ExtensionOffset > 3)
+ {
+ if (SeekBlob(image,tga_footer.ExtensionOffset,SEEK_SET) == tga_footer.ExtensionOffset)
+ {
+ tga_devel.ExtensionSize = ReadBlobLSBShort(image);
+ if (tga_devel.ExtensionSize >= 495)
+ {
+ if (ReadBlob(image, 41, tga_devel.Author) != 41)
+ status=MagickFail;
+ if (tga_devel.Author[40] != 0)
+ tga_devel.Author[40]=0;
+ if (ReadBlob(image, 324, tga_devel.Comments) != 324)
+ status=MagickFail;
+ if (tga_devel.Comments[323] != 0)
+ tga_devel.Comments[323]=0;
+ for (i=0; i<6; i++)
+ {
+ tga_devel.TimeStamp[i] = ReadBlobLSBShort(image);
+ }
+ if (ReadBlob(image, 41, tga_devel.JobNameID) != 41)
+ status=MagickFail;
+ if (tga_devel.JobNameID[40] != 0)
+ tga_devel.JobNameID[40]=0;
+ for (i=0; i<3; i++)
+ {
+ tga_devel.JobTime[i] = ReadBlobLSBShort(image);
+ }
+ if (ReadBlob(image, 41, tga_devel.SoftwareID) != 41)
+ status=MagickFail;
+ if (tga_devel.SoftwareID[40] != 0)
+ tga_devel.SoftwareID[40]=0;
+ tga_devel.VersionNumber = ReadBlobLSBShort(image);
+ tga_devel.VersionLetter = ReadBlobByte(image);
+ if (ReadBlob(image, 4, tga_devel.KeyColor) != 4)
+ status=MagickFail;
+ for (i=0; i<2; i++)
+ {
+ tga_devel.AspectRatio[i] = ReadBlobLSBShort(image);
+ }
+ for (i=0; i<2; i++)
+ {
+ tga_devel.Gamma[i] = ReadBlobLSBShort(image);
+ }
+ tga_devel.ColorCorrectionOffset = ReadBlobLSBLong(image);
+ tga_devel.PostageStampOffset = ReadBlobLSBLong(image);
+ tga_devel.ScanLineOffset = ReadBlobLSBLong(image);
+ tga_devel.AttributesType = ReadBlobByte(image);
+
+ if (image->logging)
+ LogTGADevel(&tga_devel);
+ if (status == MagickTrue) /* TGA devel is valid */
+ {
+ if (tga_devel.Comments[0] != 0)
+ SetImageAttribute(image, "TGA:file.comment", tga_devel.Comments);
+ if (tga_devel.Author[0] != 0)
+ SetImageAttribute(image, "creator", tga_devel.Author);
+ if (tga_devel.SoftwareID[0] != 0)
+ SetImageAttribute(image, "software", tga_devel.SoftwareID);
+ if (tga_devel.JobNameID[0] != 0)
+ SetImageAttribute(image, "TGA:file.JobName", tga_devel.JobNameID);
+ }
+ else
+ {
+ tga_devel.ExtensionSize = 0; /* Invalidate TGA developper area. */
+ }
+ }
+ }
+ }
+ }
+
+ status = MagickTrue;
+ if (SeekBlob(image,0,SEEK_SET) != 0)
+ {
+ ThrowReaderException(BlobError,UnableToSeekToOffset,image);
+ }
+ }
+
/*
Read TGA header information.
*/
- if (ReadBlob(image, 3, readbuffer) != 3)
+ if (LoadHeaderTGA(&tga_info, image) < 0)
ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
- readbufferpos = 0;
- tga_info.id_length=(unsigned char)ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
- tga_info.colormap_type=(unsigned char)ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
- tga_info.image_type=(unsigned char)ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
+
+ if (ValidateHeaderTGA(&tga_info) < 0)
+ ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
do
{
- if (((tga_info.image_type != TGAColormap) &&
- (tga_info.image_type != TGARGB) &&
- (tga_info.image_type != TGAMonochrome) &&
- (tga_info.image_type != TGARLEColormap) &&
- (tga_info.image_type != TGARLERGB) &&
- (tga_info.image_type != TGARLEMonochrome)) ||
- (((tga_info.image_type == TGAColormap) ||
- (tga_info.image_type == TGARLEColormap)) &&
- (tga_info.colormap_type == 0)))
- ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
-
- if (ReadBlob(image,headersize,readbuffer) != headersize)
- ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
- readbufferpos = 0;
- tga_info.colormap_index=ReadBlobLSBShortFromBuffer(readbuffer, &readbufferpos);
- tga_info.colormap_length=ReadBlobLSBShortFromBuffer(readbuffer, &readbufferpos) & 0xFFFF;
- tga_info.colormap_size=ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
- tga_info.x_origin=ReadBlobLSBShortFromBuffer(readbuffer, &readbufferpos);
- tga_info.y_origin=ReadBlobLSBShortFromBuffer(readbuffer, &readbufferpos);
- tga_info.width=ReadBlobLSBShortFromBuffer(readbuffer, &readbufferpos) & 0xFFFF;
- tga_info.height=ReadBlobLSBShortFromBuffer(readbuffer, &readbufferpos) & 0xFFFF;
- tga_info.bits_per_pixel=ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
- tga_info.attributes=ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
- assert(readbufferpos == headersize);
- if (EOFBlob(image))
- ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
-
if (image->logging)
LogTGAInfo(&tga_info);
+ if (EOFBlob(image))
+ ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
+
/*
Validate depth.
*/
if (!(((tga_info.bits_per_pixel > 1) && (tga_info.bits_per_pixel < 17)) ||
- (tga_info.bits_per_pixel == 24 ) ||
- (tga_info.bits_per_pixel == 32 )))
+ (tga_info.bits_per_pixel == 24 ) || (tga_info.bits_per_pixel == 32) ||
+ (tga_info.bits_per_pixel == 1 && tga_info.image_type == TGAMonochrome) ))
ThrowReaderException(CoderError,DataStorageTypeIsNotSupported,image);
/*
Initialize image structure.
*/
- alpha_bits=(tga_info.attributes & 0x0FU);
- image->matte=((alpha_bits > 0) || (tga_info.bits_per_pixel == 32));
- image->columns=tga_info.width;
- image->rows=tga_info.height;
+ alpha_bits = (tga_info.attributes & 0x0FU);
+ image->matte = ((alpha_bits > 0) || (tga_info.bits_per_pixel == 32));
+ if (image->matte)
+ {
+ if (tga_footer.ExtensionOffset > 3 && tga_devel.ExtensionSize >= 495) /* Valid footer and extended area. */
+ { /* Please note that alpha channel could contain a garbage. */
+ if (tga_devel.AttributesType < 3 || tga_devel.AttributesType > 4)
+ image->matte = MagickFalse; /* The attribute instruct NOT to use alpha channel. */
+ }
+ }
+ image->columns = tga_info.width;
+ image->rows = tga_info.height;
if ((tga_info.image_type != TGAColormap) && (tga_info.image_type != TGARLEColormap))
{
/*
@@ -341,7 +587,8 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
image->colors=tga_info.colormap_length;
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"Using existing colormap with %u colors.",image->colors);
-
+ if (tga_info.bits_per_pixel==1 && image->colors<=1)
+ ThrowReaderException(CoderError,ColorTypeNotSupported,image);
}
else
{
@@ -368,12 +615,10 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
/*
TGA image comment.
*/
- if (((size_t) tga_info.id_length+1) != commentsize)
- ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
- if (ReadBlob(image,tga_info.id_length,commentbuffer) != tga_info.id_length)
+ if (ReadBlob(image,tga_info.id_length,CommentAndBuffer) != tga_info.id_length)
ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
- commentbuffer[tga_info.id_length]='\0';
- (void) SetImageAttribute(image,"comment",commentbuffer);
+ CommentAndBuffer[tga_info.id_length]='\0';
+ (void) SetImageAttribute(image,"comment",CommentAndBuffer);
}
(void) memset(&pixel,0,sizeof(PixelPacket));
pixel.opacity=TransparentOpacity;
@@ -403,35 +648,26 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
/*
5 bits each of red green and blue.
*/
- unsigned int
- packet;
-
- if (ReadBlob(image, 2, readbuffer) != 2)
- ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
- readbufferpos = 0;
- packet = ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
- packet |= (((unsigned int) ReadBlobByteFromBuffer(readbuffer, &readbufferpos)) << 8);
-
- pixel.red=(packet >> 10) & 0x1f;
- pixel.red=ScaleCharToQuantum(ScaleColor5to8(pixel.red));
- pixel.green=(packet >> 5) & 0x1f;
- pixel.green=ScaleCharToQuantum(ScaleColor5to8(pixel.green));
- pixel.blue=packet & 0x1f;
- pixel.blue=ScaleCharToQuantum(ScaleColor5to8(pixel.blue));
+ const magick_uint16_t packet = ReadBlobLSBShort(image);
+ pixel.red = (packet >> 10) & 0x1f;
+ pixel.red = ScaleCharToQuantum(ScaleColor5to8(pixel.red));
+ pixel.green = (packet >> 5) & 0x1f;
+ pixel.green = ScaleCharToQuantum(ScaleColor5to8(pixel.green));
+ pixel.blue = packet & 0x1f;
+ pixel.blue = ScaleCharToQuantum(ScaleColor5to8(pixel.blue));
break;
}
case 24:
- case 32:
+ case 32: /* TODO: J.Fojtik - is this true? 32 bits, but only 24 bits read. Possible bug! */
{
/*
8 bits each of blue, green and red.
*/
if (ReadBlob(image, 3, readbuffer) != 3)
ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
- readbufferpos = 0;
- pixel.blue=ScaleCharToQuantum(ReadBlobByteFromBuffer(readbuffer, &readbufferpos));
- pixel.green=ScaleCharToQuantum(ReadBlobByteFromBuffer(readbuffer, &readbufferpos));
- pixel.red=ScaleCharToQuantum(ReadBlobByteFromBuffer(readbuffer, &readbufferpos));
+ pixel.blue = ScaleCharToQuantum(readbuffer[0]);
+ pixel.green = ScaleCharToQuantum(readbuffer[1]);
+ pixel.red = ScaleCharToQuantum(readbuffer[2]);
break;
}
}
@@ -461,17 +697,17 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
for (y=0; y < (long) image->rows; y++)
{
real=offset;
- if (((unsigned char) (tga_info.attributes & 0x20) >> 5) == 0)
+ if (((tga_info.attributes & 0x20) >> 5) == 0)
real=image->rows-real-1;
q=SetImagePixels(image,0,(long) real,image->columns,1);
if (q == (PixelPacket *) NULL)
break;
indexes=AccessMutableIndexes(image);
- for (x=0; x < (long) image->columns; x++)
+ for (x=0; x < (long)image->columns; x++)
{
if ((tga_info.image_type == TGARLEColormap) ||
(tga_info.image_type == TGARLERGB) ||
- (tga_info.image_type == TGARLEMonochrome))
+ (tga_info.image_type == TGARLEMonochrome)) /* J.F. THIS WILLL NOT WORK! Some image sample should be obtained. */
{
if (runlength != 0)
{
@@ -494,17 +730,33 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
if (!skip)
switch (tga_info.bits_per_pixel)
{
+ case 1:
+ if ((x&7) == 0) // Read byte every 8th bit.
+ index = ReadBlobByte(image);
+ else
+ index <<= 1;
+ if (image->storage_class == PseudoClass)
+ {
+ pixel = image->colormap[indexes[x] = ((index & 128) ? 1 : 0)];
+ }
+ else
+ {
+ pixel.blue=pixel.green=pixel.red = (index & 128) ? MaxRGB : 0;
+ }
+ break;
+
case 8:
default:
{
/*
Gray scale.
*/
- index=ReadBlobByte(image);
+ index = ReadBlobByte(image);
if (image->storage_class == PseudoClass)
{
VerifyColormapIndex(image,index);
pixel=image->colormap[index];
+ indexes[x] = index;
}
else
{
@@ -518,24 +770,14 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
/*
5 bits each of red green and blue.
*/
- unsigned int
- packet;
-
- if (ReadBlob(image, 2, readbuffer) != 2)
- {
- status=MagickFail;
- break;
- }
- readbufferpos = 0;
- packet = ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
- packet |= (((unsigned int) ReadBlobByteFromBuffer(readbuffer, &readbufferpos)) << 8);
-
- pixel.red=(packet >> 10) & 0x1f;
- pixel.red=ScaleCharToQuantum(ScaleColor5to8(pixel.red));
- pixel.green=(packet >> 5) & 0x1f;
- pixel.green=ScaleCharToQuantum(ScaleColor5to8(pixel.green));
- pixel.blue=packet & 0x1f;
- pixel.blue=ScaleCharToQuantum(ScaleColor5to8(pixel.blue));
+ const magick_uint16_t packet = ReadBlobLSBShort(image);
+
+ pixel.red = (packet >> 10) & 0x1f;
+ pixel.red = ScaleCharToQuantum(ScaleColor5to8(pixel.red));
+ pixel.green = (packet >> 5) & 0x1f;
+ pixel.green = ScaleCharToQuantum(ScaleColor5to8(pixel.green));
+ pixel.blue = packet & 0x1f;
+ pixel.blue = ScaleCharToQuantum(ScaleColor5to8(pixel.blue));
if (image->matte)
{
if ((packet >> 15) & 0x01)
@@ -560,10 +802,9 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
status=MagickFail;
break;
}
- readbufferpos = 0;
- pixel.blue=ScaleCharToQuantum(ReadBlobByteFromBuffer(readbuffer, &readbufferpos));
- pixel.green=ScaleCharToQuantum(ReadBlobByteFromBuffer(readbuffer, &readbufferpos));
- pixel.red=ScaleCharToQuantum(ReadBlobByteFromBuffer(readbuffer, &readbufferpos));
+ pixel.blue = ScaleCharToQuantum(readbuffer[0]);
+ pixel.green = ScaleCharToQuantum(readbuffer[1]);
+ pixel.red = ScaleCharToQuantum(readbuffer[2]);
break;
case 32:
{
@@ -575,20 +816,23 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
status=MagickFail;
break;
}
- readbufferpos = 0;
- pixel.blue=ScaleCharToQuantum(ReadBlobByteFromBuffer(readbuffer, &readbufferpos));
- pixel.green=ScaleCharToQuantum(ReadBlobByteFromBuffer(readbuffer, &readbufferpos));
- pixel.red=ScaleCharToQuantum(ReadBlobByteFromBuffer(readbuffer, &readbufferpos));
- pixel.opacity=ScaleCharToQuantum(255-ReadBlobByteFromBuffer(readbuffer, &readbufferpos));
+ pixel.blue = ScaleCharToQuantum(readbuffer[0]);
+ pixel.green = ScaleCharToQuantum(readbuffer[1]);
+ pixel.red = ScaleCharToQuantum(readbuffer[2]);
+ pixel.opacity = ScaleCharToQuantum(255-readbuffer[3]);
break;
}
}
+ else /* skip==true - Duplicate index on RLE repeat. */
+ {
+ if (image->storage_class == PseudoClass)
+ indexes[x] = index;
+ }
+
if (EOFBlob(image))
status = MagickFail;
if (status == MagickFail)
ThrowReaderException(CorruptImageError,UnableToReadImageData,image);
- if (image->storage_class == PseudoClass)
- indexes[x]=index;
*q++=pixel;
}
/*
@@ -596,12 +840,12 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
tested here. This test case can never be true and so it
is commented out for the moment.
- if (((unsigned char) (tga_info.attributes & 0xc0) >> 6) == 4)
+ if (((unsigned char) (tga_info.attributes & 0xc0) >> 6) == 4)
offset+=4;
- else
+ else
*/
if (((unsigned char) (tga_info.attributes & 0xc0) >> 6) == 2)
- offset+=2;
+ offset+=2;
else
offset++;
if (offset >= image->rows)
@@ -626,6 +870,7 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
break;
}
StopTimer(&image->timer);
+
/*
Proceed to next image.
*/
@@ -633,19 +878,13 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
if (image->scene >= (image_info->subimage+image_info->subrange-1))
break;
- status=MagickFalse;
- if (ReadBlob(image, 3, readbuffer) == 3)
+ if (LoadHeaderTGA(&tga_info, image) < 0)
{
- readbufferpos = 0;
- tga_info.id_length=(unsigned char)ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
- tga_info.colormap_type=(unsigned char)ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
- tga_info.image_type=(unsigned char)ReadBlobByteFromBuffer(readbuffer, &readbufferpos);
- status=((tga_info.image_type == TGAColormap) ||
- (tga_info.image_type == TGARGB) ||
- (tga_info.image_type == TGAMonochrome) ||
- (tga_info.image_type == TGARLEColormap) ||
- (tga_info.image_type == TGARLERGB) ||
- (tga_info.image_type == TGARLEMonochrome));
+ status = MagickFalse;
+ }
+ else
+ {
+ status = (ValidateHeaderTGA(&tga_info)<0) ? MagickFalse : MagickTrue;
}
if (!EOFBlob(image) && (status == MagickTrue))
{
@@ -658,7 +897,7 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
DestroyImageList(image);
return((Image *) NULL);
}
- image=SyncNextImageInList(image);
+ image = SyncNextImageInList(image);
if (!MagickMonitorFormatted(TellBlob(image),GetBlobSize(image),
exception,LoadImagesText,
image->filename))
@@ -799,8 +1038,8 @@ static unsigned int WriteTGAImage(const ImageInfo *image_info,Image *image)
register const PixelPacket
*p;
- register const IndexPacket
- *indexes;
+ /* register const IndexPacket
+ *indexes; */
register long
x;
@@ -918,7 +1157,7 @@ static unsigned int WriteTGAImage(const ImageInfo *image_info,Image *image)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"Writing Grayscale raster ...");
tga_info.image_type=TGAMonochrome;
- tga_info.bits_per_pixel=8;
+ tga_info.bits_per_pixel = (image->colors==2) ? 1 : 8;
tga_info.colormap_type=0;
tga_info.colormap_index=0;
tga_info.colormap_length=0;
@@ -986,7 +1225,7 @@ static unsigned int WriteTGAImage(const ImageInfo *image_info,Image *image)
Dump colormap to file (blue, green, red byte order).
*/
targa_colormap=MagickAllocateResourceLimitedArray(unsigned char *,
- tga_info.colormap_length,3);
+ tga_info.colormap_length,3);
if (targa_colormap == (unsigned char *) NULL)
ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
image);
@@ -1004,56 +1243,41 @@ static unsigned int WriteTGAImage(const ImageInfo *image_info,Image *image)
/*
Convert MIFF to TGA raster pixels.
*/
- count=(size_t) ((MagickArraySize(tga_info.bits_per_pixel,image->columns)) >> 3);
- tga_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,count);
+ count = (size_t)((7+MagickArraySize(tga_info.bits_per_pixel,image->columns)) >> 3); /*7 bits padding. */
+ tga_pixels = MagickAllocateResourceLimitedMemory(unsigned char *,count);
if (tga_pixels == (unsigned char *) NULL)
ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
- for (y=(long) (image->rows-1); y >= 0; y--)
+ for (y=(long)(image->rows-1); y>=0; y--)
{
- p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
+ p = AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
if (p == (const PixelPacket *) NULL)
break;
- q=tga_pixels;
- indexes=AccessImmutableIndexes(image);
- for (x=0; x < (long) image->columns; x++)
+ /* indexes = AccessImmutableIndexes(image); */
+
+ switch (tga_info.image_type)
{
- if (tga_info.image_type == TGAColormap)
- {
- /* Colormapped */
- *q++=*indexes;
- indexes++;
- }
- else if (tga_info.image_type == TGAMonochrome)
- {
- /* Grayscale */
- if (image->storage_class == PseudoClass)
- {
- if (image->is_grayscale)
- *q++=ScaleQuantumToChar(image->colormap[*indexes].red);
- else
- *q++=PixelIntensityToQuantum(&image->colormap[*indexes]);
- indexes++;
- }
- else
- {
- if (image->is_grayscale)
- *q++=ScaleQuantumToChar(p->red);
- else
- *q++=PixelIntensityToQuantum(p);
- }
- }
- else
+ case TGAMonochrome:
+ if (ExportImagePixelArea(image,GrayQuantum,tga_info.bits_per_pixel,tga_pixels,0,0) != MagickPass)
+ status=MagickFail;
+ break;
+ case TGAColormap:
+ if (ExportImagePixelArea(image,IndexQuantum,tga_info.bits_per_pixel,tga_pixels,0,0) != MagickPass)
+ status=MagickFail;
+ break;
+ default: /* TrueColor RGB (quantum type is BGR, ExportImagePixelArea is useless.)*/
+ q = tga_pixels;
+ for (x=0; x<(long)image->columns; x++)
{
- /* TrueColor RGB */
*q++=ScaleQuantumToChar(p->blue);
*q++=ScaleQuantumToChar(p->green);
*q++=ScaleQuantumToChar(p->red);
if (image->matte)
*q++=ScaleQuantumToChar(MaxRGB-p->opacity);
+ p++;
}
- p++;
+ break;
}
- (void) WriteBlob(image,q-tga_pixels,(char *) tga_pixels);
+ (void) WriteBlob(image,count,(char*)tga_pixels);
if (image->previous == (Image *) NULL)
if (QuantumTick(y,image->rows))
if (!MagickMonitorFormatted(y,image->rows,&image->exception,