Files
core/DesktopEditor/raster/PICT/pic.cpp
K1rillProkhorov c5436f38fa Fix bug #65485
2024-01-13 15:13:34 +03:00

3295 lines
94 KiB
C++

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "pic.h"
static const PICTCode
codes[] =
{
/* 0x00 */ { "NOP", 0, "nop" },
/* 0x01 */ { "ClipRgn", 0, "clip" },
/* 0x02 */ { "BkPat", 8, "background pattern" },
/* 0x03 */ { "TxFont", 2, "text font (word)" },
/* 0x04 */ { "TxFace", 1, "text face (byte)" },
/* 0x05 */ { "TxMode", 2, "text mode (word)" },
/* 0x06 */ { "SpExtra", 4, "space extra (fixed point)" },
/* 0x07 */ { "PnSize", 4, "pen size (point)" },
/* 0x08 */ { "PnMode", 2, "pen mode (word)" },
/* 0x09 */ { "PnPat", 8, "pen pattern" },
/* 0x0a */ { "FillPat", 8, "fill pattern" },
/* 0x0b */ { "OvSize", 4, "oval size (point)" },
/* 0x0c */ { "Origin", 4, "dh, dv (word)" },
/* 0x0d */ { "TxSize", 2, "text size (word)" },
/* 0x0e */ { "FgColor", 4, "foreground color (long longword)" },
/* 0x0f */ { "BkColor", 4, "background color (long longword)" },
/* 0x10 */ { "TxRatio", 8, "numerator (point), denominator (point)" },
/* 0x11 */ { "Version", 1, "version (byte)" },
/* 0x12 */ { "BkPixPat", 0, "color background pattern" },
/* 0x13 */ { "PnPixPat", 0, "color pen pattern" },
/* 0x14 */ { "FillPixPat", 0, "color fill pattern" },
/* 0x15 */ { "PnLocHFrac", 2, "fractional pen position" },
/* 0x16 */ { "ChExtra", 2, "extra for each character" },
/* 0x17 */ { "reserved", 0, "reserved for Apple use" },
/* 0x18 */ { "reserved", 0, "reserved for Apple use" },
/* 0x19 */ { "reserved", 0, "reserved for Apple use" },
/* 0x1a */ { "RGBFgCol", 6, "RGB foreColor" },
/* 0x1b */ { "RGBBkCol", 6, "RGB backColor" },
/* 0x1c */ { "HiliteMode", 0, "hilite mode flag" },
/* 0x1d */ { "HiliteColor", 6, "RGB hilite color" },
/* 0x1e */ { "DefHilite", 0, "Use default hilite color" },
/* 0x1f */ { "OpColor", 6, "RGB OpColor for arithmetic modes" },
/* 0x20 */ { "Line", 8, "pnLoc (point), newPt (point)" },
/* 0x21 */ { "LineFrom", 4, "newPt (point)" },
/* 0x22 */ { "ShortLine", 6, "pnLoc (point, dh, dv (-128 .. 127))" },
/* 0x23 */ { "ShortLineFrom", 2, "dh, dv (-128 .. 127)" },
/* 0x24 */ { "reserved", -1, "reserved for Apple use" },
/* 0x25 */ { "reserved", -1, "reserved for Apple use" },
/* 0x26 */ { "reserved", -1, "reserved for Apple use" },
/* 0x27 */ { "reserved", -1, "reserved for Apple use" },
/* 0x28 */ { "LongText", 0, "txLoc (point), count (0..255), text" },
/* 0x29 */ { "DHText", 0, "dh (0..255), count (0..255), text" },
/* 0x2a */ { "DVText", 0, "dv (0..255), count (0..255), text" },
/* 0x2b */ { "DHDVText", 0, "dh, dv (0..255), count (0..255), text" },
/* 0x2c */ { "reserved", -1, "reserved for Apple use" },
/* 0x2d */ { "reserved", -1, "reserved for Apple use" },
/* 0x2e */ { "reserved", -1, "reserved for Apple use" },
/* 0x2f */ { "reserved", -1, "reserved for Apple use" },
/* 0x30 */ { "frameRect", 8, "rect" },
/* 0x31 */ { "paintRect", 8, "rect" },
/* 0x32 */ { "eraseRect", 8, "rect" },
/* 0x33 */ { "invertRect", 8, "rect" },
/* 0x34 */ { "fillRect", 8, "rect" },
/* 0x35 */ { "reserved", 8, "reserved for Apple use" },
/* 0x36 */ { "reserved", 8, "reserved for Apple use" },
/* 0x37 */ { "reserved", 8, "reserved for Apple use" },
/* 0x38 */ { "frameSameRect", 0, "rect" },
/* 0x39 */ { "paintSameRect", 0, "rect" },
/* 0x3a */ { "eraseSameRect", 0, "rect" },
/* 0x3b */ { "invertSameRect", 0, "rect" },
/* 0x3c */ { "fillSameRect", 0, "rect" },
/* 0x3d */ { "reserved", 0, "reserved for Apple use" },
/* 0x3e */ { "reserved", 0, "reserved for Apple use" },
/* 0x3f */ { "reserved", 0, "reserved for Apple use" },
/* 0x40 */ { "frameRRect", 8, "rect" },
/* 0x41 */ { "paintRRect", 8, "rect" },
/* 0x42 */ { "eraseRRect", 8, "rect" },
/* 0x43 */ { "invertRRect", 8, "rect" },
/* 0x44 */ { "fillRRrect", 8, "rect" },
/* 0x45 */ { "reserved", 8, "reserved for Apple use" },
/* 0x46 */ { "reserved", 8, "reserved for Apple use" },
/* 0x47 */ { "reserved", 8, "reserved for Apple use" },
/* 0x48 */ { "frameSameRRect", 0, "rect" },
/* 0x49 */ { "paintSameRRect", 0, "rect" },
/* 0x4a */ { "eraseSameRRect", 0, "rect" },
/* 0x4b */ { "invertSameRRect", 0, "rect" },
/* 0x4c */ { "fillSameRRect", 0, "rect" },
/* 0x4d */ { "reserved", 0, "reserved for Apple use" },
/* 0x4e */ { "reserved", 0, "reserved for Apple use" },
/* 0x4f */ { "reserved", 0, "reserved for Apple use" },
/* 0x50 */ { "frameOval", 8, "rect" },
/* 0x51 */ { "paintOval", 8, "rect" },
/* 0x52 */ { "eraseOval", 8, "rect" },
/* 0x53 */ { "invertOval", 8, "rect" },
/* 0x54 */ { "fillOval", 8, "rect" },
/* 0x55 */ { "reserved", 8, "reserved for Apple use" },
/* 0x56 */ { "reserved", 8, "reserved for Apple use" },
/* 0x57 */ { "reserved", 8, "reserved for Apple use" },
/* 0x58 */ { "frameSameOval", 0, "rect" },
/* 0x59 */ { "paintSameOval", 0, "rect" },
/* 0x5a */ { "eraseSameOval", 0, "rect" },
/* 0x5b */ { "invertSameOval", 0, "rect" },
/* 0x5c */ { "fillSameOval", 0, "rect" },
/* 0x5d */ { "reserved", 0, "reserved for Apple use" },
/* 0x5e */ { "reserved", 0, "reserved for Apple use" },
/* 0x5f */ { "reserved", 0, "reserved for Apple use" },
/* 0x60 */ { "frameArc", 12, "rect, startAngle, arcAngle" },
/* 0x61 */ { "paintArc", 12, "rect, startAngle, arcAngle" },
/* 0x62 */ { "eraseArc", 12, "rect, startAngle, arcAngle" },
/* 0x63 */ { "invertArc", 12, "rect, startAngle, arcAngle" },
/* 0x64 */ { "fillArc", 12, "rect, startAngle, arcAngle" },
/* 0x65 */ { "reserved", 12, "reserved for Apple use" },
/* 0x66 */ { "reserved", 12, "reserved for Apple use" },
/* 0x67 */ { "reserved", 12, "reserved for Apple use" },
/* 0x68 */ { "frameSameArc", 4, "rect, startAngle, arcAngle" },
/* 0x69 */ { "paintSameArc", 4, "rect, startAngle, arcAngle" },
/* 0x6a */ { "eraseSameArc", 4, "rect, startAngle, arcAngle" },
/* 0x6b */ { "invertSameArc", 4, "rect, startAngle, arcAngle" },
/* 0x6c */ { "fillSameArc", 4, "rect, startAngle, arcAngle" },
/* 0x6d */ { "reserved", 4, "reserved for Apple use" },
/* 0x6e */ { "reserved", 4, "reserved for Apple use" },
/* 0x6f */ { "reserved", 4, "reserved for Apple use" },
/* 0x70 */ { "framePoly", 0, "poly" },
/* 0x71 */ { "paintPoly", 0, "poly" },
/* 0x72 */ { "erasePoly", 0, "poly" },
/* 0x73 */ { "invertPoly", 0, "poly" },
/* 0x74 */ { "fillPoly", 0, "poly" },
/* 0x75 */ { "reserved", 0, "reserved for Apple use" },
/* 0x76 */ { "reserved", 0, "reserved for Apple use" },
/* 0x77 */ { "reserved", 0, "reserved for Apple use" },
/* 0x78 */ { "frameSamePoly", 0, "poly (NYI)" },
/* 0x79 */ { "paintSamePoly", 0, "poly (NYI)" },
/* 0x7a */ { "eraseSamePoly", 0, "poly (NYI)" },
/* 0x7b */ { "invertSamePoly", 0, "poly (NYI)" },
/* 0x7c */ { "fillSamePoly", 0, "poly (NYI)" },
/* 0x7d */ { "reserved", 0, "reserved for Apple use" },
/* 0x7e */ { "reserved", 0, "reserved for Apple use" },
/* 0x7f */ { "reserved", 0, "reserved for Apple use" },
/* 0x80 */ { "frameRgn", 0, "region" },
/* 0x81 */ { "paintRgn", 0, "region" },
/* 0x82 */ { "eraseRgn", 0, "region" },
/* 0x83 */ { "invertRgn", 0, "region" },
/* 0x84 */ { "fillRgn", 0, "region" },
/* 0x85 */ { "reserved", 0, "reserved for Apple use" },
/* 0x86 */ { "reserved", 0, "reserved for Apple use" },
/* 0x87 */ { "reserved", 0, "reserved for Apple use" },
/* 0x88 */ { "frameSameRgn", 0, "region (NYI)" },
/* 0x89 */ { "paintSameRgn", 0, "region (NYI)" },
/* 0x8a */ { "eraseSameRgn", 0, "region (NYI)" },
/* 0x8b */ { "invertSameRgn", 0, "region (NYI)" },
/* 0x8c */ { "fillSameRgn", 0, "region (NYI)" },
/* 0x8d */ { "reserved", 0, "reserved for Apple use" },
/* 0x8e */ { "reserved", 0, "reserved for Apple use" },
/* 0x8f */ { "reserved", 0, "reserved for Apple use" },
/* 0x90 */ { "BitsRect", 0, "copybits, rect clipped" },
/* 0x91 */ { "BitsRgn", 0, "copybits, rgn clipped" },
/* 0x92 */ { "reserved", -1, "reserved for Apple use" },
/* 0x93 */ { "reserved", -1, "reserved for Apple use" },
/* 0x94 */ { "reserved", -1, "reserved for Apple use" },
/* 0x95 */ { "reserved", -1, "reserved for Apple use" },
/* 0x96 */ { "reserved", -1, "reserved for Apple use" },
/* 0x97 */ { "reserved", -1, "reserved for Apple use" },
/* 0x98 */ { "PackBitsRect", 0, "packed copybits, rect clipped" },
/* 0x99 */ { "PackBitsRgn", 0, "packed copybits, rgn clipped" },
/* 0x9a */ { "DirectBitsRect", 0, "PixMap, srcRect, dstRect, mode, PixData" },
/* 0x9b */ { "DirectBitsRgn", 0, "PixMap, srcRect, dstRect, mode, maskRgn, PixData" },
/* 0x9c */ { "reserved", -1, "reserved for Apple use" },
/* 0x9d */ { "reserved", -1, "reserved for Apple use" },
/* 0x9e */ { "reserved", -1, "reserved for Apple use" },
/* 0x9f */ { "reserved", -1, "reserved for Apple use" },
/* 0xa0 */ { "ShortComment", 2, "kind (word)" },
/* 0xa1 */ { "LongComment", 0, "kind (word), size (word), data" }
};
#define BackgroundColorRGBA 255,255,255,255
#define TransparentAlpha ((unsigned char) 0)
int LocaleToLowercase(const int c)
{
if ((c == EOF) || (c != (unsigned char) c))
return(c);
return(tolower((int) ((unsigned char) c)));
}
int LocaleCompare(const char *p,const char *q)
{
if (p == (char *) NULL)
{
if (q == (char *) NULL)
return(0);
return(-1);
}
if (q == (char *) NULL)
return(1);
{
const unsigned char
*r = (const unsigned char *) p,
*s = (const unsigned char *) q;
for ( ; (*r != '\0') && (*s != '\0') && ((*r == *s) ||
(LocaleToLowercase((int) *r) == LocaleToLowercase((int) *s))); r++, s++);
return(LocaleToLowercase((int) *r)-LocaleToLowercase((int) *s));
}
}
void LocaleLower(char *string)
{
char
*q;
for (q=string; *q != '\0'; q++)
*q=(char) LocaleToLowercase((int) *q);
}
int LocaleNCompare(const char *p,const char *q,const size_t length)
{
if (p == (char *) NULL)
{
if (q == (char *) NULL)
return(0);
return(-1);
}
if (q == (char *) NULL)
return(1);
if (length == 0)
return(0);
{
const unsigned char
*s = (const unsigned char *) p,
*t = (const unsigned char *) q;
size_t
n = length;
for (n--; (*s != '\0') && (*t != '\0') && (n != 0) && ((*s == *t) ||
(LocaleToLowercase((int) *s) == LocaleToLowercase((int) *t))); s++, t++, n--);
return(LocaleToLowercase((int) *s)-LocaleToLowercase((int) *t));
}
}
char *ConstantString(const char *source)
{
char
*destination;
size_t
length;
length=0;
if (source != (char *) NULL)
length+=strlen(source);
destination=(char *) NULL;
if (~length >= 1UL)
destination=(char *) malloc(length+1UL*sizeof(*destination));
if (destination == (char *) NULL)
return NULL;
if (source != (char *) NULL)
(void) memcpy(destination,source,length*sizeof(*destination));
destination[length]='\0';
return(destination);
}
int IsStringTrue(const char *value)
{
if (value == (const char *) NULL)
return 0;
if (LocaleCompare(value,"true") == 0)
return 1;
if (LocaleCompare(value,"on") == 0)
return 1;
if (LocaleCompare(value,"yes") == 0)
return 1;
if (LocaleCompare(value,"1") == 0)
return 1;
return 0;
}
size_t CopyMagickString(char *destination,const char *source,const size_t length)
{
char
*q;
const char
*p;
size_t
n;
p=source;
q=destination;
for (n=length; n > 4; n-=4)
{
if (((*q++)=(*p++)) == '\0')
return((size_t) (p-source-1));
if (((*q++)=(*p++)) == '\0')
return((size_t) (p-source-1));
if (((*q++)=(*p++)) == '\0')
return((size_t) (p-source-1));
if (((*q++)=(*p++)) == '\0')
return((size_t) (p-source-1));
}
if (length != 0)
{
while (--n != 0)
if (((*q++)=(*p++)) == '\0')
return((size_t) (p-source-1));
*q='\0';
}
return((size_t) (p-source));
}
StringInfo *AcquireStringInfo(const size_t length)
{
StringInfo
*string_info;
string_info=(StringInfo *) malloc(sizeof(*string_info));
(void) memset(string_info,0,sizeof(*string_info));
string_info->signature=0xabacadabUL;
string_info->length=length;
if (~string_info->length >= (4096-1))
string_info->datum=(unsigned char *) malloc((string_info->length+4096)*sizeof(*string_info->datum));
if (string_info->datum == (unsigned char *) NULL)
return (StringInfo *) NULL;
(void) memset(string_info->datum,0,(length+4096)*
sizeof(*string_info->datum));
return(string_info);
}
char *CloneString(char **destination,const char *source)
{
size_t length;
if (source == (const char *) NULL)
{
if (*destination != (char *) NULL)
free(*destination);
return(NULL);
}
if (*destination == (char *) NULL)
{
*destination=(char*) malloc((strlen(source) + 4096)/* * sizeof (*destination)*/);
memcpy(*destination,source,strlen(source)/**sizeof(**destination)*/);
(*destination)[strlen(source)]='\0';
return(*destination);
}
length=strlen(source);
if (~length < 4096)
return NULL;
free(*destination);
*destination = (char*) malloc((length+4096)/**sizeof (**destination)*/);
if (*destination == (char *) NULL)
return NULL;
if (length != 0)
memcpy(*destination,source,length/**sizeof(**destination)*/);
(*destination)[length]='\0';
return(*destination);
}
StringInfo *CloneStringInfo(const StringInfo *string_info)
{
StringInfo *clone_info;
clone_info=AcquireStringInfo(string_info->length);
CloneString(&clone_info->path,string_info->path);
CloneString(&clone_info->name,string_info->name);
if (string_info->length != 0)
memcpy(clone_info->datum,string_info->datum,string_info->length+1);
return(clone_info);
}
StringInfo *DestroyStringInfo(StringInfo *string_info)
{
if (string_info->datum != (unsigned char *) NULL)
free(string_info->datum);
if (string_info->name != (char *) NULL)
free(string_info->name);
if (string_info->path != (char *) NULL)
free(string_info->path);
string_info->signature=(~0xabacadabUL);
free(string_info);
return(string_info);
}
StringInfo *BlobToStringInfo(const void *blob,const size_t length)
{
StringInfo
*string_info;
if (~length < 4096)
return (StringInfo*) NULL;
string_info=(StringInfo *) malloc(sizeof(*string_info));
(void) memset(string_info,0,sizeof(*string_info));
string_info->signature=0xabacadabUL;
if (string_info == (StringInfo*) NULL)
return (StringInfo*) NULL;
string_info->length=length;
string_info->datum=(unsigned char *) malloc(length+4096*sizeof(*string_info->datum));
if (string_info->datum == (unsigned char *) NULL)
{
string_info = DestroyStringInfo(string_info);
return((StringInfo *) NULL);
}
if (blob != (const void *) NULL)
(void) memcpy(string_info->datum,blob,length);
else
(void) memset(string_info->datum,0,length*sizeof(*string_info->datum));
(void) memset(string_info->datum+length,0,4096*sizeof(*string_info->datum));
return(string_info);
}
void DeletePixelsMemory(ImagePICT* image)
{
if (image->ppixels != NULL)
{
free(image->ppixels);
image->ppixels = NULL;
image->m_nPixelsSize = 0;
}
}
PixelChannelMap *AcquirePixelChannelMap()
{
PixelChannelMap
*channel_map;
long long
i;
channel_map=(PixelChannelMap *) malloc(65*sizeof(*channel_map));
if (channel_map == (PixelChannelMap *) NULL)
return (PixelChannelMap *) NULL;
(void) memset(channel_map,0,65*sizeof(*channel_map));
for (i=0; i <= 64; i++)
channel_map[i].channel=(PixelChannel) i;
channel_map[RedPixelChannel].offset = 0;
channel_map[GreenPixelChannel].offset = 1;
channel_map[BluePixelChannel].offset = 2;
channel_map[AlphaPixelChannel].offset = 3;
channel_map[IndexPixelChannel].offset = 5;
return(channel_map);
}
void GetPixelInfo(ImagePICT *image,PixelInfo *pixel)
{
(void) memset(pixel,0,sizeof(*pixel));
pixel->storage_class=DirectClass;
pixel->colorspace=sRGBColorspace;
pixel->depth=8;
pixel->alpha_trait=UndefinedPixelTrait;
pixel->alpha=255.0;
if (image == (const ImagePICT *) NULL)
return;
pixel->storage_class=image->storage_class;
pixel->colorspace=image->colorspace;
pixel->alpha_trait=image->alpha_trait;
pixel->depth=image->m_ndepth;
pixel->fuzz=image->fuzz;
}
void GetPixelInfoRGBA(const unsigned char red,const unsigned char green, const unsigned char blue,const unsigned char alpha,PixelInfo *pixel)
{
GetPixelInfo((ImagePICT *) NULL,pixel);
pixel->red=red;
pixel->green=green;
pixel->blue=blue;
pixel->alpha=alpha;
}
unsigned char GetPixelWriteMask(const ImagePICT *image,const unsigned char *pixel)
{
if (image->channel_map[WriteMaskPixelChannel].traits == UndefinedPixelTrait)
return((unsigned char) 255);
return(pixel[image->channel_map[WriteMaskPixelChannel].offset]);
}
int IsValidOffset(const long long x, const size_t a)
{
if (a == 0)
return 0;
if ((x >= (LLONG_MAX / 64 / (long long) a)) ||
(x <= ((-LLONG_MAX - 1) / 64 / (long long) a)))
return 0;
return 1;
}
int ReadPixels(ImagePICT* image, const long long x, const long long y, const size_t width, const size_t height, unsigned char* pixels)
{
long long
offset,
i;
size_t
extent,
length,
number_channels,
rows;
unsigned char
*q,
*p;
if (IsValidOffset(y, image->m_nWidth) == 0)
return 0;
offset = y * (long long) image->m_nWidth;
if ((offset/ (long long) image->m_nWidth) != y)
{
strcpy(image->error, "UncorrectOffset");
return 0;
}
offset += x;
number_channels = image->number_channels;
length = (size_t) number_channels * width * sizeof(unsigned char);
if ((length / number_channels / sizeof(unsigned char)) != width)
{
strcpy(image->error, "UncorrectLength");
return 0;
}
rows = height;
extent = length * rows;
if ((extent == 0) || ((extent/length) != rows))
{
strcpy(image->error, "UncorrectExtent");
return 0;
}
i = 0;
q = pixels;
/*
Read pixels from memory.
*/
if ((image->m_nWidth == width) &&
(extent == (size_t) extent))
{
length=extent;
rows=1UL;
}
p = image->ppixels + image->number_channels * offset;
for (i=0; i < (long long) rows; i++)
{
(void) memcpy(q,p,(size_t) length);
p += image->number_channels * image->m_nWidth;
q += image->number_channels * width;
}
if (i < rows)
{
strcpy(image->error, "Overflow");
return 0;
}
return 1;
}
unsigned char* GetPixels(ImagePICT* image, const long long x, const long long y, const size_t width, const size_t height)
{
unsigned char
*pixels;
pixels = image->ppixels + image->number_channels * (y * image->m_nWidth + x);
if (pixels == (unsigned char *) NULL)
return((unsigned char *) NULL);
if (ReadPixels(image, x, y, width, height, pixels) == 0)
{
return ((unsigned char *) NULL);
}
return pixels;
}
static inline float PerceptibleReciprocal(const float x)
{
float sign = x < (float) 0.0 ? (float) -1.0 : (float) 1.0;
return((sign*x) >= 1.0e-12 ? (float) 1.0/x : sign*((float) 1.0/1.0e-12));
}
unsigned char GetPixelChannel(const ImagePICT *image,const PixelChannel channel,const unsigned char *pixel)
{
if ((size_t) channel >= 64)
return((unsigned char) 0);
if (image->channel_map[channel].traits == UndefinedPixelTrait)
return((unsigned char) 0);
return(pixel[image->channel_map[channel].offset]);
}
unsigned char GetPixelAlpha(const ImagePICT *image,const unsigned char *pixel)
{
if (image->channel_map[AlphaPixelChannel].traits == UndefinedPixelTrait)
return (unsigned char) 0;
return(pixel[image->channel_map[AlphaPixelChannel].offset]);
}
void SetPixelChannel(const ImagePICT *image,const PixelChannel channel,const unsigned char Quantum,unsigned char *pixel)
{
if ((size_t) channel >= 64)
return;
if (image->channel_map[channel].traits != UndefinedPixelTrait)
pixel[image->channel_map[channel].offset]=Quantum;
}
PixelChannel GetPixelChannelChannel(const ImagePICT *image,const long long offset)
{
if ((offset < 0) || (offset >= 64))
return(UndefinedPixelChannel);
return(image->channel_map[offset].channel);
}
PixelTrait GetPixelChannelTraits(const ImagePICT *image,const PixelChannel channel)
{
if ((size_t) channel >= 64)
return(UndefinedPixelTrait);
return(image->channel_map[channel].traits);
}
static inline void SetPixelIndex(const ImagePICT *image,
const unsigned char index,unsigned char *pixel)
{
if (image->channel_map[IndexPixelChannel].traits != UndefinedPixelTrait)
pixel[image->channel_map[IndexPixelChannel].offset]=index;
}
static inline void SetPixelAlpha(const ImagePICT *image,
const unsigned char alpha,unsigned char *pixel)
{
if (image->channel_map[AlphaPixelChannel].traits != UndefinedPixelTrait)
pixel[image->channel_map[AlphaPixelChannel].offset]=alpha;
}
static inline void SetPixelRed(const ImagePICT *image,
const unsigned char red,unsigned char *pixel)
{
pixel[image->channel_map[RedPixelChannel].offset]=red;
}
static inline void SetPixelGreen(const ImagePICT *image,
const unsigned char green,unsigned char *pixel)
{
pixel[image->channel_map[GreenPixelChannel].offset]=green;
}
static inline void SetPixelBlue(const ImagePICT *image,
const unsigned char blue,unsigned char *pixel)
{
pixel[image->channel_map[BluePixelChannel].offset]=blue;
}
int AquirePixelsMemory(ImagePICT* image)
{
if ((image->m_nHeight == 0) || (image->m_nWidth == 0))
{
strcpy(image->error, "PixelSizeIsNull");
return 0;
}
image->m_nPixelsSize = image->m_nHeight * image->m_nWidth * image->number_channels;
if (image->ppixels == NULL)
image->ppixels = (unsigned char*) malloc(image->m_nPixelsSize);
else
image->ppixels = (unsigned char*) realloc(image->ppixels, image->m_nPixelsSize);
return 1;
}
int SetImageAlpha(ImagePICT* image, const unsigned char Alpha)
{
int
status,
y;
if (AquirePixelsMemory(image) == 0)
return 0;
image->alpha_trait = BlendPixelTrait;
image->channel_map[AlphaPixelChannel].traits = UpdatePixelTrait;
status = 1;
for (y = 0; y < image->m_nHeight; y++)
{
unsigned char
*q;
int
x;
if (status == 0)
continue;
q = image->ppixels + image->number_channels * (y * image->m_nWidth);
if (q == (unsigned char*) NULL)
{
status = 0;
continue;
}
for (x = 0; x < image->m_nWidth; x++)
{
if (GetPixelWriteMask(image, q) > (255 / 2))
SetPixelAlpha(image, Alpha, q);
q += image->number_channels;
}
}
return status;
}
int AquireImageColormap(ImagePICT* image, const size_t colors)
{
long long
i;
if (image == (ImagePICT*) NULL)
return 0;
if (colors > 256UL)
{
image->colors = 0;
image->storage_class = DirectClass;
strcpy(image->error, "UnableToCreateColormap");
return 0;
}
if (colors > 1)
image->colors = colors;
else
image->colors = 1;
if (image->colormap == (PixelInfo*) NULL)
image->colormap = (PixelInfo*) malloc((image->colors + 1) * sizeof(*image->colormap));
else
image->colormap = (PixelInfo*) realloc(image->colormap, (image->colors + 1) * sizeof(*image->colormap));
if (image->colormap == (PixelInfo*) NULL)
{
image->colors = 0;
image->storage_class = DirectClass;
strcpy(image->error, "MemoryAllocationFailed");
return 0;
}
for (i = 0; i < image->colors; i++)
{
double
pixel;
GetPixelInfo(image, image->colormap+i);
if (colors - 1 > 1)
pixel = ((double) i * (255 / (colors - 1)));
else
pixel = ((double) i * 255);
image->colormap[i].red = pixel;
image->colormap[i].green = pixel;
image->colormap[i].blue = pixel;
image->colormap[i].alpha = 255.0;
image->colormap[i].alpha_trait = BlendPixelTrait;
}
image->storage_class=PseudoClass;
return 1;
}
static inline int IsRGBColorspace(const ColorspaceType colorspace)
{
if ((colorspace == RGBColorspace) || (colorspace == scRGBColorspace) ||
(colorspace == LinearGRAYColorspace))
return 1;
return 0;
}
static inline int IssRGBColorspace(
const ColorspaceType colorspace)
{
if ((colorspace == sRGBColorspace) || (colorspace == TransparentColorspace))
return 1;
return 0;
}
static inline int IsGrayColorspace(
const ColorspaceType colorspace)
{
if ((colorspace == LinearGRAYColorspace) || (colorspace == GRAYColorspace))
return 1;
return 0;
}
int SetImageColorspace(ImagePICT *image, const ColorspaceType colorspace)
{
ImageType
type;
if (image->colorspace == colorspace)
return 1;
image->colorspace=colorspace;
image->gamma=1.000/2.200;
(void) memset(&image->chromaticity,0,sizeof(image->chromaticity));
type=image->type;
if (IsGrayColorspace(colorspace) != 0)
{
if (colorspace == LinearGRAYColorspace)
image->gamma=1.000;
type=GrayscaleType;
}
else
if ((IsRGBColorspace(colorspace) != 0) ||
(colorspace == XYZColorspace) || (colorspace == xyYColorspace))
image->gamma=1.000;
else
{
image->chromaticity.red_primary.x=0.6400;
image->chromaticity.red_primary.y=0.3300;
image->chromaticity.red_primary.z=0.0300;
image->chromaticity.green_primary.x=0.3000;
image->chromaticity.green_primary.y=0.6000;
image->chromaticity.green_primary.z=0.1000;
image->chromaticity.blue_primary.x=0.1500;
image->chromaticity.blue_primary.y=0.0600;
image->chromaticity.blue_primary.z=0.7900;
image->chromaticity.white_point.x=0.3127;
image->chromaticity.white_point.y=0.3290;
image->chromaticity.white_point.z=0.3583;
}
if (image->ppixels == (unsigned char*) NULL)
return 0;
image->type=type;
return 1;
}
long long CastDoubleToLong(const double x)
{
if (floor(x) > ((double) LLONG_MAX-1))
{
return((long long) LLONG_MAX);
}
if (ceil(x) < ((double) LLONG_MIN+1))
{
return((long long) LLONG_MIN);
}
return((long long) x);
}
static inline unsigned char ClampPixel(const double pixel)
{
if (pixel < 0.0)
return ((unsigned char) 0);
if (pixel >= 255.0)
return ((unsigned char) 255);
return ((unsigned char) (pixel));
}
static inline unsigned char ClampToQuantum(const double pixel)
{
if ((isnan(pixel) != 0) || (pixel <= 0.0))
return ((unsigned char) 0);
if (pixel >= 255.0)
return (unsigned char) 255;
return ((unsigned char) (pixel));
}
int Clamp(double x, double min, double max) {
if (x < min) {
return min;
} else if (x > max) {
return max;
} else {
return x;
}
}
static inline int CopyPixel(const ImagePICT *image,
const unsigned char *source,unsigned char *destination)
{
long long
i;
if (source == (const unsigned char *) NULL)
{
destination[RedPixelChannel]=(unsigned char) (Clamp(image->background_color.red, 0.0f, 255.0f) + 0.5f);
destination[GreenPixelChannel]=(unsigned char) (Clamp(image->background_color.green, 0.0f, 255.0f) + 0.5f);
destination[BluePixelChannel]=(unsigned char) (Clamp(image->background_color.blue, 0.0f, 255.0f) + 0.5f);
destination[BlackPixelChannel]=(unsigned char) (Clamp(image->background_color.black, 0.0f, 255.0f) + 0.5f);
destination[AlphaPixelChannel]=(unsigned char) (Clamp(image->background_color.alpha, 0.0f, 255.0f) + 0.5f);
return 0;
}
for (i=0; i < 4; i++)
{
PixelChannel channel = GetPixelChannelChannel(image,i);
destination[channel]=source[i];
}
return 1;
}
int GetOneVirtualPixel(ImagePICT *image,const long long x,const long long y,unsigned char *pixel)
{
const unsigned char
*p;
(void) memset(pixel,0,64*sizeof(*pixel));
p = GetPixels(image, x, y, 1UL, 1UL);
return(CopyPixel(image,p,pixel));
}
void AquireImage(ImagePICT* image)
{
image->storage_class = DirectClass;
image->colorspace = sRGBColorspace;
image->gamma=1.000/2.200;
image->chromaticity.red_primary.x=0.6400;
image->chromaticity.red_primary.y=0.3300;
image->chromaticity.red_primary.z=0.0300;
image->chromaticity.green_primary.x=0.3000;
image->chromaticity.green_primary.y=0.6000;
image->chromaticity.green_primary.z=0.1000;
image->chromaticity.blue_primary.x=0.1500;
image->chromaticity.blue_primary.y=0.0600;
image->chromaticity.blue_primary.z=0.7900;
image->chromaticity.white_point.x=0.3127;
image->chromaticity.white_point.y=0.3290;
image->chromaticity.white_point.z=0.3583;
image->m_pctVersion = 0;
image->m_nHeight = 0;
image->m_nWidth = 0;
image->m_ndepth = 8;
image->colors = 0;
image->profiles = NULL;
image->artifacts = NULL;
image->fuzz = 0.0;
image->resolutionX = 0.0;
image->resolutionY = 0.0;
image->type = UndefinedType;
GetPixelInfoRGBA(BackgroundColorRGBA, &image->background_color);
image->alpha_trait = UndefinedPixelTrait;
image->ppixels = NULL;
image->m_nPixelsSize = 0;
image->colormap = NULL;
image->channel_map = AcquirePixelChannelMap();
image->mask_trait = UndefinedPixelTrait;
image->taint = 0;
image->number_channels = 4;
}
size_t GetSize(FILE* file)
{
long long
file_discription;
struct stat
st;
file_discription = fileno(file);
if (fstat(file_discription, &st) == 0)
return st.st_size;
return(0);
}
int Read(FILE* file, const int length, void* data)
{
if (!file) return 0;
if (data == NULL) return 0;
unsigned char* q;
q = (unsigned char*) data;
return fread(q, 1, length, file);
}
int ReadByte(FILE* file)
{
return getc(file);
}
const void *ReadBlobStream(FILE* file, const size_t length, void *data, long long* count)
{
*count = Read(file, length, (unsigned char*) data);
return data;
}
unsigned short ReadShortValue(FILE* file)
{
unsigned short
value;
unsigned char
buffer[2];
const unsigned char
*p;
long long
count;
*buffer='\0';
p = (const unsigned char*) ReadBlobStream(file, 2, buffer, &count);
if (count != 2)
{
return(EOF);
}
value = (unsigned short) ((*p++) << 8);
value |= (unsigned short) (*p++);
return ((unsigned short) (value & 0xffff));
}
signed short ReadSignedShortValue(FILE* file)
{
union
{
unsigned short unsigned_value;
signed short signed_value;
} Quantum;
Quantum.unsigned_value = ReadShortValue(file);
return (Quantum.signed_value);
}
unsigned int ReadLongValue(FILE* file)
{
const unsigned char
*p;
unsigned int
value;
int
count;
unsigned char
buffer[4];
*buffer='\0';
count = Read(file, 4, buffer);
if (count != 4)
{
return(EOF);
}
p = (const unsigned char*) buffer;
value=(unsigned int) (*p++) << 24;
value|=(unsigned int) (*p++) << 16;
value|=(unsigned int) (*p++) << 8;
value|=(unsigned int) (*p++);
return value;
}
int ReadRectangle(FILE* file, PICTrectangle *frame)
{
frame->top = (short) ReadShortValue(file);
frame->left = (short) ReadShortValue(file);
frame->bottom = (short) ReadShortValue(file);
frame->right = (short) ReadShortValue(file);
if (feof(file) != 0)
{
return 0;
}
if (frame->bottom < frame->top)
{
return 0;
}
if (frame->right < frame->left)
{
return 0;
}
return 1;
}
int ReadPixmap(FILE* file,PICTPixmap *pixmap)
{
pixmap->version=(short) ReadShortValue(file);
pixmap->pack_type=(short) ReadShortValue(file);
pixmap->pack_size=ReadLongValue(file);
pixmap->horizontal_resolution=1UL*ReadShortValue(file);
(void) ReadShortValue(file);
pixmap->vertical_resolution=1UL*ReadShortValue(file);
(void) ReadShortValue(file);
pixmap->pixel_type=(short) ReadShortValue(file);
pixmap->bits_per_pixel=(short) ReadShortValue(file);
pixmap->component_count=(short) ReadShortValue(file);
pixmap->component_size=(short) ReadShortValue(file);
pixmap->plane_bytes=ReadLongValue(file);
pixmap->table=ReadLongValue(file);
pixmap->reserved=ReadLongValue(file);
if ((feof(file) != 0) || (pixmap->bits_per_pixel <= 0) ||
(pixmap->bits_per_pixel > 32) || (pixmap->component_count <= 0) ||
(pixmap->component_count > 4) || (pixmap->component_size <= 0))
return(0);
return(1);
}
SplayTreeInfo *DestroySplayTree(SplayTreeInfo *splay_tree)
{
NodeInfo
*node;
NodeInfo
*active,
*pend;
if (splay_tree->root != (NodeInfo *) NULL)
{
for (pend=splay_tree->root; pend != (NodeInfo *) NULL; )
{
active=pend;
for (pend=(NodeInfo *) NULL; active != (NodeInfo *) NULL; )
{
if (active->left != (NodeInfo *) NULL)
{
free(active->left->key);
free(active->left->value);
pend=active->left;
}
if (active->right != (NodeInfo *) NULL)
{
free(active->right->key);
free(active->right->value);
pend=active->right;
}
node=active;
active=(NodeInfo *) node->key;
free(node);
}
}
}
free(splay_tree);
return(splay_tree);
}
SplayTreeInfo *NewSplayTree(int (*compare)(const void *,const void *))
{
SplayTreeInfo
*splay_tree;
splay_tree=(SplayTreeInfo *) malloc(sizeof(*splay_tree));
(void) memset(splay_tree,0,sizeof(*splay_tree));
splay_tree->root=(NodeInfo *) NULL;
splay_tree->compare=compare;
splay_tree->balance=0;
splay_tree->key=(void *) NULL;
splay_tree->next=(void *) NULL;
splay_tree->nodes=0;
splay_tree->signature=0xabacadabUL;
return(splay_tree);
}
static inline void *GetFirstSplayTreeNode(SplayTreeInfo *splay_tree)
{
NodeInfo
*node;
node=splay_tree->root;
if (splay_tree->root == (NodeInfo *) NULL)
return((NodeInfo *) NULL);
while (node->left != (NodeInfo *) NULL)
node=node->left;
return(node->key);
}
NodeInfo *Splay(SplayTreeInfo *splay_tree,const size_t depth,const void *key,NodeInfo **node,NodeInfo **parent,NodeInfo **grandparent)
{
int
compare;
NodeInfo
**next;
NodeInfo
*n,
*p;
n=(*node);
if (n == (NodeInfo *) NULL)
{
if (parent != (NodeInfo **) NULL)
return(*parent);
else
return((NodeInfo *) NULL);
}
if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
compare=splay_tree->compare(n->key,key);
else
compare=(n->key > key) ? 1 : ((n->key < key) ? -1 : 0);
next=(NodeInfo **) NULL;
if (compare > 0)
next=(&n->left);
else
if (compare < 0)
next=(&n->right);
if (next != (NodeInfo **) NULL)
{
if (depth >= 1024)
{
splay_tree->balance=1;
return(n);
}
n=Splay(splay_tree,depth+1,key,next,node,parent);
if ((n != *node) || (splay_tree->balance != 0))
return(n);
}
if (parent == (NodeInfo **) NULL)
return(n);
if (grandparent == (NodeInfo **) NULL)
{
if (n == (*parent)->left)
{
*node=n->right;
n->right=(*parent);
}
else
{
*node=n->left;
n->left=(*parent);
}
*parent=n;
return(n);
}
if ((n == (*parent)->left) && (*parent == (*grandparent)->left))
{
p=(*parent);
(*grandparent)->left=p->right;
p->right=(*grandparent);
p->left=n->right;
n->right=p;
*grandparent=n;
return(n);
}
if ((n == (*parent)->right) && (*parent == (*grandparent)->right))
{
p=(*parent);
(*grandparent)->right=p->left;
p->left=(*grandparent);
p->right=n->left;
n->left=p;
*grandparent=n;
return(n);
}
if (n == (*parent)->left)
{
(*parent)->left=n->right;
n->right=(*parent);
(*grandparent)->right=n->left;
n->left=(*grandparent);
*grandparent=n;
return(n);
}
(*parent)->right=n->left;
n->left=(*parent);
(*grandparent)->left=n->right;
n->right=(*grandparent);
*grandparent=n;
return(n);
}
int IterateOverSplayTree(SplayTreeInfo *splay_tree,
int (*method)(NodeInfo *,const void *),const void *value)
{
typedef enum
{
LeftTransition,
RightTransition,
DownTransition,
UpTransition
} TransitionType;
int
status;
int
final_transition;
NodeInfo
**nodes;
long long
i;
NodeInfo
*node;
TransitionType
transition;
unsigned char
*transitions;
if (splay_tree->root == (NodeInfo *) NULL)
return(0);
nodes=(NodeInfo **) malloc((size_t) splay_tree->nodes*sizeof(*nodes));
transitions=(unsigned char *) malloc((size_t) splay_tree->nodes*sizeof(*transitions));
if ((nodes == (NodeInfo **) NULL) || (transitions == (unsigned char *) NULL))
return 0;
status=0;
final_transition=0;
nodes[0]=splay_tree->root;
transitions[0]=(unsigned char) LeftTransition;
for (i=0; final_transition == 0; )
{
node=nodes[i];
transition=(TransitionType) transitions[i];
switch (transition)
{
case LeftTransition:
{
transitions[i]=(unsigned char) DownTransition;
if (node->left == (NodeInfo *) NULL)
break;
i++;
nodes[i]=node->left;
transitions[i]=(unsigned char) LeftTransition;
break;
}
case RightTransition:
{
transitions[i]=(unsigned char) UpTransition;
if (node->right == (NodeInfo *) NULL)
break;
i++;
nodes[i]=node->right;
transitions[i]=(unsigned char) LeftTransition;
break;
}
case DownTransition:
default:
{
transitions[i]=(unsigned char) RightTransition;
status=(*method)(node,value);
if (status != 0)
final_transition=1;
break;
}
case UpTransition:
{
if (i == 0)
{
final_transition=1;
break;
}
i--;
break;
}
}
}
free(nodes);
free(transitions);
return(status);
}
NodeInfo *LinkSplayTreeNodes(NodeInfo **nodes,const size_t low,const size_t high)
{
NodeInfo
*node;
size_t
bisect;
bisect=low+(high-low)/2;
node=nodes[bisect];
if ((low+1) > bisect)
node->left=(NodeInfo *) NULL;
else
node->left=LinkSplayTreeNodes(nodes,low,bisect-1);
if ((bisect+1) > high)
node->right=(NodeInfo *) NULL;
else
node->right=LinkSplayTreeNodes(nodes,bisect+1,high);
return(node);
}
inline int SplayTreeToNodeArray(NodeInfo *node,const void *nodes)
{
const NodeInfo
***p;
p=(const NodeInfo ***) nodes;
*(*p)=node;
(*p)++;
return(0);
}
void BalanceSplayTree(SplayTreeInfo *splay_tree)
{
NodeInfo
**node,
**nodes;
if (splay_tree->nodes <= 2)
{
splay_tree->balance=0;
return;
}
nodes=(NodeInfo **) malloc((size_t) splay_tree->nodes*sizeof(*nodes));
if (nodes == (NodeInfo **) NULL)
return;
node=nodes;
(void) IterateOverSplayTree(splay_tree,SplayTreeToNodeArray,(const void *)
&node);
splay_tree->root=LinkSplayTreeNodes(nodes,0,splay_tree->nodes-1);
splay_tree->balance=0;
free(nodes);
}
void SplaySplayTree(SplayTreeInfo *splay_tree,const void *key)
{
if (splay_tree->root == (NodeInfo *) NULL)
return;
if (splay_tree->key != (void *) NULL)
{
int
compare;
if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
compare=splay_tree->compare(splay_tree->root->key,key);
else
compare=(splay_tree->key > key) ? 1 :
((splay_tree->key < key) ? -1 : 0);
if (compare == 0)
return;
}
(void) Splay(splay_tree,0UL,key,&splay_tree->root,(NodeInfo **) NULL,
(NodeInfo **) NULL);
if (splay_tree->balance != 0)
{
BalanceSplayTree(splay_tree);
(void) Splay(splay_tree,0UL,key,&splay_tree->root,(NodeInfo **) NULL,
(NodeInfo **) NULL);
if (splay_tree->balance != 0)
return;
}
splay_tree->key=(void *) key;
}
int AddValueToSplayTree(SplayTreeInfo *splay_tree,const void *key,const void *value)
{
int
compare;
NodeInfo
*node;
SplaySplayTree(splay_tree,key);
compare=0;
if (splay_tree->root != (NodeInfo *) NULL)
{
if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
compare=splay_tree->compare(splay_tree->root->key,key);
else
compare=(splay_tree->root->key > key) ? 1 :
((splay_tree->root->key < key) ? -1 : 0);
if (compare == 0)
{
splay_tree->root->key=(void *) key;
splay_tree->root->value=(void *) value;
return(1);
}
}
node=(NodeInfo *) malloc(sizeof(*node));
if (node == (NodeInfo *) NULL)
return(0);
node->key=(void *) key;
node->value=(void *) value;
if (splay_tree->root == (NodeInfo *) NULL)
{
node->left=(NodeInfo *) NULL;
node->right=(NodeInfo *) NULL;
}
else
if (compare < 0)
{
node->left=splay_tree->root;
node->right=node->left->right;
node->left->right=(NodeInfo *) NULL;
}
else
{
node->right=splay_tree->root;
node->left=node->right->left;
node->right->left=(NodeInfo *) NULL;
}
splay_tree->root=node;
splay_tree->key=(void *) NULL;
splay_tree->nodes++;
return(1);
}
SplayTreeInfo *CloneSplayTree(SplayTreeInfo *splay_tree, void *(*clone_key)(void *),void *(*clone_value)(void *))
{
NodeInfo
*next,
*node;
SplayTreeInfo
*clone_tree;
clone_tree=NewSplayTree(splay_tree->compare);
if (splay_tree->root == (NodeInfo *) NULL)
{
return(clone_tree);
}
next=(NodeInfo *) GetFirstSplayTreeNode(splay_tree);
while (next != (NodeInfo *) NULL)
{
SplaySplayTree(splay_tree,next);
(void) AddValueToSplayTree(clone_tree,clone_key(splay_tree->root->key),
clone_value(splay_tree->root->value));
next=(NodeInfo *) NULL;
node=splay_tree->root->right;
if (node != (NodeInfo *) NULL)
{
while (node->left != (NodeInfo *) NULL)
node=node->left;
next=(NodeInfo *) node->key;
}
}
return(clone_tree);
}
int CompareSplayTreeString(const void *target,const void *source)
{
const char
*p,
*q;
p=(const char *) target;
q=(const char *) source;
return(LocaleCompare(p,q));
}
const void *GetValueFromSplayTree(SplayTreeInfo *splay_tree, const void *key)
{
int
compare;
void
*value;
if (splay_tree->root == (NodeInfo *) NULL)
return((void *) NULL);
SplaySplayTree(splay_tree,key);
if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
compare=splay_tree->compare(splay_tree->root->key,key);
else
compare=(splay_tree->root->key > key) ? 1 :
((splay_tree->root->key < key) ? -1 : 0);
if (compare != 0)
return((void *) NULL);
value=splay_tree->root->value;
return(value);
}
const void *GetRootValueFromSplayTree(SplayTreeInfo *splay_tree)
{
const void
*value;
value=(const void *) NULL;
if (splay_tree->root != (NodeInfo *) NULL)
value=splay_tree->root->value;
return(value);
}
const unsigned char *ReadResourceShort(const unsigned char *p, unsigned short *Quantum)
{
*Quantum=(unsigned short) (*p++) << 8;
*Quantum|=(unsigned short) (*p++);
return(p);
}
const unsigned char *ReadResourceByte(const unsigned char *p, unsigned char *Quantum)
{
*Quantum=(*p++);
return(p);
}
const unsigned char *ReadResourceLong(const unsigned char *p, unsigned int *Quantum)
{
*Quantum=(unsigned int) (*p++) << 24;
*Quantum|=(unsigned int) (*p++) << 16;
*Quantum|=(unsigned int) (*p++) << 8;
*Quantum|=(unsigned int) (*p++);
return(p);
}
void WriteResourceLong(unsigned char *p,
const unsigned int Quantum)
{
unsigned char
buffer[4];
buffer[0]=(unsigned char) (Quantum >> 24);
buffer[1]=(unsigned char) (Quantum >> 16);
buffer[2]=(unsigned char) (Quantum >> 8);
buffer[3]=(unsigned char) Quantum;
(void) memcpy(p,buffer,4);
}
void WriteTo8BimProfile(ImagePICT *image,const char *name, const StringInfo *profile)
{
const unsigned char
*datum,
*q;
const unsigned char
*p;
size_t
length;
StringInfo
*profile_8bim;
long long
count;
unsigned char
length_byte;
unsigned int
value;
unsigned short
id,
profile_id;
if (LocaleCompare(name,"icc") == 0)
profile_id=0x040f;
else
if (LocaleCompare(name,"iptc") == 0)
profile_id=0x0404;
else
if (LocaleCompare(name,"xmp") == 0)
profile_id=0x0424;
else
return;
profile_8bim=(StringInfo *) GetValueFromSplayTree((SplayTreeInfo *) image->profiles,"8bim");
if (profile_8bim == (StringInfo *) NULL)
return;
datum=profile_8bim->datum;
length=profile_8bim->length;
for (p=datum; p < (datum+length-16); )
{
q=p;
if (LocaleNCompare((char *) p,"8BIM",4) != 0)
break;
p+=4;
p=ReadResourceShort(p,&id);
p=ReadResourceByte(p,&length_byte);
p+=length_byte;
if (((length_byte+1) & 0x01) != 0)
p++;
if (p > (datum+length-4))
break;
p=ReadResourceLong(p,&value);
count=(long long) value;
if ((count & 0x01) != 0)
count++;
if ((count < 0) || (p > (datum+length-count)) || (count > (long long) length))
break;
if (id != profile_id)
p+=count;
else
{
size_t
extent,
offset;
long long
extract_extent;
StringInfo
*extract_profile;
extract_extent=0;
extent=(size_t) ((datum+length)-(p+count));
if (profile == (StringInfo *) NULL)
{
offset=(size_t) (q-datum);
extract_profile=AcquireStringInfo(offset+extent);
(void) memcpy(extract_profile->datum,datum,offset);
}
else
{
offset=(size_t) (p-datum);
extract_extent=(long long) profile->length;
if ((extract_extent & 0x01) != 0)
extract_extent++;
extract_profile=AcquireStringInfo(offset+(size_t) extract_extent+
extent);
(void) memcpy(extract_profile->datum,datum,offset-4);
WriteResourceLong(extract_profile->datum+offset-4,(unsigned int)
profile->length);
(void) memcpy(extract_profile->datum+offset,
profile->datum,profile->length);
}
(void) memcpy(extract_profile->datum+offset+extract_extent,
p+count,extent);
(void) AddValueToSplayTree((SplayTreeInfo *) image->profiles, ConstantString("8bim"),CloneStringInfo(extract_profile));
extract_profile=DestroyStringInfo(extract_profile);
break;
}
}
}
int SetImageProfileInternal(ImagePICT *image,const char *name,const StringInfo *profile,const int recursive)
{
char
key[4096];
int
status;
StringInfo
*clone_profile;
clone_profile=CloneStringInfo(profile);
if (image->profiles == (SplayTreeInfo *) NULL)
image->profiles=NewSplayTree(CompareSplayTreeString);
(void) CopyMagickString(key,name,4096);
LocaleLower(key);
status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,ConstantString(key),clone_profile);
if (status != 0)
{
WriteTo8BimProfile(image,name,clone_profile);
}
return(status);
}
const char *GetImageArtifact(const ImagePICT *image,const char *artifact)
{
const char
*p;
p=(const char *) NULL;
if (image->artifacts != (void *) NULL)
{
if (artifact == (const char *) NULL)
return((const char *) GetRootValueFromSplayTree((SplayTreeInfo *)
image->artifacts));
p=(const char *) GetValueFromSplayTree((SplayTreeInfo *) image->artifacts,
artifact);
if (p != (const char *) NULL)
return(p);
}
return(p);
}
ImagePICT *DestroyImage(ImagePICT *image)
{
/*
Destroy image.
*/
free(image->ppixels);
free(image->channel_map);
delete image;
return(ImagePICT *) NULL;
}
ImagePICT* CloneImage(const ImagePICT* image, const size_t colums, const size_t rows)
{
if (image == (const ImagePICT*) NULL)
{
return((ImagePICT*) NULL);
}
ImagePICT* clone_image = new ImagePICT;
AquireImage(clone_image);
clone_image->storage_class = image->storage_class;
clone_image->fuzz = image->fuzz;
clone_image->colorspace = image->colorspace;
clone_image->chromaticity.blue_primary = image->chromaticity.blue_primary;
clone_image->chromaticity.green_primary = image->chromaticity.green_primary;
clone_image->chromaticity.red_primary = image->chromaticity.red_primary;
clone_image->chromaticity.white_point = image->chromaticity.white_point;
clone_image->gamma = image->gamma;
clone_image->m_nHeight = image->m_nHeight;
if (rows != 0)
clone_image->m_nHeight = rows;
clone_image->m_nWidth = image->m_nWidth;
if (colums != 0)
clone_image->m_nWidth = colums;
clone_image->number_channels = image->number_channels;
clone_image->m_nPixelsSize = image->m_nPixelsSize;
clone_image->ppixels = NULL;
clone_image->resolutionX = image->resolutionX;
clone_image->resolutionY = image->resolutionY;
clone_image->alpha_trait = image->alpha_trait;
clone_image->background_color.blue = image->background_color.blue;
clone_image->background_color.green = image->background_color.green;
clone_image->background_color.red = image->background_color.red;
clone_image->colors = image->colors;
if (image->colormap != NULL)
{
clone_image->colormap = (PixelInfo*) malloc((clone_image->colors + 1) * sizeof(*clone_image->colormap));
memcpy(clone_image->colormap, image->colormap, clone_image->colors * sizeof(*clone_image->colormap));
}
if (image->channel_map != NULL)
{
clone_image->channel_map = (PixelChannelMap*) malloc(65 * sizeof (image->channel_map));
memcpy(clone_image->channel_map, image->channel_map, 65 * sizeof (image->channel_map));
}
if (image->profiles != NULL)
clone_image->profiles = CloneSplayTree(image->profiles, (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
if (image->artifacts != NULL)
clone_image->artifacts = CloneSplayTree(image->artifacts, (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
clone_image->mask_trait = image->mask_trait;
clone_image->taint = image->taint;
return clone_image;
}
static inline unsigned char GetPixelReadMask(const ImagePICT *image,
const unsigned char *pixel)
{
if (image->channel_map[ReadMaskPixelChannel].traits == UndefinedPixelTrait)
return((unsigned char) 255);
return(pixel[image->channel_map[ReadMaskPixelChannel].offset]);
}
int CompositeImage(ImagePICT *image, const ImagePICT *composite, const int clip_to_self,const long long x_offset,const long long y_offset)
{
#define CompositeImageTag "Composite/Image"
const char
*value;
GeometryInfo
geometry_info;
ImagePICT
*canvas_image,
*source_image;
int
clamp,
compose_sync,
status;
long long
progress;
double
amount,
canvas_dissolve,
midpoint,
percent_luma,
percent_chroma,
source_dissolve,
threshold;
long long
y;
image->storage_class = DirectClass;
if (image->ppixels == (unsigned char*) NULL)
return 0;
source_image=CloneImage(composite,0,0);
if (!AquirePixelsMemory(source_image))
return 0;
(void) memcpy(source_image->ppixels, composite->ppixels, source_image->m_nPixelsSize);
if (source_image == (const ImagePICT *) NULL)
return 0;
(void) SetImageColorspace(source_image,image->colorspace);
amount = 0.5;
canvas_image = (ImagePICT *) NULL;
canvas_dissolve = 1.0;
clamp = 1;
value = GetImageArtifact(image,"compose:clamp");
if (value != (const char *) NULL)
clamp=IsStringTrue(value);
compose_sync = 1;
value = GetImageArtifact(image,"compose:sync");
if (value != (const char *) NULL)
compose_sync = IsStringTrue(value);
(void) memset(&geometry_info,0,sizeof(geometry_info));
percent_luma=100.0;
percent_chroma=100.0;
source_dissolve=1.0;
threshold=0.05f;
image->channel_map[RedPixelChannel].traits = UpdatePixelTrait;
image->channel_map[GreenPixelChannel].traits = UpdatePixelTrait;
image->channel_map[BluePixelChannel].traits = UpdatePixelTrait;
image->channel_map[AlphaPixelChannel].traits = UpdatePixelTrait;
source_image->channel_map[RedPixelChannel].traits = CopyPixelTrait;
source_image->channel_map[GreenPixelChannel].traits = CopyPixelTrait;
source_image->channel_map[BluePixelChannel].traits = CopyPixelTrait;
source_image->channel_map[AlphaPixelChannel].traits = CopyPixelTrait;
if (!((x_offset < 0) || (y_offset < 0)) && !((x_offset+(long long) source_image->m_nWidth) > (long long) image->m_nWidth) && !((y_offset+(long long) source_image->m_nHeight) > (long long) image->m_nHeight))
{
if ((source_image->alpha_trait == UndefinedPixelTrait) &&
(image->alpha_trait != UndefinedPixelTrait))
(void) SetImageAlpha(source_image, (const unsigned char) 255);
status = 1;
for (y=0; y < (long long) source_image->m_nHeight; y++)
{
const unsigned char
*p;
unsigned char
*q;
long long
x;
if (status == 0)
continue;
p=GetPixels(source_image,0,y,source_image->m_nWidth,1);
q=GetPixels(image,x_offset,y+y_offset, source_image->m_nWidth,1);
if ((p == (const unsigned char *) NULL) || (q == (unsigned char *) NULL))
{
status=0;
continue;
}
for (x=0; x < (long long) source_image->m_nWidth; x++)
{
long long
i;
if (GetPixelReadMask(source_image, p) <= (255/2))
{
p+=source_image->number_channels;
q+=image->number_channels;
continue;
}
for (i=0; i < source_image->number_channels; i++)
{
PixelChannel channel = GetPixelChannelChannel(source_image,i);
PixelTrait source_traits = GetPixelChannelTraits(source_image,
channel);
PixelTrait traits = GetPixelChannelTraits(image,channel);
if ((source_traits == UndefinedPixelTrait) ||
(traits == UndefinedPixelTrait))
continue;
SetPixelChannel(image,channel,p[i],q);
}
p+=source_image->number_channels;
q+=image->number_channels;
}
}
source_image=DestroyImage(source_image);
return(status);
}
/*
Composite image.
*/
status=1;
progress=0;
midpoint=128.0;
for (y=0; y < (long long) image->m_nHeight; y++)
{
const unsigned char
*pixels;
PixelInfo
canvas_pixel,
source_pixel;
const unsigned char
*p;
unsigned char
*q;
long long
x;
if (status == 0)
continue;
if (clip_to_self != 0)
{
if (y < y_offset)
continue;
if ((y-(double) y_offset) >= (double) source_image->m_nHeight)
continue;
}
/*
If pixels is NULL, y is outside overlay region.
*/
pixels=(unsigned char *) NULL;
p=(unsigned char *) NULL;
if ((y >= y_offset) &&
((y-(double) y_offset) < (double) source_image->m_nHeight))
{
p=GetPixels(source_image,0,y-y_offset,source_image->m_nWidth,1);
if (p == (const unsigned char *) NULL)
{
status=0;
continue;
}
pixels=p;
if (x_offset < 0)
p-=x_offset*source_image->number_channels;
}
q=GetPixels(image,0,y,image->m_nWidth,1);
if (q == (unsigned char *) NULL)
{
status=0;
continue;
}
GetPixelInfo(image,&canvas_pixel);
GetPixelInfo(source_image,&source_pixel);
for (x=0; x < (long long) image->m_nWidth; x++)
{
double
gamma = 0.0;
double
alpha = 0.0,
Da = 0.0,
Dc = 0.0,
Dca = 0.0,
DcaDa = 0.0,
Sa = 0.0,
SaSca = 0.0,
Sc = 0.0,
Sca = 0.0;
size_t
channels;
long long
i;
if (clip_to_self != 0)
{
if (x < x_offset)
{
q+=image->number_channels;
continue;
}
if ((x-(double) x_offset) >= (double) source_image->m_nWidth)
break;
}
if ((pixels == (unsigned char *) NULL) || (x < x_offset) ||
((x-(double) x_offset) >= (double) source_image->m_nWidth))
{
unsigned char
source[64];
/*
Virtual composite:
Sc: source color.
Dc: canvas color.
*/
for (i=0; i < image->number_channels; i++)
{
double
pixel = 0;
PixelChannel channel = GetPixelChannelChannel(image,i);
PixelTrait traits = GetPixelChannelTraits(image,channel);
PixelTrait source_traits = GetPixelChannelTraits(source_image,
channel);
if ((traits == UndefinedPixelTrait) ||
(source_traits == UndefinedPixelTrait))
continue;
//////////////////////////////////////////////////////////////////////////
if (channel == AlphaPixelChannel)
pixel = TransparentAlpha;
else
pixel=0;
/////////////////////////////////////////////////////////////////////////
q[i]=clamp != 0 ? ClampPixel(pixel) :
ClampToQuantum(pixel);
}
q+=image->number_channels;
continue;
}
/*
Authentic composite:
Sa: normalized source alpha.
Da: normalized canvas alpha.
*/
Sa = (1.0/255.0)* GetPixelAlpha(source_image,p);
Sa = Sa == 0 ? 1 : Sa;
Da = (1.0/255.0)* GetPixelAlpha(image,q);
///////////////////////////////////////////////////////////////////////
alpha = 1.0;
//////////////////////////////////////////////////////////////////////
for (i=0; i < image->number_channels; i++)
{
double
pixel = 0.0;
PixelChannel channel = GetPixelChannelChannel(image,i);
PixelTrait traits = GetPixelChannelTraits(image,channel);
PixelTrait source_traits = GetPixelChannelTraits(source_image,channel);
if (traits == UndefinedPixelTrait)
continue;
if ((channel == AlphaPixelChannel) &&
((traits & UpdatePixelTrait) != 0))
{
/*
Set alpha channel.
*/
/////////////////////////////////////////////////////////////////////
pixel=255.0*Sa;
////////////////////////////////////////////////////////////////////
q[i]=clamp != 0 ? ClampPixel(pixel) :
ClampToQuantum(pixel);
continue;
}
if (source_traits == UndefinedPixelTrait)
continue;
/*
Sc: source color.
Dc: canvas color.
*/
Sc= GetPixelChannel(source_image,channel,p);
Dc=q[i];
if ((traits & CopyPixelTrait) != 0)
{
/*
Copy channel.
*/
q[i]=ClampToQuantum(Dc);
continue;
}
/*
Porter-Duff compositions:
Sca: source normalized color multiplied by alpha.
Dca: normalized canvas color multiplied by alpha.
*/
Sca=(1.0/255.0)*Sa*Sc;
Dca=(1.0/255.0)*Da*Dc;
SaSca=Sa*PerceptibleReciprocal(Sca);
DcaDa=Dca*PerceptibleReciprocal(Da);
/////////////////////////////////////////////////////////////////////
gamma=PerceptibleReciprocal(alpha);
////////////////////////////////////////////////////////////////////
pixel=Dc;
///////////////////////////////////////////////////////////////////
pixel=255.0*Sca;
//////////////////////////////////////////////////////////////////
q[i]=clamp != 0 ? ClampPixel(pixel) :
ClampToQuantum(pixel);
}
p+=source_image->number_channels;
channels=source_image->number_channels;
if (p >= (pixels+channels*source_image->m_nWidth))
p=pixels;
q+=image->number_channels;
}
}
if (canvas_image != (ImagePICT * ) NULL)
canvas_image=DestroyImage(canvas_image);
else
source_image=DestroyImage(source_image);
return(status);
}
int DecodeHeader(FILE* hFile, ImagePICT* image)
{
unsigned char
header[4];
unsigned char
skip[1];
int
c;
PICTrectangle
frame;
Read(hFile, 4, header);
if (!((header[0] == 0x50) && (header[1] == 0x49) &&
(header[2] == 0x43) && (header[3] == 0x54 )))
{
frame.top =(short) ((header[2] << 8) | header[3]);
frame.left = (short) ReadShortValue(hFile);
frame.bottom = (short) ReadShortValue(hFile);
frame.right = (short) ReadShortValue(hFile);
Read(hFile, 1, skip);
c = ReadByte(hFile);
if (c != 0x11)
{
fseek(hFile, 512, 0);
(void) ReadShortValue(hFile);
if (ReadRectangle(hFile, &frame) == 0)
{
strcpy(image->error, "ImproperImageHeader");
return 0;
}
Read(hFile, 1, skip);
c = ReadByte(hFile);
if (c == 0x11)
{
long long version = ReadByte(hFile);
if (version == 2)
{
long long version2 = ReadByte(hFile);
if (version2 != 0xff)
return 0;
image->m_pctVersion = 2;
if ((frame.left < 0) || (frame.right < 0) || (frame.top < 0) ||
(frame.bottom < 0) || (frame.left >= frame.right) ||
(frame.top >= frame.bottom))
{
strcpy(image->error, "ImproperImageHeader");
return 0;
}
image->m_nWidth=(size_t) (frame.right-frame.left);
image->m_nHeight=(size_t) (frame.bottom-frame.top);
return 1;
}
else if (version == 1)
{
image->m_pctVersion = 1;
if ((frame.left < 0) || (frame.right < 0) || (frame.top < 0) ||
(frame.bottom < 0) || (frame.left >= frame.right) ||
(frame.top >= frame.bottom))
{
strcpy(image->error, "ImproperImageHeader");
return 0;
}
image->m_nWidth=(size_t) (frame.right-frame.left);
image->m_nHeight=(size_t) (frame.bottom-frame.top);
return 1;
}
else
{
strcpy(image->error, "ImproperImageHeader");
return 0;
}
}
else
{
strcpy(image->error, "ImproperImageHeader");
return 0;
}
}
}
long long version = ReadByte(hFile);
if (version == 2)
{
long long version2 = ReadByte(hFile);
if (version2 != 0xff)
return 0;
image->m_pctVersion = 2;
if ((frame.left < 0) || (frame.right < 0) || (frame.top < 0) ||
(frame.bottom < 0) || (frame.left >= frame.right) ||
(frame.top >= frame.bottom))
{
strcpy(image->error, "ImproperImageHeader");
return 0;
}
image->m_nWidth = (size_t) (frame.right - frame.left);
image->m_nHeight=(size_t) (frame.bottom-frame.top);
}
else
{
image->m_pctVersion = 1;
image->m_nWidth = (size_t) (frame.right - frame.left);
image->m_nHeight=(size_t) (frame.bottom-frame.top);
}
return 1;
}
static const unsigned char *UnpackScanline(
const unsigned char *pixels,const unsigned int bits_per_pixel,
unsigned char* scanline,size_t *bytes_per_line)
{
const unsigned char
*p;
long long
i;
unsigned char
*q;
p=pixels;
q=scanline;
switch (bits_per_pixel)
{
case 8:
case 16:
case 32:
return(pixels);
case 4:
{
for (i=0; i < (long long) *bytes_per_line; i++)
{
*q++=(*p >> 4) & 0xff;
*q++=(*p & 15);
p++;
}
*bytes_per_line*=2;
break;
}
case 2:
{
for (i=0; i < (long long) *bytes_per_line; i++)
{
*q++=(*p >> 6) & 0x03;
*q++=(*p >> 4) & 0x03;
*q++=(*p >> 2) & 0x03;
*q++=(*p & 3);
p++;
}
*bytes_per_line*=4;
break;
}
case 1:
{
for (i=0; i < (long long) *bytes_per_line; i++)
{
*q++=(*p >> 7) & 0x01;
*q++=(*p >> 6) & 0x01;
*q++=(*p >> 5) & 0x01;
*q++=(*p >> 4) & 0x01;
*q++=(*p >> 3) & 0x01;
*q++=(*p >> 2) & 0x01;
*q++=(*p >> 1) & 0x01;
*q++=(*p & 0x01);
p++;
}
*bytes_per_line*=8;
break;
}
default:
break;
}
return(scanline);
}
static unsigned char *DecodeImage(FILE *blob,ImagePICT *image,
size_t bytes_per_line,const unsigned int bits_per_pixel,size_t *extent)
{
int
status;
size_t
number_pixels;
const unsigned char
*p;
long long
i;
unsigned char
*q;
size_t
bytes_per_pixel,
length,
row_bytes,
scanline_length,
width;
long long
count,
j,
y;
unsigned char
*pixels,
*scanline,
unpack_buffer[8*256];
/*
Determine pixel buffer size.
*/
if (bits_per_pixel <= 8)
bytes_per_line&=0x7fff;
width=image->m_nWidth;
bytes_per_pixel=1;
if (bits_per_pixel == 16)
{
bytes_per_pixel=2;
width*=2;
}
else
if (bits_per_pixel == 32)
width*=image->alpha_trait ? 4 : 3;
if (bytes_per_line == 0)
bytes_per_line=width;
row_bytes=(size_t) (image->m_nWidth | 0x8000);
if (image->storage_class == DirectClass)
row_bytes=(size_t) ((4*image->m_nWidth) | 0x8000);
/*
Allocate pixel and scanline buffer.
*/
pixels=(unsigned char *) malloc(image->m_nHeight*row_bytes*
sizeof(*pixels));
if (pixels == (unsigned char *) NULL)
return((unsigned char *) NULL);
*extent=row_bytes*image->m_nHeight*sizeof(*pixels);
(void) memset(pixels,0,*extent);
scanline=(unsigned char *) malloc(row_bytes*2*
sizeof(*scanline));
if (scanline == (unsigned char *) NULL)
{
free(pixels);
return((unsigned char *) NULL);
}
(void) memset(scanline,0,2*row_bytes*sizeof(*scanline));
(void) memset(unpack_buffer,0,sizeof(unpack_buffer));
status=1;
if (bytes_per_line < 8)
{
/*
Pixels are already uncompressed.
*/
for (y=0; y < (long long) image->m_nHeight; y++)
{
q=pixels+y*(long long) width*image->number_channels;
number_pixels=bytes_per_line;
count=Read(blob,(size_t) number_pixels,scanline);
if (count != (long long) number_pixels)
{
status=0;
break;
}
p=UnpackScanline(scanline,bits_per_pixel,unpack_buffer,&number_pixels);
if ((q+number_pixels) > (pixels+(*extent)))
{
status=0;
break;
}
(void) memcpy(q,p,(size_t) number_pixels);
}
free(scanline);
if (status == 0)
free(pixels);
return(pixels);
}
/*
Uncompress RLE pixels into uncompressed pixel buffer.
*/
for (y=0; y < (long long) image->m_nHeight; y++)
{
q=pixels+y*(long long) width;
if (bytes_per_line > 250)
scanline_length=ReadShortValue(blob);
else
scanline_length=(size_t) ReadByte(blob);
if ((scanline_length >= row_bytes) || (scanline_length == 0))
{
status=0;
break;
}
count=Read(blob,scanline_length,scanline);
if (count != (long long) scanline_length)
{
status=0;
break;
}
for (j=0; j < (long long) scanline_length; )
if ((scanline[j] & 0x80) == 0)
{
length=(size_t) ((scanline[j] & 0xff)+1);
number_pixels=length*bytes_per_pixel;
p=UnpackScanline(scanline+j+1,bits_per_pixel,unpack_buffer,
&number_pixels);
if ((size_t) (q-pixels+(long long) number_pixels) <= *extent)
(void) memcpy(q,p,(size_t) number_pixels);
q+=number_pixels;
j+=(long long) (length*bytes_per_pixel+1);
}
else
{
length=(size_t) (((scanline[j] ^ 0xff) & 0xff)+2);
number_pixels=bytes_per_pixel;
p=UnpackScanline(scanline+j+1,bits_per_pixel,unpack_buffer,
&number_pixels);
for (i=0; i < (long long) length; i++)
{
if ((size_t) (q-pixels+(long long) number_pixels) <= *extent)
(void) memcpy(q,p,(size_t) number_pixels);
q+=number_pixels;
}
j+=(long long) bytes_per_pixel+1;
}
}
free(scanline);
if (status == 0)
{
free(pixels);
pixels = NULL;
}
return(pixels);
}
int DecodePICT(FILE* hFile, ImagePICT* image)
{
long long
flags,
i,
j,
count,
x,
y;
int
jpeg,
code,
status;
size_t
extent,
length;
unsigned char
index;
unsigned char
*q;
PICTrectangle
frame;
PICTPixmap
pixmap;
ImagePICT*
tile_image;
StringInfo
*profile;
if (hFile == NULL)
{
strcpy(image->error, "FileError");
return 0;
}
pixmap.bits_per_pixel=0;
pixmap.component_count=0;
if (!DecodeHeader(hFile, image))
{
return 0;
}
if (feof(hFile) != 0)
{
strcpy(image->error, "EOFfile");
return 0;
}
flags = 0;
image->m_ndepth = 8;
image->resolutionX = 72.0;
image->resolutionY = 72.0;
if (!AquirePixelsMemory(image))
{
return 0;
}
jpeg = 0;
for (code = 0; feof(hFile) == 0; )
{
if ((image->m_pctVersion == 1) || ((ftell(hFile) % 2) != 0))
code = ReadByte(hFile);
if (image->m_pctVersion == 2)
code = ReadSignedShortValue(hFile);
code &= 0xffff;
if (code < 0)
break;
if (code == 0)
continue;
if (code <= 0xa1)
{
switch(code)
{
case 0x01:
{
/*
Clipping rectangle.
*/
length = ReadShortValue(hFile);
if (length > GetSize(hFile))
{
strcpy(image->error, "InsufficientImageDataInFile");
return 0;
}
if (length != 0x000a)
{
for (i = 0; i < length - 2; i++)
if (ReadByte(hFile) == EOF)
break;
break;
}
if (ReadRectangle(hFile, &frame) == 0)
return 0;
if (((frame.left & 0x8000) != 0) || ((frame.top & 0x8000) != 0))
break;
image->m_nHeight = (size_t) (frame.bottom - frame.top);
image->m_nWidth = (size_t) (frame.right - frame.left);
if (!AquirePixelsMemory(image))
{
return 0;
}
break;
}
case 0x12:
case 0x13:
case 0x14:
{
int
pattern;
size_t
height,
width;
/*
Skip pattern definition.
*/
pattern = (int) ReadShortValue(hFile);
for (i = 0; i < 8; i++)
if (ReadByte(hFile) == EOF)
break;
if (pattern == 2)
{
for (i=0; i < 5; i++)
if (ReadByte(hFile) == EOF)
break;
break;
}
if (pattern != 1)
{
DeletePixelsMemory(image);
strcpy(image->error, "UnknownPatternType");
return 0;
}
length = ReadShortValue(hFile);
if (length > GetSize(hFile))
{
DeletePixelsMemory(image);
strcpy(image->error, "InsufficientImageDataInFile");
return 0;
}
if (ReadRectangle(hFile, &frame) == 0)
{
DeletePixelsMemory(image);
strcpy(image->error, "ImproperImageHeader");
return 0;
}
if (ReadPixmap(hFile, &pixmap) == 0)
{
DeletePixelsMemory(image);
strcpy(image->error, "ImproperImageHeader");
return 0;
}
image->m_ndepth = (size_t) pixmap.component_size;
image->resolutionX = 1.0 * pixmap.horizontal_resolution;
image->resolutionY = 1.0 * pixmap.vertical_resolution;
(void) ReadLongValue(hFile);
flags=(long long) ReadShortValue(hFile);
length=ReadShortValue(hFile);
if (length > GetSize(hFile))
{
DeletePixelsMemory(image);
strcpy(image->error, "InsufficientImageDataInFile");
return 0;
}
for (i = 0; i < length; i++)
(void) ReadLongValue(hFile);
width=(size_t) (frame.bottom-frame.top);
height=(size_t) (frame.right-frame.left);
if (pixmap.bits_per_pixel <= 8)
length &= 0x7fff;
if (pixmap.bits_per_pixel == 16)
width <<= 1;
if (length == 0)
length = width;
if (length < 8)
{
for (i = 0; i < (length*height); i++)
if (ReadByte(hFile) == EOF)
break;
}
else
for (i = 0; i < height; i++)
{
size_t
scanline_length;
if (feof(hFile) != 0)
break;
if (length > 200)
scanline_length=ReadShortValue(hFile);
else
scanline_length=(size_t) ReadByte(hFile);
if (scanline_length > GetSize(hFile))
{
DeletePixelsMemory(image);
strcpy(image->error, "InsufficientImageDataInFile");
return 0;
}
for (j=0; j < scanline_length; j++)
if (ReadByte(hFile) == EOF)
break;
}
break;
}
case 0x1b:
{
/*
Initialize image background color.
*/
image->background_color.red = 257.0 * ReadShortValue(hFile);
image->background_color.green = 257.0 * ReadShortValue(hFile);
image->background_color.blue = 257.0 * ReadShortValue(hFile);
break;
}
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76:
case 0x77:
{
/*
Skip polygon or region.
*/
length = ReadShortValue(hFile);
if (length > GetSize(hFile))
{
DeletePixelsMemory(image);
strcpy(image->error, "InsufficientImageDataInFile");
return 0;
}
for (i=0; i < (length-2); i++)
if (ReadByte(hFile) == EOF)
break;
break;
}
case 0x90:
case 0x91:
case 0x98:
case 0x99:
case 0x9a:
case 0x9b:
{
PICTrectangle
source,
destination;
unsigned char
*p;
size_t
k;
long long
bytes_per_line;
unsigned char
*pixels;
/*
Pixmap clipped by a rectangle.
*/
bytes_per_line = 0;
if ((code != 0x9a) && (code != 0x9b))
bytes_per_line= (long long) ReadShortValue(hFile);
else
{
(void) ReadShortValue(hFile);
(void) ReadShortValue(hFile);
(void) ReadShortValue(hFile);
}
if (ReadRectangle(hFile, &frame) == 0)
{
DeletePixelsMemory(image);
strcpy(image->error, "ImproperImageHeader");
return 0;
}
/*
Initialize tile image.
*/
tile_image = CloneImage(image, (size_t) (frame.right-frame.left), (size_t) (frame.bottom-frame.top));
if (tile_image == (ImagePICT*) NULL)
{
DeletePixelsMemory(image);
strcpy(image->error, "ImproperImageHeader");
return 0;
}
if (!AquirePixelsMemory(tile_image))
{
DeletePixelsMemory(image);
return 0;
}
if ((code == 0x9a) || (code == 0x9b) ||
((bytes_per_line & 0x8000) != 0))
{
if (ReadPixmap(hFile, &pixmap) == 0)
{
DeletePixelsMemory(image);
DeletePixelsMemory(tile_image);
strcpy(image->error, "ImproperImageHeader");
return 0;
}
tile_image->m_ndepth=(size_t) pixmap.component_size;
tile_image->alpha_trait=pixmap.component_count == 4 ?
BlendPixelTrait : UndefinedPixelTrait;
tile_image->resolutionX=(double) pixmap.horizontal_resolution;
tile_image->resolutionY=(double) pixmap.vertical_resolution;
if (tile_image->alpha_trait != UndefinedPixelTrait)
(void) SetImageAlpha(tile_image, 255);
}
if ((code != 0x9a) && (code != 0x9b))
{
/*
Initialize colormap.
*/
tile_image->colors = 2;
if ((bytes_per_line & 0x8000) != 0)
{
(void) ReadLongValue(hFile);
flags = (long long) ReadShortValue(hFile);
tile_image->colors = 1UL * ReadShortValue(hFile) + 1;
}
status = AquireImageColormap(tile_image, tile_image->colors);
if (status == 0)
{
DeletePixelsMemory(image);
DeletePixelsMemory(tile_image);
return 0;
}
if ((bytes_per_line & 0x8000) != 0)
{
for (i = 0; i < tile_image->colors; i++)
{
k = ReadShortValue(hFile) % tile_image->colors;
if ((flags & 0x8000) != 0)
k = (size_t) i;
tile_image->colormap[k].red = (unsigned char) ReadShortValue(hFile)/* + 128U / 257U*/;
tile_image->colormap[k].green = (unsigned char) ReadShortValue(hFile)/* + 128U / 257U*/;
tile_image->colormap[k].blue = (unsigned char) ReadShortValue(hFile)/* + 128U / 257U*/;
}
}
else
{
for (i=0; i < (long long) tile_image->colors; i++)
{
tile_image->colormap[i].red=((double) 255 - tile_image->colormap[i].blue);
tile_image->colormap[i].green=((double) 255 - tile_image->colormap[i].green);
tile_image->colormap[i].blue=((double) 255 - tile_image->colormap[i].red);
}
}
}
if (feof(hFile) != 0)
{
DeletePixelsMemory(image);
DeletePixelsMemory(tile_image);
strcpy(image->error, "EOFfile");
return 0;
}
if (ReadRectangle(hFile, &source) == 0)
{
DeletePixelsMemory(image);
DeletePixelsMemory(tile_image);
strcpy(image->error, "ImproperImageHeader");
return 0;
}
if (ReadRectangle(hFile, &destination) == 0)
{
DeletePixelsMemory(image);
DeletePixelsMemory(tile_image);
strcpy(image->error, "ImproperImageHeader");
return 0;
}
(void) ReadShortValue(hFile);
if ((code == 0x91) || (code == 0x99) || (code == 0x9b))
{
/*
Skip region.
*/
length = ReadShortValue(hFile);
if ((size_t) length > GetSize(hFile))
{
DeletePixelsMemory(image);
DeletePixelsMemory(tile_image);
strcpy(image->error, "InsufficientImageDataInFile");
return 0;
}
for (i = 0; i < length - 2; i++)
if (ReadByte(hFile) == EOF)
break;
}
if ((code != 0x9a) && (code != 0x9b) && (bytes_per_line & 0x8000) == 0)
pixels = DecodeImage(hFile, tile_image, (size_t) bytes_per_line, 1, &extent);
else
pixels = DecodeImage(hFile, tile_image, (size_t) bytes_per_line, (unsigned int) pixmap.bits_per_pixel, &extent);
if (pixels == (unsigned char*) NULL)
{
DeletePixelsMemory(image);
DeletePixelsMemory(tile_image);
strcpy(image->error, "UnableToUncompressImage");
return 0;
}
/*
Convert PICT tile image to pixel packets.
*/
p = pixels;
for (y=0; y < (long long) tile_image->m_nHeight; y++)
{
if (p > (pixels+extent+image->m_nWidth))
{
free(pixels);
DeletePixelsMemory(image);
DeletePixelsMemory(tile_image);
strcpy(image->error, "NotEnoughPixelData");
return 0;
}
q = tile_image->ppixels + tile_image->number_channels * (y * tile_image->m_nWidth);
if (q == (unsigned char *) NULL)
break;
for (x=0; x < tile_image->m_nWidth; x++)
{
if (tile_image->storage_class == PseudoClass)
{
if (((long long) *p < 0) || ((long long) *p >= (long long) tile_image->colors))
index=0;
else
index=(long long) *p;
SetPixelIndex(tile_image,index,q);
SetPixelRed(tile_image,
tile_image->colormap[(long long) index].red,q);
SetPixelGreen(tile_image,
tile_image->colormap[(long long) index].green,q);
SetPixelBlue(tile_image,
tile_image->colormap[(long long) index].blue,q);
}
else
{
if (pixmap.bits_per_pixel == 16)
{
i=(long long) (*p++);
k=(size_t) (*p);
SetPixelRed(tile_image,(unsigned char) ((i & 0x7c) << 1),q);
SetPixelGreen(tile_image,(unsigned char) ((size_t) ((i & 0x03) << 6) |((k & 0xe0) >> 2)),q);
SetPixelBlue(tile_image,(unsigned char) ((k & 0x1f) << 3),q);
}
else
if (tile_image->alpha_trait == UndefinedPixelTrait)
{
if (p > (pixels+extent+2*image->m_nWidth))
{
free(pixels);
DeletePixelsMemory(image);
DeletePixelsMemory(tile_image);
strcpy(image->error, "NotEnoughPixelData");
return 0;
}
SetPixelRed(tile_image,*p,q);
SetPixelGreen(tile_image,*(p+tile_image->m_nWidth),q);
SetPixelBlue(tile_image,*(p+2*tile_image->m_nWidth),q);
}
else
{
if (p > (pixels+extent+3*image->m_nWidth))
{
free(pixels);
DeletePixelsMemory(image);
DeletePixelsMemory(tile_image);
strcpy(image->error, "NotEnoughPixelData");
return 0;
}
SetPixelAlpha(tile_image,*p,q);
SetPixelRed(tile_image,*(p+1*tile_image->m_nWidth),q);
SetPixelGreen(tile_image,*(p+2*tile_image->m_nWidth),q);
SetPixelBlue(tile_image,*(p+3*tile_image->m_nWidth),q);
}
}
p++;
q+=tile_image->number_channels;
}
if ((tile_image->storage_class == DirectClass) &&
(pixmap.bits_per_pixel != 16))
{
p+=(pixmap.component_count-1)*(long long) tile_image->m_nWidth;
if (p < pixels)
break;
}
}
if (tile_image->storage_class == PseudoClass)
(void) SetImageAlpha(tile_image, 255);
else if (pixmap.bits_per_pixel == 16)
(void) SetImageAlpha(tile_image, 255);
else if (tile_image->alpha_trait == UndefinedPixelTrait)
(void) SetImageAlpha(tile_image, 255);
free(pixels);
if ((jpeg == 0) && (feof(hFile) == 0))
if ((code == 0x9a) || (code == 0x9b) ||
((bytes_per_line & 0x8000) != 0))
(void) CompositeImage(image,tile_image,1,(long long) destination.left,(long long)destination.top);
tile_image=DestroyImage(tile_image);
break;
}
case 0xa1:
{
unsigned char
*info;
size_t
type;
/*
Comment.
*/
type = ReadShortValue(hFile);
length = ReadShortValue(hFile);
if ((size_t) length > GetSize(hFile))
{
DeletePixelsMemory(image);
strcpy(image->error, "InsufficientImageDataInFile");
return 0;
}
if (length == 0)
break;
info = (unsigned char*) malloc(length * sizeof (*info));
if (info == (unsigned char*) NULL)
break;
count = Read(hFile, length, info);
if (count != length)
{
free(info);
DeletePixelsMemory(image);
strcpy(image->error, "UnableToReadImageData");
return 0;
}
switch (type)
{
case 0xe0:
{
profile = BlobToStringInfo((const void *) NULL, length);
if (profile->length != 0)
(void) memcpy(profile->datum,info,profile->length);
status = SetImageProfileInternal(image, "icc", profile, 0);
profile = DestroyStringInfo(profile);
if (status == 0)
{
free(info);
DeletePixelsMemory(image);
strcpy(image->error, "MemoryAllocationFailed");
return 0;
}
break;
}
case 0x1f2:
{
profile=BlobToStringInfo((const void *) NULL,length);
if (profile->length != 0)
(void) memcpy(profile->datum,info,profile->length);
status=SetImageProfileInternal(image,"iptc",profile,0);
if (status == 0)
{
free(info);
DeletePixelsMemory(image);
strcpy(image->error, "MemoryAllocationFailed");
return 0;
}
profile=DestroyStringInfo(profile);
break;
}
default:
break;
}
free(info);
break;
}
default:
/*
Skip to next op code.
*/
if (codes[code].length == -1)
(void) ReadShortValue(hFile);
else
for (i=0; i < (long long) codes[code].length; i++)
if (ReadByte(hFile) == EOF)
break;
}
}
if (code == 0xc00)
{
/*
Skip header.
*/
for (i=0; i < 24; i++)
if (ReadByte(hFile) == EOF)
break;
continue;
}
if (((code >= 0xb0) && (code <= 0xcf)) ||
((code >= 0x8000) && (code <= 0x80ff)))
continue;
if ((code == 0xff) || (code == 0xffff))
continue;
if (((code >= 0xd0) && (code <= 0xfe)) ||
((code >= 0x8100) && (code <= 0xffff)))
{
/*
Skip reserved.
*/
length=ReadShortValue(hFile);
if (length > GetSize(hFile))
{
DeletePixelsMemory(image);
strcpy(image->error, "ImproperImageHeader");
return 0;
}
for (i=0; i < (long long) length; i++)
if (ReadByte(hFile) == EOF)
break;
continue;
}
if ((code >= 0x100) && (code <= 0x7fff))
{
/*
Skip reserved.
*/
length=(size_t) ((code >> 7) & 0xff);
if (length > GetSize(hFile))
{
DeletePixelsMemory(image);
strcpy(image->error, "ImproperImageHeader");
return 0;
}
for (i=0; i < (long long) length; i++)
if (ReadByte(hFile) == EOF)
break;
continue;
}
}
return 1;
}