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