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