]> granicus.if.org Git - imagemagick/blob - coders/wpg.c
(no commit message)
[imagemagick] / coders / wpg.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                            W   W  PPPP    GGGG                              %
6 %                            W   W  P   P  G                                  %
7 %                            W W W  PPPP   G GGG                              %
8 %                            WW WW  P      G   G                              %
9 %                            W   W  P       GGG                               %
10 %                                                                             %
11 %                                                                             %
12 %                       Read WordPerfect Image Format                         %
13 %                                                                             %
14 %                              Software Design                                %
15 %                              Jaroslav Fojtik                                %
16 %                                 June 2000                                   %
17 %                                                                             %
18 %                                                                             %
19 %  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
20 %  dedicated to making software imaging solutions freely available.           %
21 %                                                                             %
22 %  You may not use this file except in compliance with the License.  You may  %
23 %  obtain a copy of the License at                                            %
24 %                                                                             %
25 %    http://www.imagemagick.org/script/license.php                            %
26 %                                                                             %
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.                                             %
32 %                                                                             %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 %
35 %
36 */
37 \f
38 /*
39   Include declarations.
40 */
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/image.h"
52 #include "MagickCore/image-private.h"
53 #include "MagickCore/list.h"
54 #include "MagickCore/magic.h"
55 #include "MagickCore/magick.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/resource_.h"
58 #include "MagickCore/pixel-accessor.h"
59 #include "MagickCore/quantum-private.h"
60 #include "MagickCore/shear.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 \f
67 typedef struct
68    {
69    unsigned char Red;
70    unsigned char Blue;
71    unsigned char Green;
72    } RGB_Record;
73
74 /* Default palette for WPG level 1 */
75 const RGB_Record WPG1_Palette[256]={
76 {  0,  0,  0},    {  0,  0,168},
77 {  0,168,  0},    {  0,168,168},
78 {168,  0,  0},    {168,  0,168},
79 {168, 84,  0},    {168,168,168},
80 { 84, 84, 84},    { 84, 84,252},
81 { 84,252, 84},    { 84,252,252},
82 {252, 84, 84},    {252, 84,252},
83 {252,252, 84},    {252,252,252},  /*16*/
84 {  0,  0,  0},    { 20, 20, 20},
85 { 32, 32, 32},    { 44, 44, 44},
86 { 56, 56, 56},    { 68, 68, 68},
87 { 80, 80, 80},    { 96, 96, 96},
88 {112,112,112},    {128,128,128},
89 {144,144,144},    {160,160,160},
90 {180,180,180},    {200,200,200},
91 {224,224,224},    {252,252,252},  /*32*/
92 {  0,  0,252},    { 64,  0,252},
93 {124,  0,252},    {188,  0,252},
94 {252,  0,252},    {252,  0,188},
95 {252,  0,124},    {252,  0, 64},
96 {252,  0,  0},    {252, 64,  0},
97 {252,124,  0},    {252,188,  0},
98 {252,252,  0},    {188,252,  0},
99 {124,252,  0},    { 64,252,  0},  /*48*/
100 {  0,252,  0},    {  0,252, 64},
101 {  0,252,124},    {  0,252,188},
102 {  0,252,252},    {  0,188,252},
103 {  0,124,252},    {  0, 64,252},
104 {124,124,252},    {156,124,252},
105 {188,124,252},    {220,124,252},
106 {252,124,252},    {252,124,220},
107 {252,124,188},    {252,124,156},  /*64*/
108 {252,124,124},    {252,156,124},
109 {252,188,124},    {252,220,124},
110 {252,252,124},    {220,252,124},
111 {188,252,124},    {156,252,124},
112 {124,252,124},    {124,252,156},
113 {124,252,188},    {124,252,220},
114 {124,252,252},    {124,220,252},
115 {124,188,252},    {124,156,252},  /*80*/
116 {180,180,252},    {196,180,252},
117 {216,180,252},    {232,180,252},
118 {252,180,252},    {252,180,232},
119 {252,180,216},    {252,180,196},
120 {252,180,180},    {252,196,180},
121 {252,216,180},    {252,232,180},
122 {252,252,180},    {232,252,180},
123 {216,252,180},    {196,252,180},  /*96*/
124 {180,220,180},    {180,252,196},
125 {180,252,216},    {180,252,232},
126 {180,252,252},    {180,232,252},
127 {180,216,252},    {180,196,252},
128 {0,0,112},    {28,0,112},
129 {56,0,112},    {84,0,112},
130 {112,0,112},    {112,0,84},
131 {112,0,56},    {112,0,28},  /*112*/
132 {112,0,0},    {112,28,0},
133 {112,56,0},    {112,84,0},
134 {112,112,0},    {84,112,0},
135 {56,112,0},    {28,112,0},
136 {0,112,0},    {0,112,28},
137 {0,112,56},    {0,112,84},
138 {0,112,112},    {0,84,112},
139 {0,56,112},    {0,28,112},   /*128*/
140 {56,56,112},    {68,56,112},
141 {84,56,112},    {96,56,112},
142 {112,56,112},    {112,56,96},
143 {112,56,84},    {112,56,68},
144 {112,56,56},    {112,68,56},
145 {112,84,56},    {112,96,56},
146 {112,112,56},    {96,112,56},
147 {84,112,56},    {68,112,56},  /*144*/
148 {56,112,56},    {56,112,69},
149 {56,112,84},    {56,112,96},
150 {56,112,112},    {56,96,112},
151 {56,84,112},    {56,68,112},
152 {80,80,112},    {88,80,112},
153 {96,80,112},    {104,80,112},
154 {112,80,112},    {112,80,104},
155 {112,80,96},    {112,80,88},  /*160*/
156 {112,80,80},    {112,88,80},
157 {112,96,80},    {112,104,80},
158 {112,112,80},    {104,112,80},
159 {96,112,80},    {88,112,80},
160 {80,112,80},    {80,112,88},
161 {80,112,96},    {80,112,104},
162 {80,112,112},    {80,114,112},
163 {80,96,112},    {80,88,112},  /*176*/
164 {0,0,64},    {16,0,64},
165 {32,0,64},    {48,0,64},
166 {64,0,64},    {64,0,48},
167 {64,0,32},    {64,0,16},
168 {64,0,0},    {64,16,0},
169 {64,32,0},    {64,48,0},
170 {64,64,0},    {48,64,0},
171 {32,64,0},    {16,64,0},  /*192*/
172 {0,64,0},    {0,64,16},
173 {0,64,32},    {0,64,48},
174 {0,64,64},    {0,48,64},
175 {0,32,64},    {0,16,64},
176 {32,32,64},    {40,32,64},
177 {48,32,64},    {56,32,64},
178 {64,32,64},    {64,32,56},
179 {64,32,48},    {64,32,40},  /*208*/
180 {64,32,32},    {64,40,32},
181 {64,48,32},    {64,56,32},
182 {64,64,32},    {56,64,32},
183 {48,64,32},    {40,64,32},
184 {32,64,32},    {32,64,40},
185 {32,64,48},    {32,64,56},
186 {32,64,64},    {32,56,64},
187 {32,48,64},    {32,40,64},  /*224*/
188 {44,44,64},    {48,44,64},
189 {52,44,64},    {60,44,64},
190 {64,44,64},    {64,44,60},
191 {64,44,52},    {64,44,48},
192 {64,44,44},    {64,48,44},
193 {64,52,44},    {64,60,44},
194 {64,64,44},    {60,64,44},
195 {52,64,44},    {48,64,44},  /*240*/
196 {44,64,44},    {44,64,48},
197 {44,64,52},    {44,64,60},
198 {44,64,64},    {44,60,64},
199 {44,55,64},    {44,48,64},
200 {0,0,0},    {0,0,0},
201 {0,0,0},    {0,0,0},
202 {0,0,0},    {0,0,0},
203 {0,0,0},    {0,0,0}    /*256*/
204 };
205 \f
206 /*
207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208 %                                                                             %
209 %                                                                             %
210 %                                                                             %
211 %   I s W P G                                                                 %
212 %                                                                             %
213 %                                                                             %
214 %                                                                             %
215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216 %
217 %  IsWPG() returns True if the image format type, identified by the magick
218 %  string, is WPG.
219 %
220 %  The format of the IsWPG method is:
221 %
222 %      unsigned int IsWPG(const unsigned char *magick,const size_t length)
223 %
224 %  A description of each parameter follows:
225 %
226 %    o status:  Method IsWPG returns True if the image format type is WPG.
227 %
228 %    o magick: compare image format pattern against these bytes.
229 %
230 %    o length: Specifies the length of the magick string.
231 %
232 */
233 static unsigned int IsWPG(const unsigned char *magick,const size_t length)
234 {
235   if (length < 4)
236     return(MagickFalse);
237   if (memcmp(magick,"\377WPC",4) == 0)
238     return(MagickTrue);
239   return(MagickFalse);
240 }
241 \f
242
243 static void Rd_WP_DWORD(Image *image,size_t *d)
244 {
245   unsigned char
246     b;
247
248   b=ReadBlobByte(image);
249   *d=b;
250   if (b < 0xFFU)
251     return;
252   b=ReadBlobByte(image);
253   *d=(size_t) b;
254   b=ReadBlobByte(image);
255   *d+=(size_t) b*256l;
256   if (*d < 0x8000)
257     return;
258   *d=(*d & 0x7FFF) << 16;
259   b=ReadBlobByte(image);
260   *d+=(size_t) b;
261   b=ReadBlobByte(image);
262   *d+=(size_t) b*256l;
263   return;
264 }
265
266 static void InsertRow(unsigned char *p,ssize_t y,Image *image, int bpp)
267 {
268   ExceptionInfo
269     *exception;
270
271   int
272     bit;
273
274   Quantum
275     index;
276
277   register Quantum
278     *q;
279
280   ssize_t
281     x;
282
283   exception=(&image->exception);
284   switch (bpp)
285     {
286     case 1:  /* Convert bitmap scanline. */
287       {
288         q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
289         if (q == (const Quantum *) NULL)
290           break;
291         for (x=0; x < ((ssize_t) image->columns-7); x+=8)
292         {
293           for (bit=0; bit < 8; bit++)
294           {
295             index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
296             SetPixelIndex(image,index,q);
297             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
298             q+=GetPixelComponents(image);
299           }
300           p++;
301         }
302         if ((image->columns % 8) != 0)
303           {
304             for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
305             {
306               index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
307               SetPixelIndex(image,index,q);
308               SetPixelPacket(image,image->colormap+(ssize_t) index,q);
309               q+=GetPixelComponents(image);
310             }
311             p++;
312           }
313         if (!SyncAuthenticPixels(image,exception))
314           break;
315         break;
316       }
317     case 2:  /* Convert PseudoColor scanline. */
318       {
319         q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
320         if (q == (const Quantum *) NULL)
321           break;
322         for (x=0; x < ((ssize_t) image->columns-1); x+=2)
323         {
324             index=ConstrainColormapIndex(image,(*p >> 6) & 0x3);
325             SetPixelIndex(image,index,q);
326             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
327             q+=GetPixelComponents(image);
328             index=ConstrainColormapIndex(image,(*p >> 4) & 0x3);
329             SetPixelIndex(image,index,q);
330             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
331             q+=GetPixelComponents(image);
332             index=ConstrainColormapIndex(image,(*p >> 2) & 0x3);
333             SetPixelIndex(image,index,q);
334             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
335             q+=GetPixelComponents(image);
336             index=ConstrainColormapIndex(image,(*p) & 0x3);
337             SetPixelIndex(image,index,q);
338             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
339             p++;
340             q+=GetPixelComponents(image);
341         }
342        if ((image->columns % 4) != 0)
343           {
344             index=ConstrainColormapIndex(image,(*p >> 6) & 0x3);
345             SetPixelIndex(image,index,q);
346             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
347             q+=GetPixelComponents(image);
348             if ((image->columns % 4) >= 1)
349
350               {
351                 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3);
352                 SetPixelIndex(image,index,q);
353                 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
354                 q+=GetPixelComponents(image);
355                 if ((image->columns % 4) >= 2)
356
357                   {
358                     index=ConstrainColormapIndex(image,(*p >> 2) & 0x3);
359                     SetPixelIndex(image,index,q);
360                     SetPixelPacket(image,image->colormap+(ssize_t) index,q);
361                     q+=GetPixelComponents(image);
362                   }
363               }
364             p++;
365           }
366         if (SyncAuthenticPixels(image,exception) == MagickFalse)
367           break;
368         break;
369       }
370  
371     case 4:  /* Convert PseudoColor scanline. */
372       {
373         q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
374         if (q == (const Quantum *) NULL)
375           break;
376         for (x=0; x < ((ssize_t) image->columns-1); x+=2)
377           { 
378             index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f);
379             SetPixelIndex(image,index,q);
380             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
381             q+=GetPixelComponents(image);
382             index=ConstrainColormapIndex(image,(*p) & 0x0f);
383             SetPixelIndex(image,index,q);
384             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
385             p++;
386             q+=GetPixelComponents(image);
387           }
388         if ((image->columns % 2) != 0)
389           {
390             index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f);
391             SetPixelIndex(image,index,q);
392             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
393             p++;
394             q+=GetPixelComponents(image);
395           }
396         if (SyncAuthenticPixels(image,exception) == MagickFalse)
397           break;
398         break;
399       }
400     case 8: /* Convert PseudoColor scanline. */
401       {
402         q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
403         if (q == (const Quantum *) NULL) break;
404
405         for (x=0; x < (ssize_t) image->columns; x++)
406           {
407             index=ConstrainColormapIndex(image,*p);
408             SetPixelIndex(image,index,q);
409             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
410             p++;
411             q+=GetPixelComponents(image);
412           }
413         if (SyncAuthenticPixels(image,exception) == MagickFalse)
414           break;
415       }
416       break;
417      
418     case 24:     /*  Convert DirectColor scanline.  */
419       q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
420       if (q == (const Quantum *) NULL)
421         break;
422       for (x=0; x < (ssize_t) image->columns; x++)
423         {
424           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
425           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
426           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
427           q+=GetPixelComponents(image);
428         }
429       if (!SyncAuthenticPixels(image,exception))
430         break;
431       break;     
432     }
433 }
434
435
436 /* Helper for WPG1 raster reader. */
437 #define InsertByte(b) \
438 { \
439   BImgBuff[x]=b; \
440   x++; \
441   if((ssize_t) x>=ldblk) \
442   { \
443     InsertRow(BImgBuff,(ssize_t) y,image,bpp); \
444     x=0; \
445     y++; \
446     } \
447 }
448 /* WPG1 raster reader. */
449 static int UnpackWPGRaster(Image *image,int bpp)
450 {
451   int
452     x,
453     y,
454     i;
455
456   unsigned char
457     bbuf,
458     *BImgBuff,
459     RunCount;
460
461   ssize_t
462     ldblk;
463
464   x=0;
465   y=0;
466
467   ldblk=(ssize_t) ((bpp*image->columns+7)/8);
468   BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
469     sizeof(*BImgBuff));
470   if(BImgBuff==NULL) return(-2);
471
472   while(y<(ssize_t) image->rows)
473     {
474       bbuf=ReadBlobByte(image);
475
476       RunCount=bbuf & 0x7F;
477       if(bbuf & 0x80)
478         {
479           if(RunCount)  /* repeat next byte runcount * */
480             {
481               bbuf=ReadBlobByte(image);
482               for(i=0;i<(int) RunCount;i++) InsertByte(bbuf);
483             }
484           else {  /* read next byte as RunCount; repeat 0xFF runcount* */
485             RunCount=ReadBlobByte(image);
486             for(i=0;i<(int) RunCount;i++) InsertByte(0xFF);
487           }
488         }
489       else {
490         if(RunCount)   /* next runcount byte are readed directly */
491           {
492             for(i=0;i < (int) RunCount;i++)
493               {
494                 bbuf=ReadBlobByte(image);
495                 InsertByte(bbuf);
496               }
497           }
498         else {  /* repeat previous line runcount* */
499           RunCount=ReadBlobByte(image);
500           if(x) {    /* attempt to duplicate row from x position: */
501             /* I do not know what to do here */
502             BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
503             return(-3);
504           }
505           for(i=0;i < (int) RunCount;i++)
506             {
507               x=0;
508               y++;    /* Here I need to duplicate previous row RUNCOUNT* */
509               if(y<2) continue;
510               if(y>(ssize_t) image->rows)
511                 {
512                   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
513                   return(-4);
514                 }
515               InsertRow(BImgBuff,y-1,image,bpp);
516             }
517         }
518       }
519     }
520   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
521   return(0);
522 }
523
524
525 /* Helper for WPG2 reader. */
526 #define InsertByte6(b) \
527 { \
528   if(XorMe)\
529     BImgBuff[x] = (unsigned char)~b;\
530   else\
531     BImgBuff[x] = b;\
532   x++; \
533   if((ssize_t) x >= ldblk) \
534   { \
535     InsertRow(BImgBuff,(ssize_t) y,image,bpp); \
536     x=0; \
537     y++; \
538    } \
539 }
540 /* WPG2 raster reader. */
541 static int UnpackWPG2Raster(Image *image,int bpp)
542 {
543   size_t
544     x,
545     y;
546
547   ssize_t
548     ldblk;
549
550   int XorMe = 0;
551
552   unsigned int
553     SampleSize=1;
554
555   unsigned char
556     bbuf,
557     *BImgBuff,
558     RunCount,
559     SampleBuffer[8];
560
561   unsigned int
562     i;
563
564   x=0;
565   y=0;
566   ldblk=(ssize_t) ((bpp*image->columns+7)/8);
567   BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
568     sizeof(*BImgBuff));
569   if(BImgBuff==NULL)
570     return(-2);
571
572   while( y< image->rows)
573     {
574       bbuf=ReadBlobByte(image);
575
576       switch(bbuf)
577         {
578         case 0x7D:
579           SampleSize=ReadBlobByte(image);  /* DSZ */
580           if(SampleSize>8)
581             return(-2);
582           if(SampleSize<1)
583             return(-2);
584           break;
585         case 0x7E:
586           (void) FormatLocaleFile(stderr,
587             "\nUnsupported WPG token XOR, please report!");
588           XorMe=!XorMe;
589           break;
590         case 0x7F:
591           RunCount=ReadBlobByte(image);   /* BLK */
592           for(i=0; i < SampleSize*(RunCount+1); i++)
593             {
594               InsertByte6(0);
595             }
596           break;
597         case 0xFD:
598           RunCount=ReadBlobByte(image);   /* EXT */
599           for(i=0; i<= RunCount;i++)
600             for(bbuf=0; bbuf < SampleSize; bbuf++)
601               InsertByte6(SampleBuffer[bbuf]);          
602           break;
603         case 0xFE:
604           RunCount=ReadBlobByte(image);  /* RST */
605           if(x!=0)
606             {
607               (void) FormatLocaleFile(stderr,
608                 "\nUnsupported WPG2 unaligned token RST x=%.20g, please report!\n"
609                 ,(double) x);
610               return(-3);
611             }
612           {
613             /* duplicate the previous row RunCount x */
614             for(i=0;i<=RunCount;i++)
615               {      
616                 InsertRow(BImgBuff,(ssize_t) (image->rows >= y ? y : image->rows-1),
617                           image,bpp);
618                 y++;
619               }    
620           }
621           break;
622         case 0xFF:
623           RunCount=ReadBlobByte(image);   /* WHT */
624           for(i=0; i < SampleSize*(RunCount+1); i++)
625             {
626               InsertByte6(0xFF);
627             }
628           break;
629         default:
630           RunCount=bbuf & 0x7F;
631
632           if(bbuf & 0x80)     /* REP */
633             {  
634               for(i=0; i < SampleSize; i++)
635                 SampleBuffer[i]=ReadBlobByte(image);
636               for(i=0;i<=RunCount;i++)
637                 for(bbuf=0;bbuf<SampleSize;bbuf++)
638                   InsertByte6(SampleBuffer[bbuf]);
639             }
640           else {      /* NRP */
641             for(i=0; i< SampleSize*(RunCount+1);i++)
642               {
643                 bbuf=ReadBlobByte(image);
644                 InsertByte6(bbuf);
645               }
646           }
647         }
648     }
649   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
650   return(0);
651 }
652
653
654 typedef float tCTM[3][3];
655
656 static unsigned LoadWPG2Flags(Image *image,char Precision,float *Angle,tCTM *CTM)
657 {
658 const unsigned char TPR=1,TRN=2,SKW=4,SCL=8,ROT=0x10,OID=0x20,LCK=0x80;
659 ssize_t x;
660 unsigned DenX;
661 unsigned Flags;
662
663  (void) memset(*CTM,0,sizeof(*CTM));     /*CTM.erase();CTM.resize(3,3);*/
664  (*CTM)[0][0]=1;
665  (*CTM)[1][1]=1;
666  (*CTM)[2][2]=1;
667
668  Flags=ReadBlobLSBShort(image);
669  if(Flags & LCK) x=ReadBlobLSBLong(image);  /*Edit lock*/
670  if(Flags & OID)
671   {
672   if(Precision==0)
673     {x=ReadBlobLSBShort(image);}  /*ObjectID*/
674   else
675     {x=ReadBlobLSBLong(image);}  /*ObjectID (Double precision)*/
676   }
677  if(Flags & ROT)
678   {
679   x=ReadBlobLSBLong(image);  /*Rot Angle*/
680   if(Angle) *Angle=x/65536.0;
681   }
682  if(Flags & (ROT|SCL))
683   {
684   x=ReadBlobLSBLong(image);  /*Sx*cos()*/
685   (*CTM)[0][0] = (float)x/0x10000;
686   x=ReadBlobLSBLong(image);  /*Sy*cos()*/
687   (*CTM)[1][1] = (float)x/0x10000;
688   }
689  if(Flags & (ROT|SKW))
690   {
691   x=ReadBlobLSBLong(image);       /*Kx*sin()*/
692   (*CTM)[1][0] = (float)x/0x10000;
693   x=ReadBlobLSBLong(image);       /*Ky*sin()*/
694   (*CTM)[0][1] = (float)x/0x10000;
695   }
696  if(Flags & TRN)
697   {
698   x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image);  /*Tx*/
699         if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
700             else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
701   x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image);  /*Ty*/
702   (*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
703         if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
704             else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
705   }
706  if(Flags & TPR)
707   {
708   x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image);  /*Px*/
709   (*CTM)[2][0] = x + (float)DenX/0x10000;;
710   x=ReadBlobLSBShort(image);  DenX=ReadBlobLSBShort(image); /*Py*/
711   (*CTM)[2][1] = x + (float)DenX/0x10000;
712   }
713  return(Flags);
714 }
715
716
717 static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
718   MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo *exception)
719 {
720   char
721     postscript_file[MaxTextExtent];
722
723   const MagicInfo
724     *magic_info;    
725
726   FILE
727     *ps_file;
728
729   ImageInfo
730     *clone_info;
731     
732   Image
733     *image2;
734     
735   unsigned char
736     magick[2*MaxTextExtent];    
737     
738
739   if ((clone_info=CloneImageInfo(image_info)) == NULL)
740     return(image);
741   clone_info->blob=(void *) NULL;
742   clone_info->length=0;
743
744   /* Obtain temporary file */
745   AcquireUniqueFilename(postscript_file);
746   ps_file=OpenMagickStream(postscript_file,"wb");
747   if (ps_file == (FILE *) NULL)
748     goto FINISH;
749
750   /* Copy postscript to temporary file */
751   (void) SeekBlob(image,PS_Offset,SEEK_SET);
752   (void) ReadBlob(image, 2*MaxTextExtent, magick);
753   
754   (void) SeekBlob(image,PS_Offset,SEEK_SET);
755   while(PS_Size-- > 0)
756     {
757       (void) fputc(ReadBlobByte(image),ps_file);
758     }
759   (void) fclose(ps_file);
760   
761     /* Detect file format - Check magic.mgk configuration file. */
762   magic_info=GetMagicInfo(magick,2*MaxTextExtent,exception);
763   if(magic_info == (const MagicInfo *) NULL) goto FINISH_UNL;
764   /*     printf("Detected:%s  \n",magic_info->name); */
765   if(exception->severity != UndefinedException) goto FINISH_UNL;     
766   if(magic_info->name == (char *) NULL) goto FINISH_UNL;
767     
768   (void) CopyMagickMemory(clone_info->magick,magic_info->name,MaxTextExtent);
769   
770     /* Read nested image */
771   /*FormatString(clone_info->filename,"%s:%s",magic_info->name,postscript_file);*/
772   FormatLocaleString(clone_info->filename,MaxTextExtent,"%s",postscript_file);
773   image2=ReadImage(clone_info,exception);
774
775   if (!image2)
776     goto FINISH_UNL;
777
778   /*
779     Replace current image with new image while copying base image
780     attributes.
781   */
782   (void) CopyMagickMemory(image2->filename,image->filename,MaxTextExtent);
783   (void) CopyMagickMemory(image2->magick_filename,image->magick_filename,MaxTextExtent);
784   (void) CopyMagickMemory(image2->magick,image->magick,MaxTextExtent);
785   image2->depth=image->depth;
786   DestroyBlob(image2);
787   image2->blob=ReferenceBlob(image->blob);
788
789   if ((image->rows == 0) || (image->columns == 0))
790     DeleteImageFromList(&image);
791
792   AppendImageToList(&image,image2);
793
794  FINISH_UNL:    
795   (void) RelinquishUniqueFileResource(postscript_file);
796  FINISH:
797   DestroyImageInfo(clone_info);
798   return(image);
799 }
800 \f
801 /*
802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
803 %                                                                             %
804 %                                                                             %
805 %                                                                             %
806 %   R e a d W P G I m a g e                                                   %
807 %                                                                             %
808 %                                                                             %
809 %                                                                             %
810 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
811 %
812 %  Method ReadWPGImage reads an WPG X image file and returns it.  It
813 %  allocates the memory necessary for the new Image structure and returns a
814 %  pointer to the new image.
815 %
816 %  The format of the ReadWPGImage method is:
817 %
818 %    Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
819 %
820 %  A description of each parameter follows:
821 %
822 %    o image:  Method ReadWPGImage returns a pointer to the image after
823 %      reading. A null image is returned if there is a memory shortage or if
824 %      the image cannot be read.
825 %
826 %    o image_info: Specifies a pointer to a ImageInfo structure.
827 %
828 %    o exception: return any errors or warnings in this structure.
829 %
830 */
831 static Image *ReadWPGImage(const ImageInfo *image_info,
832   ExceptionInfo *exception)
833 {
834   typedef struct
835   {
836     size_t FileId;
837     MagickOffsetType DataOffset;
838     unsigned int ProductType;
839     unsigned int FileType;
840     unsigned char MajorVersion;
841     unsigned char MinorVersion;
842     unsigned int EncryptKey;
843     unsigned int Reserved;
844   } WPGHeader;
845
846   typedef struct
847   {
848     unsigned char RecType;
849     size_t RecordLength;
850   } WPGRecord;
851
852   typedef struct
853   {
854     unsigned char Class;
855     unsigned char RecType;
856     size_t Extension;
857     size_t RecordLength;
858   } WPG2Record;
859
860   typedef struct
861   {
862     unsigned  HorizontalUnits;
863     unsigned  VerticalUnits;
864     unsigned char PosSizePrecision;
865   } WPG2Start;
866
867   typedef struct
868   {
869     unsigned int Width;
870     unsigned int Heigth;
871     unsigned int Depth;
872     unsigned int HorzRes;
873     unsigned int VertRes;
874   } WPGBitmapType1;
875
876   typedef struct
877   {
878     unsigned int Width;
879     unsigned int Heigth;
880     unsigned char Depth;
881     unsigned char Compression;
882   } WPG2BitmapType1;
883
884   typedef struct
885   {
886     unsigned int RotAngle;
887     unsigned int LowLeftX;
888     unsigned int LowLeftY;
889     unsigned int UpRightX;
890     unsigned int UpRightY;
891     unsigned int Width;
892     unsigned int Heigth;
893     unsigned int Depth;
894     unsigned int HorzRes;
895     unsigned int VertRes;
896   } WPGBitmapType2;
897
898   typedef struct
899   {
900     unsigned int StartIndex;
901     unsigned int NumOfEntries;
902   } WPGColorMapRec;
903
904   typedef struct {
905     size_t PS_unknown1;
906     unsigned int PS_unknown2;
907     unsigned int PS_unknown3;
908   } WPGPSl1Record;  
909
910   Image
911     *image,
912     *rotated_image;
913
914   unsigned int
915     status;
916
917   WPGHeader
918     Header;
919
920   WPGRecord
921     Rec;
922
923   WPG2Record
924     Rec2;
925
926   WPG2Start StartWPG;
927
928   WPGBitmapType1
929     BitmapHeader1;
930
931   WPG2BitmapType1
932     Bitmap2Header1;
933
934   WPGBitmapType2
935     BitmapHeader2;
936
937   WPGColorMapRec
938     WPG_Palette;
939
940   int
941     i,
942     bpp,
943     WPG2Flags;
944
945   ssize_t
946     ldblk;
947
948   size_t
949     one;
950
951   unsigned char
952     *BImgBuff;
953
954   tCTM CTM;         /*current transform matrix*/
955
956   /*
957     Open image file.
958   */
959   assert(image_info != (const ImageInfo *) NULL);
960   assert(image_info->signature == MagickSignature);
961   assert(exception != (ExceptionInfo *) NULL);
962   assert(exception->signature == MagickSignature);
963   one=1;
964   image=AcquireImage(image_info);
965   image->depth=8;
966   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
967   if (status == MagickFalse)
968     {
969       image=DestroyImageList(image);
970       return((Image *) NULL);
971     }
972   /*
973     Read WPG image.
974   */
975   Header.FileId=ReadBlobLSBLong(image);
976   Header.DataOffset=(MagickOffsetType) ReadBlobLSBLong(image);
977   Header.ProductType=ReadBlobLSBShort(image);
978   Header.FileType=ReadBlobLSBShort(image);
979   Header.MajorVersion=ReadBlobByte(image);
980   Header.MinorVersion=ReadBlobByte(image);
981   Header.EncryptKey=ReadBlobLSBShort(image);
982   Header.Reserved=ReadBlobLSBShort(image);
983
984   if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
985     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
986   if (Header.EncryptKey!=0)
987     ThrowReaderException(CoderError,"EncryptedWPGImageFileNotSupported");
988
989   image->columns = 1;
990   image->rows = 1;
991   image->colors = 0;
992   bpp=0;
993   BitmapHeader2.RotAngle=0;
994
995   switch(Header.FileType)
996     {
997     case 1:     /* WPG level 1 */
998       while(!EOFBlob(image)) /* object parser loop */
999         {
1000           (void) SeekBlob(image,Header.DataOffset,SEEK_SET);
1001           if(EOFBlob(image))
1002             break;
1003
1004           Rec.RecType=(i=ReadBlobByte(image));
1005           if(i==EOF)
1006             break;
1007           Rd_WP_DWORD(image,&Rec.RecordLength);
1008           if(EOFBlob(image))
1009             break;
1010
1011           Header.DataOffset=TellBlob(image)+Rec.RecordLength;
1012
1013           switch(Rec.RecType)
1014             {
1015             case 0x0B: /* bitmap type 1 */
1016               BitmapHeader1.Width=ReadBlobLSBShort(image);
1017               BitmapHeader1.Heigth=ReadBlobLSBShort(image);
1018               BitmapHeader1.Depth=ReadBlobLSBShort(image);
1019               BitmapHeader1.HorzRes=ReadBlobLSBShort(image);
1020               BitmapHeader1.VertRes=ReadBlobLSBShort(image);
1021
1022               if(BitmapHeader1.HorzRes && BitmapHeader1.VertRes)
1023                 {
1024                   image->units=PixelsPerCentimeterResolution;
1025                   image->x_resolution=BitmapHeader1.HorzRes/470.0;
1026                   image->y_resolution=BitmapHeader1.VertRes/470.0;
1027                 }
1028               image->columns=BitmapHeader1.Width;
1029               image->rows=BitmapHeader1.Heigth;
1030               bpp=BitmapHeader1.Depth;
1031
1032               goto UnpackRaster;
1033
1034             case 0x0E:  /*Color palette */
1035               WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1036               WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1037
1038               image->colors=WPG_Palette.NumOfEntries;
1039               if (!AcquireImageColormap(image,image->colors))
1040                 goto NoMemory;
1041               for (i=WPG_Palette.StartIndex;
1042                    i < (int)WPG_Palette.NumOfEntries; i++)
1043                 {
1044                   image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1045                     ReadBlobByte(image));
1046                   image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1047                     ReadBlobByte(image));
1048                   image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1049                     ReadBlobByte(image));
1050                 }
1051               break;
1052      
1053             case 0x11:  /* Start PS l1 */
1054               if(Rec.RecordLength > 8)
1055                 image=ExtractPostscript(image,image_info,
1056                   TellBlob(image)+8,   /* skip PS header in the wpg */
1057                   (ssize_t) Rec.RecordLength-8,exception);
1058               break;     
1059
1060             case 0x14:  /* bitmap type 2 */
1061               BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
1062               BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
1063               BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
1064               BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
1065               BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
1066               BitmapHeader2.Width=ReadBlobLSBShort(image);
1067               BitmapHeader2.Heigth=ReadBlobLSBShort(image);
1068               BitmapHeader2.Depth=ReadBlobLSBShort(image);
1069               BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
1070               BitmapHeader2.VertRes=ReadBlobLSBShort(image);
1071
1072               image->units=PixelsPerCentimeterResolution;
1073               image->page.width=(unsigned int)
1074                 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
1075               image->page.height=(unsigned int)
1076                 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
1077               image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
1078               image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
1079               if(BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
1080                 {
1081                   image->x_resolution=BitmapHeader2.HorzRes/470.0;
1082                   image->y_resolution=BitmapHeader2.VertRes/470.0;
1083                 }
1084               image->columns=BitmapHeader2.Width;
1085               image->rows=BitmapHeader2.Heigth;
1086               bpp=BitmapHeader2.Depth;
1087
1088             UnpackRaster:      
1089               if ((image->colors == 0) && (bpp != 24))
1090                 {
1091                   image->colors=one << bpp;
1092                   if (!AcquireImageColormap(image,image->colors))
1093                     {
1094                     NoMemory:
1095                       ThrowReaderException(ResourceLimitError,
1096                         "MemoryAllocationFailed");
1097                     }
1098                   /* printf("Load default colormap \n"); */
1099                   for (i=0; (i < (int) image->colors) && (i < 256); i++)
1100                     {               
1101                       image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
1102                       image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
1103                       image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
1104                     }
1105                 }
1106               else
1107                 {
1108                   if (bpp < 24)
1109                     if ( (image->colors < (one << bpp)) && (bpp != 24) )
1110                       image->colormap=(PixelPacket *) ResizeQuantumMemory(
1111                         image->colormap,(size_t) (one << bpp),
1112                         sizeof(*image->colormap));
1113                 }
1114           
1115               if (bpp == 1)
1116                 {
1117                   if(image->colormap[0].red==0 &&
1118                      image->colormap[0].green==0 &&
1119                      image->colormap[0].blue==0 &&
1120                      image->colormap[1].red==0 &&
1121                      image->colormap[1].green==0 &&
1122                      image->colormap[1].blue==0)
1123                     {  /* fix crippled monochrome palette */
1124                       image->colormap[1].red =
1125                         image->colormap[1].green =
1126                         image->colormap[1].blue = QuantumRange;
1127                     }
1128                 }      
1129
1130               if(UnpackWPGRaster(image,bpp) < 0)
1131                 /* The raster cannot be unpacked */
1132                 {
1133                 DecompressionFailed:
1134                   ThrowReaderException(CoderError,"UnableToDecompressImage");
1135                     }
1136
1137               if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1138                 {  
1139                   /* flop command */
1140                   if(BitmapHeader2.RotAngle & 0x8000)
1141                     {
1142                       rotated_image = FlopImage(image, exception);
1143                       rotated_image->blob = image->blob;
1144                       DuplicateBlob(rotated_image,image);
1145                       (void) RemoveLastImageFromList(&image);
1146                       AppendImageToList(&image,rotated_image);
1147                     }
1148                   /* flip command */
1149                   if(BitmapHeader2.RotAngle & 0x2000)
1150                     {
1151                       rotated_image = FlipImage(image, exception);
1152                       rotated_image->blob = image->blob;
1153                       DuplicateBlob(rotated_image,image);
1154                       (void) RemoveLastImageFromList(&image);
1155                       AppendImageToList(&image,rotated_image);    
1156                     }
1157     
1158       /* rotate command */
1159                   if(BitmapHeader2.RotAngle & 0x0FFF)
1160                     {
1161                       rotated_image = RotateImage(image, (BitmapHeader2.RotAngle & 0x0FFF), exception);
1162                       rotated_image->blob = image->blob;
1163                       DuplicateBlob(rotated_image,image);
1164                       (void) RemoveLastImageFromList(&image);
1165                       AppendImageToList(&image,rotated_image);    
1166                     }                
1167                 }
1168
1169               /* Allocate next image structure. */
1170               AcquireNextImage(image_info,image);
1171               image->depth=8;
1172               if (image->next == (Image *) NULL)
1173                 goto Finish;
1174               image=SyncNextImageInList(image);
1175               image->columns=image->rows=0;
1176               image->colors=0;
1177               break;
1178
1179             case 0x1B:  /* Postscript l2 */
1180               if(Rec.RecordLength>0x3C)
1181                 image=ExtractPostscript(image,image_info,
1182                   TellBlob(image)+0x3C,   /* skip PS l2 header in the wpg */
1183                   (ssize_t) Rec.RecordLength-0x3C,exception);
1184               break;
1185             }
1186         }
1187       break;
1188
1189     case 2:  /* WPG level 2 */
1190       (void) memset(CTM,0,sizeof(CTM));
1191       StartWPG.PosSizePrecision = 0;
1192       while(!EOFBlob(image)) /* object parser loop */
1193         {
1194           (void) SeekBlob(image,Header.DataOffset,SEEK_SET);
1195           if(EOFBlob(image))
1196             break;
1197
1198           Rec2.Class=(i=ReadBlobByte(image));
1199           if(i==EOF)
1200             break;
1201           Rec2.RecType=(i=ReadBlobByte(image));
1202           if(i==EOF)
1203             break;
1204           Rd_WP_DWORD(image,&Rec2.Extension);
1205           Rd_WP_DWORD(image,&Rec2.RecordLength);
1206           if(EOFBlob(image))
1207             break;
1208
1209           Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1210
1211           switch(Rec2.RecType)
1212             {
1213       case 1:
1214               StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1215               StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1216               StartWPG.PosSizePrecision=ReadBlobByte(image);
1217               break;
1218             case 0x0C:    /* Color palette */
1219               WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1220               WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1221
1222               image->colors=WPG_Palette.NumOfEntries;
1223               if (AcquireImageColormap(image,image->colors) == MagickFalse)
1224                 ThrowReaderException(ResourceLimitError,
1225                   "MemoryAllocationFailed");
1226               for (i=WPG_Palette.StartIndex;
1227                    i < (int)WPG_Palette.NumOfEntries; i++)
1228                 {
1229                   image->colormap[i].red=ScaleCharToQuantum((char)
1230                     ReadBlobByte(image));
1231                   image->colormap[i].green=ScaleCharToQuantum((char)
1232                     ReadBlobByte(image));
1233                   image->colormap[i].blue=ScaleCharToQuantum((char)
1234                     ReadBlobByte(image));
1235                   (void) ReadBlobByte(image);   /*Opacity??*/
1236                 }
1237               break;
1238             case 0x0E:
1239               Bitmap2Header1.Width=ReadBlobLSBShort(image);
1240               Bitmap2Header1.Heigth=ReadBlobLSBShort(image);
1241               Bitmap2Header1.Depth=ReadBlobByte(image);
1242               Bitmap2Header1.Compression=ReadBlobByte(image);
1243
1244               if(Bitmap2Header1.Compression > 1)
1245                 continue; /*Unknown compression method */
1246               switch(Bitmap2Header1.Depth)
1247                 {
1248                 case 1:
1249                   bpp=1;
1250                   break;
1251                 case 2:
1252                   bpp=2;
1253                   break;
1254                 case 3:
1255                   bpp=4;
1256                   break;
1257                 case 4:
1258                   bpp=8;
1259                   break;
1260                 case 8:
1261                   bpp=24;
1262                   break;
1263                 default:
1264                   continue;  /*Ignore raster with unknown depth*/
1265                 }
1266               image->columns=Bitmap2Header1.Width;
1267               image->rows=Bitmap2Header1.Heigth;  
1268
1269               if ((image->colors == 0) && (bpp != 24))
1270                 {
1271                   size_t
1272                     one;
1273
1274                   one=1;
1275                   image->colors=one << bpp;
1276                   if (!AcquireImageColormap(image,image->colors))
1277                     goto NoMemory;
1278                 }
1279               else
1280                 {
1281                   if(bpp < 24)
1282                     if( image->colors<(one << bpp) && bpp!=24 )
1283                       image->colormap=(PixelPacket *) ResizeQuantumMemory(
1284                        image->colormap,(size_t) (one << bpp),
1285                        sizeof(*image->colormap));
1286                 }
1287
1288
1289               switch(Bitmap2Header1.Compression)
1290                 {
1291                 case 0:    /*Uncompressed raster*/
1292                   {
1293                     ldblk=(ssize_t) ((bpp*image->columns+7)/8);
1294                     BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t)
1295                       ldblk,sizeof(*BImgBuff));
1296                     if (BImgBuff == (unsigned char *) NULL)
1297                       goto NoMemory;
1298
1299                     for(i=0; i< (ssize_t) image->rows; i++)
1300                       {
1301                         (void) ReadBlob(image,ldblk,BImgBuff);
1302                         InsertRow(BImgBuff,i,image,bpp);
1303                       }
1304
1305                     if(BImgBuff)
1306                       BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);;
1307                     break;
1308                   }
1309                 case 1:    /*RLE for WPG2 */
1310                   {
1311                     if( UnpackWPG2Raster(image,bpp) < 0)
1312                       goto DecompressionFailed;
1313                     break;
1314                   }   
1315                 }
1316
1317               if(CTM[0][0]<0 && !image_info->ping)
1318     {    /*?? RotAngle=360-RotAngle;*/
1319       rotated_image = FlopImage(image, exception);
1320       rotated_image->blob = image->blob;
1321       DuplicateBlob(rotated_image,image);
1322       (void) RemoveLastImageFromList(&image);
1323       AppendImageToList(&image,rotated_image);
1324                   /* Try to change CTM according to Flip - I am not sure, must be checked.      
1325                      Tx(0,0)=-1;      Tx(1,0)=0;   Tx(2,0)=0;
1326                      Tx(0,1)= 0;      Tx(1,1)=1;   Tx(2,1)=0;
1327                      Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1328                      Tx(1,2)=0;   Tx(2,2)=1; */                  
1329                 }
1330               if(CTM[1][1]<0 && !image_info->ping)
1331     {    /*?? RotAngle=360-RotAngle;*/
1332       rotated_image = FlipImage(image, exception);
1333       rotated_image->blob = image->blob;
1334       DuplicateBlob(rotated_image,image);
1335       (void) RemoveLastImageFromList(&image);
1336       AppendImageToList(&image,rotated_image);
1337                   /* Try to change CTM according to Flip - I am not sure, must be checked.
1338                      float_matrix Tx(3,3);
1339                      Tx(0,0)= 1;   Tx(1,0)= 0;   Tx(2,0)=0;
1340                      Tx(0,1)= 0;   Tx(1,1)=-1;   Tx(2,1)=0;
1341                      Tx(0,2)= 0;   Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1342                      Tx(2,2)=1; */      
1343     }    
1344     
1345
1346               /* Allocate next image structure. */
1347               AcquireNextImage(image_info,image);
1348               image->depth=8;
1349               if (image->next == (Image *) NULL)
1350                 goto Finish;
1351               image=SyncNextImageInList(image);
1352               image->columns=image->rows=1;
1353               image->colors=0;
1354               break;
1355
1356             case 0x12:  /* Postscript WPG2*/
1357         i=ReadBlobLSBShort(image);
1358               if(Rec2.RecordLength > (unsigned int) i)
1359                 image=ExtractPostscript(image,image_info,
1360                   TellBlob(image)+i,    /*skip PS header in the wpg2*/
1361                   (ssize_t) (Rec2.RecordLength-i-2),exception);
1362               break;
1363
1364       case 0x1B:          /*bitmap rectangle*/
1365               WPG2Flags = LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM);
1366               (void) WPG2Flags;
1367               break;
1368             }
1369         }
1370
1371       break;
1372
1373     default:
1374       {
1375          ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
1376       }
1377    }
1378
1379  Finish:
1380   (void) CloseBlob(image);
1381
1382   {
1383     Image
1384       *p;
1385
1386     ssize_t
1387       scene=0;
1388
1389     /*
1390       Rewind list, removing any empty images while rewinding.
1391     */
1392     p=image;
1393     image=NULL;
1394     while (p != (Image *) NULL)
1395       {
1396         Image *tmp=p;
1397         if ((p->rows == 0) || (p->columns == 0)) {
1398           p=p->previous;
1399           DeleteImageFromList(&tmp);
1400         } else {
1401           image=p;
1402           p=p->previous;
1403         }
1404       }
1405     /*
1406       Fix scene numbers.
1407     */
1408     for (p=image; p != (Image *) NULL; p=p->next)
1409       p->scene=(size_t) scene++;
1410   }
1411   if (image == (Image *) NULL)
1412     ThrowReaderException(CorruptImageError,
1413       "ImageFileDoesNotContainAnyImageData");
1414   return(image);
1415 }
1416 \f
1417 /*
1418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419 %                                                                             %
1420 %                                                                             %
1421 %                                                                             %
1422 %   R e g i s t e r W P G I m a g e                                           %
1423 %                                                                             %
1424 %                                                                             %
1425 %                                                                             %
1426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427 %
1428 %  Method RegisterWPGImage adds attributes for the WPG image format to
1429 %  the list of supported formats.  The attributes include the image format
1430 %  tag, a method to read and/or write the format, whether the format
1431 %  supports the saving of more than one frame to the same file or blob,
1432 %  whether the format supports native in-memory I/O, and a brief
1433 %  description of the format.
1434 %
1435 %  The format of the RegisterWPGImage method is:
1436 %
1437 %      size_t RegisterWPGImage(void)
1438 %
1439 */
1440 ModuleExport size_t RegisterWPGImage(void)
1441 {
1442   MagickInfo
1443     *entry;
1444
1445   entry=SetMagickInfo("WPG");
1446   entry->decoder=(DecodeImageHandler *) ReadWPGImage;
1447   entry->magick=(IsImageFormatHandler *) IsWPG;
1448   entry->description=AcquireString("Word Perfect Graphics");
1449   entry->module=ConstantString("WPG");
1450   entry->seekable_stream=MagickTrue;
1451   (void) RegisterMagickInfo(entry);
1452   return(MagickImageCoderSignature);
1453 }
1454 \f
1455 /*
1456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457 %                                                                             %
1458 %                                                                             %
1459 %                                                                             %
1460 %   U n r e g i s t e r W P G I m a g e                                       %
1461 %                                                                             %
1462 %                                                                             %
1463 %                                                                             %
1464 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465 %
1466 %  Method UnregisterWPGImage removes format registrations made by the
1467 %  WPG module from the list of supported formats.
1468 %
1469 %  The format of the UnregisterWPGImage method is:
1470 %
1471 %      UnregisterWPGImage(void)
1472 %
1473 */
1474 ModuleExport void UnregisterWPGImage(void)
1475 {
1476   (void) UnregisterMagickInfo("WPG");
1477 }