2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12 % Read WordPerfect Image Format %
19 % Copyright 1999-2010 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 % http://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 "magick/studio.h"
42 #include "magick/blob.h"
43 #include "magick/blob-private.h"
44 #include "magick/color-private.h"
45 #include "magick/colormap.h"
46 #include "magick/colormap-private.h"
47 #include "magick/constitute.h"
48 #include "magick/exception.h"
49 #include "magick/exception-private.h"
50 #include "magick/cache.h"
51 #include "magick/image.h"
52 #include "magick/image-private.h"
53 #include "magick/list.h"
54 #include "magick/magic.h"
55 #include "magick/magick.h"
56 #include "magick/memory_.h"
57 #include "magick/resource_.h"
58 #include "magick/quantum-private.h"
59 #include "magick/shear.h"
60 #include "magick/static.h"
61 #include "magick/string_.h"
62 #include "magick/module.h"
63 #include "magick/transform.h"
64 #include "magick/utility.h"
73 /* Default palette for WPG level 1 */
74 const RGB_Record WPG1_Palette[256]={
75 { 0, 0, 0}, { 0, 0,168},
76 { 0,168, 0}, { 0,168,168},
77 {168, 0, 0}, {168, 0,168},
78 {168, 84, 0}, {168,168,168},
79 { 84, 84, 84}, { 84, 84,252},
80 { 84,252, 84}, { 84,252,252},
81 {252, 84, 84}, {252, 84,252},
82 {252,252, 84}, {252,252,252}, /*16*/
83 { 0, 0, 0}, { 20, 20, 20},
84 { 32, 32, 32}, { 44, 44, 44},
85 { 56, 56, 56}, { 68, 68, 68},
86 { 80, 80, 80}, { 96, 96, 96},
87 {112,112,112}, {128,128,128},
88 {144,144,144}, {160,160,160},
89 {180,180,180}, {200,200,200},
90 {224,224,224}, {252,252,252}, /*32*/
91 { 0, 0,252}, { 64, 0,252},
92 {124, 0,252}, {188, 0,252},
93 {252, 0,252}, {252, 0,188},
94 {252, 0,124}, {252, 0, 64},
95 {252, 0, 0}, {252, 64, 0},
96 {252,124, 0}, {252,188, 0},
97 {252,252, 0}, {188,252, 0},
98 {124,252, 0}, { 64,252, 0}, /*48*/
99 { 0,252, 0}, { 0,252, 64},
100 { 0,252,124}, { 0,252,188},
101 { 0,252,252}, { 0,188,252},
102 { 0,124,252}, { 0, 64,252},
103 {124,124,252}, {156,124,252},
104 {188,124,252}, {220,124,252},
105 {252,124,252}, {252,124,220},
106 {252,124,188}, {252,124,156}, /*64*/
107 {252,124,124}, {252,156,124},
108 {252,188,124}, {252,220,124},
109 {252,252,124}, {220,252,124},
110 {188,252,124}, {156,252,124},
111 {124,252,124}, {124,252,156},
112 {124,252,188}, {124,252,220},
113 {124,252,252}, {124,220,252},
114 {124,188,252}, {124,156,252}, /*80*/
115 {180,180,252}, {196,180,252},
116 {216,180,252}, {232,180,252},
117 {252,180,252}, {252,180,232},
118 {252,180,216}, {252,180,196},
119 {252,180,180}, {252,196,180},
120 {252,216,180}, {252,232,180},
121 {252,252,180}, {232,252,180},
122 {216,252,180}, {196,252,180}, /*96*/
123 {180,220,180}, {180,252,196},
124 {180,252,216}, {180,252,232},
125 {180,252,252}, {180,232,252},
126 {180,216,252}, {180,196,252},
127 {0,0,112}, {28,0,112},
128 {56,0,112}, {84,0,112},
129 {112,0,112}, {112,0,84},
130 {112,0,56}, {112,0,28}, /*112*/
131 {112,0,0}, {112,28,0},
132 {112,56,0}, {112,84,0},
133 {112,112,0}, {84,112,0},
134 {56,112,0}, {28,112,0},
135 {0,112,0}, {0,112,28},
136 {0,112,56}, {0,112,84},
137 {0,112,112}, {0,84,112},
138 {0,56,112}, {0,28,112}, /*128*/
139 {56,56,112}, {68,56,112},
140 {84,56,112}, {96,56,112},
141 {112,56,112}, {112,56,96},
142 {112,56,84}, {112,56,68},
143 {112,56,56}, {112,68,56},
144 {112,84,56}, {112,96,56},
145 {112,112,56}, {96,112,56},
146 {84,112,56}, {68,112,56}, /*144*/
147 {56,112,56}, {56,112,69},
148 {56,112,84}, {56,112,96},
149 {56,112,112}, {56,96,112},
150 {56,84,112}, {56,68,112},
151 {80,80,112}, {88,80,112},
152 {96,80,112}, {104,80,112},
153 {112,80,112}, {112,80,104},
154 {112,80,96}, {112,80,88}, /*160*/
155 {112,80,80}, {112,88,80},
156 {112,96,80}, {112,104,80},
157 {112,112,80}, {104,112,80},
158 {96,112,80}, {88,112,80},
159 {80,112,80}, {80,112,88},
160 {80,112,96}, {80,112,104},
161 {80,112,112}, {80,114,112},
162 {80,96,112}, {80,88,112}, /*176*/
164 {32,0,64}, {48,0,64},
165 {64,0,64}, {64,0,48},
166 {64,0,32}, {64,0,16},
168 {64,32,0}, {64,48,0},
169 {64,64,0}, {48,64,0},
170 {32,64,0}, {16,64,0}, /*192*/
172 {0,64,32}, {0,64,48},
173 {0,64,64}, {0,48,64},
174 {0,32,64}, {0,16,64},
175 {32,32,64}, {40,32,64},
176 {48,32,64}, {56,32,64},
177 {64,32,64}, {64,32,56},
178 {64,32,48}, {64,32,40}, /*208*/
179 {64,32,32}, {64,40,32},
180 {64,48,32}, {64,56,32},
181 {64,64,32}, {56,64,32},
182 {48,64,32}, {40,64,32},
183 {32,64,32}, {32,64,40},
184 {32,64,48}, {32,64,56},
185 {32,64,64}, {32,56,64},
186 {32,48,64}, {32,40,64}, /*224*/
187 {44,44,64}, {48,44,64},
188 {52,44,64}, {60,44,64},
189 {64,44,64}, {64,44,60},
190 {64,44,52}, {64,44,48},
191 {64,44,44}, {64,48,44},
192 {64,52,44}, {64,60,44},
193 {64,64,44}, {60,64,44},
194 {52,64,44}, {48,64,44}, /*240*/
195 {44,64,44}, {44,64,48},
196 {44,64,52}, {44,64,60},
197 {44,64,64}, {44,60,64},
198 {44,55,64}, {44,48,64},
202 {0,0,0}, {0,0,0} /*256*/
206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216 % IsWPG() returns True if the image format type, identified by the magick
219 % The format of the IsWPG method is:
221 % unsigned int IsWPG(const unsigned char *magick,const size_t length)
223 % A description of each parameter follows:
225 % o status: Method IsWPG returns True if the image format type is WPG.
227 % o magick: compare image format pattern against these bytes.
229 % o length: Specifies the length of the magick string.
232 static unsigned int IsWPG(const unsigned char *magick,const size_t length)
236 if (memcmp(magick,"\377WPC",4) == 0)
242 static void Rd_WP_DWORD(Image *image,size_t *d)
247 b=ReadBlobByte(image);
251 b=ReadBlobByte(image);
253 b=ReadBlobByte(image);
257 *d=(*d & 0x7FFF) << 16;
258 b=ReadBlobByte(image);
260 b=ReadBlobByte(image);
265 static void InsertRow(unsigned char *p,ssize_t y,Image *image, int bpp)
285 exception=(&image->exception);
288 case 1: /* Convert bitmap scanline. */
290 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
291 if (q == (PixelPacket *) NULL)
293 indexes=GetAuthenticIndexQueue(image);
294 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
296 for (bit=0; bit < 8; bit++)
298 index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
299 indexes[x+bit]=index;
300 *q++=image->colormap[(int) index];
304 if ((image->columns % 8) != 0)
306 for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
308 index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
309 indexes[x+bit]=index;
310 *q++=image->colormap[(int) index];
314 if (!SyncAuthenticPixels(image,exception))
318 case 2: /* Convert PseudoColor scanline. */
320 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
321 if (q == (PixelPacket *) NULL)
323 indexes=GetAuthenticIndexQueue(image);
324 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
326 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3);
328 *q++=image->colormap[(ssize_t) index];
329 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3);
331 *q++=image->colormap[(ssize_t) index];
332 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3);
334 *q++=image->colormap[(ssize_t) index];
335 index=ConstrainColormapIndex(image,(*p) & 0x3);
337 *q++=image->colormap[(ssize_t) index];
340 if ((image->columns % 4) != 0)
342 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3);
344 *q++=image->colormap[(ssize_t) index];
345 if ((image->columns % 4) >= 1)
348 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3);
350 *q++=image->colormap[(ssize_t) index];
351 if ((image->columns % 4) >= 2)
354 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3);
356 *q++=image->colormap[(ssize_t) index];
361 if (SyncAuthenticPixels(image,exception) == MagickFalse)
366 case 4: /* Convert PseudoColor scanline. */
368 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
369 if (q == (PixelPacket *) NULL)
371 indexes=GetAuthenticIndexQueue(image);
372 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
374 index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f);
376 *q++=image->colormap[(ssize_t) index];
377 index=ConstrainColormapIndex(image,(*p) & 0x0f);
379 *q++=image->colormap[(ssize_t) index];
382 if ((image->columns % 2) != 0)
384 index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f);
386 *q++=image->colormap[(ssize_t) index];
389 if (SyncAuthenticPixels(image,exception) == MagickFalse)
393 case 8: /* Convert PseudoColor scanline. */
395 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
396 if (q == (PixelPacket *) NULL) break;
397 indexes=GetAuthenticIndexQueue(image);
399 for (x=0; x < (ssize_t) image->columns; x++)
401 index=ConstrainColormapIndex(image,*p);
403 *q++=image->colormap[(ssize_t) index];
406 if (SyncAuthenticPixels(image,exception) == MagickFalse)
411 case 24: /* Convert DirectColor scanline. */
412 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
413 if (q == (PixelPacket *) NULL)
415 for (x=0; x < (ssize_t) image->columns; x++)
417 q->red=ScaleCharToQuantum(*p++);
418 q->green=ScaleCharToQuantum(*p++);
419 q->blue=ScaleCharToQuantum(*p++);
422 if (!SyncAuthenticPixels(image,exception))
429 /* Helper for WPG1 raster reader. */
430 #define InsertByte(b) \
434 if((ssize_t) x>=ldblk) \
436 InsertRow(BImgBuff,(ssize_t) y,image,bpp); \
441 /* WPG1 raster reader. */
442 static int UnpackWPGRaster(Image *image,int bpp)
460 ldblk=(ssize_t) ((bpp*image->columns+7)/8);
461 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
463 if(BImgBuff==NULL) return(-2);
465 while(y<(ssize_t) image->rows)
467 bbuf=ReadBlobByte(image);
469 RunCount=bbuf & 0x7F;
472 if(RunCount) /* repeat next byte runcount * */
474 bbuf=ReadBlobByte(image);
475 for(i=0;i<(int) RunCount;i++) InsertByte(bbuf);
477 else { /* read next byte as RunCount; repeat 0xFF runcount* */
478 RunCount=ReadBlobByte(image);
479 for(i=0;i<(int) RunCount;i++) InsertByte(0xFF);
483 if(RunCount) /* next runcount byte are readed directly */
485 for(i=0;i < (int) RunCount;i++)
487 bbuf=ReadBlobByte(image);
491 else { /* repeat previous line runcount* */
492 RunCount=ReadBlobByte(image);
493 if(x) { /* attempt to duplicate row from x position: */
494 /* I do not know what to do here */
495 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
498 for(i=0;i < (int) RunCount;i++)
501 y++; /* Here I need to duplicate previous row RUNCOUNT* */
503 if(y>(ssize_t) image->rows)
505 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
508 InsertRow(BImgBuff,y-1,image,bpp);
513 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
518 /* Helper for WPG2 reader. */
519 #define InsertByte6(b) \
522 BImgBuff[x] = (unsigned char)~b;\
526 if((ssize_t) x >= ldblk) \
528 InsertRow(BImgBuff,(ssize_t) y,image,bpp); \
533 /* WPG2 raster reader. */
534 static int UnpackWPG2Raster(Image *image,int bpp)
559 ldblk=(ssize_t) ((bpp*image->columns+7)/8);
560 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
565 while( y< image->rows)
567 bbuf=ReadBlobByte(image);
572 SampleSize=ReadBlobByte(image); /* DSZ */
579 (void) fprintf(stderr,"\nUnsupported WPG token XOR, please report!");
583 RunCount=ReadBlobByte(image); /* BLK */
584 for(i=0; i < SampleSize*(RunCount+1); i++)
590 RunCount=ReadBlobByte(image); /* EXT */
591 for(i=0; i<= RunCount;i++)
592 for(bbuf=0; bbuf < SampleSize; bbuf++)
593 InsertByte6(SampleBuffer[bbuf]);
596 RunCount=ReadBlobByte(image); /* RST */
599 (void) fprintf(stderr,
600 "\nUnsupported WPG2 unaligned token RST x=%.20g, please report!\n"
605 /* duplicate the previous row RunCount x */
606 for(i=0;i<=RunCount;i++)
608 InsertRow(BImgBuff,(ssize_t) (image->rows >= y ? y : image->rows-1),
615 RunCount=ReadBlobByte(image); /* WHT */
616 for(i=0; i < SampleSize*(RunCount+1); i++)
622 RunCount=bbuf & 0x7F;
624 if(bbuf & 0x80) /* REP */
626 for(i=0; i < SampleSize; i++)
627 SampleBuffer[i]=ReadBlobByte(image);
628 for(i=0;i<=RunCount;i++)
629 for(bbuf=0;bbuf<SampleSize;bbuf++)
630 InsertByte6(SampleBuffer[bbuf]);
633 for(i=0; i< SampleSize*(RunCount+1);i++)
635 bbuf=ReadBlobByte(image);
641 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
646 typedef float tCTM[3][3];
648 static unsigned LoadWPG2Flags(Image *image,char Precision,float *Angle,tCTM *CTM)
650 const unsigned char TPR=1,TRN=2,SKW=4,SCL=8,ROT=0x10,OID=0x20,LCK=0x80;
655 (void) memset(*CTM,0,sizeof(*CTM)); /*CTM.erase();CTM.resize(3,3);*/
660 Flags=ReadBlobLSBShort(image);
661 if(Flags & LCK) x=ReadBlobLSBLong(image); /*Edit lock*/
665 {x=ReadBlobLSBShort(image);} /*ObjectID*/
667 {x=ReadBlobLSBLong(image);} /*ObjectID (Double precision)*/
671 x=ReadBlobLSBLong(image); /*Rot Angle*/
672 if(Angle) *Angle=x/65536.0;
674 if(Flags & (ROT|SCL))
676 x=ReadBlobLSBLong(image); /*Sx*cos()*/
677 (*CTM)[0][0] = (float)x/0x10000;
678 x=ReadBlobLSBLong(image); /*Sy*cos()*/
679 (*CTM)[1][1] = (float)x/0x10000;
681 if(Flags & (ROT|SKW))
683 x=ReadBlobLSBLong(image); /*Kx*sin()*/
684 (*CTM)[1][0] = (float)x/0x10000;
685 x=ReadBlobLSBLong(image); /*Ky*sin()*/
686 (*CTM)[0][1] = (float)x/0x10000;
690 x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Tx*/
691 if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
692 else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
693 x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Ty*/
694 (*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
695 if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
696 else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
700 x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Px*/
701 (*CTM)[2][0] = x + (float)DenX/0x10000;;
702 x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Py*/
703 (*CTM)[2][1] = x + (float)DenX/0x10000;
709 static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
710 MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo *exception)
713 postscript_file[MaxTextExtent];
728 magick[2*MaxTextExtent];
731 if ((clone_info=CloneImageInfo(image_info)) == NULL)
733 clone_info->blob=(void *) NULL;
734 clone_info->length=0;
736 /* Obtain temporary file */
737 AcquireUniqueFilename(postscript_file);
738 ps_file=OpenMagickStream(postscript_file,"wb");
739 if (ps_file == (FILE *) NULL)
742 /* Copy postscript to temporary file */
743 (void) SeekBlob(image,PS_Offset,SEEK_SET);
744 (void) ReadBlob(image, 2*MaxTextExtent, magick);
746 (void) SeekBlob(image,PS_Offset,SEEK_SET);
749 (void) fputc(ReadBlobByte(image),ps_file);
751 (void) fclose(ps_file);
753 /* Detect file format - Check magic.mgk configuration file. */
754 magic_info=GetMagicInfo(magick,2*MaxTextExtent,exception);
755 if(magic_info == (const MagicInfo *) NULL) goto FINISH_UNL;
756 /* printf("Detected:%s \n",magic_info->name); */
757 if(exception->severity != UndefinedException) goto FINISH_UNL;
758 if(magic_info->name == (char *) NULL) goto FINISH_UNL;
760 (void) CopyMagickMemory(clone_info->magick,magic_info->name,MaxTextExtent);
762 /* Read nested image */
763 /*FormatString(clone_info->filename,"%s:%.1024s",magic_info->name,postscript_file);*/
764 FormatMagickString(clone_info->filename,MaxTextExtent,"%.1024s",postscript_file);
765 image2=ReadImage(clone_info,exception);
771 Replace current image with new image while copying base image
774 (void) CopyMagickMemory(image2->filename,image->filename,MaxTextExtent);
775 (void) CopyMagickMemory(image2->magick_filename,image->magick_filename,MaxTextExtent);
776 (void) CopyMagickMemory(image2->magick,image->magick,MaxTextExtent);
777 image2->depth=image->depth;
779 image2->blob=ReferenceBlob(image->blob);
781 if ((image->rows == 0) || (image->columns == 0))
782 DeleteImageFromList(&image);
784 AppendImageToList(&image,image2);
787 (void) RelinquishUniqueFileResource(postscript_file);
789 DestroyImageInfo(clone_info);
794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
798 % R e a d W P G I m a g e %
802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
804 % Method ReadWPGImage reads an WPG X image file and returns it. It
805 % allocates the memory necessary for the new Image structure and returns a
806 % pointer to the new image.
808 % The format of the ReadWPGImage method is:
810 % Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
812 % A description of each parameter follows:
814 % o image: Method ReadWPGImage returns a pointer to the image after
815 % reading. A null image is returned if there is a memory shortage or if
816 % the image cannot be read.
818 % o image_info: Specifies a pointer to a ImageInfo structure.
820 % o exception: return any errors or warnings in this structure.
823 static Image *ReadWPGImage(const ImageInfo *image_info,
824 ExceptionInfo *exception)
829 MagickOffsetType DataOffset;
830 unsigned int ProductType;
831 unsigned int FileType;
832 unsigned char MajorVersion;
833 unsigned char MinorVersion;
834 unsigned int EncryptKey;
835 unsigned int Reserved;
840 unsigned char RecType;
847 unsigned char RecType;
854 unsigned HorizontalUnits;
855 unsigned VerticalUnits;
856 unsigned char PosSizePrecision;
864 unsigned int HorzRes;
865 unsigned int VertRes;
873 unsigned char Compression;
878 unsigned int RotAngle;
879 unsigned int LowLeftX;
880 unsigned int LowLeftY;
881 unsigned int UpRightX;
882 unsigned int UpRightY;
886 unsigned int HorzRes;
887 unsigned int VertRes;
892 unsigned int StartIndex;
893 unsigned int NumOfEntries;
898 unsigned int PS_unknown2;
899 unsigned int PS_unknown3;
946 tCTM CTM; /*current transform matrix*/
951 assert(image_info != (const ImageInfo *) NULL);
952 assert(image_info->signature == MagickSignature);
953 assert(exception != (ExceptionInfo *) NULL);
954 assert(exception->signature == MagickSignature);
956 image=AcquireImage(image_info);
958 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
959 if (status == MagickFalse)
961 image=DestroyImageList(image);
962 return((Image *) NULL);
967 Header.FileId=ReadBlobLSBLong(image);
968 Header.DataOffset=(MagickOffsetType) ReadBlobLSBLong(image);
969 Header.ProductType=ReadBlobLSBShort(image);
970 Header.FileType=ReadBlobLSBShort(image);
971 Header.MajorVersion=ReadBlobByte(image);
972 Header.MinorVersion=ReadBlobByte(image);
973 Header.EncryptKey=ReadBlobLSBShort(image);
974 Header.Reserved=ReadBlobLSBShort(image);
976 if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
977 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
978 if (Header.EncryptKey!=0)
979 ThrowReaderException(CoderError,"EncryptedWPGImageFileNotSupported");
985 BitmapHeader2.RotAngle=0;
987 switch(Header.FileType)
989 case 1: /* WPG level 1 */
990 while(!EOFBlob(image)) /* object parser loop */
992 (void) SeekBlob(image,Header.DataOffset,SEEK_SET);
996 Rec.RecType=(i=ReadBlobByte(image));
999 Rd_WP_DWORD(image,&Rec.RecordLength);
1003 Header.DataOffset=TellBlob(image)+Rec.RecordLength;
1007 case 0x0B: /* bitmap type 1 */
1008 BitmapHeader1.Width=ReadBlobLSBShort(image);
1009 BitmapHeader1.Heigth=ReadBlobLSBShort(image);
1010 BitmapHeader1.Depth=ReadBlobLSBShort(image);
1011 BitmapHeader1.HorzRes=ReadBlobLSBShort(image);
1012 BitmapHeader1.VertRes=ReadBlobLSBShort(image);
1014 if(BitmapHeader1.HorzRes && BitmapHeader1.VertRes)
1016 image->units=PixelsPerCentimeterResolution;
1017 image->x_resolution=BitmapHeader1.HorzRes/470.0;
1018 image->y_resolution=BitmapHeader1.VertRes/470.0;
1020 image->columns=BitmapHeader1.Width;
1021 image->rows=BitmapHeader1.Heigth;
1022 bpp=BitmapHeader1.Depth;
1026 case 0x0E: /*Color palette */
1027 WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1028 WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1030 image->colors=WPG_Palette.NumOfEntries;
1031 if (!AcquireImageColormap(image,image->colors))
1033 for (i=WPG_Palette.StartIndex;
1034 i < (int)WPG_Palette.NumOfEntries; i++)
1036 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1037 ReadBlobByte(image));
1038 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1039 ReadBlobByte(image));
1040 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1041 ReadBlobByte(image));
1045 case 0x11: /* Start PS l1 */
1046 if(Rec.RecordLength > 8)
1047 image=ExtractPostscript(image,image_info,
1048 TellBlob(image)+8, /* skip PS header in the wpg */
1049 (ssize_t) Rec.RecordLength-8,exception);
1052 case 0x14: /* bitmap type 2 */
1053 BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
1054 BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
1055 BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
1056 BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
1057 BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
1058 BitmapHeader2.Width=ReadBlobLSBShort(image);
1059 BitmapHeader2.Heigth=ReadBlobLSBShort(image);
1060 BitmapHeader2.Depth=ReadBlobLSBShort(image);
1061 BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
1062 BitmapHeader2.VertRes=ReadBlobLSBShort(image);
1064 image->units=PixelsPerCentimeterResolution;
1065 image->page.width=(unsigned int)
1066 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
1067 image->page.height=(unsigned int)
1068 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
1069 image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
1070 image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
1071 if(BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
1073 image->x_resolution=BitmapHeader2.HorzRes/470.0;
1074 image->y_resolution=BitmapHeader2.VertRes/470.0;
1076 image->columns=BitmapHeader2.Width;
1077 image->rows=BitmapHeader2.Heigth;
1078 bpp=BitmapHeader2.Depth;
1081 if ((image->colors == 0) && (bpp != 24))
1083 image->colors=one << bpp;
1084 if (!AcquireImageColormap(image,image->colors))
1087 ThrowReaderException(ResourceLimitError,
1088 "MemoryAllocationFailed");
1090 /* printf("Load default colormap \n"); */
1091 for (i=0; (i < (int) image->colors) && (i < 256); i++)
1093 image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
1094 image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
1095 image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
1101 if ( (image->colors < (one << bpp)) && (bpp != 24) )
1102 image->colormap=(PixelPacket *) ResizeQuantumMemory(
1103 image->colormap,(size_t) (one << bpp),
1104 sizeof(*image->colormap));
1109 if(image->colormap[0].red==0 &&
1110 image->colormap[0].green==0 &&
1111 image->colormap[0].blue==0 &&
1112 image->colormap[1].red==0 &&
1113 image->colormap[1].green==0 &&
1114 image->colormap[1].blue==0)
1115 { /* fix crippled monochrome palette */
1116 image->colormap[1].red =
1117 image->colormap[1].green =
1118 image->colormap[1].blue = QuantumRange;
1122 if(UnpackWPGRaster(image,bpp) < 0)
1123 /* The raster cannot be unpacked */
1125 DecompressionFailed:
1126 ThrowReaderException(CoderError,"UnableToDecompressImage");
1129 if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1132 if(BitmapHeader2.RotAngle & 0x8000)
1134 rotated_image = FlopImage(image, exception);
1135 rotated_image->blob = image->blob;
1136 DuplicateBlob(rotated_image,image);
1137 (void) RemoveLastImageFromList(&image);
1138 AppendImageToList(&image,rotated_image);
1141 if(BitmapHeader2.RotAngle & 0x2000)
1143 rotated_image = FlipImage(image, exception);
1144 rotated_image->blob = image->blob;
1145 DuplicateBlob(rotated_image,image);
1146 (void) RemoveLastImageFromList(&image);
1147 AppendImageToList(&image,rotated_image);
1150 /* rotate command */
1151 if(BitmapHeader2.RotAngle & 0x0FFF)
1153 rotated_image = RotateImage(image, (BitmapHeader2.RotAngle & 0x0FFF), exception);
1154 rotated_image->blob = image->blob;
1155 DuplicateBlob(rotated_image,image);
1156 (void) RemoveLastImageFromList(&image);
1157 AppendImageToList(&image,rotated_image);
1161 /* Allocate next image structure. */
1162 AcquireNextImage(image_info,image);
1164 if (image->next == (Image *) NULL)
1166 image=SyncNextImageInList(image);
1167 image->columns=image->rows=0;
1171 case 0x1B: /* Postscript l2 */
1172 if(Rec.RecordLength>0x3C)
1173 image=ExtractPostscript(image,image_info,
1174 TellBlob(image)+0x3C, /* skip PS l2 header in the wpg */
1175 (ssize_t) Rec.RecordLength-0x3C,exception);
1181 case 2: /* WPG level 2 */
1182 (void) memset(CTM,0,sizeof(CTM));
1183 StartWPG.PosSizePrecision = 0;
1184 while(!EOFBlob(image)) /* object parser loop */
1186 (void) SeekBlob(image,Header.DataOffset,SEEK_SET);
1190 Rec2.Class=(i=ReadBlobByte(image));
1193 Rec2.RecType=(i=ReadBlobByte(image));
1196 Rd_WP_DWORD(image,&Rec2.Extension);
1197 Rd_WP_DWORD(image,&Rec2.RecordLength);
1201 Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1203 switch(Rec2.RecType)
1206 StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1207 StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1208 StartWPG.PosSizePrecision=ReadBlobByte(image);
1210 case 0x0C: /* Color palette */
1211 WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1212 WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1214 image->colors=WPG_Palette.NumOfEntries;
1215 if (AcquireImageColormap(image,image->colors) == MagickFalse)
1216 ThrowReaderException(ResourceLimitError,
1217 "MemoryAllocationFailed");
1218 for (i=WPG_Palette.StartIndex;
1219 i < (int)WPG_Palette.NumOfEntries; i++)
1221 image->colormap[i].red=ScaleCharToQuantum((char)
1222 ReadBlobByte(image));
1223 image->colormap[i].green=ScaleCharToQuantum((char)
1224 ReadBlobByte(image));
1225 image->colormap[i].blue=ScaleCharToQuantum((char)
1226 ReadBlobByte(image));
1227 (void) ReadBlobByte(image); /*Opacity??*/
1231 Bitmap2Header1.Width=ReadBlobLSBShort(image);
1232 Bitmap2Header1.Heigth=ReadBlobLSBShort(image);
1233 Bitmap2Header1.Depth=ReadBlobByte(image);
1234 Bitmap2Header1.Compression=ReadBlobByte(image);
1236 if(Bitmap2Header1.Compression > 1)
1237 continue; /*Unknown compression method */
1238 switch(Bitmap2Header1.Depth)
1256 continue; /*Ignore raster with unknown depth*/
1258 image->columns=Bitmap2Header1.Width;
1259 image->rows=Bitmap2Header1.Heigth;
1261 if ((image->colors == 0) && (bpp != 24))
1267 image->colors=one << bpp;
1268 if (!AcquireImageColormap(image,image->colors))
1274 if( image->colors<(one << bpp) && bpp!=24 )
1275 image->colormap=(PixelPacket *) ResizeQuantumMemory(
1276 image->colormap,(size_t) (one << bpp),
1277 sizeof(*image->colormap));
1281 switch(Bitmap2Header1.Compression)
1283 case 0: /*Uncompressed raster*/
1285 ldblk=(ssize_t) ((bpp*image->columns+7)/8);
1286 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t)
1287 ldblk,sizeof(*BImgBuff));
1288 if (BImgBuff == (unsigned char *) NULL)
1291 for(i=0; i< (ssize_t) image->rows; i++)
1293 (void) ReadBlob(image,ldblk,BImgBuff);
1294 InsertRow(BImgBuff,i,image,bpp);
1298 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);;
1301 case 1: /*RLE for WPG2 */
1303 if( UnpackWPG2Raster(image,bpp) < 0)
1304 goto DecompressionFailed;
1309 if(CTM[0][0]<0 && !image_info->ping)
1310 { /*?? RotAngle=360-RotAngle;*/
1311 rotated_image = FlopImage(image, exception);
1312 rotated_image->blob = image->blob;
1313 DuplicateBlob(rotated_image,image);
1314 (void) RemoveLastImageFromList(&image);
1315 AppendImageToList(&image,rotated_image);
1316 /* Try to change CTM according to Flip - I am not sure, must be checked.
1317 Tx(0,0)=-1; Tx(1,0)=0; Tx(2,0)=0;
1318 Tx(0,1)= 0; Tx(1,1)=1; Tx(2,1)=0;
1319 Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1320 Tx(1,2)=0; Tx(2,2)=1; */
1322 if(CTM[1][1]<0 && !image_info->ping)
1323 { /*?? RotAngle=360-RotAngle;*/
1324 rotated_image = FlipImage(image, exception);
1325 rotated_image->blob = image->blob;
1326 DuplicateBlob(rotated_image,image);
1327 (void) RemoveLastImageFromList(&image);
1328 AppendImageToList(&image,rotated_image);
1329 /* Try to change CTM according to Flip - I am not sure, must be checked.
1330 float_matrix Tx(3,3);
1331 Tx(0,0)= 1; Tx(1,0)= 0; Tx(2,0)=0;
1332 Tx(0,1)= 0; Tx(1,1)=-1; Tx(2,1)=0;
1333 Tx(0,2)= 0; Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1338 /* Allocate next image structure. */
1339 AcquireNextImage(image_info,image);
1341 if (image->next == (Image *) NULL)
1343 image=SyncNextImageInList(image);
1344 image->columns=image->rows=1;
1348 case 0x12: /* Postscript WPG2*/
1349 i=ReadBlobLSBShort(image);
1350 if(Rec2.RecordLength > (unsigned int) i)
1351 image=ExtractPostscript(image,image_info,
1352 TellBlob(image)+i, /*skip PS header in the wpg2*/
1353 (ssize_t) (Rec2.RecordLength-i-2),exception);
1356 case 0x1B: /*bitmap rectangle*/
1357 WPG2Flags = LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM);
1366 ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
1371 (void) CloseBlob(image);
1381 Rewind list, removing any empty images while rewinding.
1385 while (p != (Image *) NULL)
1388 if ((p->rows == 0) || (p->columns == 0)) {
1390 DeleteImageFromList(&tmp);
1399 for (p=image; p != (Image *) NULL; p=p->next)
1400 p->scene=(size_t) scene++;
1402 if (image == (Image *) NULL)
1403 ThrowReaderException(CorruptImageError,
1404 "ImageFileDoesNotContainAnyImageData");
1409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413 % R e g i s t e r W P G I m a g e %
1417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419 % Method RegisterWPGImage adds attributes for the WPG image format to
1420 % the list of supported formats. The attributes include the image format
1421 % tag, a method to read and/or write the format, whether the format
1422 % supports the saving of more than one frame to the same file or blob,
1423 % whether the format supports native in-memory I/O, and a brief
1424 % description of the format.
1426 % The format of the RegisterWPGImage method is:
1428 % size_t RegisterWPGImage(void)
1431 ModuleExport size_t RegisterWPGImage(void)
1436 entry=SetMagickInfo("WPG");
1437 entry->decoder=(DecodeImageHandler *) ReadWPGImage;
1438 entry->magick=(IsImageFormatHandler *) IsWPG;
1439 entry->description=AcquireString("Word Perfect Graphics");
1440 entry->module=ConstantString("WPG");
1441 entry->seekable_stream=MagickTrue;
1442 (void) RegisterMagickInfo(entry);
1443 return(MagickImageCoderSignature);
1447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1451 % U n r e g i s t e r W P G I m a g e %
1455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457 % Method UnregisterWPGImage removes format registrations made by the
1458 % WPG module from the list of supported formats.
1460 % The format of the UnregisterWPGImage method is:
1462 % UnregisterWPGImage(void)
1465 ModuleExport void UnregisterWPGImage(void)
1467 (void) UnregisterMagickInfo("WPG");