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