You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1688 lines
54 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% W W PPPP GGGG %
% W W P P G %
% W W W PPPP G GGG %
% WW WW P G G %
% W W P GGG %
% %
% %
% Read WordPerfect Image Format %
% %
% Software Design %
% Jaroslav Fojtik %
% June 2000 %
% %
% %
% Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/
/*
Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/blob.h"
#include "MagickCore/blob-private.h"
#include "MagickCore/color-private.h"
#include "MagickCore/colormap.h"
#include "MagickCore/colormap-private.h"
#include "MagickCore/constitute.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/cache.h"
#include "MagickCore/distort.h"
#include "MagickCore/image.h"
#include "MagickCore/image-private.h"
#include "MagickCore/list.h"
#include "MagickCore/magic.h"
#include "MagickCore/magick.h"
#include "MagickCore/memory_.h"
#include "MagickCore/resource_.h"
#include "MagickCore/pixel-accessor.h"
#include "MagickCore/quantum-private.h"
#include "MagickCore/static.h"
#include "MagickCore/string_.h"
#include "MagickCore/module.h"
#include "MagickCore/transform.h"
#include "MagickCore/utility.h"
#include "MagickCore/utility-private.h"
typedef struct
{
unsigned char Red;
unsigned char Blue;
unsigned char Green;
} RGB_Record;
/* Default palette for WPG level 1 */
static const RGB_Record WPG1_Palette[256]={
{ 0, 0, 0}, { 0, 0,168},
{ 0,168, 0}, { 0,168,168},
{168, 0, 0}, {168, 0,168},
{168, 84, 0}, {168,168,168},
{ 84, 84, 84}, { 84, 84,252},
{ 84,252, 84}, { 84,252,252},
{252, 84, 84}, {252, 84,252},
{252,252, 84}, {252,252,252}, /*16*/
{ 0, 0, 0}, { 20, 20, 20},
{ 32, 32, 32}, { 44, 44, 44},
{ 56, 56, 56}, { 68, 68, 68},
{ 80, 80, 80}, { 96, 96, 96},
{112,112,112}, {128,128,128},
{144,144,144}, {160,160,160},
{180,180,180}, {200,200,200},
{224,224,224}, {252,252,252}, /*32*/
{ 0, 0,252}, { 64, 0,252},
{124, 0,252}, {188, 0,252},
{252, 0,252}, {252, 0,188},
{252, 0,124}, {252, 0, 64},
{252, 0, 0}, {252, 64, 0},
{252,124, 0}, {252,188, 0},
{252,252, 0}, {188,252, 0},
{124,252, 0}, { 64,252, 0}, /*48*/
{ 0,252, 0}, { 0,252, 64},
{ 0,252,124}, { 0,252,188},
{ 0,252,252}, { 0,188,252},
{ 0,124,252}, { 0, 64,252},
{124,124,252}, {156,124,252},
{188,124,252}, {220,124,252},
{252,124,252}, {252,124,220},
{252,124,188}, {252,124,156}, /*64*/
{252,124,124}, {252,156,124},
{252,188,124}, {252,220,124},
{252,252,124}, {220,252,124},
{188,252,124}, {156,252,124},
{124,252,124}, {124,252,156},
{124,252,188}, {124,252,220},
{124,252,252}, {124,220,252},
{124,188,252}, {124,156,252}, /*80*/
{180,180,252}, {196,180,252},
{216,180,252}, {232,180,252},
{252,180,252}, {252,180,232},
{252,180,216}, {252,180,196},
{252,180,180}, {252,196,180},
{252,216,180}, {252,232,180},
{252,252,180}, {232,252,180},
{216,252,180}, {196,252,180}, /*96*/
{180,220,180}, {180,252,196},
{180,252,216}, {180,252,232},
{180,252,252}, {180,232,252},
{180,216,252}, {180,196,252},
{0,0,112}, {28,0,112},
{56,0,112}, {84,0,112},
{112,0,112}, {112,0,84},
{112,0,56}, {112,0,28}, /*112*/
{112,0,0}, {112,28,0},
{112,56,0}, {112,84,0},
{112,112,0}, {84,112,0},
{56,112,0}, {28,112,0},
{0,112,0}, {0,112,28},
{0,112,56}, {0,112,84},
{0,112,112}, {0,84,112},
{0,56,112}, {0,28,112}, /*128*/
{56,56,112}, {68,56,112},
{84,56,112}, {96,56,112},
{112,56,112}, {112,56,96},
{112,56,84}, {112,56,68},
{112,56,56}, {112,68,56},
{112,84,56}, {112,96,56},
{112,112,56}, {96,112,56},
{84,112,56}, {68,112,56}, /*144*/
{56,112,56}, {56,112,69},
{56,112,84}, {56,112,96},
{56,112,112}, {56,96,112},
{56,84,112}, {56,68,112},
{80,80,112}, {88,80,112},
{96,80,112}, {104,80,112},
{112,80,112}, {112,80,104},
{112,80,96}, {112,80,88}, /*160*/
{112,80,80}, {112,88,80},
{112,96,80}, {112,104,80},
{112,112,80}, {104,112,80},
{96,112,80}, {88,112,80},
{80,112,80}, {80,112,88},
{80,112,96}, {80,112,104},
{80,112,112}, {80,114,112},
{80,96,112}, {80,88,112}, /*176*/
{0,0,64}, {16,0,64},
{32,0,64}, {48,0,64},
{64,0,64}, {64,0,48},
{64,0,32}, {64,0,16},
{64,0,0}, {64,16,0},
{64,32,0}, {64,48,0},
{64,64,0}, {48,64,0},
{32,64,0}, {16,64,0}, /*192*/
{0,64,0}, {0,64,16},
{0,64,32}, {0,64,48},
{0,64,64}, {0,48,64},
{0,32,64}, {0,16,64},
{32,32,64}, {40,32,64},
{48,32,64}, {56,32,64},
{64,32,64}, {64,32,56},
{64,32,48}, {64,32,40}, /*208*/
{64,32,32}, {64,40,32},
{64,48,32}, {64,56,32},
{64,64,32}, {56,64,32},
{48,64,32}, {40,64,32},
{32,64,32}, {32,64,40},
{32,64,48}, {32,64,56},
{32,64,64}, {32,56,64},
{32,48,64}, {32,40,64}, /*224*/
{44,44,64}, {48,44,64},
{52,44,64}, {60,44,64},
{64,44,64}, {64,44,60},
{64,44,52}, {64,44,48},
{64,44,44}, {64,48,44},
{64,52,44}, {64,60,44},
{64,64,44}, {60,64,44},
{52,64,44}, {48,64,44}, /*240*/
{44,64,44}, {44,64,48},
{44,64,52}, {44,64,60},
{44,64,64}, {44,60,64},
{44,55,64}, {44,48,64},
{0,0,0}, {0,0,0},
{0,0,0}, {0,0,0},
{0,0,0}, {0,0,0},
{0,0,0}, {0,0,0} /*256*/
};
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% I s W P G %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% IsWPG() returns True if the image format type, identified by the magick
% string, is WPG.
%
% The format of the IsWPG method is:
%
% unsigned int IsWPG(const unsigned char *magick,const size_t length)
%
% A description of each parameter follows:
%
% o status: Method IsWPG returns True if the image format type is WPG.
%
% o magick: compare image format pattern against these bytes.
%
% o length: Specifies the length of the magick string.
%
*/
static unsigned int IsWPG(const unsigned char *magick,const size_t length)
{
if (length < 4)
return(MagickFalse);
if (memcmp(magick,"\377WPC",4) == 0)
return(MagickTrue);
return(MagickFalse);
}
static void Rd_WP_DWORD(Image *image,size_t *d)
{
unsigned char
b;
b=ReadBlobByte(image);
*d=b;
if (b < 0xFFU)
return;
b=ReadBlobByte(image);
*d=(size_t) b;
b=ReadBlobByte(image);
*d+=(size_t) b*256l;
if (*d < 0x8000)
return;
*d=(*d & 0x7FFF) << 16;
b=ReadBlobByte(image);
*d+=(size_t) b;
b=ReadBlobByte(image);
*d+=(size_t) b*256l;
return;
}
static MagickBooleanType InsertRow(Image *image,unsigned char *p,ssize_t y,
int bpp,ExceptionInfo *exception)
{
int
bit;
Quantum
index;
Quantum
*q;
ssize_t
x;
q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
if (q == (Quantum *) NULL)
return(MagickFalse);
switch (bpp)
{
case 1: /* Convert bitmap scanline. */
{
for (x=0; x < ((ssize_t) image->columns-7); x+=8)
{
for (bit=0; bit < 8; bit++)
{
index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
q+=GetPixelChannels(image);
}
p++;
}
if ((image->columns % 8) != 0)
{
for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
{
index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
q+=GetPixelChannels(image);
}
p++;
}
break;
}
case 2: /* Convert PseudoColor scanline. */
{
for (x=0; x < ((ssize_t) image->columns-3); x+=4)
{
index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
q+=GetPixelChannels(image);
index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
q+=GetPixelChannels(image);
index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
q+=GetPixelChannels(image);
index=ConstrainColormapIndex(image,(*p) & 0x3,exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
q+=GetPixelChannels(image);
p++;
}
if ((image->columns % 4) != 0)
{
index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
q+=GetPixelChannels(image);
if ((image->columns % 4) > 1)
{
index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
q+=GetPixelChannels(image);
if ((image->columns % 4) > 2)
{
index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,
exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
index,q);
q+=GetPixelChannels(image);
}
}
p++;
}
break;
}
case 4: /* Convert PseudoColor scanline. */
{
for (x=0; x < ((ssize_t) image->columns-1); x+=2)
{
index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
q+=GetPixelChannels(image);
index=ConstrainColormapIndex(image,(*p) & 0x0f,exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
p++;
q+=GetPixelChannels(image);
}
if ((image->columns % 2) != 0)
{
index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
p++;
q+=GetPixelChannels(image);
}
break;
}
case 8: /* Convert PseudoColor scanline. */
{
for (x=0; x < (ssize_t) image->columns; x++)
{
index=ConstrainColormapIndex(image,*p,exception);
SetPixelIndex(image,index,q);
if (index < image->colors)
SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
p++;
q+=GetPixelChannels(image);
}
}
break;
case 24: /* Convert DirectColor scanline. */
for (x=0; x < (ssize_t) image->columns; x++)
{
SetPixelRed(image,ScaleCharToQuantum(*p++),q);
SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
q+=GetPixelChannels(image);
}
break;
}
if (!SyncAuthenticPixels(image,exception))
return(MagickFalse);
return(MagickTrue);
}
/* Helper for WPG1 raster reader. */
#define InsertByte(b) \
{ \
BImgBuff[x]=b; \
x++; \
if((ssize_t) x>=ldblk) \
{ \
if (InsertRow(image,BImgBuff,(ssize_t) y,bpp,exception) != MagickFalse) \
y++; \
x=0; \
} \
}
/* WPG1 raster reader. */
static int UnpackWPGRaster(Image *image,int bpp,ExceptionInfo *exception)
{
int
x,
y,
i;
unsigned char
bbuf,
*BImgBuff,
RunCount;
ssize_t
ldblk;
x=0;
y=0;
ldblk=(ssize_t) ((bpp*image->columns+7)/8);
BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
8*sizeof(*BImgBuff));
if(BImgBuff==NULL) return(-2);
(void) memset(BImgBuff,0,(size_t) ldblk*8*sizeof(*BImgBuff));
while(y<(ssize_t) image->rows)
{
int
c;
c=ReadBlobByte(image);
if (c == EOF)
break;
bbuf=(unsigned char) c;
RunCount=bbuf & 0x7F;
if(bbuf & 0x80)
{
if(RunCount) /* repeat next byte runcount * */
{
bbuf=ReadBlobByte(image);
for(i=0;i<(int) RunCount;i++) InsertByte(bbuf);
}
else { /* read next byte as RunCount; repeat 0xFF runcount* */
c=ReadBlobByte(image);
if (c < 0)
break;
RunCount=(unsigned char) c;
for(i=0;i<(int) RunCount;i++) InsertByte(0xFF);
}
}
else {
if(RunCount) /* next runcount byte are readed directly */
{
for(i=0;i < (int) RunCount;i++)
{
c=ReadBlobByte(image);
if (c < 0)
break;
InsertByte(c);
}
}
else { /* repeat previous line runcount* */
c=ReadBlobByte(image);
if (c == EOF)
{
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
return(-7);
}
RunCount=(unsigned char) c;
if(x) { /* attempt to duplicate row from x position: */
/* I do not know what to do here */
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
return(-3);
}
for(i=0;i < (int) RunCount;i++)
{
x=0;
y++; /* Here I need to duplicate previous row RUNCOUNT* */
if(y<2) continue;
if(y>(ssize_t) image->rows)
{
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
return(-4);
}
if (InsertRow(image,BImgBuff,y-1,bpp,exception) == MagickFalse)
{
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
return(-5);
}
}
}
}
if (EOFBlob(image) != MagickFalse)
break;
}
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
return(y <(ssize_t) image->rows ? -5 : 0);
}
/* Helper for WPG2 reader. */
#define InsertByte6(b) \
{ \
DisableMSCWarning(4310) \
if(XorMe)\
BImgBuff[x] = (unsigned char)~b;\
else\
BImgBuff[x] = b;\
RestoreMSCWarning \
x++; \
if((ssize_t) x >= ldblk) \
{ \
if (InsertRow(image,BImgBuff,(ssize_t) y,bpp,exception) != MagickFalse) \
y++; \
x=0; \
} \
}
/* WPG2 raster reader. */
static int UnpackWPG2Raster(Image *image,int bpp,ExceptionInfo *exception)
{
int
RunCount,
XorMe = 0;
ssize_t
i;
size_t
x,
y;
ssize_t
ldblk;
unsigned int
SampleSize=1;
unsigned char
bbuf,
*BImgBuff,
SampleBuffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
x=0;
y=0;
ldblk=(ssize_t) ((bpp*image->columns+7)/8);
BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
sizeof(*BImgBuff));
if(BImgBuff==NULL)
return(-2);
(void) memset(BImgBuff,0,ldblk*sizeof(*BImgBuff));
while( y< image->rows)
{
bbuf=ReadBlobByte(image);
switch(bbuf)
{
case 0x7D:
SampleSize=ReadBlobByte(image); /* DSZ */
if(SampleSize>8)
{
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
return(-2);
}
if(SampleSize<1)
{
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
return(-2);
}
break;
case 0x7E:
if (y == 0)
(void) FormatLocaleFile(stderr,
"\nUnsupported WPG token XOR, please report!");
XorMe=!XorMe;
break;
case 0x7F:
RunCount=ReadBlobByte(image); /* BLK */
if (RunCount < 0)
break;
for(i=0; i < ((ssize_t) SampleSize*(RunCount+1)); i++)
{
InsertByte6(0);
}
break;
case 0xFD:
RunCount=ReadBlobByte(image); /* EXT */
if (RunCount < 0)
break;
for(i=0; i<= RunCount;i++)
for(bbuf=0; bbuf < SampleSize; bbuf++)
InsertByte6(SampleBuffer[bbuf]);
break;
case 0xFE:
RunCount=ReadBlobByte(image); /* RST */
if (RunCount < 0)
break;
if(x!=0)
{
(void) FormatLocaleFile(stderr,
"\nUnsupported WPG2 unaligned token RST x=%.20g, please report!\n"
,(double) x);
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
return(-3);
}
{
/* duplicate the previous row RunCount x */
for(i=0;i<=RunCount;i++)
{
if (InsertRow(image,BImgBuff,(ssize_t) (image->rows > y ? y : image->rows-1),bpp,exception) == MagickFalse)
{
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
return(-3);
}
y++;
}
}
break;
case 0xFF:
RunCount=ReadBlobByte(image); /* WHT */
if (RunCount < 0)
break;
for(i=0; i < ((ssize_t) SampleSize*(RunCount+1)); i++)
{
InsertByte6(0xFF);
}
break;
default:
RunCount=bbuf & 0x7F;
if(bbuf & 0x80) /* REP */
{
for(i=0; i < SampleSize; i++)
SampleBuffer[i]=ReadBlobByte(image);
for(i=0;i<=RunCount;i++)
for(bbuf=0;bbuf<SampleSize;bbuf++)
InsertByte6(SampleBuffer[bbuf]);
}
else { /* NRP */
for(i=0; i < (ssize_t) (SampleSize*(RunCount+1)); i++)
{
bbuf=ReadBlobByte(image);
InsertByte6(bbuf);
}
}
}
if (EOFBlob(image) != MagickFalse)
break;
}
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
return(0);
}
typedef float tCTM[3][3];
static unsigned LoadWPG2Flags(Image *image,char Precision,float *Angle,tCTM *CTM)
{
const unsigned char TPR=1,TRN=2,SKW=4,SCL=8,ROT=0x10,OID=0x20,LCK=0x80;
ssize_t x;
unsigned DenX;
unsigned Flags;
(void) memset(*CTM,0,sizeof(*CTM)); /*CTM.erase();CTM.resize(3,3);*/
(*CTM)[0][0]=1;
(*CTM)[1][1]=1;
(*CTM)[2][2]=1;
Flags=ReadBlobLSBShort(image);
if(Flags & LCK) (void) ReadBlobLSBLong(image); /*Edit lock*/
if(Flags & OID)
{
if(Precision==0)
{(void) ReadBlobLSBShort(image);} /*ObjectID*/
else
{(void) ReadBlobLSBLong(image);} /*ObjectID (Double precision)*/
}
if(Flags & ROT)
{
x=ReadBlobLSBLong(image); /*Rot Angle*/
if(Angle) *Angle=x/65536.0;
}
if(Flags & (ROT|SCL))
{
x=ReadBlobLSBLong(image); /*Sx*cos()*/
(*CTM)[0][0] = (float)x/0x10000;
x=ReadBlobLSBLong(image); /*Sy*cos()*/
(*CTM)[1][1] = (float)x/0x10000;
}
if(Flags & (ROT|SKW))
{
x=ReadBlobLSBLong(image); /*Kx*sin()*/
(*CTM)[1][0] = (float)x/0x10000;
x=ReadBlobLSBLong(image); /*Ky*sin()*/
(*CTM)[0][1] = (float)x/0x10000;
}
if(Flags & TRN)
{
x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Tx*/
if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Ty*/
(*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
}
if(Flags & TPR)
{
x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Px*/
(*CTM)[2][0] = x + (float)DenX/0x10000;;
x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Py*/
(*CTM)[2][1] = x + (float)DenX/0x10000;
}
return(Flags);
}
static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo *exception)
{
char
postscript_file[MagickPathExtent];
const MagicInfo
*magic_info;
FILE
*ps_file;
int
c;
ImageInfo
*clone_info;
Image
*image2;
MagickBooleanType
status;
unsigned char
magick[2*MagickPathExtent];
ssize_t
count;
if ((clone_info=CloneImageInfo(image_info)) == NULL)
return(image);
clone_info->blob=(void *) NULL;
clone_info->length=0;
status=MagickFalse;
/* Obtain temporary file */
(void) AcquireUniqueFilename(postscript_file);
ps_file=fopen_utf8(postscript_file,"wb");
if (ps_file == (FILE *) NULL)
goto FINISH;
/* Copy postscript to temporary file */
if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
{
(void) fclose(ps_file);
ThrowException(exception,CorruptImageError,"ImproperImageHeader",
image->filename);
goto FINISH_UNL;
}
count=ReadBlob(image, 2*MagickPathExtent, magick);
if (count < 1)
{
(void) fclose(ps_file);
ThrowException(exception,CorruptImageError,"ImproperImageHeader",
image->filename);
goto FINISH_UNL;
}
if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
{
(void) fclose(ps_file);
ThrowException(exception,CorruptImageError,"ImproperImageHeader",
image->filename);
goto FINISH_UNL;
}
while (PS_Size-- > 0)
{
c=ReadBlobByte(image);
if (c == EOF)
{
(void) fclose(ps_file);
ThrowException(exception,CorruptImageError,"ImproperImageHeader",
image->filename);
goto FINISH_UNL;
}
(void) fputc(c,ps_file);
}
(void) fclose(ps_file);
/* Detect file format - Check magic.mgk configuration file. */
magic_info=GetMagicInfo(magick,count,exception);
if(magic_info == (const MagicInfo *) NULL) goto FINISH_UNL;
/* printf("Detected:%s \n",magic_info->name); */
if(exception->severity != UndefinedException) goto FINISH_UNL;
(void) CopyMagickString(clone_info->magick,GetMagicName(magic_info),
MagickPathExtent);
if (LocaleCompare(clone_info->magick,"PFB") != 0)
{
ThrowException(exception,CorruptImageError,"ImproperImageHeader",
image->filename);
goto FINISH_UNL;
}
/* Read nested image */
/*FormatString(clone_info->filename,"%s:%s",magic_info->name,postscript_file);*/
FormatLocaleString(clone_info->filename,MagickPathExtent,"%.1024s:%.1024s",
clone_info->magick,postscript_file);
image2=ReadImage(clone_info,exception);
if (!image2)
goto FINISH_UNL;
if(exception->severity>=ErrorException)
{
CloseBlob(image2);
DestroyImageList(image2);
goto FINISH_UNL;
}
{
Image
*p;
/*
Replace current image with new image while copying base image attributes.
*/
p=image2;
do
{
(void) CopyMagickString(p->filename,image->filename,MagickPathExtent);
(void) CopyMagickString(p->magick_filename,image->magick_filename,
MagickPathExtent);
(void) CopyMagickString(p->magick,image->magick,MagickPathExtent);
if ((p->rows == 0) || (p->columns == 0))
{
DeleteImageFromList(&p);
if (p == (Image *) NULL)
{
image2=(Image *) NULL;
goto FINISH_UNL;
}
}
else
{
DestroyBlob(p);
p->blob=ReferenceBlob(image->blob);
p=p->next;
}
} while (p != (Image *) NULL);
}
if ((image->rows == 0 || image->columns == 0) &&
(image->previous != NULL || image->next != NULL))
{
DeleteImageFromList(&image);
}
AppendImageToList(&image,image2);
while (image->next != NULL)
image=image->next;
status=MagickTrue;
FINISH_UNL:
(void) RelinquishUniqueFileResource(postscript_file);
FINISH:
DestroyImageInfo(clone_info);
if (status == MagickFalse)
return(DestroyImageList(image));
return(image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e a d W P G I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Method ReadWPGImage reads an WPG X image file and returns it. It
% allocates the memory necessary for the new Image structure and returns a
% pointer to the new image.
%
% The format of the ReadWPGImage method is:
%
% Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: Method ReadWPGImage returns a pointer to the image after
% reading. A null image is returned if there is a memory shortage or if
% the image cannot be read.
%
% o image_info: Specifies a pointer to a ImageInfo structure.
%
% o exception: return any errors or warnings in this structure.
%
*/
static Image *ReadWPGImage(const ImageInfo *image_info,
ExceptionInfo *exception)
{
typedef struct
{
size_t FileId;
MagickOffsetType DataOffset;
unsigned int ProductType;
unsigned int FileType;
unsigned char MajorVersion;
unsigned char MinorVersion;
unsigned int EncryptKey;
unsigned int Reserved;
} WPGHeader;
typedef struct
{
unsigned char RecType;
size_t RecordLength;
} WPGRecord;
typedef struct
{
unsigned char Class;
unsigned char RecType;
size_t Extension;
size_t RecordLength;
} WPG2Record;
typedef struct
{
unsigned HorizontalUnits;
unsigned VerticalUnits;
unsigned char PosSizePrecision;
} WPG2Start;
typedef struct
{
unsigned int Width;
unsigned int Height;
unsigned int Depth;
unsigned int HorzRes;
unsigned int VertRes;
} WPGBitmapType1;
typedef struct
{
unsigned int Width;
unsigned int Height;
unsigned char Depth;
unsigned char Compression;
} WPG2BitmapType1;
typedef struct
{
unsigned int RotAngle;
unsigned int LowLeftX;
unsigned int LowLeftY;
unsigned int UpRightX;
unsigned int UpRightY;
unsigned int Width;
unsigned int Height;
unsigned int Depth;
unsigned int HorzRes;
unsigned int VertRes;
} WPGBitmapType2;
typedef struct
{
unsigned int StartIndex;
unsigned int NumOfEntries;
} WPGColorMapRec;
/*
typedef struct {
size_t PS_unknown1;
unsigned int PS_unknown2;
unsigned int PS_unknown3;
} WPGPSl1Record;
*/
Image
*image;
unsigned int
status;
WPGHeader
Header;
WPGRecord
Rec;
WPG2Record
Rec2;
WPG2Start StartWPG;
WPGBitmapType1
BitmapHeader1;
WPG2BitmapType1
Bitmap2Header1;
WPGBitmapType2
BitmapHeader2;
WPGColorMapRec
WPG_Palette;
int
i,
bpp,
WPG2Flags;
ssize_t
ldblk;
size_t
one;
unsigned char
*BImgBuff;
tCTM CTM; /*current transform matrix*/
/*
Open image file.
*/
assert(image_info != (const ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);
one=1;
image=AcquireImage(image_info,exception);
image->depth=8;
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
if (status == MagickFalse)
{
image=DestroyImageList(image);
return((Image *) NULL);
}
/*
Read WPG image.
*/
Header.FileId=ReadBlobLSBLong(image);
Header.DataOffset=(MagickOffsetType) ReadBlobLSBLong(image);
Header.ProductType=ReadBlobLSBShort(image);
Header.FileType=ReadBlobLSBShort(image);
Header.MajorVersion=ReadBlobByte(image);
Header.MinorVersion=ReadBlobByte(image);
Header.EncryptKey=ReadBlobLSBShort(image);
Header.Reserved=ReadBlobLSBShort(image);
if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
ThrowReaderException(CorruptImageError,"ImproperImageHeader");
if (Header.EncryptKey!=0)
ThrowReaderException(CoderError,"EncryptedWPGImageFileNotSupported");
image->columns = 1;
image->rows = 1;
image->colors = 0;
image->storage_class=DirectClass;
(void) ResetImagePixels(image,exception);
bpp=0;
BitmapHeader2.RotAngle=0;
Rec2.RecordLength=0;
switch(Header.FileType)
{
case 1: /* WPG level 1 */
while(!EOFBlob(image)) /* object parser loop */
{
if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
break;
if(EOFBlob(image))
break;
Rec.RecType=(i=ReadBlobByte(image));
if(i==EOF)
break;
Rd_WP_DWORD(image,&Rec.RecordLength);
if (Rec.RecordLength > GetBlobSize(image))
ThrowReaderException(CorruptImageError,"ImproperImageHeader");
if(EOFBlob(image))
break;
Header.DataOffset=TellBlob(image)+Rec.RecordLength;
switch(Rec.RecType)
{
case 0x0B: /* bitmap type 1 */
BitmapHeader1.Width=ReadBlobLSBShort(image);
BitmapHeader1.Height=ReadBlobLSBShort(image);
if ((BitmapHeader1.Width == 0) || (BitmapHeader1.Height == 0))
ThrowReaderException(CorruptImageError,"ImproperImageHeader");
BitmapHeader1.Depth=ReadBlobLSBShort(image);
BitmapHeader1.HorzRes=ReadBlobLSBShort(image);
BitmapHeader1.VertRes=ReadBlobLSBShort(image);
if(BitmapHeader1.HorzRes && BitmapHeader1.VertRes)
{
image->units=PixelsPerCentimeterResolution;
image->resolution.x=BitmapHeader1.HorzRes/470.0;
image->resolution.y=BitmapHeader1.VertRes/470.0;
}
image->columns=BitmapHeader1.Width;
image->rows=BitmapHeader1.Height;
bpp=BitmapHeader1.Depth;
goto UnpackRaster;
case 0x0E: /*Color palette */
WPG_Palette.StartIndex=ReadBlobLSBShort(image);
WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
(Rec2.RecordLength-2-2)/3)
ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
if (WPG_Palette.StartIndex > WPG_Palette.NumOfEntries)
ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
image->colors=WPG_Palette.NumOfEntries;
if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
goto NoMemory;
for (i=WPG_Palette.StartIndex;
i < (int)WPG_Palette.NumOfEntries; i++)
{
image->colormap[i].red=ScaleCharToQuantum((unsigned char)
ReadBlobByte(image));
image->colormap[i].green=ScaleCharToQuantum((unsigned char)
ReadBlobByte(image));
image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
ReadBlobByte(image));
}
break;
case 0x11: /* Start PS l1 */
if (Rec.RecordLength > 8)
{
image=ExtractPostscript(image,image_info,
TellBlob(image)+8, /* skip PS header in the wpg */
(ssize_t) Rec.RecordLength-8,exception);
if (image == NULL)
ThrowReaderException(CorruptImageError,
"ImproperImageHeader");
}
break;
case 0x14: /* bitmap type 2 */
BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
BitmapHeader2.Width=ReadBlobLSBShort(image);
BitmapHeader2.Height=ReadBlobLSBShort(image);
if ((BitmapHeader2.Width == 0) || (BitmapHeader2.Height == 0))
ThrowReaderException(CorruptImageError,"ImproperImageHeader");
BitmapHeader2.Depth=ReadBlobLSBShort(image);
BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
BitmapHeader2.VertRes=ReadBlobLSBShort(image);
image->units=PixelsPerCentimeterResolution;
image->page.width=(unsigned int)
((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
image->page.height=(unsigned int)
((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
if(BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
{
image->resolution.x=BitmapHeader2.HorzRes/470.0;
image->resolution.y=BitmapHeader2.VertRes/470.0;
}
image->columns=BitmapHeader2.Width;
image->rows=BitmapHeader2.Height;
bpp=BitmapHeader2.Depth;
UnpackRaster:
status=SetImageExtent(image,image->columns,image->rows,exception);
if (status == MagickFalse)
break;
(void) ResetImagePixels(image,exception);
if ((image->storage_class != PseudoClass) && (bpp < 24))
{
image->colors=one << bpp;
if (image->colors > GetBlobSize(image))
ThrowReaderException(CorruptImageError,
"InsufficientImageDataInFile");
if (!AcquireImageColormap(image,image->colors,exception))
{
NoMemory:
ThrowReaderException(ResourceLimitError,
"MemoryAllocationFailed");
}
/* printf("Load default colormap \n"); */
for (i=0; (i < (int) image->colors) && (i < 256); i++)
{
image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
image->colormap[i].alpha=OpaqueAlpha;
}
}
else
{
if (bpp < 24)
if ( (image->colors < (one << bpp)) && (bpp != 24) )
{
PixelInfo
*colormap;
size_t
colors;
colormap=image->colormap;
colors=image->colors;
image->colormap=(PixelInfo *) NULL;
if (AcquireImageColormap(image,one << bpp,exception) == MagickFalse)
{
colormap=(PixelInfo *)
RelinquishMagickMemory(colormap);
goto NoMemory;
}
(void) memcpy(image->colormap,colormap,MagickMin(
image->colors,colors)*sizeof(*image->colormap));
colormap=(PixelInfo *)
RelinquishMagickMemory(colormap);
}
}
if ((bpp == 1) && (image->colors > 1))
{
if(image->colormap[0].red==0 &&
image->colormap[0].green==0 &&
image->colormap[0].blue==0 &&
image->colormap[1].red==0 &&
image->colormap[1].green==0 &&
image->colormap[1].blue==0)
{ /* fix crippled monochrome palette */
image->colormap[1].red =
image->colormap[1].green =
image->colormap[1].blue = QuantumRange;
image->colormap[1].alpha=OpaqueAlpha;
}
}
if(!image_info->ping)
if(UnpackWPGRaster(image,bpp,exception) < 0)
/* The raster cannot be unpacked */
{
DecompressionFailed:
ThrowReaderException(CoderError,"UnableToDecompressImage");
}
if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
{
/* flop command */
if(BitmapHeader2.RotAngle & 0x8000)
{
Image
*flop_image;
flop_image = FlopImage(image, exception);
if (flop_image != (Image *) NULL) {
DuplicateBlob(flop_image,image);
ReplaceImageInList(&image,flop_image);
}
}
/* flip command */
if(BitmapHeader2.RotAngle & 0x2000)
{
Image
*flip_image;
flip_image = FlipImage(image, exception);
if (flip_image != (Image *) NULL) {
DuplicateBlob(flip_image,image);
ReplaceImageInList(&image,flip_image);
}
}
/* rotate command */
if(BitmapHeader2.RotAngle & 0x0FFF)
{
Image
*rotate_image;
rotate_image=RotateImage(image,(BitmapHeader2.RotAngle &
0x0FFF), exception);
if (rotate_image != (Image *) NULL) {
DuplicateBlob(rotate_image,image);
ReplaceImageInList(&image,rotate_image);
}
}
}
/* Allocate next image structure. */
if ((image_info->ping != MagickFalse) &&
(image_info->number_scenes != 0))
if (image->scene >= (image_info->scene+image_info->number_scenes-1))
goto Finish;
AcquireNextImage(image_info,image,exception);
image->depth=8;
if (image->next == (Image *) NULL)
goto Finish;
image=SyncNextImageInList(image);
image->columns=image->rows=0;
image->colors=0;
break;
case 0x1B: /* Postscript l2 */
if (Rec.RecordLength>0x3C)
{
image=ExtractPostscript(image,image_info,
TellBlob(image)+0x3C, /* skip PS l2 header in the wpg */
(ssize_t) Rec.RecordLength-0x3C,exception);
if (image == NULL)
ThrowReaderException(CorruptImageError,
"ImproperImageHeader");
}
break;
}
}
break;
case 2: /* WPG level 2 */
(void) memset(CTM,0,sizeof(CTM));
StartWPG.PosSizePrecision = 0;
while(!EOFBlob(image)) /* object parser loop */
{
if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
break;
if (EOFBlob(image))
break;
Rec2.Class=(i=ReadBlobByte(image));
if(i==EOF)
break;
Rec2.RecType=(i=ReadBlobByte(image));
if(i==EOF)
break;
Rd_WP_DWORD(image,&Rec2.Extension);
Rd_WP_DWORD(image,&Rec2.RecordLength);
if(EOFBlob(image))
break;
Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
switch(Rec2.RecType)
{
case 1:
StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
StartWPG.VerticalUnits=ReadBlobLSBShort(image);
StartWPG.PosSizePrecision=ReadBlobByte(image);
break;
case 0x0C: /* Color palette */
WPG_Palette.StartIndex=ReadBlobLSBShort(image);
WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
(Rec2.RecordLength-2-2) / 3)
ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
if (WPG_Palette.StartIndex >= WPG_Palette.NumOfEntries)
ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
image->colors=WPG_Palette.NumOfEntries;
if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
ThrowReaderException(ResourceLimitError,
"MemoryAllocationFailed");
for (i=WPG_Palette.StartIndex;
i < (int)WPG_Palette.NumOfEntries; i++)
{
image->colormap[i].red=ScaleCharToQuantum((char)
ReadBlobByte(image));
image->colormap[i].green=ScaleCharToQuantum((char)
ReadBlobByte(image));
image->colormap[i].blue=ScaleCharToQuantum((char)
ReadBlobByte(image));
image->colormap[i].alpha=OpaqueAlpha;
(void) ReadBlobByte(image); /*Opacity??*/
}
break;
case 0x0E:
Bitmap2Header1.Width=ReadBlobLSBShort(image);
Bitmap2Header1.Height=ReadBlobLSBShort(image);
if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Height == 0))
ThrowReaderException(CorruptImageError,"ImproperImageHeader");
Bitmap2Header1.Depth=ReadBlobByte(image);
Bitmap2Header1.Compression=ReadBlobByte(image);
if(Bitmap2Header1.Compression > 1)
continue; /*Unknown compression method */
switch(Bitmap2Header1.Depth)
{
case 1:
bpp=1;
break;
case 2:
bpp=2;
break;
case 3:
bpp=4;
break;
case 4:
bpp=8;
break;
case 8:
bpp=24;
break;
default:
continue; /*Ignore raster with unknown depth*/
}
image->columns=Bitmap2Header1.Width;
image->rows=Bitmap2Header1.Height;
if (image_info->ping != MagickFalse)
return(image);
status=SetImageExtent(image,image->columns,image->rows,exception);
if (status != MagickFalse)
status=ResetImagePixels(image,exception);
if (status == MagickFalse)
break;
if ((image->colors == 0) && (bpp != 24))
{
image->colors=one << bpp;
if (!AcquireImageColormap(image,image->colors,exception))
goto NoMemory;
}
else
{
if(bpp < 24)
if( image->colors<(one << bpp) && bpp!=24 )
image->colormap=(PixelInfo *) ResizeQuantumMemory(
image->colormap,(size_t) (one << bpp),
sizeof(*image->colormap));
}
switch(Bitmap2Header1.Compression)
{
case 0: /*Uncompressed raster*/
{
ldblk=(ssize_t) ((bpp*image->columns+7)/8);
BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t)
ldblk+1,sizeof(*BImgBuff));
if (BImgBuff == (unsigned char *) NULL)
goto NoMemory;
for (i=0; i< (ssize_t) image->rows; i++)
{
ssize_t
count;
count=ReadBlob(image,(size_t) ldblk,BImgBuff);
if (count != ldblk)
break;
if (InsertRow(image,BImgBuff,i,bpp,exception) == MagickFalse)
break;
}
BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
if (i < (ssize_t) image->rows)
goto DecompressionFailed;
break;
}
case 1: /*RLE for WPG2 */
{
if( UnpackWPG2Raster(image,bpp,exception) < 0)
goto DecompressionFailed;
break;
}
}
if(CTM[0][0]<0 && !image_info->ping)
{ /*?? RotAngle=360-RotAngle;*/
Image
*flop_image;
flop_image = FlopImage(image, exception);
if (flop_image != (Image *) NULL) {
DuplicateBlob(flop_image,image);
ReplaceImageInList(&image,flop_image);
}
/* Try to change CTM according to Flip - I am not sure, must be checked.
Tx(0,0)=-1; Tx(1,0)=0; Tx(2,0)=0;
Tx(0,1)= 0; Tx(1,1)=1; Tx(2,1)=0;
Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
Tx(1,2)=0; Tx(2,2)=1; */
}
if(CTM[1][1]<0 && !image_info->ping)
{ /*?? RotAngle=360-RotAngle;*/
Image
*flip_image;
flip_image = FlipImage(image, exception);
if (flip_image != (Image *) NULL) {
DuplicateBlob(flip_image,image);
ReplaceImageInList(&image,flip_image);
}
/* Try to change CTM according to Flip - I am not sure, must be checked.
float_matrix Tx(3,3);
Tx(0,0)= 1; Tx(1,0)= 0; Tx(2,0)=0;
Tx(0,1)= 0; Tx(1,1)=-1; Tx(2,1)=0;
Tx(0,2)= 0; Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
Tx(2,2)=1; */
}
/* Allocate next image structure. */
if ((image_info->ping != MagickFalse) &&
(image_info->number_scenes != 0))
if (image->scene >= (image_info->scene+image_info->number_scenes-1))
goto Finish;
AcquireNextImage(image_info,image,exception);
image->depth=8;
if (image->next == (Image *) NULL)
goto Finish;
image=SyncNextImageInList(image);
image->columns=image->rows=0;
image->colors=0;
break;
case 0x12: /* Postscript WPG2*/
i=ReadBlobLSBShort(image);
if (Rec2.RecordLength > (unsigned int) i)
{
image=ExtractPostscript(image,image_info,
TellBlob(image)+i, /*skip PS header in the wpg2*/
(ssize_t) (Rec2.RecordLength-i-2),exception);
if (image == NULL)
ThrowReaderException(CorruptImageError,
"ImproperImageHeader");
}
break;
case 0x1B: /*bitmap rectangle*/
WPG2Flags = LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM);
(void) WPG2Flags;
break;
}
}
break;
default:
{
ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
}
}
Finish:
(void) CloseBlob(image);
{
Image
*p;
ssize_t
scene=0;
/*
Rewind list, removing any empty images while rewinding.
*/
p=image;
image=NULL;
while (p != (Image *) NULL)
{
Image *tmp=p;
if ((p->rows == 0) || (p->columns == 0)) {
p=p->previous;
DeleteImageFromList(&tmp);
} else {
image=p;
p=p->previous;
}
}
/*
Fix scene numbers.
*/
for (p=image; p != (Image *) NULL; p=p->next)
p->scene=(size_t) scene++;
}
if (image == (Image *) NULL)
ThrowReaderException(CorruptImageError,
"ImageFileDoesNotContainAnyImageData");
return(image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e g i s t e r W P G I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Method RegisterWPGImage adds attributes for the WPG image format to
% the list of supported formats. The attributes include the image format
% tag, a method to read and/or write the format, whether the format
% supports the saving of more than one frame to the same file or blob,
% whether the format supports native in-memory I/O, and a brief
% description of the format.
%
% The format of the RegisterWPGImage method is:
%
% size_t RegisterWPGImage(void)
%
*/
ModuleExport size_t RegisterWPGImage(void)
{
MagickInfo
*entry;
entry=AcquireMagickInfo("WPG","WPG","Word Perfect Graphics");
entry->decoder=(DecodeImageHandler *) ReadWPGImage;
entry->magick=(IsImageFormatHandler *) IsWPG;
entry->flags|=CoderDecoderSeekableStreamFlag;
(void) RegisterMagickInfo(entry);
return(MagickImageCoderSignature);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% U n r e g i s t e r W P G I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Method UnregisterWPGImage removes format registrations made by the
% WPG module from the list of supported formats.
%
% The format of the UnregisterWPGImage method is:
%
% UnregisterWPGImage(void)
%
*/
ModuleExport void UnregisterWPGImage(void)
{
(void) UnregisterMagickInfo("WPG");
}