2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12 % Read WordPerfect Image Format %
19 % Copyright 1999-2018 ImageMagick Studio LLC, a non-profit organization %
20 % dedicated to making software imaging solutions freely available. %
22 % You may not use this file except in compliance with the License. You may %
23 % obtain a copy of the License at %
25 % https://www.imagemagick.org/script/license.php %
27 % Unless required by applicable law or agreed to in writing, software %
28 % distributed under the License is distributed on an "AS IS" BASIS, %
29 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
30 % See the License for the specific language governing permissions and %
31 % limitations under the License. %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41 #include "MagickCore/studio.h"
42 #include "MagickCore/blob.h"
43 #include "MagickCore/blob-private.h"
44 #include "MagickCore/color-private.h"
45 #include "MagickCore/colormap.h"
46 #include "MagickCore/colormap-private.h"
47 #include "MagickCore/constitute.h"
48 #include "MagickCore/exception.h"
49 #include "MagickCore/exception-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/distort.h"
52 #include "MagickCore/image.h"
53 #include "MagickCore/image-private.h"
54 #include "MagickCore/list.h"
55 #include "MagickCore/magic.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/resource_.h"
59 #include "MagickCore/pixel-accessor.h"
60 #include "MagickCore/quantum-private.h"
61 #include "MagickCore/static.h"
62 #include "MagickCore/string_.h"
63 #include "MagickCore/module.h"
64 #include "MagickCore/transform.h"
65 #include "MagickCore/utility.h"
66 #include "MagickCore/utility-private.h"
75 /* Default palette for WPG level 1 */
76 static const RGB_Record WPG1_Palette[256]={
77 { 0, 0, 0}, { 0, 0,168},
78 { 0,168, 0}, { 0,168,168},
79 {168, 0, 0}, {168, 0,168},
80 {168, 84, 0}, {168,168,168},
81 { 84, 84, 84}, { 84, 84,252},
82 { 84,252, 84}, { 84,252,252},
83 {252, 84, 84}, {252, 84,252},
84 {252,252, 84}, {252,252,252}, /*16*/
85 { 0, 0, 0}, { 20, 20, 20},
86 { 32, 32, 32}, { 44, 44, 44},
87 { 56, 56, 56}, { 68, 68, 68},
88 { 80, 80, 80}, { 96, 96, 96},
89 {112,112,112}, {128,128,128},
90 {144,144,144}, {160,160,160},
91 {180,180,180}, {200,200,200},
92 {224,224,224}, {252,252,252}, /*32*/
93 { 0, 0,252}, { 64, 0,252},
94 {124, 0,252}, {188, 0,252},
95 {252, 0,252}, {252, 0,188},
96 {252, 0,124}, {252, 0, 64},
97 {252, 0, 0}, {252, 64, 0},
98 {252,124, 0}, {252,188, 0},
99 {252,252, 0}, {188,252, 0},
100 {124,252, 0}, { 64,252, 0}, /*48*/
101 { 0,252, 0}, { 0,252, 64},
102 { 0,252,124}, { 0,252,188},
103 { 0,252,252}, { 0,188,252},
104 { 0,124,252}, { 0, 64,252},
105 {124,124,252}, {156,124,252},
106 {188,124,252}, {220,124,252},
107 {252,124,252}, {252,124,220},
108 {252,124,188}, {252,124,156}, /*64*/
109 {252,124,124}, {252,156,124},
110 {252,188,124}, {252,220,124},
111 {252,252,124}, {220,252,124},
112 {188,252,124}, {156,252,124},
113 {124,252,124}, {124,252,156},
114 {124,252,188}, {124,252,220},
115 {124,252,252}, {124,220,252},
116 {124,188,252}, {124,156,252}, /*80*/
117 {180,180,252}, {196,180,252},
118 {216,180,252}, {232,180,252},
119 {252,180,252}, {252,180,232},
120 {252,180,216}, {252,180,196},
121 {252,180,180}, {252,196,180},
122 {252,216,180}, {252,232,180},
123 {252,252,180}, {232,252,180},
124 {216,252,180}, {196,252,180}, /*96*/
125 {180,220,180}, {180,252,196},
126 {180,252,216}, {180,252,232},
127 {180,252,252}, {180,232,252},
128 {180,216,252}, {180,196,252},
129 {0,0,112}, {28,0,112},
130 {56,0,112}, {84,0,112},
131 {112,0,112}, {112,0,84},
132 {112,0,56}, {112,0,28}, /*112*/
133 {112,0,0}, {112,28,0},
134 {112,56,0}, {112,84,0},
135 {112,112,0}, {84,112,0},
136 {56,112,0}, {28,112,0},
137 {0,112,0}, {0,112,28},
138 {0,112,56}, {0,112,84},
139 {0,112,112}, {0,84,112},
140 {0,56,112}, {0,28,112}, /*128*/
141 {56,56,112}, {68,56,112},
142 {84,56,112}, {96,56,112},
143 {112,56,112}, {112,56,96},
144 {112,56,84}, {112,56,68},
145 {112,56,56}, {112,68,56},
146 {112,84,56}, {112,96,56},
147 {112,112,56}, {96,112,56},
148 {84,112,56}, {68,112,56}, /*144*/
149 {56,112,56}, {56,112,69},
150 {56,112,84}, {56,112,96},
151 {56,112,112}, {56,96,112},
152 {56,84,112}, {56,68,112},
153 {80,80,112}, {88,80,112},
154 {96,80,112}, {104,80,112},
155 {112,80,112}, {112,80,104},
156 {112,80,96}, {112,80,88}, /*160*/
157 {112,80,80}, {112,88,80},
158 {112,96,80}, {112,104,80},
159 {112,112,80}, {104,112,80},
160 {96,112,80}, {88,112,80},
161 {80,112,80}, {80,112,88},
162 {80,112,96}, {80,112,104},
163 {80,112,112}, {80,114,112},
164 {80,96,112}, {80,88,112}, /*176*/
166 {32,0,64}, {48,0,64},
167 {64,0,64}, {64,0,48},
168 {64,0,32}, {64,0,16},
170 {64,32,0}, {64,48,0},
171 {64,64,0}, {48,64,0},
172 {32,64,0}, {16,64,0}, /*192*/
174 {0,64,32}, {0,64,48},
175 {0,64,64}, {0,48,64},
176 {0,32,64}, {0,16,64},
177 {32,32,64}, {40,32,64},
178 {48,32,64}, {56,32,64},
179 {64,32,64}, {64,32,56},
180 {64,32,48}, {64,32,40}, /*208*/
181 {64,32,32}, {64,40,32},
182 {64,48,32}, {64,56,32},
183 {64,64,32}, {56,64,32},
184 {48,64,32}, {40,64,32},
185 {32,64,32}, {32,64,40},
186 {32,64,48}, {32,64,56},
187 {32,64,64}, {32,56,64},
188 {32,48,64}, {32,40,64}, /*224*/
189 {44,44,64}, {48,44,64},
190 {52,44,64}, {60,44,64},
191 {64,44,64}, {64,44,60},
192 {64,44,52}, {64,44,48},
193 {64,44,44}, {64,48,44},
194 {64,52,44}, {64,60,44},
195 {64,64,44}, {60,64,44},
196 {52,64,44}, {48,64,44}, /*240*/
197 {44,64,44}, {44,64,48},
198 {44,64,52}, {44,64,60},
199 {44,64,64}, {44,60,64},
200 {44,55,64}, {44,48,64},
204 {0,0,0}, {0,0,0} /*256*/
208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218 % IsWPG() returns True if the image format type, identified by the magick
221 % The format of the IsWPG method is:
223 % unsigned int IsWPG(const unsigned char *magick,const size_t length)
225 % A description of each parameter follows:
227 % o status: Method IsWPG returns True if the image format type is WPG.
229 % o magick: compare image format pattern against these bytes.
231 % o length: Specifies the length of the magick string.
234 static unsigned int IsWPG(const unsigned char *magick,const size_t length)
238 if (memcmp(magick,"\377WPC",4) == 0)
244 static void Rd_WP_DWORD(Image *image,size_t *d)
249 b=ReadBlobByte(image);
253 b=ReadBlobByte(image);
255 b=ReadBlobByte(image);
259 *d=(*d & 0x7FFF) << 16;
260 b=ReadBlobByte(image);
262 b=ReadBlobByte(image);
267 static MagickBooleanType InsertRow(Image *image,unsigned char *p,ssize_t y,
268 int bpp,ExceptionInfo *exception)
282 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
283 if (q == (Quantum *) NULL)
287 case 1: /* Convert bitmap scanline. */
289 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
291 for (bit=0; bit < 8; bit++)
293 index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
294 SetPixelIndex(image,index,q);
295 if (index < image->colors)
296 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
297 q+=GetPixelChannels(image);
301 if ((image->columns % 8) != 0)
303 for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
305 index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
306 SetPixelIndex(image,index,q);
307 if (index < image->colors)
308 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
309 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
310 q+=GetPixelChannels(image);
316 case 2: /* Convert PseudoColor scanline. */
318 for (x=0; x < ((ssize_t) image->columns-3); x+=4)
320 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
321 SetPixelIndex(image,index,q);
322 if (index < image->colors)
323 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
324 q+=GetPixelChannels(image);
325 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
326 SetPixelIndex(image,index,q);
327 if (index < image->colors)
328 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
329 q+=GetPixelChannels(image);
330 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,exception);
331 SetPixelIndex(image,index,q);
332 if (index < image->colors)
333 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
334 q+=GetPixelChannels(image);
335 index=ConstrainColormapIndex(image,(*p) & 0x3,exception);
336 SetPixelIndex(image,index,q);
337 if (index < image->colors)
338 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
339 q+=GetPixelChannels(image);
342 if ((image->columns % 4) != 0)
344 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
345 SetPixelIndex(image,index,q);
346 if (index < image->colors)
347 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
348 q+=GetPixelChannels(image);
349 if ((image->columns % 4) > 1)
351 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
352 SetPixelIndex(image,index,q);
353 if (index < image->colors)
354 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
355 q+=GetPixelChannels(image);
356 if ((image->columns % 4) > 2)
358 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,
360 SetPixelIndex(image,index,q);
361 if (index < image->colors)
362 SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
364 q+=GetPixelChannels(image);
372 case 4: /* Convert PseudoColor scanline. */
374 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
376 index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
377 SetPixelIndex(image,index,q);
378 if (index < image->colors)
379 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
380 q+=GetPixelChannels(image);
381 index=ConstrainColormapIndex(image,(*p) & 0x0f,exception);
382 SetPixelIndex(image,index,q);
383 if (index < image->colors)
384 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
386 q+=GetPixelChannels(image);
388 if ((image->columns % 2) != 0)
390 index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
391 SetPixelIndex(image,index,q);
392 if (index < image->colors)
393 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
395 q+=GetPixelChannels(image);
399 case 8: /* Convert PseudoColor scanline. */
401 for (x=0; x < (ssize_t) image->columns; x++)
403 index=ConstrainColormapIndex(image,*p,exception);
404 SetPixelIndex(image,index,q);
405 if (index < image->colors)
406 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
408 q+=GetPixelChannels(image);
413 case 24: /* Convert DirectColor scanline. */
414 for (x=0; x < (ssize_t) image->columns; x++)
416 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
417 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
418 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
419 q+=GetPixelChannels(image);
423 if (!SyncAuthenticPixels(image,exception))
429 /* Helper for WPG1 raster reader. */
430 #define InsertByte(b) \
434 if((ssize_t) x>=ldblk) \
436 if (InsertRow(image,BImgBuff,(ssize_t) y,bpp,exception) != MagickFalse) \
441 /* WPG1 raster reader. */
442 static int UnpackWPGRaster(Image *image,int bpp,ExceptionInfo *exception)
460 ldblk=(ssize_t) ((bpp*image->columns+7)/8);
461 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
462 8*sizeof(*BImgBuff));
463 if(BImgBuff==NULL) return(-2);
464 (void) memset(BImgBuff,0,(size_t) ldblk*8*sizeof(*BImgBuff));
466 while(y<(ssize_t) image->rows)
471 c=ReadBlobByte(image);
474 bbuf=(unsigned char) c;
475 RunCount=bbuf & 0x7F;
478 if(RunCount) /* repeat next byte runcount * */
480 bbuf=ReadBlobByte(image);
481 for(i=0;i<(int) RunCount;i++) InsertByte(bbuf);
483 else { /* read next byte as RunCount; repeat 0xFF runcount* */
484 c=ReadBlobByte(image);
487 RunCount=(unsigned char) c;
488 for(i=0;i<(int) RunCount;i++) InsertByte(0xFF);
492 if(RunCount) /* next runcount byte are readed directly */
494 for(i=0;i < (int) RunCount;i++)
496 c=ReadBlobByte(image);
502 else { /* repeat previous line runcount* */
503 c=ReadBlobByte(image);
506 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
509 RunCount=(unsigned char) c;
510 if(x) { /* attempt to duplicate row from x position: */
511 /* I do not know what to do here */
512 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
515 for(i=0;i < (int) RunCount;i++)
518 y++; /* Here I need to duplicate previous row RUNCOUNT* */
520 if(y>(ssize_t) image->rows)
522 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
525 if (InsertRow(image,BImgBuff,y-1,bpp,exception) == MagickFalse)
527 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
533 if (EOFBlob(image) != MagickFalse)
536 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
537 return(y <(ssize_t) image->rows ? -5 : 0);
541 /* Helper for WPG2 reader. */
542 #define InsertByte6(b) \
544 DisableMSCWarning(4310) \
546 BImgBuff[x] = (unsigned char)~b;\
551 if((ssize_t) x >= ldblk) \
553 if (InsertRow(image,BImgBuff,(ssize_t) y,bpp,exception) != MagickFalse) \
558 /* WPG2 raster reader. */
559 static int UnpackWPG2Raster(Image *image,int bpp,ExceptionInfo *exception)
579 SampleBuffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
583 ldblk=(ssize_t) ((bpp*image->columns+7)/8);
584 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
588 (void) memset(BImgBuff,0,ldblk*sizeof(*BImgBuff));
590 while( y< image->rows)
592 bbuf=ReadBlobByte(image);
597 SampleSize=ReadBlobByte(image); /* DSZ */
600 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
605 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
611 (void) FormatLocaleFile(stderr,
612 "\nUnsupported WPG token XOR, please report!");
616 RunCount=ReadBlobByte(image); /* BLK */
619 for(i=0; i < SampleSize*(RunCount+1); i++)
625 RunCount=ReadBlobByte(image); /* EXT */
628 for(i=0; i<= RunCount;i++)
629 for(bbuf=0; bbuf < SampleSize; bbuf++)
630 InsertByte6(SampleBuffer[bbuf]);
633 RunCount=ReadBlobByte(image); /* RST */
638 (void) FormatLocaleFile(stderr,
639 "\nUnsupported WPG2 unaligned token RST x=%.20g, please report!\n"
641 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
645 /* duplicate the previous row RunCount x */
646 for(i=0;i<=RunCount;i++)
648 if (InsertRow(image,BImgBuff,(ssize_t) (image->rows > y ? y : image->rows-1),bpp,exception) != MagickFalse)
654 RunCount=ReadBlobByte(image); /* WHT */
657 for(i=0; i < SampleSize*(RunCount+1); i++)
663 RunCount=bbuf & 0x7F;
665 if(bbuf & 0x80) /* REP */
667 for(i=0; i < SampleSize; i++)
668 SampleBuffer[i]=ReadBlobByte(image);
669 for(i=0;i<=RunCount;i++)
670 for(bbuf=0;bbuf<SampleSize;bbuf++)
671 InsertByte6(SampleBuffer[bbuf]);
674 for(i=0; i< SampleSize*(RunCount+1);i++)
676 bbuf=ReadBlobByte(image);
681 if (EOFBlob(image) != MagickFalse)
684 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
689 typedef float tCTM[3][3];
691 static unsigned LoadWPG2Flags(Image *image,char Precision,float *Angle,tCTM *CTM)
693 const unsigned char TPR=1,TRN=2,SKW=4,SCL=8,ROT=0x10,OID=0x20,LCK=0x80;
698 (void) memset(*CTM,0,sizeof(*CTM)); /*CTM.erase();CTM.resize(3,3);*/
703 Flags=ReadBlobLSBShort(image);
704 if(Flags & LCK) (void) ReadBlobLSBLong(image); /*Edit lock*/
708 {(void) ReadBlobLSBShort(image);} /*ObjectID*/
710 {(void) ReadBlobLSBLong(image);} /*ObjectID (Double precision)*/
714 x=ReadBlobLSBLong(image); /*Rot Angle*/
715 if(Angle) *Angle=x/65536.0;
717 if(Flags & (ROT|SCL))
719 x=ReadBlobLSBLong(image); /*Sx*cos()*/
720 (*CTM)[0][0] = (float)x/0x10000;
721 x=ReadBlobLSBLong(image); /*Sy*cos()*/
722 (*CTM)[1][1] = (float)x/0x10000;
724 if(Flags & (ROT|SKW))
726 x=ReadBlobLSBLong(image); /*Kx*sin()*/
727 (*CTM)[1][0] = (float)x/0x10000;
728 x=ReadBlobLSBLong(image); /*Ky*sin()*/
729 (*CTM)[0][1] = (float)x/0x10000;
733 x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Tx*/
734 if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
735 else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
736 x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Ty*/
737 (*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
738 if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
739 else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
743 x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Px*/
744 (*CTM)[2][0] = x + (float)DenX/0x10000;;
745 x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Py*/
746 (*CTM)[2][1] = x + (float)DenX/0x10000;
752 static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
753 MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo *exception)
756 postscript_file[MagickPathExtent];
777 magick[2*MagickPathExtent];
782 if ((clone_info=CloneImageInfo(image_info)) == NULL)
784 clone_info->blob=(void *) NULL;
785 clone_info->length=0;
788 /* Obtain temporary file */
789 (void) AcquireUniqueFilename(postscript_file);
790 ps_file=fopen_utf8(postscript_file,"wb");
791 if (ps_file == (FILE *) NULL)
794 /* Copy postscript to temporary file */
795 if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
797 (void) fclose(ps_file);
798 ThrowException(exception,CorruptImageError,"ImproperImageHeader",
802 count=ReadBlob(image, 2*MagickPathExtent, magick);
805 (void) fclose(ps_file);
806 ThrowException(exception,CorruptImageError,"ImproperImageHeader",
811 if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
813 (void) fclose(ps_file);
814 ThrowException(exception,CorruptImageError,"ImproperImageHeader",
818 while (PS_Size-- > 0)
820 c=ReadBlobByte(image);
823 (void) fclose(ps_file);
824 ThrowException(exception,CorruptImageError,"ImproperImageHeader",
828 (void) fputc(c,ps_file);
830 (void) fclose(ps_file);
832 /* Detect file format - Check magic.mgk configuration file. */
833 magic_info=GetMagicInfo(magick,count,exception);
834 if(magic_info == (const MagicInfo *) NULL) goto FINISH_UNL;
835 /* printf("Detected:%s \n",magic_info->name); */
836 if(exception->severity != UndefinedException) goto FINISH_UNL;
837 if(magic_info->name == (char *) NULL) goto FINISH_UNL;
838 (void) strncpy(clone_info->magick,magic_info->name,MagickPathExtent-1);
839 if (LocaleCompare(clone_info->magick,"PFB") != 0)
841 ThrowException(exception,CorruptImageError,"ImproperImageHeader",
846 /* Read nested image */
847 /*FormatString(clone_info->filename,"%s:%s",magic_info->name,postscript_file);*/
848 FormatLocaleString(clone_info->filename,MagickPathExtent,"%.1024s:%.1024s",
849 clone_info->magick,postscript_file);
850 image2=ReadImage(clone_info,exception);
854 if(exception->severity>=ErrorException)
857 DestroyImageList(image2);
866 Replace current image with new image while copying base image attributes.
871 (void) CopyMagickString(p->filename,image->filename,MagickPathExtent);
872 (void) CopyMagickString(p->magick_filename,image->magick_filename,
874 (void) CopyMagickString(p->magick,image->magick,MagickPathExtent);
875 if ((p->rows == 0) || (p->columns == 0))
877 DeleteImageFromList(&p);
878 if (p == (Image *) NULL)
880 image2=(Image *) NULL;
887 p->blob=ReferenceBlob(image->blob);
890 } while (p != (Image *) NULL);
893 if ((image->rows == 0 || image->columns == 0) &&
894 (image->previous != NULL || image->next != NULL))
896 DeleteImageFromList(&image);
899 AppendImageToList(&image,image2);
900 while (image->next != NULL)
905 (void) RelinquishUniqueFileResource(postscript_file);
907 DestroyImageInfo(clone_info);
908 if (status == MagickFalse)
909 return(DestroyImageList(image));
914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
918 % R e a d W P G I m a g e %
922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
924 % Method ReadWPGImage reads an WPG X image file and returns it. It
925 % allocates the memory necessary for the new Image structure and returns a
926 % pointer to the new image.
928 % The format of the ReadWPGImage method is:
930 % Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
932 % A description of each parameter follows:
934 % o image: Method ReadWPGImage returns a pointer to the image after
935 % reading. A null image is returned if there is a memory shortage or if
936 % the image cannot be read.
938 % o image_info: Specifies a pointer to a ImageInfo structure.
940 % o exception: return any errors or warnings in this structure.
943 static Image *ReadWPGImage(const ImageInfo *image_info,
944 ExceptionInfo *exception)
949 MagickOffsetType DataOffset;
950 unsigned int ProductType;
951 unsigned int FileType;
952 unsigned char MajorVersion;
953 unsigned char MinorVersion;
954 unsigned int EncryptKey;
955 unsigned int Reserved;
960 unsigned char RecType;
967 unsigned char RecType;
974 unsigned HorizontalUnits;
975 unsigned VerticalUnits;
976 unsigned char PosSizePrecision;
984 unsigned int HorzRes;
985 unsigned int VertRes;
993 unsigned char Compression;
998 unsigned int RotAngle;
999 unsigned int LowLeftX;
1000 unsigned int LowLeftY;
1001 unsigned int UpRightX;
1002 unsigned int UpRightY;
1004 unsigned int Height;
1006 unsigned int HorzRes;
1007 unsigned int VertRes;
1012 unsigned int StartIndex;
1013 unsigned int NumOfEntries;
1019 unsigned int PS_unknown2;
1020 unsigned int PS_unknown3;
1067 tCTM CTM; /*current transform matrix*/
1072 assert(image_info != (const ImageInfo *) NULL);
1073 assert(image_info->signature == MagickCoreSignature);
1074 assert(exception != (ExceptionInfo *) NULL);
1075 assert(exception->signature == MagickCoreSignature);
1077 image=AcquireImage(image_info,exception);
1079 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1080 if (status == MagickFalse)
1082 image=DestroyImageList(image);
1083 return((Image *) NULL);
1088 Header.FileId=ReadBlobLSBLong(image);
1089 Header.DataOffset=(MagickOffsetType) ReadBlobLSBLong(image);
1090 Header.ProductType=ReadBlobLSBShort(image);
1091 Header.FileType=ReadBlobLSBShort(image);
1092 Header.MajorVersion=ReadBlobByte(image);
1093 Header.MinorVersion=ReadBlobByte(image);
1094 Header.EncryptKey=ReadBlobLSBShort(image);
1095 Header.Reserved=ReadBlobLSBShort(image);
1097 if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
1098 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1099 if (Header.EncryptKey!=0)
1100 ThrowReaderException(CoderError,"EncryptedWPGImageFileNotSupported");
1105 (void) ResetImagePixels(image,exception);
1107 BitmapHeader2.RotAngle=0;
1108 Rec2.RecordLength=0;
1110 switch(Header.FileType)
1112 case 1: /* WPG level 1 */
1113 while(!EOFBlob(image)) /* object parser loop */
1115 if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1120 Rec.RecType=(i=ReadBlobByte(image));
1123 Rd_WP_DWORD(image,&Rec.RecordLength);
1124 if (Rec.RecordLength > GetBlobSize(image))
1125 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1129 Header.DataOffset=TellBlob(image)+Rec.RecordLength;
1133 case 0x0B: /* bitmap type 1 */
1134 BitmapHeader1.Width=ReadBlobLSBShort(image);
1135 BitmapHeader1.Height=ReadBlobLSBShort(image);
1136 if ((BitmapHeader1.Width == 0) || (BitmapHeader1.Height == 0))
1137 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1138 BitmapHeader1.Depth=ReadBlobLSBShort(image);
1139 BitmapHeader1.HorzRes=ReadBlobLSBShort(image);
1140 BitmapHeader1.VertRes=ReadBlobLSBShort(image);
1142 if(BitmapHeader1.HorzRes && BitmapHeader1.VertRes)
1144 image->units=PixelsPerCentimeterResolution;
1145 image->resolution.x=BitmapHeader1.HorzRes/470.0;
1146 image->resolution.y=BitmapHeader1.VertRes/470.0;
1148 image->columns=BitmapHeader1.Width;
1149 image->rows=BitmapHeader1.Height;
1150 bpp=BitmapHeader1.Depth;
1154 case 0x0E: /*Color palette */
1155 WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1156 WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1157 if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
1158 (Rec2.RecordLength-2-2)/3)
1159 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1160 if (WPG_Palette.StartIndex > WPG_Palette.NumOfEntries)
1161 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1162 image->colors=WPG_Palette.NumOfEntries;
1163 if (!AcquireImageColormap(image,image->colors,exception))
1165 for (i=WPG_Palette.StartIndex;
1166 i < (int)WPG_Palette.NumOfEntries; i++)
1168 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1169 ReadBlobByte(image));
1170 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1171 ReadBlobByte(image));
1172 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1173 ReadBlobByte(image));
1177 case 0x11: /* Start PS l1 */
1178 if (Rec.RecordLength > 8)
1180 image=ExtractPostscript(image,image_info,
1181 TellBlob(image)+8, /* skip PS header in the wpg */
1182 (ssize_t) Rec.RecordLength-8,exception);
1184 ThrowReaderException(CorruptImageError,
1185 "ImproperImageHeader");
1189 case 0x14: /* bitmap type 2 */
1190 BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
1191 BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
1192 BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
1193 BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
1194 BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
1195 BitmapHeader2.Width=ReadBlobLSBShort(image);
1196 BitmapHeader2.Height=ReadBlobLSBShort(image);
1197 if ((BitmapHeader2.Width == 0) || (BitmapHeader2.Height == 0))
1198 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1199 BitmapHeader2.Depth=ReadBlobLSBShort(image);
1200 BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
1201 BitmapHeader2.VertRes=ReadBlobLSBShort(image);
1203 image->units=PixelsPerCentimeterResolution;
1204 image->page.width=(unsigned int)
1205 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
1206 image->page.height=(unsigned int)
1207 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
1208 image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
1209 image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
1210 if(BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
1212 image->resolution.x=BitmapHeader2.HorzRes/470.0;
1213 image->resolution.y=BitmapHeader2.VertRes/470.0;
1215 image->columns=BitmapHeader2.Width;
1216 image->rows=BitmapHeader2.Height;
1217 bpp=BitmapHeader2.Depth;
1220 status=SetImageExtent(image,image->columns,image->rows,exception);
1221 if (status == MagickFalse)
1223 (void) ResetImagePixels(image,exception);
1224 if ((image->storage_class != PseudoClass) && (bpp < 24))
1226 image->colors=one << bpp;
1227 if (image->colors > GetBlobSize(image))
1228 ThrowReaderException(CorruptImageError,
1229 "InsufficientImageDataInFile");
1230 if (!AcquireImageColormap(image,image->colors,exception))
1233 ThrowReaderException(ResourceLimitError,
1234 "MemoryAllocationFailed");
1236 /* printf("Load default colormap \n"); */
1237 for (i=0; (i < (int) image->colors) && (i < 256); i++)
1239 image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
1240 image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
1241 image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
1242 image->colormap[i].alpha=OpaqueAlpha;
1248 if ( (image->colors < (one << bpp)) && (bpp != 24) )
1249 image->colormap=(PixelInfo *) ResizeQuantumMemory(
1250 image->colormap,(size_t) (one << bpp),
1251 sizeof(*image->colormap));
1254 if ((bpp == 1) && (image->colors > 1))
1256 if(image->colormap[0].red==0 &&
1257 image->colormap[0].green==0 &&
1258 image->colormap[0].blue==0 &&
1259 image->colormap[1].red==0 &&
1260 image->colormap[1].green==0 &&
1261 image->colormap[1].blue==0)
1262 { /* fix crippled monochrome palette */
1263 image->colormap[1].red =
1264 image->colormap[1].green =
1265 image->colormap[1].blue = QuantumRange;
1266 image->colormap[1].alpha=OpaqueAlpha;
1269 if(!image_info->ping)
1270 if(UnpackWPGRaster(image,bpp,exception) < 0)
1271 /* The raster cannot be unpacked */
1273 DecompressionFailed:
1274 ThrowReaderException(CoderError,"UnableToDecompressImage");
1277 if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1280 if(BitmapHeader2.RotAngle & 0x8000)
1285 flop_image = FlopImage(image, exception);
1286 if (flop_image != (Image *) NULL) {
1287 DuplicateBlob(flop_image,image);
1288 ReplaceImageInList(&image,flop_image);
1292 if(BitmapHeader2.RotAngle & 0x2000)
1297 flip_image = FlipImage(image, exception);
1298 if (flip_image != (Image *) NULL) {
1299 DuplicateBlob(flip_image,image);
1300 ReplaceImageInList(&image,flip_image);
1303 /* rotate command */
1304 if(BitmapHeader2.RotAngle & 0x0FFF)
1309 rotate_image=RotateImage(image,(BitmapHeader2.RotAngle &
1310 0x0FFF), exception);
1311 if (rotate_image != (Image *) NULL) {
1312 DuplicateBlob(rotate_image,image);
1313 ReplaceImageInList(&image,rotate_image);
1318 /* Allocate next image structure. */
1319 AcquireNextImage(image_info,image,exception);
1321 if (image->next == (Image *) NULL)
1323 image=SyncNextImageInList(image);
1324 image->columns=image->rows=0;
1328 case 0x1B: /* Postscript l2 */
1329 if (Rec.RecordLength>0x3C)
1331 image=ExtractPostscript(image,image_info,
1332 TellBlob(image)+0x3C, /* skip PS l2 header in the wpg */
1333 (ssize_t) Rec.RecordLength-0x3C,exception);
1335 ThrowReaderException(CorruptImageError,
1336 "ImproperImageHeader");
1343 case 2: /* WPG level 2 */
1344 (void) memset(CTM,0,sizeof(CTM));
1345 StartWPG.PosSizePrecision = 0;
1346 while(!EOFBlob(image)) /* object parser loop */
1348 if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1353 Rec2.Class=(i=ReadBlobByte(image));
1356 Rec2.RecType=(i=ReadBlobByte(image));
1359 Rd_WP_DWORD(image,&Rec2.Extension);
1360 Rd_WP_DWORD(image,&Rec2.RecordLength);
1364 Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1366 switch(Rec2.RecType)
1369 StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1370 StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1371 StartWPG.PosSizePrecision=ReadBlobByte(image);
1373 case 0x0C: /* Color palette */
1374 WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1375 WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1376 if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
1377 (Rec2.RecordLength-2-2) / 3)
1378 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1379 if (WPG_Palette.StartIndex >= WPG_Palette.NumOfEntries)
1380 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1381 image->colors=WPG_Palette.NumOfEntries;
1382 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1383 ThrowReaderException(ResourceLimitError,
1384 "MemoryAllocationFailed");
1385 for (i=WPG_Palette.StartIndex;
1386 i < (int)WPG_Palette.NumOfEntries; i++)
1388 image->colormap[i].red=ScaleCharToQuantum((char)
1389 ReadBlobByte(image));
1390 image->colormap[i].green=ScaleCharToQuantum((char)
1391 ReadBlobByte(image));
1392 image->colormap[i].blue=ScaleCharToQuantum((char)
1393 ReadBlobByte(image));
1394 image->colormap[i].alpha=OpaqueAlpha;
1395 (void) ReadBlobByte(image); /*Opacity??*/
1399 Bitmap2Header1.Width=ReadBlobLSBShort(image);
1400 Bitmap2Header1.Height=ReadBlobLSBShort(image);
1401 if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Height == 0))
1402 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1403 Bitmap2Header1.Depth=ReadBlobByte(image);
1404 Bitmap2Header1.Compression=ReadBlobByte(image);
1406 if(Bitmap2Header1.Compression > 1)
1407 continue; /*Unknown compression method */
1408 switch(Bitmap2Header1.Depth)
1426 continue; /*Ignore raster with unknown depth*/
1428 image->columns=Bitmap2Header1.Width;
1429 image->rows=Bitmap2Header1.Height;
1430 if (image_info->ping != MagickFalse)
1432 status=SetImageExtent(image,image->columns,image->rows,exception);
1433 if (status != MagickFalse)
1434 status=ResetImagePixels(image,exception);
1435 if (status == MagickFalse)
1437 if ((image->colors == 0) && (bpp != 24))
1439 image->colors=one << bpp;
1440 if (!AcquireImageColormap(image,image->colors,exception))
1446 if( image->colors<(one << bpp) && bpp!=24 )
1447 image->colormap=(PixelInfo *) ResizeQuantumMemory(
1448 image->colormap,(size_t) (one << bpp),
1449 sizeof(*image->colormap));
1453 switch(Bitmap2Header1.Compression)
1455 case 0: /*Uncompressed raster*/
1457 ldblk=(ssize_t) ((bpp*image->columns+7)/8);
1458 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t)
1459 ldblk+1,sizeof(*BImgBuff));
1460 if (BImgBuff == (unsigned char *) NULL)
1462 for (i=0; i< (ssize_t) image->rows; i++)
1467 count=ReadBlob(image,(size_t) ldblk,BImgBuff);
1470 if (InsertRow(image,BImgBuff,i,bpp,exception) == MagickFalse)
1473 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
1474 if (i < (ssize_t) image->rows)
1475 goto DecompressionFailed;
1478 case 1: /*RLE for WPG2 */
1480 if( UnpackWPG2Raster(image,bpp,exception) < 0)
1481 goto DecompressionFailed;
1486 if(CTM[0][0]<0 && !image_info->ping)
1487 { /*?? RotAngle=360-RotAngle;*/
1491 flop_image = FlopImage(image, exception);
1492 if (flop_image != (Image *) NULL) {
1493 DuplicateBlob(flop_image,image);
1494 ReplaceImageInList(&image,flop_image);
1496 /* Try to change CTM according to Flip - I am not sure, must be checked.
1497 Tx(0,0)=-1; Tx(1,0)=0; Tx(2,0)=0;
1498 Tx(0,1)= 0; Tx(1,1)=1; Tx(2,1)=0;
1499 Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1500 Tx(1,2)=0; Tx(2,2)=1; */
1502 if(CTM[1][1]<0 && !image_info->ping)
1503 { /*?? RotAngle=360-RotAngle;*/
1507 flip_image = FlipImage(image, exception);
1508 if (flip_image != (Image *) NULL) {
1509 DuplicateBlob(flip_image,image);
1510 ReplaceImageInList(&image,flip_image);
1512 /* Try to change CTM according to Flip - I am not sure, must be checked.
1513 float_matrix Tx(3,3);
1514 Tx(0,0)= 1; Tx(1,0)= 0; Tx(2,0)=0;
1515 Tx(0,1)= 0; Tx(1,1)=-1; Tx(2,1)=0;
1516 Tx(0,2)= 0; Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1521 /* Allocate next image structure. */
1522 AcquireNextImage(image_info,image,exception);
1524 if (image->next == (Image *) NULL)
1526 image=SyncNextImageInList(image);
1527 image->columns=image->rows=0;
1531 case 0x12: /* Postscript WPG2*/
1532 i=ReadBlobLSBShort(image);
1533 if (Rec2.RecordLength > (unsigned int) i)
1535 image=ExtractPostscript(image,image_info,
1536 TellBlob(image)+i, /*skip PS header in the wpg2*/
1537 (ssize_t) (Rec2.RecordLength-i-2),exception);
1539 ThrowReaderException(CorruptImageError,
1540 "ImproperImageHeader");
1544 case 0x1B: /*bitmap rectangle*/
1545 WPG2Flags = LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM);
1555 ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
1560 (void) CloseBlob(image);
1570 Rewind list, removing any empty images while rewinding.
1574 while (p != (Image *) NULL)
1577 if ((p->rows == 0) || (p->columns == 0)) {
1579 DeleteImageFromList(&tmp);
1588 for (p=image; p != (Image *) NULL; p=p->next)
1589 p->scene=(size_t) scene++;
1591 if (image == (Image *) NULL)
1592 ThrowReaderException(CorruptImageError,
1593 "ImageFileDoesNotContainAnyImageData");
1598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602 % R e g i s t e r W P G I m a g e %
1606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1608 % Method RegisterWPGImage adds attributes for the WPG image format to
1609 % the list of supported formats. The attributes include the image format
1610 % tag, a method to read and/or write the format, whether the format
1611 % supports the saving of more than one frame to the same file or blob,
1612 % whether the format supports native in-memory I/O, and a brief
1613 % description of the format.
1615 % The format of the RegisterWPGImage method is:
1617 % size_t RegisterWPGImage(void)
1620 ModuleExport size_t RegisterWPGImage(void)
1625 entry=AcquireMagickInfo("WPG","WPG","Word Perfect Graphics");
1626 entry->decoder=(DecodeImageHandler *) ReadWPGImage;
1627 entry->magick=(IsImageFormatHandler *) IsWPG;
1628 entry->flags|=CoderDecoderSeekableStreamFlag;
1629 (void) RegisterMagickInfo(entry);
1630 return(MagickImageCoderSignature);
1634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638 % U n r e g i s t e r W P G I m a g e %
1642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1644 % Method UnregisterWPGImage removes format registrations made by the
1645 % WPG module from the list of supported formats.
1647 % The format of the UnregisterWPGImage method is:
1649 % UnregisterWPGImage(void)
1652 ModuleExport void UnregisterWPGImage(void)
1654 (void) UnregisterMagickInfo("WPG");