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