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