]> granicus.if.org Git - imagemagick/blob - coders/wpg.c
Added missing calls to xmlFreeDoc to fix memory leak reported in #1766.
[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-2019 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://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               q+=GetPixelChannels(image);
310             }
311             p++;
312           }
313         break;
314       }
315     case 2:  /* Convert PseudoColor scanline. */
316       {
317         for (x=0; x < ((ssize_t) image->columns-3); x+=4)
318         {
319             index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
320             SetPixelIndex(image,index,q);
321             if (index < image->colors)
322               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
323             q+=GetPixelChannels(image);
324             index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
325             SetPixelIndex(image,index,q);
326             if (index < image->colors)
327               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
328             q+=GetPixelChannels(image);
329             index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,exception);
330             SetPixelIndex(image,index,q);
331             if (index < image->colors)
332               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
333             q+=GetPixelChannels(image);
334             index=ConstrainColormapIndex(image,(*p) & 0x3,exception);
335             SetPixelIndex(image,index,q);
336             if (index < image->colors)
337               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
338             q+=GetPixelChannels(image);
339             p++;
340         }
341        if ((image->columns % 4) != 0)
342           {
343             index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
344             SetPixelIndex(image,index,q);
345             if (index < image->colors)
346               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
347             q+=GetPixelChannels(image);
348             if ((image->columns % 4) > 1)
349               {
350                 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
351                 SetPixelIndex(image,index,q);
352                 if (index < image->colors)
353                   SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
354                 q+=GetPixelChannels(image);
355                 if ((image->columns % 4) > 2)
356                   {
357                     index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,
358                       exception);
359                     SetPixelIndex(image,index,q);
360                     if (index < image->colors)
361                       SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
362                         index,q);
363                     q+=GetPixelChannels(image);
364                   }
365               }
366             p++;
367           }
368         break;
369       }
370
371     case 4:  /* Convert PseudoColor scanline. */
372       {
373         for (x=0; x < ((ssize_t) image->columns-1); x+=2)
374           {
375             index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
376             SetPixelIndex(image,index,q);
377             if (index < image->colors)
378               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
379             q+=GetPixelChannels(image);
380             index=ConstrainColormapIndex(image,(*p) & 0x0f,exception);
381             SetPixelIndex(image,index,q);
382             if (index < image->colors)
383               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
384             p++;
385             q+=GetPixelChannels(image);
386           }
387         if ((image->columns % 2) != 0)
388           {
389             index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
390             SetPixelIndex(image,index,q);
391             if (index < image->colors)
392               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
393             p++;
394             q+=GetPixelChannels(image);
395           }
396         break;
397       }
398     case 8: /* Convert PseudoColor scanline. */
399       {
400         for (x=0; x < (ssize_t) image->columns; x++)
401           {
402             index=ConstrainColormapIndex(image,*p,exception);
403             SetPixelIndex(image,index,q);
404             if (index < image->colors)
405               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
406             p++;
407             q+=GetPixelChannels(image);
408           }
409       }
410       break;
411
412     case 24:     /*  Convert DirectColor scanline.  */
413       for (x=0; x < (ssize_t) image->columns; x++)
414         {
415           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
416           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
417           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
418           q+=GetPixelChannels(image);
419         }
420       break;
421     }
422   if (!SyncAuthenticPixels(image,exception))
423     return(MagickFalse);
424   return(MagickTrue);
425 }
426
427
428 /* Helper for WPG1 raster reader. */
429 #define InsertByte(b) \
430 { \
431   BImgBuff[x]=b; \
432   x++; \
433   if((ssize_t) x>=ldblk) \
434   { \
435     if (InsertRow(image,BImgBuff,(ssize_t) y,bpp,exception) != MagickFalse) \
436       y++; \
437     x=0; \
438   } \
439 }
440 /* WPG1 raster reader. */
441 static int UnpackWPGRaster(Image *image,int bpp,ExceptionInfo *exception)
442 {
443   int
444     x,
445     y,
446     i;
447
448   unsigned char
449     bbuf,
450     *BImgBuff,
451     RunCount;
452
453   ssize_t
454     ldblk;
455
456   x=0;
457   y=0;
458
459   ldblk=(ssize_t) ((bpp*image->columns+7)/8);
460   BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
461     8*sizeof(*BImgBuff));
462   if(BImgBuff==NULL) return(-2);
463   (void) memset(BImgBuff,0,(size_t) ldblk*8*sizeof(*BImgBuff));
464
465   while(y<(ssize_t) image->rows)
466     {
467       int
468         c;
469
470       c=ReadBlobByte(image);
471       if (c == EOF)
472         break;
473       bbuf=(unsigned char) c;
474       RunCount=bbuf & 0x7F;
475       if(bbuf & 0x80)
476         {
477           if(RunCount)  /* repeat next byte runcount * */
478             {
479               bbuf=ReadBlobByte(image);
480               for(i=0;i<(int) RunCount;i++) InsertByte(bbuf);
481             }
482           else {  /* read next byte as RunCount; repeat 0xFF runcount* */
483             c=ReadBlobByte(image);
484             if (c < 0)
485               break;
486             RunCount=(unsigned char) c;
487             for(i=0;i<(int) RunCount;i++) InsertByte(0xFF);
488           }
489         }
490       else {
491         if(RunCount)   /* next runcount byte are readed directly */
492           {
493             for(i=0;i < (int) RunCount;i++)
494               {
495                 c=ReadBlobByte(image);
496                 if (c < 0)
497                   break;
498                 InsertByte(c);
499               }
500           }
501         else {  /* repeat previous line runcount* */
502           c=ReadBlobByte(image);
503           if (c == EOF)
504             {
505               BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
506               return(-7);
507             }
508           RunCount=(unsigned char) c;
509           if(x) {    /* attempt to duplicate row from x position: */
510             /* I do not know what to do here */
511             BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
512             return(-3);
513           }
514           for(i=0;i < (int) RunCount;i++)
515             {
516               x=0;
517               y++;    /* Here I need to duplicate previous row RUNCOUNT* */
518               if(y<2) continue;
519               if(y>(ssize_t) image->rows)
520                 {
521                   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
522                   return(-4);
523                 }
524               if (InsertRow(image,BImgBuff,y-1,bpp,exception) == MagickFalse)
525                 {
526                   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
527                   return(-5);
528                 }
529             }
530         }
531       }
532       if (EOFBlob(image) != MagickFalse)
533         break;
534     }
535   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
536   return(y <(ssize_t) image->rows ? -5 : 0);
537 }
538
539
540 /* Helper for WPG2 reader. */
541 #define InsertByte6(b) \
542 { \
543 DisableMSCWarning(4310) \
544   if(XorMe)\
545     BImgBuff[x] = (unsigned char)~b;\
546   else\
547     BImgBuff[x] = b;\
548 RestoreMSCWarning \
549   x++; \
550   if((ssize_t) x >= ldblk) \
551   { \
552     if (InsertRow(image,BImgBuff,(ssize_t) y,bpp,exception) != MagickFalse) \
553       y++; \
554     x=0; \
555    } \
556 }
557 /* WPG2 raster reader. */
558 static int UnpackWPG2Raster(Image *image,int bpp,ExceptionInfo *exception)
559 {
560   int
561     RunCount,
562     XorMe = 0;
563
564   size_t
565     x,
566     y;
567
568   ssize_t
569     i,
570     ldblk;
571
572   unsigned int
573     SampleSize=1;
574
575   unsigned char
576     bbuf,
577     *BImgBuff,
578     SampleBuffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
579
580   x=0;
581   y=0;
582   ldblk=(ssize_t) ((bpp*image->columns+7)/8);
583   BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
584     sizeof(*BImgBuff));
585   if(BImgBuff==NULL)
586     return(-2);
587   (void) memset(BImgBuff,0,ldblk*sizeof(*BImgBuff));
588
589   while( y< image->rows)
590     {
591       bbuf=ReadBlobByte(image);
592
593       switch(bbuf)
594         {
595         case 0x7D:
596           SampleSize=ReadBlobByte(image);  /* DSZ */
597           if(SampleSize>8)
598             {
599               BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
600               return(-2);
601             }
602           if(SampleSize<1)
603             {
604               BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
605               return(-2);
606             }
607           break;
608         case 0x7E:
609           if (y == 0)
610             (void) FormatLocaleFile(stderr,
611               "\nUnsupported WPG token XOR, please report!");
612           XorMe=!XorMe;
613           break;
614         case 0x7F:
615           RunCount=ReadBlobByte(image);   /* BLK */
616           if (RunCount < 0)
617             break;
618           for(i=0; i < SampleSize*(RunCount+1); i++)
619             {
620               InsertByte6(0);
621             }
622           break;
623         case 0xFD:
624           RunCount=ReadBlobByte(image);   /* EXT */
625           if (RunCount < 0)
626             break;
627           for(i=0; i<= RunCount;i++)
628             for(bbuf=0; bbuf < SampleSize; bbuf++)
629               InsertByte6(SampleBuffer[bbuf]);
630           break;
631         case 0xFE:
632           RunCount=ReadBlobByte(image);  /* RST */
633           if (RunCount < 0)
634             break;
635           if(x!=0)
636             {
637               (void) FormatLocaleFile(stderr,
638                 "\nUnsupported WPG2 unaligned token RST x=%.20g, please report!\n"
639                 ,(double) x);
640               BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
641               return(-3);
642             }
643           {
644             /* duplicate the previous row RunCount x */
645             for(i=0;i<=RunCount;i++)
646               {
647                 if (InsertRow(image,BImgBuff,(ssize_t) (image->rows > y ? y : image->rows-1),bpp,exception) != MagickFalse)
648                   y++;
649               }
650           }
651           break;
652         case 0xFF:
653           RunCount=ReadBlobByte(image);   /* WHT */
654           if (RunCount < 0)
655             break;
656           for(i=0; i < SampleSize*(RunCount+1); i++)
657             {
658               InsertByte6(0xFF);
659             }
660           break;
661         default:
662           RunCount=bbuf & 0x7F;
663
664           if(bbuf & 0x80)     /* REP */
665             {
666               for(i=0; i < SampleSize; i++)
667                 SampleBuffer[i]=ReadBlobByte(image);
668               for(i=0;i<=RunCount;i++)
669                 for(bbuf=0;bbuf<SampleSize;bbuf++)
670                   InsertByte6(SampleBuffer[bbuf]);
671             }
672           else {      /* NRP */
673             for(i=0; i< SampleSize*(RunCount+1);i++)
674               {
675                 bbuf=ReadBlobByte(image);
676                 InsertByte6(bbuf);
677               }
678           }
679         }
680       if (EOFBlob(image) != MagickFalse)
681         break;
682     }
683   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
684   return(0);
685 }
686
687
688 typedef float tCTM[3][3];
689
690 static unsigned LoadWPG2Flags(Image *image,char Precision,float *Angle,tCTM *CTM)
691 {
692 const unsigned char TPR=1,TRN=2,SKW=4,SCL=8,ROT=0x10,OID=0x20,LCK=0x80;
693 ssize_t x;
694 unsigned DenX;
695 unsigned Flags;
696
697  (void) memset(*CTM,0,sizeof(*CTM));     /*CTM.erase();CTM.resize(3,3);*/
698  (*CTM)[0][0]=1;
699  (*CTM)[1][1]=1;
700  (*CTM)[2][2]=1;
701
702  Flags=ReadBlobLSBShort(image);
703  if(Flags & LCK) (void) ReadBlobLSBLong(image);  /*Edit lock*/
704  if(Flags & OID)
705   {
706   if(Precision==0)
707     {(void) ReadBlobLSBShort(image);}  /*ObjectID*/
708   else
709     {(void) ReadBlobLSBLong(image);}  /*ObjectID (Double precision)*/
710   }
711  if(Flags & ROT)
712   {
713   x=ReadBlobLSBLong(image);  /*Rot Angle*/
714   if(Angle) *Angle=x/65536.0;
715   }
716  if(Flags & (ROT|SCL))
717   {
718   x=ReadBlobLSBLong(image);  /*Sx*cos()*/
719   (*CTM)[0][0] = (float)x/0x10000;
720   x=ReadBlobLSBLong(image);  /*Sy*cos()*/
721   (*CTM)[1][1] = (float)x/0x10000;
722   }
723  if(Flags & (ROT|SKW))
724   {
725   x=ReadBlobLSBLong(image);       /*Kx*sin()*/
726   (*CTM)[1][0] = (float)x/0x10000;
727   x=ReadBlobLSBLong(image);       /*Ky*sin()*/
728   (*CTM)[0][1] = (float)x/0x10000;
729   }
730  if(Flags & TRN)
731   {
732   x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image);  /*Tx*/
733         if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
734             else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
735   x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image);  /*Ty*/
736   (*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
737         if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
738             else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
739   }
740  if(Flags & TPR)
741   {
742   x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image);  /*Px*/
743   (*CTM)[2][0] = x + (float)DenX/0x10000;;
744   x=ReadBlobLSBShort(image);  DenX=ReadBlobLSBShort(image); /*Py*/
745   (*CTM)[2][1] = x + (float)DenX/0x10000;
746   }
747  return(Flags);
748 }
749
750
751 static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
752   MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo *exception)
753 {
754   char
755     postscript_file[MagickPathExtent];
756
757   const MagicInfo
758     *magic_info;
759
760   FILE
761     *ps_file;
762
763   int
764     c;
765
766   ImageInfo
767     *clone_info;
768
769   Image
770     *image2;
771
772   MagickBooleanType
773     status;
774
775   unsigned char
776     magick[2*MagickPathExtent];
777
778   ssize_t
779     count;
780
781   if ((clone_info=CloneImageInfo(image_info)) == NULL)
782     return(image);
783   clone_info->blob=(void *) NULL;
784   clone_info->length=0;
785   status=MagickFalse;
786
787   /* Obtain temporary file */
788   (void) AcquireUniqueFilename(postscript_file);
789   ps_file=fopen_utf8(postscript_file,"wb");
790   if (ps_file == (FILE *) NULL)
791     goto FINISH;
792
793   /* Copy postscript to temporary file */
794   if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
795     {
796       (void) fclose(ps_file);
797       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
798         image->filename);
799       goto FINISH_UNL;
800     }
801   count=ReadBlob(image, 2*MagickPathExtent, magick);
802   if (count < 1)
803     {
804       (void) fclose(ps_file);
805       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
806         image->filename);
807       goto FINISH_UNL;
808     }
809
810   if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
811     {
812       (void) fclose(ps_file);
813       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
814         image->filename);
815       goto FINISH_UNL;
816     }
817   while (PS_Size-- > 0)
818   {
819     c=ReadBlobByte(image);
820     if (c == EOF)
821       {      
822         (void) fclose(ps_file);
823         ThrowException(exception,CorruptImageError,"ImproperImageHeader",
824           image->filename);
825         goto FINISH_UNL;
826       }
827     (void) fputc(c,ps_file);
828   }
829   (void) fclose(ps_file);
830
831     /* Detect file format - Check magic.mgk configuration file. */
832   magic_info=GetMagicInfo(magick,count,exception);
833   if(magic_info == (const MagicInfo *) NULL) goto FINISH_UNL;
834   /*     printf("Detected:%s  \n",magic_info->name); */
835   if(exception->severity != UndefinedException) goto FINISH_UNL;
836   (void) strncpy(clone_info->magick,GetMagicName(magic_info),
837     MagickPathExtent-1);
838   if (LocaleCompare(clone_info->magick,"PFB") != 0)
839     {      
840       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
841         image->filename);
842       goto FINISH_UNL;
843     }
844
845     /* Read nested image */
846   /*FormatString(clone_info->filename,"%s:%s",magic_info->name,postscript_file);*/
847   FormatLocaleString(clone_info->filename,MagickPathExtent,"%.1024s:%.1024s",
848     clone_info->magick,postscript_file);
849   image2=ReadImage(clone_info,exception);
850
851   if (!image2)
852     goto FINISH_UNL;
853   if(exception->severity>=ErrorException)
854   {
855     CloseBlob(image2);
856     DestroyImageList(image2);
857     goto FINISH_UNL;
858   }
859
860   {
861     Image
862       *p;
863
864     /*
865       Replace current image with new image while copying base image attributes.
866     */
867     p=image2;
868     do
869     {
870       (void) CopyMagickString(p->filename,image->filename,MagickPathExtent);
871       (void) CopyMagickString(p->magick_filename,image->magick_filename,
872         MagickPathExtent);
873       (void) CopyMagickString(p->magick,image->magick,MagickPathExtent);
874       if ((p->rows == 0) || (p->columns == 0))
875         {
876           DeleteImageFromList(&p);
877           if (p == (Image *) NULL)
878             {
879               image2=(Image *) NULL;
880               goto FINISH_UNL;
881             }
882         }
883       else
884         {
885           DestroyBlob(p);
886           p->blob=ReferenceBlob(image->blob);
887           p=p->next;
888         }
889     } while (p != (Image *) NULL);
890   }
891
892   if ((image->rows == 0 || image->columns == 0) &&
893       (image->previous != NULL || image->next != NULL))
894   {
895     DeleteImageFromList(&image);
896   }
897
898   AppendImageToList(&image,image2);
899   while (image->next != NULL)
900     image=image->next;
901   status=MagickTrue;
902
903  FINISH_UNL:
904   (void) RelinquishUniqueFileResource(postscript_file);
905  FINISH:
906   DestroyImageInfo(clone_info);
907   if (status == MagickFalse)
908     return(DestroyImageList(image));
909   return(image);
910 }
911 \f
912 /*
913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
914 %                                                                             %
915 %                                                                             %
916 %                                                                             %
917 %   R e a d W P G I m a g e                                                   %
918 %                                                                             %
919 %                                                                             %
920 %                                                                             %
921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
922 %
923 %  Method ReadWPGImage reads an WPG X image file and returns it.  It
924 %  allocates the memory necessary for the new Image structure and returns a
925 %  pointer to the new image.
926 %
927 %  The format of the ReadWPGImage method is:
928 %
929 %    Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
930 %
931 %  A description of each parameter follows:
932 %
933 %    o image:  Method ReadWPGImage returns a pointer to the image after
934 %      reading. A null image is returned if there is a memory shortage or if
935 %      the image cannot be read.
936 %
937 %    o image_info: Specifies a pointer to a ImageInfo structure.
938 %
939 %    o exception: return any errors or warnings in this structure.
940 %
941 */
942 static Image *ReadWPGImage(const ImageInfo *image_info,
943   ExceptionInfo *exception)
944 {
945   typedef struct
946   {
947     size_t FileId;
948     MagickOffsetType DataOffset;
949     unsigned int ProductType;
950     unsigned int FileType;
951     unsigned char MajorVersion;
952     unsigned char MinorVersion;
953     unsigned int EncryptKey;
954     unsigned int Reserved;
955   } WPGHeader;
956
957   typedef struct
958   {
959     unsigned char RecType;
960     size_t RecordLength;
961   } WPGRecord;
962
963   typedef struct
964   {
965     unsigned char Class;
966     unsigned char RecType;
967     size_t Extension;
968     size_t RecordLength;
969   } WPG2Record;
970
971   typedef struct
972   {
973     unsigned  HorizontalUnits;
974     unsigned  VerticalUnits;
975     unsigned char PosSizePrecision;
976   } WPG2Start;
977
978   typedef struct
979   {
980     unsigned int Width;
981     unsigned int Height;
982     unsigned int Depth;
983     unsigned int HorzRes;
984     unsigned int VertRes;
985   } WPGBitmapType1;
986
987   typedef struct
988   {
989     unsigned int Width;
990     unsigned int Height;
991     unsigned char Depth;
992     unsigned char Compression;
993   } WPG2BitmapType1;
994
995   typedef struct
996   {
997     unsigned int RotAngle;
998     unsigned int LowLeftX;
999     unsigned int LowLeftY;
1000     unsigned int UpRightX;
1001     unsigned int UpRightY;
1002     unsigned int Width;
1003     unsigned int Height;
1004     unsigned int Depth;
1005     unsigned int HorzRes;
1006     unsigned int VertRes;
1007   } WPGBitmapType2;
1008
1009   typedef struct
1010   {
1011     unsigned int StartIndex;
1012     unsigned int NumOfEntries;
1013   } WPGColorMapRec;
1014
1015   /*
1016   typedef struct {
1017     size_t PS_unknown1;
1018     unsigned int PS_unknown2;
1019     unsigned int PS_unknown3;
1020   } WPGPSl1Record;
1021   */
1022
1023   Image
1024     *image;
1025
1026   unsigned int
1027     status;
1028
1029   WPGHeader
1030     Header;
1031
1032   WPGRecord
1033     Rec;
1034
1035   WPG2Record
1036     Rec2;
1037
1038   WPG2Start StartWPG;
1039
1040   WPGBitmapType1
1041     BitmapHeader1;
1042
1043   WPG2BitmapType1
1044     Bitmap2Header1;
1045
1046   WPGBitmapType2
1047     BitmapHeader2;
1048
1049   WPGColorMapRec
1050     WPG_Palette;
1051
1052   int
1053     i,
1054     bpp,
1055     WPG2Flags;
1056
1057   ssize_t
1058     ldblk;
1059
1060   size_t
1061     one;
1062
1063   unsigned char
1064     *BImgBuff;
1065
1066   tCTM CTM;         /*current transform matrix*/
1067
1068   /*
1069     Open image file.
1070   */
1071   assert(image_info != (const ImageInfo *) NULL);
1072   assert(image_info->signature == MagickCoreSignature);
1073   assert(exception != (ExceptionInfo *) NULL);
1074   assert(exception->signature == MagickCoreSignature);
1075   one=1;
1076   image=AcquireImage(image_info,exception);
1077   image->depth=8;
1078   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1079   if (status == MagickFalse)
1080     {
1081       image=DestroyImageList(image);
1082       return((Image *) NULL);
1083     }
1084   /*
1085     Read WPG image.
1086   */
1087   Header.FileId=ReadBlobLSBLong(image);
1088   Header.DataOffset=(MagickOffsetType) ReadBlobLSBLong(image);
1089   Header.ProductType=ReadBlobLSBShort(image);
1090   Header.FileType=ReadBlobLSBShort(image);
1091   Header.MajorVersion=ReadBlobByte(image);
1092   Header.MinorVersion=ReadBlobByte(image);
1093   Header.EncryptKey=ReadBlobLSBShort(image);
1094   Header.Reserved=ReadBlobLSBShort(image);
1095
1096   if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
1097     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1098   if (Header.EncryptKey!=0)
1099     ThrowReaderException(CoderError,"EncryptedWPGImageFileNotSupported");
1100
1101   image->columns = 1;
1102   image->rows = 1;
1103   image->colors = 0;
1104   image->storage_class=DirectClass;
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) == MagickFalse)
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                     {
1250                       PixelInfo
1251                         *colormap;
1252
1253                       size_t
1254                         colors;
1255
1256                       colormap=image->colormap;
1257                       colors=image->colors;
1258                       image->colormap=(PixelInfo *) NULL;
1259                       if (AcquireImageColormap(image,one << bpp,exception) == MagickFalse)
1260                         {
1261                           colormap=(PixelInfo *)
1262                             RelinquishMagickMemory(colormap);
1263                           goto NoMemory;
1264                         }
1265                       (void) memcpy(image->colormap,colormap,MagickMin(
1266                         image->colors,colors)*sizeof(*image->colormap));
1267                       colormap=(PixelInfo *)
1268                         RelinquishMagickMemory(colormap);
1269                     }
1270                 }
1271
1272               if ((bpp == 1) && (image->colors > 1))
1273                 {
1274                   if(image->colormap[0].red==0 &&
1275                      image->colormap[0].green==0 &&
1276                      image->colormap[0].blue==0 &&
1277                      image->colormap[1].red==0 &&
1278                      image->colormap[1].green==0 &&
1279                      image->colormap[1].blue==0)
1280                     {  /* fix crippled monochrome palette */
1281                       image->colormap[1].red =
1282                         image->colormap[1].green =
1283                         image->colormap[1].blue = QuantumRange;
1284                       image->colormap[1].alpha=OpaqueAlpha;
1285                     }
1286                 }
1287               if(!image_info->ping)
1288                 if(UnpackWPGRaster(image,bpp,exception) < 0)
1289                   /* The raster cannot be unpacked */
1290                   {
1291                   DecompressionFailed:
1292                     ThrowReaderException(CoderError,"UnableToDecompressImage");
1293                   }
1294
1295               if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1296                 {
1297                   /* flop command */
1298                   if(BitmapHeader2.RotAngle & 0x8000)
1299                     {
1300                       Image
1301                         *flop_image;
1302
1303                       flop_image = FlopImage(image, exception);
1304                       if (flop_image != (Image *) NULL) {
1305                         DuplicateBlob(flop_image,image);
1306                         ReplaceImageInList(&image,flop_image);
1307                       }
1308                     }
1309                   /* flip command */
1310                   if(BitmapHeader2.RotAngle & 0x2000)
1311                     {
1312                       Image
1313                         *flip_image;
1314
1315                       flip_image = FlipImage(image, exception);
1316                       if (flip_image != (Image *) NULL) {
1317                         DuplicateBlob(flip_image,image);
1318                         ReplaceImageInList(&image,flip_image);
1319                       }
1320                     }
1321                   /* rotate command */
1322                   if(BitmapHeader2.RotAngle & 0x0FFF)
1323                     {
1324                       Image
1325                         *rotate_image;
1326
1327                       rotate_image=RotateImage(image,(BitmapHeader2.RotAngle &
1328                         0x0FFF), exception);
1329                       if (rotate_image != (Image *) NULL) {
1330                         DuplicateBlob(rotate_image,image);
1331                         ReplaceImageInList(&image,rotate_image);
1332                       }
1333                     }
1334                 }
1335
1336               /* Allocate next image structure. */
1337               if ((image_info->ping != MagickFalse) &&
1338                   (image_info->number_scenes != 0))
1339                 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1340                   goto Finish;
1341               AcquireNextImage(image_info,image,exception);
1342               image->depth=8;
1343               if (image->next == (Image *) NULL)
1344                 goto Finish;
1345               image=SyncNextImageInList(image);
1346               image->columns=image->rows=0;
1347               image->colors=0;
1348               break;
1349
1350             case 0x1B:  /* Postscript l2 */
1351               if (Rec.RecordLength>0x3C)
1352                 {
1353                   image=ExtractPostscript(image,image_info,
1354                     TellBlob(image)+0x3C,   /* skip PS l2 header in the wpg */
1355                     (ssize_t) Rec.RecordLength-0x3C,exception);
1356                   if (image == NULL)
1357                     ThrowReaderException(CorruptImageError,
1358                       "ImproperImageHeader");
1359                 }
1360               break;
1361             }
1362         }
1363       break;
1364
1365     case 2:  /* WPG level 2 */
1366       (void) memset(CTM,0,sizeof(CTM));
1367       StartWPG.PosSizePrecision = 0;
1368       while(!EOFBlob(image)) /* object parser loop */
1369         {
1370           if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1371             break;
1372           if (EOFBlob(image))
1373             break;
1374
1375           Rec2.Class=(i=ReadBlobByte(image));
1376           if(i==EOF)
1377             break;
1378           Rec2.RecType=(i=ReadBlobByte(image));
1379           if(i==EOF)
1380             break;
1381           Rd_WP_DWORD(image,&Rec2.Extension);
1382           Rd_WP_DWORD(image,&Rec2.RecordLength);
1383           if(EOFBlob(image))
1384             break;
1385
1386           Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1387
1388           switch(Rec2.RecType)
1389             {
1390       case 1:
1391               StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1392               StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1393               StartWPG.PosSizePrecision=ReadBlobByte(image);
1394               break;
1395             case 0x0C:    /* Color palette */
1396               WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1397               WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1398               if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
1399                   (Rec2.RecordLength-2-2) / 3)
1400                 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1401               if (WPG_Palette.StartIndex >= WPG_Palette.NumOfEntries)
1402                 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1403               image->colors=WPG_Palette.NumOfEntries;
1404               if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1405                 ThrowReaderException(ResourceLimitError,
1406                   "MemoryAllocationFailed");
1407               for (i=WPG_Palette.StartIndex;
1408                    i < (int)WPG_Palette.NumOfEntries; i++)
1409                 {
1410                   image->colormap[i].red=ScaleCharToQuantum((char)
1411                     ReadBlobByte(image));
1412                   image->colormap[i].green=ScaleCharToQuantum((char)
1413                     ReadBlobByte(image));
1414                   image->colormap[i].blue=ScaleCharToQuantum((char)
1415                     ReadBlobByte(image));
1416                   image->colormap[i].alpha=OpaqueAlpha;
1417                   (void) ReadBlobByte(image);   /*Opacity??*/
1418                 }
1419               break;
1420             case 0x0E:
1421               Bitmap2Header1.Width=ReadBlobLSBShort(image);
1422               Bitmap2Header1.Height=ReadBlobLSBShort(image);
1423               if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Height == 0))
1424                 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1425               Bitmap2Header1.Depth=ReadBlobByte(image);
1426               Bitmap2Header1.Compression=ReadBlobByte(image);
1427
1428               if(Bitmap2Header1.Compression > 1)
1429                 continue; /*Unknown compression method */
1430               switch(Bitmap2Header1.Depth)
1431                 {
1432                 case 1:
1433                   bpp=1;
1434                   break;
1435                 case 2:
1436                   bpp=2;
1437                   break;
1438                 case 3:
1439                   bpp=4;
1440                   break;
1441                 case 4:
1442                   bpp=8;
1443                   break;
1444                 case 8:
1445                   bpp=24;
1446                   break;
1447                 default:
1448                   continue;  /*Ignore raster with unknown depth*/
1449                 }
1450               image->columns=Bitmap2Header1.Width;
1451               image->rows=Bitmap2Header1.Height;
1452               if (image_info->ping != MagickFalse)
1453                 return(image);
1454               status=SetImageExtent(image,image->columns,image->rows,exception);
1455               if (status != MagickFalse)
1456                 status=ResetImagePixels(image,exception);
1457               if (status == MagickFalse)
1458                 break;
1459               if ((image->colors == 0) && (bpp != 24))
1460                 {
1461                   image->colors=one << bpp;
1462                   if (!AcquireImageColormap(image,image->colors,exception))
1463                     goto NoMemory;
1464                 }
1465               else
1466                 {
1467                   if(bpp < 24)
1468                     if( image->colors<(one << bpp) && bpp!=24 )
1469                       image->colormap=(PixelInfo *) ResizeQuantumMemory(
1470                        image->colormap,(size_t) (one << bpp),
1471                        sizeof(*image->colormap));
1472                 }
1473
1474
1475               switch(Bitmap2Header1.Compression)
1476                 {
1477                 case 0:    /*Uncompressed raster*/
1478                   {
1479                     ldblk=(ssize_t) ((bpp*image->columns+7)/8);
1480                     BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t)
1481                       ldblk+1,sizeof(*BImgBuff));
1482                     if (BImgBuff == (unsigned char *) NULL)
1483                       goto NoMemory;
1484                     for (i=0; i< (ssize_t) image->rows; i++)
1485                     {
1486                       ssize_t
1487                         count;
1488
1489                       count=ReadBlob(image,(size_t) ldblk,BImgBuff);
1490                       if (count != ldblk)
1491                         break;
1492                       if (InsertRow(image,BImgBuff,i,bpp,exception) == MagickFalse)
1493                         break;
1494                     }
1495                     BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
1496                     if (i < (ssize_t) image->rows)
1497                       goto DecompressionFailed;
1498                     break;
1499                   }
1500                 case 1:    /*RLE for WPG2 */
1501                   {
1502                     if( UnpackWPG2Raster(image,bpp,exception) < 0)
1503                       goto DecompressionFailed;
1504                     break;
1505                   }
1506                 }
1507
1508               if(CTM[0][0]<0 && !image_info->ping)
1509                 {    /*?? RotAngle=360-RotAngle;*/
1510                   Image
1511                     *flop_image;
1512
1513                   flop_image = FlopImage(image, exception);
1514                   if (flop_image != (Image *) NULL) {
1515                     DuplicateBlob(flop_image,image);
1516                     ReplaceImageInList(&image,flop_image);
1517                   }
1518                   /* Try to change CTM according to Flip - I am not sure, must be checked.
1519                      Tx(0,0)=-1;      Tx(1,0)=0;   Tx(2,0)=0;
1520                      Tx(0,1)= 0;      Tx(1,1)=1;   Tx(2,1)=0;
1521                      Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1522                      Tx(1,2)=0;   Tx(2,2)=1; */
1523                 }
1524               if(CTM[1][1]<0 && !image_info->ping)
1525                 {    /*?? RotAngle=360-RotAngle;*/
1526                   Image
1527                     *flip_image;
1528
1529                    flip_image = FlipImage(image, exception);
1530                    if (flip_image != (Image *) NULL) {
1531                      DuplicateBlob(flip_image,image);
1532                      ReplaceImageInList(&image,flip_image);
1533                     }
1534                   /* Try to change CTM according to Flip - I am not sure, must be checked.
1535                      float_matrix Tx(3,3);
1536                      Tx(0,0)= 1;   Tx(1,0)= 0;   Tx(2,0)=0;
1537                      Tx(0,1)= 0;   Tx(1,1)=-1;   Tx(2,1)=0;
1538                      Tx(0,2)= 0;   Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1539                      Tx(2,2)=1; */
1540               }
1541
1542
1543               /* Allocate next image structure. */
1544               if ((image_info->ping != MagickFalse) &&
1545                   (image_info->number_scenes != 0))
1546                 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1547                   goto Finish;
1548               AcquireNextImage(image_info,image,exception);
1549               image->depth=8;
1550               if (image->next == (Image *) NULL)
1551                 goto Finish;
1552               image=SyncNextImageInList(image);
1553               image->columns=image->rows=0;
1554               image->colors=0;
1555               break;
1556
1557             case 0x12:  /* Postscript WPG2*/
1558         i=ReadBlobLSBShort(image);
1559               if (Rec2.RecordLength > (unsigned int) i)
1560                 {
1561                   image=ExtractPostscript(image,image_info,
1562                     TellBlob(image)+i,    /*skip PS header in the wpg2*/
1563                     (ssize_t) (Rec2.RecordLength-i-2),exception);
1564                   if (image == NULL)
1565                     ThrowReaderException(CorruptImageError,
1566                       "ImproperImageHeader");
1567                 }
1568               break;
1569
1570       case 0x1B:          /*bitmap rectangle*/
1571               WPG2Flags = LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM);
1572               (void) WPG2Flags;
1573               break;
1574             }
1575         }
1576
1577       break;
1578
1579     default:
1580       {
1581          ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
1582       }
1583    }
1584
1585  Finish:
1586   (void) CloseBlob(image);
1587
1588   {
1589     Image
1590       *p;
1591
1592     ssize_t
1593       scene=0;
1594
1595     /*
1596       Rewind list, removing any empty images while rewinding.
1597     */
1598     p=image;
1599     image=NULL;
1600     while (p != (Image *) NULL)
1601       {
1602         Image *tmp=p;
1603         if ((p->rows == 0) || (p->columns == 0)) {
1604           p=p->previous;
1605           DeleteImageFromList(&tmp);
1606         } else {
1607           image=p;
1608           p=p->previous;
1609         }
1610       }
1611     /*
1612       Fix scene numbers.
1613     */
1614     for (p=image; p != (Image *) NULL; p=p->next)
1615       p->scene=(size_t) scene++;
1616   }
1617   if (image == (Image *) NULL)
1618     ThrowReaderException(CorruptImageError,
1619       "ImageFileDoesNotContainAnyImageData");
1620   return(image);
1621 }
1622 \f
1623 /*
1624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 %                                                                             %
1626 %                                                                             %
1627 %                                                                             %
1628 %   R e g i s t e r W P G I m a g e                                           %
1629 %                                                                             %
1630 %                                                                             %
1631 %                                                                             %
1632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 %
1634 %  Method RegisterWPGImage adds attributes for the WPG image format to
1635 %  the list of supported formats.  The attributes include the image format
1636 %  tag, a method to read and/or write the format, whether the format
1637 %  supports the saving of more than one frame to the same file or blob,
1638 %  whether the format supports native in-memory I/O, and a brief
1639 %  description of the format.
1640 %
1641 %  The format of the RegisterWPGImage method is:
1642 %
1643 %      size_t RegisterWPGImage(void)
1644 %
1645 */
1646 ModuleExport size_t RegisterWPGImage(void)
1647 {
1648   MagickInfo
1649     *entry;
1650
1651   entry=AcquireMagickInfo("WPG","WPG","Word Perfect Graphics");
1652   entry->decoder=(DecodeImageHandler *) ReadWPGImage;
1653   entry->magick=(IsImageFormatHandler *) IsWPG;
1654   entry->flags|=CoderDecoderSeekableStreamFlag;
1655   (void) RegisterMagickInfo(entry);
1656   return(MagickImageCoderSignature);
1657 }
1658 \f
1659 /*
1660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1661 %                                                                             %
1662 %                                                                             %
1663 %                                                                             %
1664 %   U n r e g i s t e r W P G I m a g e                                       %
1665 %                                                                             %
1666 %                                                                             %
1667 %                                                                             %
1668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1669 %
1670 %  Method UnregisterWPGImage removes format registrations made by the
1671 %  WPG module from the list of supported formats.
1672 %
1673 %  The format of the UnregisterWPGImage method is:
1674 %
1675 %      UnregisterWPGImage(void)
1676 %
1677 */
1678 ModuleExport void UnregisterWPGImage(void)
1679 {
1680   (void) UnregisterMagickInfo("WPG");
1681 }