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-2016 ImageMagick Studio LLC, a non-profit organization      %
20%  dedicated to making software imaging solutions freely available.           %
21%                                                                             %
22%  You may not use this file except in compliance with the License.  You may  %
23%  obtain a copy of the License at                                            %
24%                                                                             %
25%    http://www.imagemagick.org/script/license.php                            %
26%                                                                             %
27%  Unless required by applicable law or agreed to in writing, software        %
28%  distributed under the License is distributed on an "AS IS" BASIS,          %
29%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30%  See the License for the specific language governing permissions and        %
31%  limitations under the License.                                             %
32%                                                                             %
33%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34%
35%
36*/
37
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
68typedef 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 */
76static 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
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*/
234static 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
243
244static 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
267static 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. */
446static 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{ \
538DisableMSCWarning(4310) \
539  if(XorMe)\
540    BImgBuff[x] = (unsigned char)~b;\
541  else\
542    BImgBuff[x] = b;\
543RestoreMSCWarning \
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. */
553static 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            return(-2);
593          if(SampleSize<1)
594            return(-2);
595          break;
596        case 0x7E:
597          (void) FormatLocaleFile(stderr,
598            "\nUnsupported WPG token XOR, please report!");
599          XorMe=!XorMe;
600          break;
601        case 0x7F:
602          RunCount=ReadBlobByte(image);   /* BLK */
603          if (RunCount < 0)
604            break;
605          for(i=0; i < SampleSize*(RunCount+1); i++)
606            {
607              InsertByte6(0);
608            }
609          break;
610        case 0xFD:
611          RunCount=ReadBlobByte(image);   /* EXT */
612          if (RunCount < 0)
613            break;
614          for(i=0; i<= RunCount;i++)
615            for(bbuf=0; bbuf < SampleSize; bbuf++)
616              InsertByte6(SampleBuffer[bbuf]);
617          break;
618        case 0xFE:
619          RunCount=ReadBlobByte(image);  /* RST */
620          if (RunCount < 0)
621            break;
622          if(x!=0)
623            {
624              (void) FormatLocaleFile(stderr,
625                "\nUnsupported WPG2 unaligned token RST x=%.20g, please report!\n"
626                ,(double) x);
627              return(-3);
628            }
629          {
630            /* duplicate the previous row RunCount x */
631            for(i=0;i<=RunCount;i++)
632              {
633                InsertRow(image,BImgBuff,(ssize_t) (image->rows >= y ? y : image->rows-1),
634                          bpp,exception);
635                y++;
636              }
637          }
638          break;
639        case 0xFF:
640          RunCount=ReadBlobByte(image);   /* WHT */
641          if (RunCount < 0)
642            break;
643          for(i=0; i < SampleSize*(RunCount+1); i++)
644            {
645              InsertByte6(0xFF);
646            }
647          break;
648        default:
649          RunCount=bbuf & 0x7F;
650
651          if(bbuf & 0x80)     /* REP */
652            {
653              for(i=0; i < SampleSize; i++)
654                SampleBuffer[i]=ReadBlobByte(image);
655              for(i=0;i<=RunCount;i++)
656                for(bbuf=0;bbuf<SampleSize;bbuf++)
657                  InsertByte6(SampleBuffer[bbuf]);
658            }
659          else {      /* NRP */
660            for(i=0; i< SampleSize*(RunCount+1);i++)
661              {
662                bbuf=ReadBlobByte(image);
663                InsertByte6(bbuf);
664              }
665          }
666        }
667      if (EOFBlob(image) != MagickFalse)
668        break;
669    }
670  BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
671  return(0);
672}
673
674
675typedef float tCTM[3][3];
676
677static unsigned LoadWPG2Flags(Image *image,char Precision,float *Angle,tCTM *CTM)
678{
679const unsigned char TPR=1,TRN=2,SKW=4,SCL=8,ROT=0x10,OID=0x20,LCK=0x80;
680ssize_t x;
681unsigned DenX;
682unsigned Flags;
683
684 (void) memset(*CTM,0,sizeof(*CTM));     /*CTM.erase();CTM.resize(3,3);*/
685 (*CTM)[0][0]=1;
686 (*CTM)[1][1]=1;
687 (*CTM)[2][2]=1;
688
689 Flags=ReadBlobLSBShort(image);
690 if(Flags & LCK) (void) ReadBlobLSBLong(image);  /*Edit lock*/
691 if(Flags & OID)
692  {
693  if(Precision==0)
694    {(void) ReadBlobLSBShort(image);}  /*ObjectID*/
695  else
696    {(void) ReadBlobLSBLong(image);}  /*ObjectID (Double precision)*/
697  }
698 if(Flags & ROT)
699  {
700  x=ReadBlobLSBLong(image);  /*Rot Angle*/
701  if(Angle) *Angle=x/65536.0;
702  }
703 if(Flags & (ROT|SCL))
704  {
705  x=ReadBlobLSBLong(image);  /*Sx*cos()*/
706  (*CTM)[0][0] = (float)x/0x10000;
707  x=ReadBlobLSBLong(image);  /*Sy*cos()*/
708  (*CTM)[1][1] = (float)x/0x10000;
709  }
710 if(Flags & (ROT|SKW))
711  {
712  x=ReadBlobLSBLong(image);       /*Kx*sin()*/
713  (*CTM)[1][0] = (float)x/0x10000;
714  x=ReadBlobLSBLong(image);       /*Ky*sin()*/
715  (*CTM)[0][1] = (float)x/0x10000;
716  }
717 if(Flags & TRN)
718  {
719  x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image);  /*Tx*/
720        if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
721            else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
722  x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image);  /*Ty*/
723  (*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
724        if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
725            else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
726  }
727 if(Flags & TPR)
728  {
729  x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image);  /*Px*/
730  (*CTM)[2][0] = x + (float)DenX/0x10000;;
731  x=ReadBlobLSBShort(image);  DenX=ReadBlobLSBShort(image); /*Py*/
732  (*CTM)[2][1] = x + (float)DenX/0x10000;
733  }
734 return(Flags);
735}
736
737
738static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
739  MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo *exception)
740{
741  char
742    postscript_file[MagickPathExtent];
743
744  const MagicInfo
745    *magic_info;
746
747  FILE
748    *ps_file;
749
750  ImageInfo
751    *clone_info;
752
753  Image
754    *image2;
755
756  unsigned char
757    magick[2*MagickPathExtent];
758
759
760  if ((clone_info=CloneImageInfo(image_info)) == NULL)
761    return(image);
762  clone_info->blob=(void *) NULL;
763  clone_info->length=0;
764
765  /* Obtain temporary file */
766  (void) AcquireUniqueFilename(postscript_file);
767  ps_file=fopen_utf8(postscript_file,"wb");
768  if (ps_file == (FILE *) NULL)
769    goto FINISH;
770
771  /* Copy postscript to temporary file */
772  (void) SeekBlob(image,PS_Offset,SEEK_SET);
773  (void) ReadBlob(image, 2*MagickPathExtent, magick);
774
775  (void) SeekBlob(image,PS_Offset,SEEK_SET);
776  while(PS_Size-- > 0)
777    {
778      (void) fputc(ReadBlobByte(image),ps_file);
779    }
780  (void) fclose(ps_file);
781
782    /* Detect file format - Check magic.mgk configuration file. */
783  magic_info=GetMagicInfo(magick,2*MagickPathExtent,exception);
784  if(magic_info == (const MagicInfo *) NULL) goto FINISH_UNL;
785  /*     printf("Detected:%s  \n",magic_info->name); */
786  if(exception->severity != UndefinedException) goto FINISH_UNL;
787  if(magic_info->name == (char *) NULL) goto FINISH_UNL;
788
789  (void) strncpy(clone_info->magick,magic_info->name,MagickPathExtent);
790
791    /* Read nested image */
792  /*FormatString(clone_info->filename,"%s:%s",magic_info->name,postscript_file);*/
793  FormatLocaleString(clone_info->filename,MagickPathExtent,"%s",postscript_file);
794  image2=ReadImage(clone_info,exception);
795
796  if (!image2)
797    goto FINISH_UNL;
798
799  /*
800    Replace current image with new image while copying base image
801    attributes.
802  */
803  (void) CopyMagickString(image2->filename,image->filename,MagickPathExtent);
804  (void) CopyMagickString(image2->magick_filename,image->magick_filename,MagickPathExtent);
805  (void) CopyMagickString(image2->magick,image->magick,MagickPathExtent);
806  image2->depth=image->depth;
807  DestroyBlob(image2);
808  image2->blob=ReferenceBlob(image->blob);
809
810  if ((image->rows == 0) || (image->columns == 0))
811    DeleteImageFromList(&image);
812
813  AppendImageToList(&image,image2);
814
815 FINISH_UNL:
816  (void) RelinquishUniqueFileResource(postscript_file);
817 FINISH:
818  DestroyImageInfo(clone_info);
819  return(image);
820}
821
822/*
823%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824%                                                                             %
825%                                                                             %
826%                                                                             %
827%   R e a d W P G I m a g e                                                   %
828%                                                                             %
829%                                                                             %
830%                                                                             %
831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
832%
833%  Method ReadWPGImage reads an WPG X image file and returns it.  It
834%  allocates the memory necessary for the new Image structure and returns a
835%  pointer to the new image.
836%
837%  The format of the ReadWPGImage method is:
838%
839%    Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
840%
841%  A description of each parameter follows:
842%
843%    o image:  Method ReadWPGImage returns a pointer to the image after
844%      reading. A null image is returned if there is a memory shortage or if
845%      the image cannot be read.
846%
847%    o image_info: Specifies a pointer to a ImageInfo structure.
848%
849%    o exception: return any errors or warnings in this structure.
850%
851*/
852static Image *ReadWPGImage(const ImageInfo *image_info,
853  ExceptionInfo *exception)
854{
855  typedef struct
856  {
857    size_t FileId;
858    MagickOffsetType DataOffset;
859    unsigned int ProductType;
860    unsigned int FileType;
861    unsigned char MajorVersion;
862    unsigned char MinorVersion;
863    unsigned int EncryptKey;
864    unsigned int Reserved;
865  } WPGHeader;
866
867  typedef struct
868  {
869    unsigned char RecType;
870    size_t RecordLength;
871  } WPGRecord;
872
873  typedef struct
874  {
875    unsigned char Class;
876    unsigned char RecType;
877    size_t Extension;
878    size_t RecordLength;
879  } WPG2Record;
880
881  typedef struct
882  {
883    unsigned  HorizontalUnits;
884    unsigned  VerticalUnits;
885    unsigned char PosSizePrecision;
886  } WPG2Start;
887
888  typedef struct
889  {
890    unsigned int Width;
891    unsigned int Height;
892    unsigned int Depth;
893    unsigned int HorzRes;
894    unsigned int VertRes;
895  } WPGBitmapType1;
896
897  typedef struct
898  {
899    unsigned int Width;
900    unsigned int Height;
901    unsigned char Depth;
902    unsigned char Compression;
903  } WPG2BitmapType1;
904
905  typedef struct
906  {
907    unsigned int RotAngle;
908    unsigned int LowLeftX;
909    unsigned int LowLeftY;
910    unsigned int UpRightX;
911    unsigned int UpRightY;
912    unsigned int Width;
913    unsigned int Height;
914    unsigned int Depth;
915    unsigned int HorzRes;
916    unsigned int VertRes;
917  } WPGBitmapType2;
918
919  typedef struct
920  {
921    unsigned int StartIndex;
922    unsigned int NumOfEntries;
923  } WPGColorMapRec;
924
925  /*
926  typedef struct {
927    size_t PS_unknown1;
928    unsigned int PS_unknown2;
929    unsigned int PS_unknown3;
930  } WPGPSl1Record;
931  */
932
933  Image
934    *image;
935
936  unsigned int
937    status;
938
939  WPGHeader
940    Header;
941
942  WPGRecord
943    Rec;
944
945  WPG2Record
946    Rec2;
947
948  WPG2Start StartWPG;
949
950  WPGBitmapType1
951    BitmapHeader1;
952
953  WPG2BitmapType1
954    Bitmap2Header1;
955
956  WPGBitmapType2
957    BitmapHeader2;
958
959  WPGColorMapRec
960    WPG_Palette;
961
962  int
963    i,
964    bpp,
965    WPG2Flags;
966
967  ssize_t
968    ldblk;
969
970  size_t
971    one;
972
973  unsigned char
974    *BImgBuff;
975
976  tCTM CTM;         /*current transform matrix*/
977
978  /*
979    Open image file.
980  */
981  assert(image_info != (const ImageInfo *) NULL);
982  assert(image_info->signature == MagickCoreSignature);
983  assert(exception != (ExceptionInfo *) NULL);
984  assert(exception->signature == MagickCoreSignature);
985  one=1;
986  image=AcquireImage(image_info,exception);
987  image->depth=8;
988  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
989  if (status == MagickFalse)
990    {
991      image=DestroyImageList(image);
992      return((Image *) NULL);
993    }
994  /*
995    Read WPG image.
996  */
997  Header.FileId=ReadBlobLSBLong(image);
998  Header.DataOffset=(MagickOffsetType) ReadBlobLSBLong(image);
999  Header.ProductType=ReadBlobLSBShort(image);
1000  Header.FileType=ReadBlobLSBShort(image);
1001  Header.MajorVersion=ReadBlobByte(image);
1002  Header.MinorVersion=ReadBlobByte(image);
1003  Header.EncryptKey=ReadBlobLSBShort(image);
1004  Header.Reserved=ReadBlobLSBShort(image);
1005
1006  if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
1007    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1008  if (Header.EncryptKey!=0)
1009    ThrowReaderException(CoderError,"EncryptedWPGImageFileNotSupported");
1010
1011  image->columns = 1;
1012  image->rows = 1;
1013  image->colors = 0;
1014  bpp=0;
1015  BitmapHeader2.RotAngle=0;
1016
1017  switch(Header.FileType)
1018    {
1019    case 1:     /* WPG level 1 */
1020      while(!EOFBlob(image)) /* object parser loop */
1021        {
1022          (void) SeekBlob(image,Header.DataOffset,SEEK_SET);
1023          if(EOFBlob(image))
1024            break;
1025
1026          Rec.RecType=(i=ReadBlobByte(image));
1027          if(i==EOF)
1028            break;
1029          Rd_WP_DWORD(image,&Rec.RecordLength);
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
1062              image->colors=WPG_Palette.NumOfEntries;
1063              if (!AcquireImageColormap(image,image->colors,exception))
1064                goto NoMemory;
1065              for (i=WPG_Palette.StartIndex;
1066                   i < (int)WPG_Palette.NumOfEntries; i++)
1067                {
1068                  image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1069                    ReadBlobByte(image));
1070                  image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1071                    ReadBlobByte(image));
1072                  image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1073                    ReadBlobByte(image));
1074                }
1075              break;
1076
1077            case 0x11:  /* Start PS l1 */
1078              if(Rec.RecordLength > 8)
1079                image=ExtractPostscript(image,image_info,
1080                  TellBlob(image)+8,   /* skip PS header in the wpg */
1081                  (ssize_t) Rec.RecordLength-8,exception);
1082              break;
1083
1084            case 0x14:  /* bitmap type 2 */
1085              BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
1086              BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
1087              BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
1088              BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
1089              BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
1090              BitmapHeader2.Width=ReadBlobLSBShort(image);
1091              BitmapHeader2.Height=ReadBlobLSBShort(image);
1092              if ((BitmapHeader2.Width == 0) || (BitmapHeader2.Height == 0))
1093                ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1094              BitmapHeader2.Depth=ReadBlobLSBShort(image);
1095              BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
1096              BitmapHeader2.VertRes=ReadBlobLSBShort(image);
1097
1098              image->units=PixelsPerCentimeterResolution;
1099              image->page.width=(unsigned int)
1100                ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
1101              image->page.height=(unsigned int)
1102                ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
1103              image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
1104              image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
1105              if(BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
1106                {
1107                  image->resolution.x=BitmapHeader2.HorzRes/470.0;
1108                  image->resolution.y=BitmapHeader2.VertRes/470.0;
1109                }
1110              image->columns=BitmapHeader2.Width;
1111              image->rows=BitmapHeader2.Height;
1112              bpp=BitmapHeader2.Depth;
1113
1114            UnpackRaster:
1115              status=SetImageExtent(image,image->columns,image->rows,exception);
1116              if (status == MagickFalse)
1117                break;
1118              if ((image->colors == 0) && (bpp != 24))
1119                {
1120                  image->colors=one << bpp;
1121                  if (!AcquireImageColormap(image,image->colors,exception))
1122                    {
1123                    NoMemory:
1124                      ThrowReaderException(ResourceLimitError,
1125                        "MemoryAllocationFailed");
1126                    }
1127                  /* printf("Load default colormap \n"); */
1128                  for (i=0; (i < (int) image->colors) && (i < 256); i++)
1129                    {
1130                      image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
1131                      image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
1132                      image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
1133                    }
1134                }
1135              else
1136                {
1137                  if (bpp < 24)
1138                    if ( (image->colors < (one << bpp)) && (bpp != 24) )
1139                      image->colormap=(PixelInfo *) ResizeQuantumMemory(
1140                        image->colormap,(size_t) (one << bpp),
1141                        sizeof(*image->colormap));
1142                }
1143
1144              if (bpp == 1)
1145                {
1146                  if(image->colormap[0].red==0 &&
1147                     image->colormap[0].green==0 &&
1148                     image->colormap[0].blue==0 &&
1149                     image->colormap[1].red==0 &&
1150                     image->colormap[1].green==0 &&
1151                     image->colormap[1].blue==0)
1152                    {  /* fix crippled monochrome palette */
1153                      image->colormap[1].red =
1154                        image->colormap[1].green =
1155                        image->colormap[1].blue = QuantumRange;
1156                    }
1157                }
1158
1159              if(UnpackWPGRaster(image,bpp,exception) < 0)
1160                /* The raster cannot be unpacked */
1161                {
1162                DecompressionFailed:
1163                  ThrowReaderException(CoderError,"UnableToDecompressImage");
1164                    }
1165
1166              if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1167                {
1168                  /* flop command */
1169                  if(BitmapHeader2.RotAngle & 0x8000)
1170                    {
1171                      Image
1172                        *flop_image;
1173
1174                      flop_image = FlopImage(image, exception);
1175                      if (flop_image != (Image *) NULL) {
1176                        DuplicateBlob(flop_image,image);
1177                        (void) RemoveLastImageFromList(&image);
1178                        AppendImageToList(&image,flop_image);
1179                      }
1180                    }
1181                  /* flip command */
1182                  if(BitmapHeader2.RotAngle & 0x2000)
1183                    {
1184                      Image
1185                        *flip_image;
1186
1187                      flip_image = FlipImage(image, exception);
1188                      if (flip_image != (Image *) NULL) {
1189                        DuplicateBlob(flip_image,image);
1190                        (void) RemoveLastImageFromList(&image);
1191                        AppendImageToList(&image,flip_image);
1192                      }
1193                    }
1194                  /* rotate command */
1195                  if(BitmapHeader2.RotAngle & 0x0FFF)
1196                    {
1197                      Image
1198                        *rotate_image;
1199
1200                      rotate_image=RotateImage(image,(BitmapHeader2.RotAngle &
1201                        0x0FFF), exception);
1202                      if (rotate_image != (Image *) NULL) {
1203                        DuplicateBlob(rotate_image,image);
1204                        (void) RemoveLastImageFromList(&image);
1205                        AppendImageToList(&image,rotate_image);
1206                      }
1207                    }
1208                }
1209
1210              /* Allocate next image structure. */
1211              AcquireNextImage(image_info,image,exception);
1212              image->depth=8;
1213              if (image->next == (Image *) NULL)
1214                goto Finish;
1215              image=SyncNextImageInList(image);
1216              image->columns=image->rows=1;
1217              image->colors=0;
1218              break;
1219
1220            case 0x1B:  /* Postscript l2 */
1221              if(Rec.RecordLength>0x3C)
1222                image=ExtractPostscript(image,image_info,
1223                  TellBlob(image)+0x3C,   /* skip PS l2 header in the wpg */
1224                  (ssize_t) Rec.RecordLength-0x3C,exception);
1225              break;
1226            }
1227        }
1228      break;
1229
1230    case 2:  /* WPG level 2 */
1231      (void) memset(CTM,0,sizeof(CTM));
1232      StartWPG.PosSizePrecision = 0;
1233      while(!EOFBlob(image)) /* object parser loop */
1234        {
1235          (void) SeekBlob(image,Header.DataOffset,SEEK_SET);
1236          if(EOFBlob(image))
1237            break;
1238
1239          Rec2.Class=(i=ReadBlobByte(image));
1240          if(i==EOF)
1241            break;
1242          Rec2.RecType=(i=ReadBlobByte(image));
1243          if(i==EOF)
1244            break;
1245          Rd_WP_DWORD(image,&Rec2.Extension);
1246          Rd_WP_DWORD(image,&Rec2.RecordLength);
1247          if(EOFBlob(image))
1248            break;
1249
1250          Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1251
1252          switch(Rec2.RecType)
1253            {
1254      case 1:
1255              StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1256              StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1257              StartWPG.PosSizePrecision=ReadBlobByte(image);
1258              break;
1259            case 0x0C:    /* Color palette */
1260              WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1261              WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1262
1263              image->colors=WPG_Palette.NumOfEntries;
1264              if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1265                ThrowReaderException(ResourceLimitError,
1266                  "MemoryAllocationFailed");
1267              for (i=WPG_Palette.StartIndex;
1268                   i < (int)WPG_Palette.NumOfEntries; i++)
1269                {
1270                  image->colormap[i].red=ScaleCharToQuantum((char)
1271                    ReadBlobByte(image));
1272                  image->colormap[i].green=ScaleCharToQuantum((char)
1273                    ReadBlobByte(image));
1274                  image->colormap[i].blue=ScaleCharToQuantum((char)
1275                    ReadBlobByte(image));
1276                  (void) ReadBlobByte(image);   /*Opacity??*/
1277                }
1278              break;
1279            case 0x0E:
1280              Bitmap2Header1.Width=ReadBlobLSBShort(image);
1281              Bitmap2Header1.Height=ReadBlobLSBShort(image);
1282              if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Height == 0))
1283                ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1284              Bitmap2Header1.Depth=ReadBlobByte(image);
1285              Bitmap2Header1.Compression=ReadBlobByte(image);
1286
1287              if(Bitmap2Header1.Compression > 1)
1288                continue; /*Unknown compression method */
1289              switch(Bitmap2Header1.Depth)
1290                {
1291                case 1:
1292                  bpp=1;
1293                  break;
1294                case 2:
1295                  bpp=2;
1296                  break;
1297                case 3:
1298                  bpp=4;
1299                  break;
1300                case 4:
1301                  bpp=8;
1302                  break;
1303                case 8:
1304                  bpp=24;
1305                  break;
1306                default:
1307                  continue;  /*Ignore raster with unknown depth*/
1308                }
1309              image->columns=Bitmap2Header1.Width;
1310              image->rows=Bitmap2Header1.Height;
1311              status=SetImageExtent(image,image->columns,image->rows,exception);
1312              if (status == MagickFalse)
1313                break;
1314              if ((image->colors == 0) && (bpp != 24))
1315                {
1316                  size_t
1317                    one;
1318
1319                  one=1;
1320                  image->colors=one << bpp;
1321                  if (!AcquireImageColormap(image,image->colors,exception))
1322                    goto NoMemory;
1323                }
1324              else
1325                {
1326                  if(bpp < 24)
1327                    if( image->colors<(one << bpp) && bpp!=24 )
1328                      image->colormap=(PixelInfo *) ResizeQuantumMemory(
1329                       image->colormap,(size_t) (one << bpp),
1330                       sizeof(*image->colormap));
1331                }
1332
1333
1334              switch(Bitmap2Header1.Compression)
1335                {
1336                case 0:    /*Uncompressed raster*/
1337                  {
1338                    ldblk=(ssize_t) ((bpp*image->columns+7)/8);
1339                    BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t)
1340                      ldblk+1,sizeof(*BImgBuff));
1341                    if (BImgBuff == (unsigned char *) NULL)
1342                      goto NoMemory;
1343
1344                    for(i=0; i< (ssize_t) image->rows; i++)
1345                      {
1346                        (void) ReadBlob(image,ldblk,BImgBuff);
1347                        InsertRow(image,BImgBuff,i,bpp,exception);
1348                      }
1349
1350                    if(BImgBuff)
1351                      BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
1352                    break;
1353                  }
1354                case 1:    /*RLE for WPG2 */
1355                  {
1356                    if( UnpackWPG2Raster(image,bpp,exception) < 0)
1357                      goto DecompressionFailed;
1358                    break;
1359                  }
1360                }
1361
1362              if(CTM[0][0]<0 && !image_info->ping)
1363                {    /*?? RotAngle=360-RotAngle;*/
1364                  Image
1365                    *flop_image;
1366
1367                  flop_image = FlopImage(image, exception);
1368                  if (flop_image != (Image *) NULL) {
1369                    DuplicateBlob(flop_image,image);
1370                    (void) RemoveLastImageFromList(&image);
1371                    AppendImageToList(&image,flop_image);
1372                  }
1373                  /* Try to change CTM according to Flip - I am not sure, must be checked.
1374                     Tx(0,0)=-1;      Tx(1,0)=0;   Tx(2,0)=0;
1375                     Tx(0,1)= 0;      Tx(1,1)=1;   Tx(2,1)=0;
1376                     Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1377                     Tx(1,2)=0;   Tx(2,2)=1; */
1378                }
1379              if(CTM[1][1]<0 && !image_info->ping)
1380                {    /*?? RotAngle=360-RotAngle;*/
1381                  Image
1382                    *flip_image;
1383
1384                   flip_image = FlipImage(image, exception);
1385                   if (flip_image != (Image *) NULL) {
1386                     DuplicateBlob(flip_image,image);
1387                     (void) RemoveLastImageFromList(&image);
1388                     AppendImageToList(&image,flip_image);
1389                    }
1390                  /* Try to change CTM according to Flip - I am not sure, must be checked.
1391                     float_matrix Tx(3,3);
1392                     Tx(0,0)= 1;   Tx(1,0)= 0;   Tx(2,0)=0;
1393                     Tx(0,1)= 0;   Tx(1,1)=-1;   Tx(2,1)=0;
1394                     Tx(0,2)= 0;   Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1395                     Tx(2,2)=1; */
1396              }
1397
1398
1399              /* Allocate next image structure. */
1400              AcquireNextImage(image_info,image,exception);
1401              image->depth=8;
1402              if (image->next == (Image *) NULL)
1403                goto Finish;
1404              image=SyncNextImageInList(image);
1405              image->columns=image->rows=1;
1406              image->colors=0;
1407              break;
1408
1409            case 0x12:  /* Postscript WPG2*/
1410        i=ReadBlobLSBShort(image);
1411              if(Rec2.RecordLength > (unsigned int) i)
1412                image=ExtractPostscript(image,image_info,
1413                  TellBlob(image)+i,    /*skip PS header in the wpg2*/
1414                  (ssize_t) (Rec2.RecordLength-i-2),exception);
1415              break;
1416
1417      case 0x1B:          /*bitmap rectangle*/
1418              WPG2Flags = LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM);
1419              (void) WPG2Flags;
1420              break;
1421            }
1422        }
1423
1424      break;
1425
1426    default:
1427      {
1428         ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
1429      }
1430   }
1431
1432 Finish:
1433  (void) CloseBlob(image);
1434
1435  {
1436    Image
1437      *p;
1438
1439    ssize_t
1440      scene=0;
1441
1442    /*
1443      Rewind list, removing any empty images while rewinding.
1444    */
1445    p=image;
1446    image=NULL;
1447    while (p != (Image *) NULL)
1448      {
1449        Image *tmp=p;
1450        if ((p->rows == 0) || (p->columns == 0)) {
1451          p=p->previous;
1452          DeleteImageFromList(&tmp);
1453        } else {
1454          image=p;
1455          p=p->previous;
1456        }
1457      }
1458    /*
1459      Fix scene numbers.
1460    */
1461    for (p=image; p != (Image *) NULL; p=p->next)
1462      p->scene=(size_t) scene++;
1463  }
1464  if (image == (Image *) NULL)
1465    ThrowReaderException(CorruptImageError,
1466      "ImageFileDoesNotContainAnyImageData");
1467  return(image);
1468}
1469
1470/*
1471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1472%                                                                             %
1473%                                                                             %
1474%                                                                             %
1475%   R e g i s t e r W P G I m a g e                                           %
1476%                                                                             %
1477%                                                                             %
1478%                                                                             %
1479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480%
1481%  Method RegisterWPGImage adds attributes for the WPG image format to
1482%  the list of supported formats.  The attributes include the image format
1483%  tag, a method to read and/or write the format, whether the format
1484%  supports the saving of more than one frame to the same file or blob,
1485%  whether the format supports native in-memory I/O, and a brief
1486%  description of the format.
1487%
1488%  The format of the RegisterWPGImage method is:
1489%
1490%      size_t RegisterWPGImage(void)
1491%
1492*/
1493ModuleExport size_t RegisterWPGImage(void)
1494{
1495  MagickInfo
1496    *entry;
1497
1498  entry=AcquireMagickInfo("WPG","WPG","Word Perfect Graphics");
1499  entry->decoder=(DecodeImageHandler *) ReadWPGImage;
1500  entry->magick=(IsImageFormatHandler *) IsWPG;
1501  entry->flags|=CoderSeekableStreamFlag;
1502  (void) RegisterMagickInfo(entry);
1503  return(MagickImageCoderSignature);
1504}
1505
1506/*
1507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1508%                                                                             %
1509%                                                                             %
1510%                                                                             %
1511%   U n r e g i s t e r W P G I m a g e                                       %
1512%                                                                             %
1513%                                                                             %
1514%                                                                             %
1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1516%
1517%  Method UnregisterWPGImage removes format registrations made by the
1518%  WPG module from the list of supported formats.
1519%
1520%  The format of the UnregisterWPGImage method is:
1521%
1522%      UnregisterWPGImage(void)
1523%
1524*/
1525ModuleExport void UnregisterWPGImage(void)
1526{
1527  (void) UnregisterMagickInfo("WPG");
1528}
1529