mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
3295 lines
94 KiB
C++
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;
|
|
}
|
|
|