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