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