Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                        PPPP   IIIII   CCCC  TTTTT                           %
      7 %                        P   P    I    C        T                             %
      8 %                        PPPP     I    C        T                             %
      9 %                        P        I    C        T                             %
     10 %                        P      IIIII   CCCC    T                             %
     11 %                                                                             %
     12 %                                                                             %
     13 %               Read/Write Apple Macintosh QuickDraw/PICT Format              %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 1992                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    http://www.imagemagick.org/script/license.php                            %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 */
     38 
     39 /*
     41   Include declarations.
     42 */
     43 #include "MagickCore/studio.h"
     44 #include "MagickCore/blob.h"
     45 #include "MagickCore/blob-private.h"
     46 #include "MagickCore/cache.h"
     47 #include "MagickCore/color-private.h"
     48 #include "MagickCore/colormap.h"
     49 #include "MagickCore/colormap-private.h"
     50 #include "MagickCore/colorspace.h"
     51 #include "MagickCore/colorspace-private.h"
     52 #include "MagickCore/composite.h"
     53 #include "MagickCore/constitute.h"
     54 #include "MagickCore/exception.h"
     55 #include "MagickCore/exception-private.h"
     56 #include "MagickCore/image.h"
     57 #include "MagickCore/image-private.h"
     58 #include "MagickCore/list.h"
     59 #include "MagickCore/log.h"
     60 #include "MagickCore/magick.h"
     61 #include "MagickCore/memory_.h"
     62 #include "MagickCore/monitor.h"
     63 #include "MagickCore/monitor-private.h"
     64 #include "MagickCore/pixel-accessor.h"
     65 #include "MagickCore/profile.h"
     66 #include "MagickCore/resource_.h"
     67 #include "MagickCore/quantum-private.h"
     68 #include "MagickCore/static.h"
     69 #include "MagickCore/string_.h"
     70 #include "MagickCore/module.h"
     71 #include "MagickCore/transform.h"
     72 #include "MagickCore/utility.h"
     73 
     74 /*
     76   ImageMagick Macintosh PICT Methods.
     77 */
     78 #define ReadPixmap(pixmap) \
     79 { \
     80   pixmap.version=(short) ReadBlobMSBShort(image); \
     81   pixmap.pack_type=(short) ReadBlobMSBShort(image); \
     82   pixmap.pack_size=ReadBlobMSBLong(image); \
     83   pixmap.horizontal_resolution=1UL*ReadBlobMSBShort(image); \
     84   (void) ReadBlobMSBShort(image); \
     85   pixmap.vertical_resolution=1UL*ReadBlobMSBShort(image); \
     86   (void) ReadBlobMSBShort(image); \
     87   pixmap.pixel_type=(short) ReadBlobMSBShort(image); \
     88   pixmap.bits_per_pixel=(short) ReadBlobMSBShort(image); \
     89   pixmap.component_count=(short) ReadBlobMSBShort(image); \
     90   pixmap.component_size=(short) ReadBlobMSBShort(image); \
     91   pixmap.plane_bytes=ReadBlobMSBLong(image); \
     92   pixmap.table=ReadBlobMSBLong(image); \
     93   pixmap.reserved=ReadBlobMSBLong(image); \
     94   if ((EOFBlob(image) != MagickFalse) || (pixmap.bits_per_pixel <= 0) || \
     95       (pixmap.bits_per_pixel > 32) || (pixmap.component_count <= 0) || \
     96       (pixmap.component_count > 4) || (pixmap.component_size <= 0)) \
     97     ThrowReaderException(CorruptImageError,"ImproperImageHeader"); \
     98 }
     99 
    100 typedef struct _PICTCode
    101 {
    102   const char
    103     *name;
    104 
    105   ssize_t
    106     length;
    107 
    108   const char
    109     *description;
    110 } PICTCode;
    111 
    112 typedef struct _PICTPixmap
    113 {
    114   short
    115     version,
    116     pack_type;
    117 
    118   size_t
    119     pack_size,
    120     horizontal_resolution,
    121     vertical_resolution;
    122 
    123   short
    124     pixel_type,
    125     bits_per_pixel,
    126     component_count,
    127     component_size;
    128 
    129   size_t
    130     plane_bytes,
    131     table,
    132     reserved;
    133 } PICTPixmap;
    134 
    135 typedef struct _PICTRectangle
    136 {
    137   short
    138     top,
    139     left,
    140     bottom,
    141     right;
    142 } PICTRectangle;
    143 
    144 static const PICTCode
    145   codes[] =
    146   {
    147     /* 0x00 */ { "NOP", 0, "nop" },
    148     /* 0x01 */ { "Clip", 0, "clip" },
    149     /* 0x02 */ { "BkPat", 8, "background pattern" },
    150     /* 0x03 */ { "TxFont", 2, "text font (word)" },
    151     /* 0x04 */ { "TxFace", 1, "text face (byte)" },
    152     /* 0x05 */ { "TxMode", 2, "text mode (word)" },
    153     /* 0x06 */ { "SpExtra", 4, "space extra (fixed point)" },
    154     /* 0x07 */ { "PnSize", 4, "pen size (point)" },
    155     /* 0x08 */ { "PnMode", 2, "pen mode (word)" },
    156     /* 0x09 */ { "PnPat", 8, "pen pattern" },
    157     /* 0x0a */ { "FillPat", 8, "fill pattern" },
    158     /* 0x0b */ { "OvSize", 4, "oval size (point)" },
    159     /* 0x0c */ { "Origin", 4, "dh, dv (word)" },
    160     /* 0x0d */ { "TxSize", 2, "text size (word)" },
    161     /* 0x0e */ { "FgColor", 4, "foreground color (ssize_tword)" },
    162     /* 0x0f */ { "BkColor", 4, "background color (ssize_tword)" },
    163     /* 0x10 */ { "TxRatio", 8, "numerator (point), denominator (point)" },
    164     /* 0x11 */ { "Version", 1, "version (byte)" },
    165     /* 0x12 */ { "BkPixPat", 0, "color background pattern" },
    166     /* 0x13 */ { "PnPixPat", 0, "color pen pattern" },
    167     /* 0x14 */ { "FillPixPat", 0, "color fill pattern" },
    168     /* 0x15 */ { "PnLocHFrac", 2, "fractional pen position" },
    169     /* 0x16 */ { "ChExtra", 2, "extra for each character" },
    170     /* 0x17 */ { "reserved", 0, "reserved for Apple use" },
    171     /* 0x18 */ { "reserved", 0, "reserved for Apple use" },
    172     /* 0x19 */ { "reserved", 0, "reserved for Apple use" },
    173     /* 0x1a */ { "RGBFgCol", 6, "RGB foreColor" },
    174     /* 0x1b */ { "RGBBkCol", 6, "RGB backColor" },
    175     /* 0x1c */ { "HiliteMode", 0, "hilite mode flag" },
    176     /* 0x1d */ { "HiliteColor", 6, "RGB hilite color" },
    177     /* 0x1e */ { "DefHilite", 0, "Use default hilite color" },
    178     /* 0x1f */ { "OpColor", 6, "RGB OpColor for arithmetic modes" },
    179     /* 0x20 */ { "Line", 8, "pnLoc (point), newPt (point)" },
    180     /* 0x21 */ { "LineFrom", 4, "newPt (point)" },
    181     /* 0x22 */ { "ShortLine", 6, "pnLoc (point, dh, dv (-128 .. 127))" },
    182     /* 0x23 */ { "ShortLineFrom", 2, "dh, dv (-128 .. 127)" },
    183     /* 0x24 */ { "reserved", -1, "reserved for Apple use" },
    184     /* 0x25 */ { "reserved", -1, "reserved for Apple use" },
    185     /* 0x26 */ { "reserved", -1, "reserved for Apple use" },
    186     /* 0x27 */ { "reserved", -1, "reserved for Apple use" },
    187     /* 0x28 */ { "LongText", 0, "txLoc (point), count (0..255), text" },
    188     /* 0x29 */ { "DHText", 0, "dh (0..255), count (0..255), text" },
    189     /* 0x2a */ { "DVText", 0, "dv (0..255), count (0..255), text" },
    190     /* 0x2b */ { "DHDVText", 0, "dh, dv (0..255), count (0..255), text" },
    191     /* 0x2c */ { "reserved", -1, "reserved for Apple use" },
    192     /* 0x2d */ { "reserved", -1, "reserved for Apple use" },
    193     /* 0x2e */ { "reserved", -1, "reserved for Apple use" },
    194     /* 0x2f */ { "reserved", -1, "reserved for Apple use" },
    195     /* 0x30 */ { "frameRect", 8, "rect" },
    196     /* 0x31 */ { "paintRect", 8, "rect" },
    197     /* 0x32 */ { "eraseRect", 8, "rect" },
    198     /* 0x33 */ { "invertRect", 8, "rect" },
    199     /* 0x34 */ { "fillRect", 8, "rect" },
    200     /* 0x35 */ { "reserved", 8, "reserved for Apple use" },
    201     /* 0x36 */ { "reserved", 8, "reserved for Apple use" },
    202     /* 0x37 */ { "reserved", 8, "reserved for Apple use" },
    203     /* 0x38 */ { "frameSameRect", 0, "rect" },
    204     /* 0x39 */ { "paintSameRect", 0, "rect" },
    205     /* 0x3a */ { "eraseSameRect", 0, "rect" },
    206     /* 0x3b */ { "invertSameRect", 0, "rect" },
    207     /* 0x3c */ { "fillSameRect", 0, "rect" },
    208     /* 0x3d */ { "reserved", 0, "reserved for Apple use" },
    209     /* 0x3e */ { "reserved", 0, "reserved for Apple use" },
    210     /* 0x3f */ { "reserved", 0, "reserved for Apple use" },
    211     /* 0x40 */ { "frameRRect", 8, "rect" },
    212     /* 0x41 */ { "paintRRect", 8, "rect" },
    213     /* 0x42 */ { "eraseRRect", 8, "rect" },
    214     /* 0x43 */ { "invertRRect", 8, "rect" },
    215     /* 0x44 */ { "fillRRrect", 8, "rect" },
    216     /* 0x45 */ { "reserved", 8, "reserved for Apple use" },
    217     /* 0x46 */ { "reserved", 8, "reserved for Apple use" },
    218     /* 0x47 */ { "reserved", 8, "reserved for Apple use" },
    219     /* 0x48 */ { "frameSameRRect", 0, "rect" },
    220     /* 0x49 */ { "paintSameRRect", 0, "rect" },
    221     /* 0x4a */ { "eraseSameRRect", 0, "rect" },
    222     /* 0x4b */ { "invertSameRRect", 0, "rect" },
    223     /* 0x4c */ { "fillSameRRect", 0, "rect" },
    224     /* 0x4d */ { "reserved", 0, "reserved for Apple use" },
    225     /* 0x4e */ { "reserved", 0, "reserved for Apple use" },
    226     /* 0x4f */ { "reserved", 0, "reserved for Apple use" },
    227     /* 0x50 */ { "frameOval", 8, "rect" },
    228     /* 0x51 */ { "paintOval", 8, "rect" },
    229     /* 0x52 */ { "eraseOval", 8, "rect" },
    230     /* 0x53 */ { "invertOval", 8, "rect" },
    231     /* 0x54 */ { "fillOval", 8, "rect" },
    232     /* 0x55 */ { "reserved", 8, "reserved for Apple use" },
    233     /* 0x56 */ { "reserved", 8, "reserved for Apple use" },
    234     /* 0x57 */ { "reserved", 8, "reserved for Apple use" },
    235     /* 0x58 */ { "frameSameOval", 0, "rect" },
    236     /* 0x59 */ { "paintSameOval", 0, "rect" },
    237     /* 0x5a */ { "eraseSameOval", 0, "rect" },
    238     /* 0x5b */ { "invertSameOval", 0, "rect" },
    239     /* 0x5c */ { "fillSameOval", 0, "rect" },
    240     /* 0x5d */ { "reserved", 0, "reserved for Apple use" },
    241     /* 0x5e */ { "reserved", 0, "reserved for Apple use" },
    242     /* 0x5f */ { "reserved", 0, "reserved for Apple use" },
    243     /* 0x60 */ { "frameArc", 12, "rect, startAngle, arcAngle" },
    244     /* 0x61 */ { "paintArc", 12, "rect, startAngle, arcAngle" },
    245     /* 0x62 */ { "eraseArc", 12, "rect, startAngle, arcAngle" },
    246     /* 0x63 */ { "invertArc", 12, "rect, startAngle, arcAngle" },
    247     /* 0x64 */ { "fillArc", 12, "rect, startAngle, arcAngle" },
    248     /* 0x65 */ { "reserved", 12, "reserved for Apple use" },
    249     /* 0x66 */ { "reserved", 12, "reserved for Apple use" },
    250     /* 0x67 */ { "reserved", 12, "reserved for Apple use" },
    251     /* 0x68 */ { "frameSameArc", 4, "rect, startAngle, arcAngle" },
    252     /* 0x69 */ { "paintSameArc", 4, "rect, startAngle, arcAngle" },
    253     /* 0x6a */ { "eraseSameArc", 4, "rect, startAngle, arcAngle" },
    254     /* 0x6b */ { "invertSameArc", 4, "rect, startAngle, arcAngle" },
    255     /* 0x6c */ { "fillSameArc", 4, "rect, startAngle, arcAngle" },
    256     /* 0x6d */ { "reserved", 4, "reserved for Apple use" },
    257     /* 0x6e */ { "reserved", 4, "reserved for Apple use" },
    258     /* 0x6f */ { "reserved", 4, "reserved for Apple use" },
    259     /* 0x70 */ { "framePoly", 0, "poly" },
    260     /* 0x71 */ { "paintPoly", 0, "poly" },
    261     /* 0x72 */ { "erasePoly", 0, "poly" },
    262     /* 0x73 */ { "invertPoly", 0, "poly" },
    263     /* 0x74 */ { "fillPoly", 0, "poly" },
    264     /* 0x75 */ { "reserved", 0, "reserved for Apple use" },
    265     /* 0x76 */ { "reserved", 0, "reserved for Apple use" },
    266     /* 0x77 */ { "reserved", 0, "reserved for Apple use" },
    267     /* 0x78 */ { "frameSamePoly", 0, "poly (NYI)" },
    268     /* 0x79 */ { "paintSamePoly", 0, "poly (NYI)" },
    269     /* 0x7a */ { "eraseSamePoly", 0, "poly (NYI)" },
    270     /* 0x7b */ { "invertSamePoly", 0, "poly (NYI)" },
    271     /* 0x7c */ { "fillSamePoly", 0, "poly (NYI)" },
    272     /* 0x7d */ { "reserved", 0, "reserved for Apple use" },
    273     /* 0x7e */ { "reserved", 0, "reserved for Apple use" },
    274     /* 0x7f */ { "reserved", 0, "reserved for Apple use" },
    275     /* 0x80 */ { "frameRgn", 0, "region" },
    276     /* 0x81 */ { "paintRgn", 0, "region" },
    277     /* 0x82 */ { "eraseRgn", 0, "region" },
    278     /* 0x83 */ { "invertRgn", 0, "region" },
    279     /* 0x84 */ { "fillRgn", 0, "region" },
    280     /* 0x85 */ { "reserved", 0, "reserved for Apple use" },
    281     /* 0x86 */ { "reserved", 0, "reserved for Apple use" },
    282     /* 0x87 */ { "reserved", 0, "reserved for Apple use" },
    283     /* 0x88 */ { "frameSameRgn", 0, "region (NYI)" },
    284     /* 0x89 */ { "paintSameRgn", 0, "region (NYI)" },
    285     /* 0x8a */ { "eraseSameRgn", 0, "region (NYI)" },
    286     /* 0x8b */ { "invertSameRgn", 0, "region (NYI)" },
    287     /* 0x8c */ { "fillSameRgn", 0, "region (NYI)" },
    288     /* 0x8d */ { "reserved", 0, "reserved for Apple use" },
    289     /* 0x8e */ { "reserved", 0, "reserved for Apple use" },
    290     /* 0x8f */ { "reserved", 0, "reserved for Apple use" },
    291     /* 0x90 */ { "BitsRect", 0, "copybits, rect clipped" },
    292     /* 0x91 */ { "BitsRgn", 0, "copybits, rgn clipped" },
    293     /* 0x92 */ { "reserved", -1, "reserved for Apple use" },
    294     /* 0x93 */ { "reserved", -1, "reserved for Apple use" },
    295     /* 0x94 */ { "reserved", -1, "reserved for Apple use" },
    296     /* 0x95 */ { "reserved", -1, "reserved for Apple use" },
    297     /* 0x96 */ { "reserved", -1, "reserved for Apple use" },
    298     /* 0x97 */ { "reserved", -1, "reserved for Apple use" },
    299     /* 0x98 */ { "PackBitsRect", 0, "packed copybits, rect clipped" },
    300     /* 0x99 */ { "PackBitsRgn", 0, "packed copybits, rgn clipped" },
    301     /* 0x9a */ { "DirectBitsRect", 0, "PixMap, srcRect, dstRect, mode, PixData" },
    302     /* 0x9b */ { "DirectBitsRgn", 0, "PixMap, srcRect, dstRect, mode, maskRgn, PixData" },
    303     /* 0x9c */ { "reserved", -1, "reserved for Apple use" },
    304     /* 0x9d */ { "reserved", -1, "reserved for Apple use" },
    305     /* 0x9e */ { "reserved", -1, "reserved for Apple use" },
    306     /* 0x9f */ { "reserved", -1, "reserved for Apple use" },
    307     /* 0xa0 */ { "ShortComment", 2, "kind (word)" },
    308     /* 0xa1 */ { "LongComment", 0, "kind (word), size (word), data" }
    309   };
    310 
    311 /*
    312   Forward declarations.
    313 */
    314 static MagickBooleanType
    315   WritePICTImage(const ImageInfo *,Image *,ExceptionInfo *);
    316 
    317 /*
    319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    320 %                                                                             %
    321 %                                                                             %
    322 %                                                                             %
    323 %   D e c o d e I m a g e                                                     %
    324 %                                                                             %
    325 %                                                                             %
    326 %                                                                             %
    327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    328 %
    329 %  DecodeImage decompresses an image via Macintosh pack bits decoding for
    330 %  Macintosh PICT images.
    331 %
    332 %  The format of the DecodeImage method is:
    333 %
    334 %      unsigned char *DecodeImage(Image *blob,Image *image,
    335 %        size_t bytes_per_line,const int bits_per_pixel,
    336 %        unsigned size_t extent)
    337 %
    338 %  A description of each parameter follows:
    339 %
    340 %    o image_info: the image info.
    341 %
    342 %    o blob,image: the address of a structure of type Image.
    343 %
    344 %    o bytes_per_line: This integer identifies the number of bytes in a
    345 %      scanline.
    346 %
    347 %    o bits_per_pixel: the number of bits in a pixel.
    348 %
    349 %    o extent: the number of pixels allocated.
    350 %
    351 */
    352 
    353 static unsigned char *ExpandBuffer(unsigned char *pixels,
    354   MagickSizeType *bytes_per_line,const unsigned int bits_per_pixel)
    355 {
    356   register ssize_t
    357     i;
    358 
    359   register unsigned char
    360     *p,
    361     *q;
    362 
    363   static unsigned char
    364     scanline[8*256];
    365 
    366   p=pixels;
    367   q=scanline;
    368   switch (bits_per_pixel)
    369   {
    370     case 8:
    371     case 16:
    372     case 32:
    373       return(pixels);
    374     case 4:
    375     {
    376       for (i=0; i < (ssize_t) *bytes_per_line; i++)
    377       {
    378         *q++=(*p >> 4) & 0xff;
    379         *q++=(*p & 15);
    380         p++;
    381       }
    382       *bytes_per_line*=2;
    383       break;
    384     }
    385     case 2:
    386     {
    387       for (i=0; i < (ssize_t) *bytes_per_line; i++)
    388       {
    389         *q++=(*p >> 6) & 0x03;
    390         *q++=(*p >> 4) & 0x03;
    391         *q++=(*p >> 2) & 0x03;
    392         *q++=(*p & 3);
    393         p++;
    394       }
    395       *bytes_per_line*=4;
    396       break;
    397     }
    398     case 1:
    399     {
    400       for (i=0; i < (ssize_t) *bytes_per_line; i++)
    401       {
    402         *q++=(*p >> 7) & 0x01;
    403         *q++=(*p >> 6) & 0x01;
    404         *q++=(*p >> 5) & 0x01;
    405         *q++=(*p >> 4) & 0x01;
    406         *q++=(*p >> 3) & 0x01;
    407         *q++=(*p >> 2) & 0x01;
    408         *q++=(*p >> 1) & 0x01;
    409         *q++=(*p & 0x01);
    410         p++;
    411       }
    412       *bytes_per_line*=8;
    413       break;
    414     }
    415     default:
    416       break;
    417   }
    418   return(scanline);
    419 }
    420 
    421 static unsigned char *DecodeImage(Image *blob,Image *image,
    422   size_t bytes_per_line,const unsigned int bits_per_pixel,size_t *extent,
    423   ExceptionInfo *exception)
    424 {
    425   MagickSizeType
    426     number_pixels;
    427 
    428   register ssize_t
    429     i;
    430 
    431   register unsigned char
    432     *p,
    433     *q;
    434 
    435   size_t
    436     bytes_per_pixel,
    437     length,
    438     row_bytes,
    439     scanline_length,
    440     width;
    441 
    442   ssize_t
    443     count,
    444     j,
    445     y;
    446 
    447   unsigned char
    448     *pixels,
    449     *scanline;
    450 
    451   /*
    452     Determine pixel buffer size.
    453   */
    454   if (bits_per_pixel <= 8)
    455     bytes_per_line&=0x7fff;
    456   width=image->columns;
    457   bytes_per_pixel=1;
    458   if (bits_per_pixel == 16)
    459     {
    460       bytes_per_pixel=2;
    461       width*=2;
    462     }
    463   else
    464     if (bits_per_pixel == 32)
    465       width*=image->alpha_trait ? 4 : 3;
    466   if (bytes_per_line == 0)
    467     bytes_per_line=width;
    468   row_bytes=(size_t) (image->columns | 0x8000);
    469   if (image->storage_class == DirectClass)
    470     row_bytes=(size_t) ((4*image->columns) | 0x8000);
    471   /*
    472     Allocate pixel and scanline buffer.
    473   */
    474   pixels=(unsigned char *) AcquireQuantumMemory(image->rows,row_bytes*
    475     sizeof(*pixels));
    476   if (pixels == (unsigned char *) NULL)
    477     return((unsigned char *) NULL);
    478   *extent=row_bytes*image->rows*sizeof(*pixels);
    479   (void) ResetMagickMemory(pixels,0,*extent);
    480   scanline=(unsigned char *) AcquireQuantumMemory(row_bytes,2*
    481     sizeof(*scanline));
    482   if (scanline == (unsigned char *) NULL)
    483     return((unsigned char *) NULL);
    484   if (bytes_per_line < 8)
    485     {
    486       /*
    487         Pixels are already uncompressed.
    488       */
    489       for (y=0; y < (ssize_t) image->rows; y++)
    490       {
    491         q=pixels+y*width*GetPixelChannels(image);;
    492         number_pixels=bytes_per_line;
    493         count=ReadBlob(blob,(size_t) number_pixels,scanline);
    494         if (count != (ssize_t) number_pixels)
    495           {
    496             (void) ThrowMagickException(exception,GetMagickModule(),
    497               CorruptImageError,"UnableToUncompressImage","`%s'",
    498               image->filename);
    499             break;
    500           }
    501         p=ExpandBuffer(scanline,&number_pixels,bits_per_pixel);
    502         if ((q+number_pixels) > (pixels+(*extent)))
    503           {
    504             (void) ThrowMagickException(exception,GetMagickModule(),
    505               CorruptImageError,"UnableToUncompressImage","`%s'",
    506               image->filename);
    507             break;
    508           }
    509         (void) CopyMagickMemory(q,p,(size_t) number_pixels);
    510       }
    511       scanline=(unsigned char *) RelinquishMagickMemory(scanline);
    512       return(pixels);
    513     }
    514   /*
    515     Uncompress RLE pixels into uncompressed pixel buffer.
    516   */
    517   for (y=0; y < (ssize_t) image->rows; y++)
    518   {
    519     q=pixels+y*width;
    520     if (bytes_per_line > 200)
    521       scanline_length=ReadBlobMSBShort(blob);
    522     else
    523       scanline_length=1UL*ReadBlobByte(blob);
    524     if (scanline_length >= row_bytes)
    525       {
    526         (void) ThrowMagickException(exception,GetMagickModule(),
    527           CorruptImageError,"UnableToUncompressImage","`%s'",image->filename);
    528         break;
    529       }
    530     count=ReadBlob(blob,scanline_length,scanline);
    531     if (count != (ssize_t) scanline_length)
    532       {
    533         (void) ThrowMagickException(exception,GetMagickModule(),
    534           CorruptImageError,"UnableToUncompressImage","`%s'",image->filename);
    535         break;
    536       }
    537     for (j=0; j < (ssize_t) scanline_length; )
    538       if ((scanline[j] & 0x80) == 0)
    539         {
    540           length=(size_t) ((scanline[j] & 0xff)+1);
    541           number_pixels=length*bytes_per_pixel;
    542           p=ExpandBuffer(scanline+j+1,&number_pixels,bits_per_pixel);
    543           if ((q-pixels+number_pixels) <= *extent)
    544             (void) CopyMagickMemory(q,p,(size_t) number_pixels);
    545           q+=number_pixels;
    546           j+=(ssize_t) (length*bytes_per_pixel+1);
    547         }
    548       else
    549         {
    550           length=(size_t) (((scanline[j] ^ 0xff) & 0xff)+2);
    551           number_pixels=bytes_per_pixel;
    552           p=ExpandBuffer(scanline+j+1,&number_pixels,bits_per_pixel);
    553           for (i=0; i < (ssize_t) length; i++)
    554           {
    555             if ((q-pixels+number_pixels) <= *extent)
    556               (void) CopyMagickMemory(q,p,(size_t) number_pixels);
    557             q+=number_pixels;
    558           }
    559           j+=(ssize_t) bytes_per_pixel+1;
    560         }
    561   }
    562   scanline=(unsigned char *) RelinquishMagickMemory(scanline);
    563   return(pixels);
    564 }
    565 
    566 /*
    568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    569 %                                                                             %
    570 %                                                                             %
    571 %                                                                             %
    572 %   E n c o d e I m a g e                                                     %
    573 %                                                                             %
    574 %                                                                             %
    575 %                                                                             %
    576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    577 %
    578 %  EncodeImage compresses an image via Macintosh pack bits encoding
    579 %  for Macintosh PICT images.
    580 %
    581 %  The format of the EncodeImage method is:
    582 %
    583 %      size_t EncodeImage(Image *image,const unsigned char *scanline,
    584 %        const size_t bytes_per_line,unsigned char *pixels)
    585 %
    586 %  A description of each parameter follows:
    587 %
    588 %    o image: the address of a structure of type Image.
    589 %
    590 %    o scanline: A pointer to an array of characters to pack.
    591 %
    592 %    o bytes_per_line: the number of bytes in a scanline.
    593 %
    594 %    o pixels: A pointer to an array of characters where the packed
    595 %      characters are stored.
    596 %
    597 */
    598 static size_t EncodeImage(Image *image,const unsigned char *scanline,
    599   const size_t bytes_per_line,unsigned char *pixels)
    600 {
    601 #define MaxCount  128
    602 #define MaxPackbitsRunlength  128
    603 
    604   register const unsigned char
    605     *p;
    606 
    607   register ssize_t
    608     i;
    609 
    610   register unsigned char
    611     *q;
    612 
    613   size_t
    614     length;
    615 
    616   ssize_t
    617     count,
    618     repeat_count,
    619     runlength;
    620 
    621   unsigned char
    622     index;
    623 
    624   /*
    625     Pack scanline.
    626   */
    627   assert(image != (Image *) NULL);
    628   assert(image->signature == MagickCoreSignature);
    629   if (image->debug != MagickFalse)
    630     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    631   assert(scanline != (unsigned char *) NULL);
    632   assert(pixels != (unsigned char *) NULL);
    633   count=0;
    634   runlength=0;
    635   p=scanline+(bytes_per_line-1);
    636   q=pixels;
    637   index=(*p);
    638   for (i=(ssize_t) bytes_per_line-1; i >= 0; i--)
    639   {
    640     if (index == *p)
    641       runlength++;
    642     else
    643       {
    644         if (runlength < 3)
    645           while (runlength > 0)
    646           {
    647             *q++=(unsigned char) index;
    648             runlength--;
    649             count++;
    650             if (count == MaxCount)
    651               {
    652                 *q++=(unsigned char) (MaxCount-1);
    653                 count-=MaxCount;
    654               }
    655           }
    656         else
    657           {
    658             if (count > 0)
    659               *q++=(unsigned char) (count-1);
    660             count=0;
    661             while (runlength > 0)
    662             {
    663               repeat_count=runlength;
    664               if (repeat_count > MaxPackbitsRunlength)
    665                 repeat_count=MaxPackbitsRunlength;
    666               *q++=(unsigned char) index;
    667               *q++=(unsigned char) (257-repeat_count);
    668               runlength-=repeat_count;
    669             }
    670           }
    671         runlength=1;
    672       }
    673     index=(*p);
    674     p--;
    675   }
    676   if (runlength < 3)
    677     while (runlength > 0)
    678     {
    679       *q++=(unsigned char) index;
    680       runlength--;
    681       count++;
    682       if (count == MaxCount)
    683         {
    684           *q++=(unsigned char) (MaxCount-1);
    685           count-=MaxCount;
    686         }
    687     }
    688   else
    689     {
    690       if (count > 0)
    691         *q++=(unsigned char) (count-1);
    692       count=0;
    693       while (runlength > 0)
    694       {
    695         repeat_count=runlength;
    696         if (repeat_count > MaxPackbitsRunlength)
    697           repeat_count=MaxPackbitsRunlength;
    698         *q++=(unsigned char) index;
    699         *q++=(unsigned char) (257-repeat_count);
    700         runlength-=repeat_count;
    701       }
    702     }
    703   if (count > 0)
    704     *q++=(unsigned char) (count-1);
    705   /*
    706     Write the number of and the packed length.
    707   */
    708   length=(size_t) (q-pixels);
    709   if (bytes_per_line > 200)
    710     {
    711       (void) WriteBlobMSBShort(image,(unsigned short) length);
    712       length+=2;
    713     }
    714   else
    715     {
    716       (void) WriteBlobByte(image,(unsigned char) length);
    717       length++;
    718     }
    719   while (q != pixels)
    720   {
    721     q--;
    722     (void) WriteBlobByte(image,*q);
    723   }
    724   return(length);
    725 }
    726 
    727 /*
    729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    730 %                                                                             %
    731 %                                                                             %
    732 %                                                                             %
    733 %   I s P I C T                                                               %
    734 %                                                                             %
    735 %                                                                             %
    736 %                                                                             %
    737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    738 %
    739 %  IsPICT()() returns MagickTrue if the image format type, identified by the
    740 %  magick string, is PICT.
    741 %
    742 %  The format of the ReadPICTImage method is:
    743 %
    744 %      MagickBooleanType IsPICT(const unsigned char *magick,const size_t length)
    745 %
    746 %  A description of each parameter follows:
    747 %
    748 %    o magick: compare image format pattern against these bytes.
    749 %
    750 %    o length: Specifies the length of the magick string.
    751 %
    752 */
    753 static MagickBooleanType IsPICT(const unsigned char *magick,const size_t length)
    754 {
    755   if (length < 12)
    756     return(MagickFalse);
    757   /*
    758     Embedded OLE2 macintosh have "PICT" instead of 512 platform header.
    759   */
    760   if (memcmp(magick,"PICT",4) == 0)
    761     return(MagickTrue);
    762   if (length < 528)
    763     return(MagickFalse);
    764   if (memcmp(magick+522,"\000\021\002\377\014\000",6) == 0)
    765     return(MagickTrue);
    766   return(MagickFalse);
    767 }
    768 
    769 #if !defined(macintosh)
    771 /*
    772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    773 %                                                                             %
    774 %                                                                             %
    775 %                                                                             %
    776 %   R e a d P I C T I m a g e                                                 %
    777 %                                                                             %
    778 %                                                                             %
    779 %                                                                             %
    780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    781 %
    782 %  ReadPICTImage() reads an Apple Macintosh QuickDraw/PICT image file
    783 %  and returns it.  It allocates the memory necessary for the new Image
    784 %  structure and returns a pointer to the new image.
    785 %
    786 %  The format of the ReadPICTImage method is:
    787 %
    788 %      Image *ReadPICTImage(const ImageInfo *image_info,
    789 %        ExceptionInfo *exception)
    790 %
    791 %  A description of each parameter follows:
    792 %
    793 %    o image_info: the image info.
    794 %
    795 %    o exception: return any errors or warnings in this structure.
    796 %
    797 */
    798 
    799 static MagickBooleanType ReadRectangle(Image *image,PICTRectangle *rectangle)
    800 {
    801   rectangle->top=(short) ReadBlobMSBShort(image);
    802   rectangle->left=(short) ReadBlobMSBShort(image);
    803   rectangle->bottom=(short) ReadBlobMSBShort(image);
    804   rectangle->right=(short) ReadBlobMSBShort(image);
    805   if ((EOFBlob(image) != MagickFalse) || (rectangle->left > rectangle->right) ||
    806       (rectangle->top > rectangle->bottom))
    807     return(MagickFalse);
    808   return(MagickTrue);
    809 }
    810 
    811 static Image *ReadPICTImage(const ImageInfo *image_info,
    812   ExceptionInfo *exception)
    813 {
    814   char
    815     geometry[MagickPathExtent],
    816     header_ole[4];
    817 
    818   Image
    819     *image;
    820 
    821   int
    822     c,
    823     code;
    824 
    825   MagickBooleanType
    826     jpeg,
    827     status;
    828 
    829   PICTRectangle
    830     frame;
    831 
    832   PICTPixmap
    833     pixmap;
    834 
    835   Quantum
    836     index;
    837 
    838   register Quantum
    839     *q;
    840 
    841   register ssize_t
    842     i,
    843     x;
    844 
    845   size_t
    846     extent,
    847     length;
    848 
    849   ssize_t
    850     count,
    851     flags,
    852     j,
    853     version,
    854     y;
    855 
    856   StringInfo
    857     *profile;
    858 
    859   /*
    860     Open image file.
    861   */
    862   assert(image_info != (const ImageInfo *) NULL);
    863   assert(image_info->signature == MagickCoreSignature);
    864   if (image_info->debug != MagickFalse)
    865     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    866       image_info->filename);
    867   assert(exception != (ExceptionInfo *) NULL);
    868   assert(exception->signature == MagickCoreSignature);
    869   image=AcquireImage(image_info,exception);
    870   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    871   if (status == MagickFalse)
    872     {
    873       image=DestroyImageList(image);
    874       return((Image *) NULL);
    875     }
    876   /*
    877     Read PICT header.
    878   */
    879   pixmap.bits_per_pixel=0;
    880   pixmap.component_count=0;
    881   /*
    882     Skip header : 512 for standard PICT and 4, ie "PICT" for OLE2.
    883   */
    884   header_ole[0]=ReadBlobByte(image);
    885   header_ole[1]=ReadBlobByte(image);
    886   header_ole[2]=ReadBlobByte(image);
    887   header_ole[3]=ReadBlobByte(image);
    888   if (!((header_ole[0] == 0x50) && (header_ole[1] == 0x49) &&
    889       (header_ole[2] == 0x43) && (header_ole[3] == 0x54 )))
    890     for (i=0; i < 508; i++)
    891       if (ReadBlobByte(image) == EOF)
    892         break;
    893   (void) ReadBlobMSBShort(image);  /* skip picture size */
    894   if (ReadRectangle(image,&frame) == MagickFalse)
    895     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    896   while ((c=ReadBlobByte(image)) == 0) ;
    897   if (c != 0x11)
    898     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    899   version=ReadBlobByte(image);
    900   if (version == 2)
    901     {
    902       c=ReadBlobByte(image);
    903       if (c != 0xff)
    904         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    905     }
    906   else
    907     if (version != 1)
    908       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    909   if ((frame.left < 0) || (frame.right < 0) || (frame.top < 0) ||
    910       (frame.bottom < 0) || (frame.left >= frame.right) ||
    911       (frame.top >= frame.bottom))
    912     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    913   /*
    914     Create black canvas.
    915   */
    916   flags=0;
    917   image->depth=8;
    918   image->columns=1UL*(frame.right-frame.left);
    919   image->rows=1UL*(frame.bottom-frame.top);
    920   image->resolution.x=DefaultResolution;
    921   image->resolution.y=DefaultResolution;
    922   image->units=UndefinedResolution;
    923   if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
    924     if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    925       {
    926         (void) CloseBlob(image);
    927         return(GetFirstImageInList(image));
    928       }
    929   status=SetImageExtent(image,image->columns,image->rows,exception);
    930   if (status == MagickFalse)
    931     return(DestroyImageList(image));
    932   /*
    933     Interpret PICT opcodes.
    934   */
    935   jpeg=MagickFalse;
    936   for (code=0; EOFBlob(image) == MagickFalse; )
    937   {
    938     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
    939       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    940         break;
    941     if ((version == 1) || ((TellBlob(image) % 2) != 0))
    942       code=ReadBlobByte(image);
    943     if (version == 2)
    944       code=ReadBlobMSBSignedShort(image);
    945     if (code < 0)
    946       break;
    947     if (code > 0xa1)
    948       {
    949         if (image->debug != MagickFalse)
    950           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%04X:",code);
    951       }
    952     else
    953       {
    954         if (image->debug != MagickFalse)
    955           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    956             "  %04X %s: %s",code,codes[code].name,codes[code].description);
    957         switch (code)
    958         {
    959           case 0x01:
    960           {
    961             /*
    962               Clipping rectangle.
    963             */
    964             length=ReadBlobMSBShort(image);
    965             if (length != 0x000a)
    966               {
    967                 for (i=0; i < (ssize_t) (length-2); i++)
    968                   if (ReadBlobByte(image) == EOF)
    969                     break;
    970                 break;
    971               }
    972             if (ReadRectangle(image,&frame) == MagickFalse)
    973               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    974             if (((frame.left & 0x8000) != 0) || ((frame.top & 0x8000) != 0))
    975               break;
    976             image->columns=1UL*(frame.right-frame.left);
    977             image->rows=1UL*(frame.bottom-frame.top);
    978             status=SetImageExtent(image,image->columns,image->rows,exception);
    979             if (status == MagickFalse)
    980               return(DestroyImageList(image));
    981             (void) SetImageBackgroundColor(image,exception);
    982             break;
    983           }
    984           case 0x12:
    985           case 0x13:
    986           case 0x14:
    987           {
    988             ssize_t
    989               pattern;
    990 
    991             size_t
    992               height,
    993               width;
    994 
    995             /*
    996               Skip pattern definition.
    997             */
    998             pattern=1L*ReadBlobMSBShort(image);
    999             for (i=0; i < 8; i++)
   1000               if (ReadBlobByte(image) == EOF)
   1001                 break;
   1002             if (pattern == 2)
   1003               {
   1004                 for (i=0; i < 5; i++)
   1005                   if (ReadBlobByte(image) == EOF)
   1006                     break;
   1007                 break;
   1008               }
   1009             if (pattern != 1)
   1010               ThrowReaderException(CorruptImageError,"UnknownPatternType");
   1011             length=ReadBlobMSBShort(image);
   1012             if (ReadRectangle(image,&frame) == MagickFalse)
   1013               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   1014             ReadPixmap(pixmap);
   1015             image->depth=1UL*pixmap.component_size;
   1016             image->resolution.x=1.0*pixmap.horizontal_resolution;
   1017             image->resolution.y=1.0*pixmap.vertical_resolution;
   1018             image->units=PixelsPerInchResolution;
   1019             (void) ReadBlobMSBLong(image);
   1020             flags=1L*ReadBlobMSBShort(image);
   1021             length=ReadBlobMSBShort(image);
   1022             for (i=0; i <= (ssize_t) length; i++)
   1023               (void) ReadBlobMSBLong(image);
   1024             width=1UL*(frame.bottom-frame.top);
   1025             height=1UL*(frame.right-frame.left);
   1026             if (pixmap.bits_per_pixel <= 8)
   1027               length&=0x7fff;
   1028             if (pixmap.bits_per_pixel == 16)
   1029               width<<=1;
   1030             if (length == 0)
   1031               length=width;
   1032             if (length < 8)
   1033               {
   1034                 for (i=0; i < (ssize_t) (length*height); i++)
   1035                   if (ReadBlobByte(image) == EOF)
   1036                     break;
   1037               }
   1038             else
   1039               for (j=0; j < (int) height; j++)
   1040                 if (length > 200)
   1041                   {
   1042                     for (j=0; j < (ssize_t) ReadBlobMSBShort(image); j++)
   1043                       if (ReadBlobByte(image) == EOF)
   1044                         break;
   1045                   }
   1046                 else
   1047                   for (j=0; j < (ssize_t) ReadBlobByte(image); j++)
   1048                     if (ReadBlobByte(image) == EOF)
   1049                       break;
   1050             break;
   1051           }
   1052           case 0x1b:
   1053           {
   1054             /*
   1055               Initialize image background color.
   1056             */
   1057             image->background_color.red=(Quantum)
   1058               ScaleShortToQuantum(ReadBlobMSBShort(image));
   1059             image->background_color.green=(Quantum)
   1060               ScaleShortToQuantum(ReadBlobMSBShort(image));
   1061             image->background_color.blue=(Quantum)
   1062               ScaleShortToQuantum(ReadBlobMSBShort(image));
   1063             break;
   1064           }
   1065           case 0x70:
   1066           case 0x71:
   1067           case 0x72:
   1068           case 0x73:
   1069           case 0x74:
   1070           case 0x75:
   1071           case 0x76:
   1072           case 0x77:
   1073           {
   1074             /*
   1075               Skip polygon or region.
   1076             */
   1077             length=ReadBlobMSBShort(image);
   1078             for (i=0; i < (ssize_t) (length-2); i++)
   1079               if (ReadBlobByte(image) == EOF)
   1080                 break;
   1081             break;
   1082           }
   1083           case 0x90:
   1084           case 0x91:
   1085           case 0x98:
   1086           case 0x99:
   1087           case 0x9a:
   1088           case 0x9b:
   1089           {
   1090             Image
   1091               *tile_image;
   1092 
   1093             PICTRectangle
   1094               source,
   1095               destination;
   1096 
   1097             register unsigned char
   1098               *p;
   1099 
   1100             size_t
   1101               j;
   1102 
   1103             ssize_t
   1104               bytes_per_line;
   1105 
   1106             unsigned char
   1107               *pixels;
   1108 
   1109             /*
   1110               Pixmap clipped by a rectangle.
   1111             */
   1112             bytes_per_line=0;
   1113             if ((code != 0x9a) && (code != 0x9b))
   1114               bytes_per_line=1L*ReadBlobMSBShort(image);
   1115             else
   1116               {
   1117                 (void) ReadBlobMSBShort(image);
   1118                 (void) ReadBlobMSBShort(image);
   1119                 (void) ReadBlobMSBShort(image);
   1120               }
   1121             if (ReadRectangle(image,&frame) == MagickFalse)
   1122               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   1123             /*
   1124               Initialize tile image.
   1125             */
   1126             tile_image=CloneImage(image,1UL*(frame.right-frame.left),
   1127               1UL*(frame.bottom-frame.top),MagickTrue,exception);
   1128             if (tile_image == (Image *) NULL)
   1129               return((Image *) NULL);
   1130             if ((code == 0x9a) || (code == 0x9b) ||
   1131                 ((bytes_per_line & 0x8000) != 0))
   1132               {
   1133                 ReadPixmap(pixmap);
   1134                 tile_image->depth=1UL*pixmap.component_size;
   1135                 tile_image->alpha_trait=pixmap.component_count == 4 ?
   1136                   BlendPixelTrait : UndefinedPixelTrait;
   1137                 tile_image->resolution.x=(double) pixmap.horizontal_resolution;
   1138                 tile_image->resolution.y=(double) pixmap.vertical_resolution;
   1139                 tile_image->units=PixelsPerInchResolution;
   1140                 if (tile_image->alpha_trait != UndefinedPixelTrait)
   1141                   image->alpha_trait=tile_image->alpha_trait;
   1142               }
   1143             if ((code != 0x9a) && (code != 0x9b))
   1144               {
   1145                 /*
   1146                   Initialize colormap.
   1147                 */
   1148                 tile_image->colors=2;
   1149                 if ((bytes_per_line & 0x8000) != 0)
   1150                   {
   1151                     (void) ReadBlobMSBLong(image);
   1152                     flags=1L*ReadBlobMSBShort(image);
   1153                     tile_image->colors=1UL*ReadBlobMSBShort(image)+1;
   1154                   }
   1155                 status=AcquireImageColormap(tile_image,tile_image->colors,
   1156                   exception);
   1157                 if (status == MagickFalse)
   1158                   {
   1159                     tile_image=DestroyImage(tile_image);
   1160                     ThrowReaderException(ResourceLimitError,
   1161                       "MemoryAllocationFailed");
   1162                   }
   1163                 if ((bytes_per_line & 0x8000) != 0)
   1164                   {
   1165                     for (i=0; i < (ssize_t) tile_image->colors; i++)
   1166                     {
   1167                       j=ReadBlobMSBShort(image) % tile_image->colors;
   1168                       if ((flags & 0x8000) != 0)
   1169                         j=(size_t) i;
   1170                       tile_image->colormap[j].red=(Quantum)
   1171                         ScaleShortToQuantum(ReadBlobMSBShort(image));
   1172                       tile_image->colormap[j].green=(Quantum)
   1173                         ScaleShortToQuantum(ReadBlobMSBShort(image));
   1174                       tile_image->colormap[j].blue=(Quantum)
   1175                         ScaleShortToQuantum(ReadBlobMSBShort(image));
   1176                     }
   1177                   }
   1178                 else
   1179                   {
   1180                     for (i=0; i < (ssize_t) tile_image->colors; i++)
   1181                     {
   1182                       tile_image->colormap[i].red=(Quantum) (QuantumRange-
   1183                         tile_image->colormap[i].red);
   1184                       tile_image->colormap[i].green=(Quantum) (QuantumRange-
   1185                         tile_image->colormap[i].green);
   1186                       tile_image->colormap[i].blue=(Quantum) (QuantumRange-
   1187                         tile_image->colormap[i].blue);
   1188                     }
   1189                   }
   1190               }
   1191             if (ReadRectangle(image,&source) == MagickFalse)
   1192               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   1193             if (ReadRectangle(image,&destination) == MagickFalse)
   1194               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   1195             (void) ReadBlobMSBShort(image);
   1196             if ((code == 0x91) || (code == 0x99) || (code == 0x9b))
   1197               {
   1198                 /*
   1199                   Skip region.
   1200                 */
   1201                 length=ReadBlobMSBShort(image);
   1202                 for (i=0; i < (ssize_t) (length-2); i++)
   1203                   if (ReadBlobByte(image) == EOF)
   1204                     break;
   1205               }
   1206             if ((code != 0x9a) && (code != 0x9b) &&
   1207                 (bytes_per_line & 0x8000) == 0)
   1208               pixels=DecodeImage(image,tile_image,1UL*bytes_per_line,1,&extent,
   1209                 exception);
   1210             else
   1211               pixels=DecodeImage(image,tile_image,1UL*bytes_per_line,1U*
   1212                 pixmap.bits_per_pixel,&extent,exception);
   1213             if (pixels == (unsigned char *) NULL)
   1214               {
   1215                 tile_image=DestroyImage(tile_image);
   1216                 ThrowReaderException(ResourceLimitError,
   1217                   "MemoryAllocationFailed");
   1218               }
   1219             /*
   1220               Convert PICT tile image to pixel packets.
   1221             */
   1222             p=pixels;
   1223             for (y=0; y < (ssize_t) tile_image->rows; y++)
   1224             {
   1225               if (p > (pixels+extent+image->columns))
   1226                 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
   1227               q=QueueAuthenticPixels(tile_image,0,y,tile_image->columns,1,
   1228                 exception);
   1229               if (q == (Quantum *) NULL)
   1230                 break;
   1231               for (x=0; x < (ssize_t) tile_image->columns; x++)
   1232               {
   1233                 if (tile_image->storage_class == PseudoClass)
   1234                   {
   1235                     index=ConstrainColormapIndex(tile_image,*p,exception);
   1236                     SetPixelIndex(tile_image,index,q);
   1237                     SetPixelRed(tile_image,
   1238                       tile_image->colormap[(ssize_t) index].red,q);
   1239                     SetPixelGreen(tile_image,
   1240                       tile_image->colormap[(ssize_t) index].green,q);
   1241                     SetPixelBlue(tile_image,
   1242                       tile_image->colormap[(ssize_t) index].blue,q);
   1243                   }
   1244                 else
   1245                   {
   1246                     if (pixmap.bits_per_pixel == 16)
   1247                       {
   1248                         i=(*p++);
   1249                         j=(*p);
   1250                         SetPixelRed(tile_image,ScaleCharToQuantum(
   1251                           (unsigned char) ((i & 0x7c) << 1)),q);
   1252                         SetPixelGreen(tile_image,ScaleCharToQuantum(
   1253                           (unsigned char) (((i & 0x03) << 6) |
   1254                           ((j & 0xe0) >> 2))),q);
   1255                         SetPixelBlue(tile_image,ScaleCharToQuantum(
   1256                           (unsigned char) ((j & 0x1f) << 3)),q);
   1257                       }
   1258                     else
   1259                       if (tile_image->alpha_trait == UndefinedPixelTrait)
   1260                         {
   1261                           if (p > (pixels+extent+2*image->columns))
   1262                             ThrowReaderException(CorruptImageError,
   1263                               "NotEnoughPixelData");
   1264                           SetPixelRed(tile_image,ScaleCharToQuantum(*p),q);
   1265                           SetPixelGreen(tile_image,ScaleCharToQuantum(
   1266                             *(p+tile_image->columns)),q);
   1267                           SetPixelBlue(tile_image,ScaleCharToQuantum(
   1268                             *(p+2*tile_image->columns)),q);
   1269                         }
   1270                       else
   1271                         {
   1272                           if (p > (pixels+extent+3*image->columns))
   1273                             ThrowReaderException(CorruptImageError,
   1274                               "NotEnoughPixelData");
   1275                           SetPixelAlpha(tile_image,ScaleCharToQuantum(*p),q);
   1276                           SetPixelRed(tile_image,ScaleCharToQuantum(
   1277                             *(p+tile_image->columns)),q);
   1278                           SetPixelGreen(tile_image,ScaleCharToQuantum(
   1279                             *(p+2*tile_image->columns)),q);
   1280                           SetPixelBlue(tile_image,ScaleCharToQuantum(
   1281                             *(p+3*tile_image->columns)),q);
   1282                         }
   1283                   }
   1284                 p++;
   1285                 q+=GetPixelChannels(tile_image);
   1286               }
   1287               if (SyncAuthenticPixels(tile_image,exception) == MagickFalse)
   1288                 break;
   1289               if ((tile_image->storage_class == DirectClass) &&
   1290                   (pixmap.bits_per_pixel != 16))
   1291                 {
   1292                   p+=(pixmap.component_count-1)*tile_image->columns;
   1293                   if (p < pixels)
   1294                     break;
   1295                 }
   1296               status=SetImageProgress(image,LoadImageTag,y,tile_image->rows);
   1297               if (status == MagickFalse)
   1298                 break;
   1299             }
   1300             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
   1301             if (jpeg == MagickFalse)
   1302               if ((code == 0x9a) || (code == 0x9b) ||
   1303                   ((bytes_per_line & 0x8000) != 0))
   1304                 (void) CompositeImage(image,tile_image,CopyCompositeOp,
   1305                   MagickTrue,destination.left,destination.top,exception);
   1306             tile_image=DestroyImage(tile_image);
   1307             break;
   1308           }
   1309           case 0xa1:
   1310           {
   1311             unsigned char
   1312               *info;
   1313 
   1314             size_t
   1315               type;
   1316 
   1317             /*
   1318               Comment.
   1319             */
   1320             type=ReadBlobMSBShort(image);
   1321             length=ReadBlobMSBShort(image);
   1322             if (length == 0)
   1323               break;
   1324             (void) ReadBlobMSBLong(image);
   1325             length-=4;
   1326             if (length == 0)
   1327               break;
   1328             info=(unsigned char *) AcquireQuantumMemory(length,sizeof(*info));
   1329             if (info == (unsigned char *) NULL)
   1330               break;
   1331             count=ReadBlob(image,length,info);
   1332             if (count != (ssize_t) length)
   1333               ThrowReaderException(ResourceLimitError,"UnableToReadImageData");
   1334             switch (type)
   1335             {
   1336               case 0xe0:
   1337               {
   1338                 profile=BlobToStringInfo((const void *) NULL,length);
   1339                 SetStringInfoDatum(profile,info);
   1340                 status=SetImageProfile(image,"icc",profile,exception);
   1341                 profile=DestroyStringInfo(profile);
   1342                 if (status == MagickFalse)
   1343                   ThrowReaderException(ResourceLimitError,
   1344                     "MemoryAllocationFailed");
   1345                 break;
   1346               }
   1347               case 0x1f2:
   1348               {
   1349                 profile=BlobToStringInfo((const void *) NULL,length);
   1350                 SetStringInfoDatum(profile,info);
   1351                 status=SetImageProfile(image,"iptc",profile,exception);
   1352                 if (status == MagickFalse)
   1353                   ThrowReaderException(ResourceLimitError,
   1354                     "MemoryAllocationFailed");
   1355                 profile=DestroyStringInfo(profile);
   1356                 break;
   1357               }
   1358               default:
   1359                 break;
   1360             }
   1361             info=(unsigned char *) RelinquishMagickMemory(info);
   1362             break;
   1363           }
   1364           default:
   1365           {
   1366             /*
   1367               Skip to next op code.
   1368             */
   1369             if (codes[code].length == -1)
   1370               (void) ReadBlobMSBShort(image);
   1371             else
   1372               for (i=0; i < (ssize_t) codes[code].length; i++)
   1373                 if (ReadBlobByte(image) == EOF)
   1374                   break;
   1375           }
   1376         }
   1377       }
   1378     if (code == 0xc00)
   1379       {
   1380         /*
   1381           Skip header.
   1382         */
   1383         for (i=0; i < 24; i++)
   1384           if (ReadBlobByte(image) == EOF)
   1385             break;
   1386         continue;
   1387       }
   1388     if (((code >= 0xb0) && (code <= 0xcf)) ||
   1389         ((code >= 0x8000) && (code <= 0x80ff)))
   1390       continue;
   1391     if (code == 0x8200)
   1392       {
   1393         FILE
   1394           *file;
   1395 
   1396         Image
   1397           *tile_image;
   1398 
   1399         ImageInfo
   1400           *read_info;
   1401 
   1402         int
   1403           unique_file;
   1404 
   1405         /*
   1406           Embedded JPEG.
   1407         */
   1408         jpeg=MagickTrue;
   1409         read_info=CloneImageInfo(image_info);
   1410         SetImageInfoBlob(read_info,(void *) NULL,0);
   1411         file=(FILE *) NULL;
   1412         unique_file=AcquireUniqueFileResource(read_info->filename);
   1413         if (unique_file != -1)
   1414           file=fdopen(unique_file,"wb");
   1415         if ((unique_file == -1) || (file == (FILE *) NULL))
   1416           {
   1417             (void) RelinquishUniqueFileResource(read_info->filename);
   1418             (void) CopyMagickString(image->filename,read_info->filename,
   1419               MagickPathExtent);
   1420             ThrowFileException(exception,FileOpenError,
   1421               "UnableToCreateTemporaryFile",image->filename);
   1422             image=DestroyImageList(image);
   1423             return((Image *) NULL);
   1424           }
   1425         length=ReadBlobMSBLong(image);
   1426         if (length > 154)
   1427           {
   1428             for (i=0; i < 6; i++)
   1429               (void) ReadBlobMSBLong(image);
   1430             if (ReadRectangle(image,&frame) == MagickFalse)
   1431               {
   1432                 (void) fclose(file);
   1433                 (void) RelinquishUniqueFileResource(read_info->filename);
   1434                 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   1435               }
   1436             for (i=0; i < 122; i++)
   1437               if (ReadBlobByte(image) == EOF)
   1438                 break;
   1439             for (i=0; i < (ssize_t) (length-154); i++)
   1440             {
   1441               c=ReadBlobByte(image);
   1442               if (c == EOF)
   1443                 break;
   1444               (void) fputc(c,file);
   1445             }
   1446           }
   1447         (void) fclose(file);
   1448         (void) close(unique_file);
   1449         tile_image=ReadImage(read_info,exception);
   1450         (void) RelinquishUniqueFileResource(read_info->filename);
   1451         read_info=DestroyImageInfo(read_info);
   1452         if (tile_image == (Image *) NULL)
   1453           continue;
   1454         (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g",
   1455           (double) MagickMax(image->columns,tile_image->columns),
   1456           (double) MagickMax(image->rows,tile_image->rows));
   1457         (void) SetImageExtent(image,
   1458           MagickMax(image->columns,tile_image->columns),
   1459           MagickMax(image->rows,tile_image->rows),exception);
   1460         (void) TransformImageColorspace(image,tile_image->colorspace,exception);
   1461         (void) CompositeImage(image,tile_image,CopyCompositeOp,MagickTrue,
   1462           frame.left,frame.right,exception);
   1463         image->compression=tile_image->compression;
   1464         tile_image=DestroyImage(tile_image);
   1465         continue;
   1466       }
   1467     if ((code == 0xff) || (code == 0xffff))
   1468       break;
   1469     if (((code >= 0xd0) && (code <= 0xfe)) ||
   1470         ((code >= 0x8100) && (code <= 0xffff)))
   1471       {
   1472         /*
   1473           Skip reserved.
   1474         */
   1475         length=ReadBlobMSBShort(image);
   1476         for (i=0; i < (ssize_t) length; i++)
   1477           if (ReadBlobByte(image) == EOF)
   1478             break;
   1479         continue;
   1480       }
   1481     if ((code >= 0x100) && (code <= 0x7fff))
   1482       {
   1483         /*
   1484           Skip reserved.
   1485         */
   1486         length=(size_t) ((code >> 7) & 0xff);
   1487         for (i=0; i < (ssize_t) length; i++)
   1488           if (ReadBlobByte(image) == EOF)
   1489             break;
   1490         continue;
   1491       }
   1492   }
   1493   (void) CloseBlob(image);
   1494   return(GetFirstImageInList(image));
   1495 }
   1496 #endif
   1497 
   1498 /*
   1500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1501 %                                                                             %
   1502 %                                                                             %
   1503 %                                                                             %
   1504 %   R e g i s t e r P I C T I m a g e                                         %
   1505 %                                                                             %
   1506 %                                                                             %
   1507 %                                                                             %
   1508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1509 %
   1510 %  RegisterPICTImage() adds attributes for the PICT image format to
   1511 %  the list of supported formats.  The attributes include the image format
   1512 %  tag, a method to read and/or write the format, whether the format
   1513 %  supports the saving of more than one frame to the same file or blob,
   1514 %  whether the format supports native in-memory I/O, and a brief
   1515 %  description of the format.
   1516 %
   1517 %  The format of the RegisterPICTImage method is:
   1518 %
   1519 %      size_t RegisterPICTImage(void)
   1520 %
   1521 */
   1522 ModuleExport size_t RegisterPICTImage(void)
   1523 {
   1524   MagickInfo
   1525     *entry;
   1526 
   1527   entry=AcquireMagickInfo("PICT","PCT","Apple Macintosh QuickDraw/PICT");
   1528   entry->decoder=(DecodeImageHandler *) ReadPICTImage;
   1529   entry->encoder=(EncodeImageHandler *) WritePICTImage;
   1530   entry->flags^=CoderAdjoinFlag;
   1531   entry->flags|=CoderSeekableStreamFlag;
   1532   entry->magick=(IsImageFormatHandler *) IsPICT;
   1533   (void) RegisterMagickInfo(entry);
   1534   entry=AcquireMagickInfo("PICT","PICT","Apple Macintosh QuickDraw/PICT");
   1535   entry->decoder=(DecodeImageHandler *) ReadPICTImage;
   1536   entry->encoder=(EncodeImageHandler *) WritePICTImage;
   1537   entry->flags^=CoderAdjoinFlag;
   1538   entry->flags|=CoderSeekableStreamFlag;
   1539   entry->magick=(IsImageFormatHandler *) IsPICT;
   1540   (void) RegisterMagickInfo(entry);
   1541   return(MagickImageCoderSignature);
   1542 }
   1543 
   1544 /*
   1546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1547 %                                                                             %
   1548 %                                                                             %
   1549 %                                                                             %
   1550 %   U n r e g i s t e r P I C T I m a g e                                     %
   1551 %                                                                             %
   1552 %                                                                             %
   1553 %                                                                             %
   1554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1555 %
   1556 %  UnregisterPICTImage() removes format registrations made by the
   1557 %  PICT module from the list of supported formats.
   1558 %
   1559 %  The format of the UnregisterPICTImage method is:
   1560 %
   1561 %      UnregisterPICTImage(void)
   1562 %
   1563 */
   1564 ModuleExport void UnregisterPICTImage(void)
   1565 {
   1566   (void) UnregisterMagickInfo("PCT");
   1567   (void) UnregisterMagickInfo("PICT");
   1568 }
   1569 
   1570 /*
   1572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1573 %                                                                             %
   1574 %                                                                             %
   1575 %                                                                             %
   1576 %   W r i t e P I C T I m a g e                                               %
   1577 %                                                                             %
   1578 %                                                                             %
   1579 %                                                                             %
   1580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1581 %
   1582 %  WritePICTImage() writes an image to a file in the Apple Macintosh
   1583 %  QuickDraw/PICT image format.
   1584 %
   1585 %  The format of the WritePICTImage method is:
   1586 %
   1587 %      MagickBooleanType WritePICTImage(const ImageInfo *image_info,
   1588 %        Image *image,ExceptionInfo *exception)
   1589 %
   1590 %  A description of each parameter follows.
   1591 %
   1592 %    o image_info: the image info.
   1593 %
   1594 %    o image:  The image.
   1595 %
   1596 %    o exception: return any errors or warnings in this structure.
   1597 %
   1598 */
   1599 static MagickBooleanType WritePICTImage(const ImageInfo *image_info,
   1600   Image *image,ExceptionInfo *exception)
   1601 {
   1602 #define MaxCount  128
   1603 #define PictCropRegionOp  0x01
   1604 #define PictEndOfPictureOp  0xff
   1605 #define PictJPEGOp  0x8200
   1606 #define PictInfoOp  0x0C00
   1607 #define PictInfoSize  512
   1608 #define PictPixmapOp  0x9A
   1609 #define PictPICTOp  0x98
   1610 #define PictVersion  0x11
   1611 
   1612   const StringInfo
   1613     *profile;
   1614 
   1615   double
   1616     x_resolution,
   1617     y_resolution;
   1618 
   1619   MagickBooleanType
   1620     status;
   1621 
   1622   MagickOffsetType
   1623     offset;
   1624 
   1625   PICTPixmap
   1626     pixmap;
   1627 
   1628   PICTRectangle
   1629     bounds,
   1630     crop_rectangle,
   1631     destination_rectangle,
   1632     frame_rectangle,
   1633     size_rectangle,
   1634     source_rectangle;
   1635 
   1636   register const Quantum
   1637     *p;
   1638 
   1639   register ssize_t
   1640     i,
   1641     x;
   1642 
   1643   size_t
   1644     bytes_per_line,
   1645     count,
   1646     row_bytes,
   1647     storage_class;
   1648 
   1649   ssize_t
   1650     y;
   1651 
   1652   unsigned char
   1653     *buffer,
   1654     *packed_scanline,
   1655     *scanline;
   1656 
   1657   unsigned short
   1658     base_address,
   1659     transfer_mode;
   1660 
   1661   /*
   1662     Open output image file.
   1663   */
   1664   assert(image_info != (const ImageInfo *) NULL);
   1665   assert(image_info->signature == MagickCoreSignature);
   1666   assert(image != (Image *) NULL);
   1667   assert(image->signature == MagickCoreSignature);
   1668   if (image->debug != MagickFalse)
   1669     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1670   if ((image->columns > 65535L) || (image->rows > 65535L))
   1671     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
   1672   assert(exception != (ExceptionInfo *) NULL);
   1673   assert(exception->signature == MagickCoreSignature);
   1674   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   1675   if (status == MagickFalse)
   1676     return(status);
   1677   (void) TransformImageColorspace(image,sRGBColorspace,exception);
   1678   /*
   1679     Initialize image info.
   1680   */
   1681   size_rectangle.top=0;
   1682   size_rectangle.left=0;
   1683   size_rectangle.bottom=(short) image->rows;
   1684   size_rectangle.right=(short) image->columns;
   1685   frame_rectangle=size_rectangle;
   1686   crop_rectangle=size_rectangle;
   1687   source_rectangle=size_rectangle;
   1688   destination_rectangle=size_rectangle;
   1689   base_address=0xff;
   1690   row_bytes=image->columns;
   1691   bounds.top=0;
   1692   bounds.left=0;
   1693   bounds.bottom=(short) image->rows;
   1694   bounds.right=(short) image->columns;
   1695   pixmap.version=0;
   1696   pixmap.pack_type=0;
   1697   pixmap.pack_size=0;
   1698   pixmap.pixel_type=0;
   1699   pixmap.bits_per_pixel=8;
   1700   pixmap.component_count=1;
   1701   pixmap.component_size=8;
   1702   pixmap.plane_bytes=0;
   1703   pixmap.table=0;
   1704   pixmap.reserved=0;
   1705   transfer_mode=0;
   1706   x_resolution=image->resolution.x != 0.0 ? image->resolution.x :
   1707     DefaultResolution;
   1708   y_resolution=image->resolution.y != 0.0 ? image->resolution.y :
   1709     DefaultResolution;
   1710   storage_class=image->storage_class;
   1711   if (image_info->compression == JPEGCompression)
   1712     storage_class=DirectClass;
   1713   if (storage_class == DirectClass)
   1714     {
   1715       pixmap.component_count=image->alpha_trait != UndefinedPixelTrait ? 4 : 3;
   1716       pixmap.pixel_type=16;
   1717       pixmap.bits_per_pixel=32;
   1718       pixmap.pack_type=0x04;
   1719       transfer_mode=0x40;
   1720       row_bytes=4*image->columns;
   1721     }
   1722   /*
   1723     Allocate memory.
   1724   */
   1725   bytes_per_line=image->columns;
   1726   if (storage_class == DirectClass)
   1727     bytes_per_line*=image->alpha_trait != UndefinedPixelTrait ? 4 : 3;
   1728   buffer=(unsigned char *) AcquireQuantumMemory(PictInfoSize,sizeof(*buffer));
   1729   packed_scanline=(unsigned char *) AcquireQuantumMemory((size_t)
   1730    (row_bytes+MaxCount),sizeof(*packed_scanline));
   1731   scanline=(unsigned char *) AcquireQuantumMemory(row_bytes,sizeof(*scanline));
   1732   if ((buffer == (unsigned char *) NULL) ||
   1733       (packed_scanline == (unsigned char *) NULL) ||
   1734       (scanline == (unsigned char *) NULL))
   1735     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   1736   (void) ResetMagickMemory(scanline,0,row_bytes);
   1737   (void) ResetMagickMemory(packed_scanline,0,(size_t) (row_bytes+MaxCount));
   1738   /*
   1739     Write header, header size, size bounding box, version, and reserved.
   1740   */
   1741   (void) ResetMagickMemory(buffer,0,PictInfoSize);
   1742   (void) WriteBlob(image,PictInfoSize,buffer);
   1743   (void) WriteBlobMSBShort(image,0);
   1744   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.top);
   1745   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.left);
   1746   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.bottom);
   1747   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.right);
   1748   (void) WriteBlobMSBShort(image,PictVersion);
   1749   (void) WriteBlobMSBShort(image,0x02ff);  /* version #2 */
   1750   (void) WriteBlobMSBShort(image,PictInfoOp);
   1751   (void) WriteBlobMSBLong(image,0xFFFE0000UL);
   1752   /*
   1753     Write full size of the file, resolution, frame bounding box, and reserved.
   1754   */
   1755   (void) WriteBlobMSBShort(image,(unsigned short) x_resolution);
   1756   (void) WriteBlobMSBShort(image,0x0000);
   1757   (void) WriteBlobMSBShort(image,(unsigned short) y_resolution);
   1758   (void) WriteBlobMSBShort(image,0x0000);
   1759   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.top);
   1760   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.left);
   1761   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.bottom);
   1762   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.right);
   1763   (void) WriteBlobMSBLong(image,0x00000000L);
   1764   profile=GetImageProfile(image,"iptc");
   1765   if (profile != (StringInfo *) NULL)
   1766     {
   1767       (void) WriteBlobMSBShort(image,0xa1);
   1768       (void) WriteBlobMSBShort(image,0x1f2);
   1769       (void) WriteBlobMSBShort(image,(unsigned short)
   1770         (GetStringInfoLength(profile)+4));
   1771       (void) WriteBlobString(image,"8BIM");
   1772       (void) WriteBlob(image,GetStringInfoLength(profile),
   1773         GetStringInfoDatum(profile));
   1774     }
   1775   profile=GetImageProfile(image,"icc");
   1776   if (profile != (StringInfo *) NULL)
   1777     {
   1778       (void) WriteBlobMSBShort(image,0xa1);
   1779       (void) WriteBlobMSBShort(image,0xe0);
   1780       (void) WriteBlobMSBShort(image,(unsigned short)
   1781         (GetStringInfoLength(profile)+4));
   1782       (void) WriteBlobMSBLong(image,0x00000000UL);
   1783       (void) WriteBlob(image,GetStringInfoLength(profile),
   1784         GetStringInfoDatum(profile));
   1785       (void) WriteBlobMSBShort(image,0xa1);
   1786       (void) WriteBlobMSBShort(image,0xe0);
   1787       (void) WriteBlobMSBShort(image,4);
   1788       (void) WriteBlobMSBLong(image,0x00000002UL);
   1789     }
   1790   /*
   1791     Write crop region opcode and crop bounding box.
   1792   */
   1793   (void) WriteBlobMSBShort(image,PictCropRegionOp);
   1794   (void) WriteBlobMSBShort(image,0xa);
   1795   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.top);
   1796   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.left);
   1797   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.bottom);
   1798   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.right);
   1799   if (image_info->compression == JPEGCompression)
   1800     {
   1801       Image
   1802         *jpeg_image;
   1803 
   1804       ImageInfo
   1805         *jpeg_info;
   1806 
   1807       size_t
   1808         length;
   1809 
   1810       unsigned char
   1811         *blob;
   1812 
   1813       jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
   1814       if (jpeg_image == (Image *) NULL)
   1815         {
   1816           (void) CloseBlob(image);
   1817           return(MagickFalse);
   1818         }
   1819       jpeg_info=CloneImageInfo(image_info);
   1820       (void) CopyMagickString(jpeg_info->magick,"JPEG",MagickPathExtent);
   1821       length=0;
   1822       blob=(unsigned char *) ImageToBlob(jpeg_info,jpeg_image,&length,
   1823         exception);
   1824       jpeg_info=DestroyImageInfo(jpeg_info);
   1825       if (blob == (unsigned char *) NULL)
   1826         return(MagickFalse);
   1827       jpeg_image=DestroyImage(jpeg_image);
   1828       (void) WriteBlobMSBShort(image,PictJPEGOp);
   1829       (void) WriteBlobMSBLong(image,(unsigned int) length+154);
   1830       (void) WriteBlobMSBShort(image,0x0000);
   1831       (void) WriteBlobMSBLong(image,0x00010000UL);
   1832       (void) WriteBlobMSBLong(image,0x00000000UL);
   1833       (void) WriteBlobMSBLong(image,0x00000000UL);
   1834       (void) WriteBlobMSBLong(image,0x00000000UL);
   1835       (void) WriteBlobMSBLong(image,0x00010000UL);
   1836       (void) WriteBlobMSBLong(image,0x00000000UL);
   1837       (void) WriteBlobMSBLong(image,0x00000000UL);
   1838       (void) WriteBlobMSBLong(image,0x00000000UL);
   1839       (void) WriteBlobMSBLong(image,0x40000000UL);
   1840       (void) WriteBlobMSBLong(image,0x00000000UL);
   1841       (void) WriteBlobMSBLong(image,0x00000000UL);
   1842       (void) WriteBlobMSBLong(image,0x00000000UL);
   1843       (void) WriteBlobMSBLong(image,0x00400000UL);
   1844       (void) WriteBlobMSBShort(image,0x0000);
   1845       (void) WriteBlobMSBShort(image,(unsigned short) image->rows);
   1846       (void) WriteBlobMSBShort(image,(unsigned short) image->columns);
   1847       (void) WriteBlobMSBShort(image,0x0000);
   1848       (void) WriteBlobMSBShort(image,768);
   1849       (void) WriteBlobMSBShort(image,0x0000);
   1850       (void) WriteBlobMSBLong(image,0x00000000UL);
   1851       (void) WriteBlobMSBLong(image,0x00566A70UL);
   1852       (void) WriteBlobMSBLong(image,0x65670000UL);
   1853       (void) WriteBlobMSBLong(image,0x00000000UL);
   1854       (void) WriteBlobMSBLong(image,0x00000001UL);
   1855       (void) WriteBlobMSBLong(image,0x00016170UL);
   1856       (void) WriteBlobMSBLong(image,0x706C0000UL);
   1857       (void) WriteBlobMSBLong(image,0x00000000UL);
   1858       (void) WriteBlobMSBShort(image,768);
   1859       (void) WriteBlobMSBShort(image,(unsigned short) image->columns);
   1860       (void) WriteBlobMSBShort(image,(unsigned short) image->rows);
   1861       (void) WriteBlobMSBShort(image,(unsigned short) x_resolution);
   1862       (void) WriteBlobMSBShort(image,0x0000);
   1863       (void) WriteBlobMSBShort(image,(unsigned short) y_resolution);
   1864       (void) WriteBlobMSBLong(image,0x00000000UL);
   1865       (void) WriteBlobMSBLong(image,0x87AC0001UL);
   1866       (void) WriteBlobMSBLong(image,0x0B466F74UL);
   1867       (void) WriteBlobMSBLong(image,0x6F202D20UL);
   1868       (void) WriteBlobMSBLong(image,0x4A504547UL);
   1869       (void) WriteBlobMSBLong(image,0x00000000UL);
   1870       (void) WriteBlobMSBLong(image,0x00000000UL);
   1871       (void) WriteBlobMSBLong(image,0x00000000UL);
   1872       (void) WriteBlobMSBLong(image,0x00000000UL);
   1873       (void) WriteBlobMSBLong(image,0x00000000UL);
   1874       (void) WriteBlobMSBLong(image,0x0018FFFFUL);
   1875       (void) WriteBlob(image,length,blob);
   1876       if ((length & 0x01) != 0)
   1877         (void) WriteBlobByte(image,'\0');
   1878       blob=(unsigned char *) RelinquishMagickMemory(blob);
   1879     }
   1880   /*
   1881     Write picture opcode, row bytes, and picture bounding box, and version.
   1882   */
   1883   if (storage_class == PseudoClass)
   1884     (void) WriteBlobMSBShort(image,PictPICTOp);
   1885   else
   1886     {
   1887       (void) WriteBlobMSBShort(image,PictPixmapOp);
   1888       (void) WriteBlobMSBLong(image,(size_t) base_address);
   1889     }
   1890   (void) WriteBlobMSBShort(image,(unsigned short) (row_bytes | 0x8000));
   1891   (void) WriteBlobMSBShort(image,(unsigned short) bounds.top);
   1892   (void) WriteBlobMSBShort(image,(unsigned short) bounds.left);
   1893   (void) WriteBlobMSBShort(image,(unsigned short) bounds.bottom);
   1894   (void) WriteBlobMSBShort(image,(unsigned short) bounds.right);
   1895   /*
   1896     Write pack type, pack size, resolution, pixel type, and pixel size.
   1897   */
   1898   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.version);
   1899   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.pack_type);
   1900   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.pack_size);
   1901   (void) WriteBlobMSBShort(image,(unsigned short) (x_resolution+0.5));
   1902   (void) WriteBlobMSBShort(image,0x0000);
   1903   (void) WriteBlobMSBShort(image,(unsigned short) (y_resolution+0.5));
   1904   (void) WriteBlobMSBShort(image,0x0000);
   1905   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.pixel_type);
   1906   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.bits_per_pixel);
   1907   /*
   1908     Write component count, size, plane bytes, table size, and reserved.
   1909   */
   1910   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.component_count);
   1911   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.component_size);
   1912   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.plane_bytes);
   1913   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.table);
   1914   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.reserved);
   1915   if (storage_class == PseudoClass)
   1916     {
   1917       /*
   1918         Write image colormap.
   1919       */
   1920       (void) WriteBlobMSBLong(image,0x00000000L);  /* color seed */
   1921       (void) WriteBlobMSBShort(image,0L);  /* color flags */
   1922       (void) WriteBlobMSBShort(image,(unsigned short) (image->colors-1));
   1923       for (i=0; i < (ssize_t) image->colors; i++)
   1924       {
   1925         (void) WriteBlobMSBShort(image,(unsigned short) i);
   1926         (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
   1927           image->colormap[i].red));
   1928         (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
   1929           image->colormap[i].green));
   1930         (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
   1931           image->colormap[i].blue));
   1932       }
   1933     }
   1934   /*
   1935     Write source and destination rectangle.
   1936   */
   1937   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.top);
   1938   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.left);
   1939   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.bottom);
   1940   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.right);
   1941   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.top);
   1942   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.left);
   1943   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.bottom);
   1944   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.right);
   1945   (void) WriteBlobMSBShort(image,(unsigned short) transfer_mode);
   1946   /*
   1947     Write picture data.
   1948   */
   1949   count=0;
   1950   if (storage_class == PseudoClass)
   1951     for (y=0; y < (ssize_t) image->rows; y++)
   1952     {
   1953       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
   1954       if (p == (const Quantum *) NULL)
   1955         break;
   1956       for (x=0; x < (ssize_t) image->columns; x++)
   1957       {
   1958         scanline[x]=(unsigned char) GetPixelIndex(image,p);
   1959         p+=GetPixelChannels(image);
   1960       }
   1961       count+=EncodeImage(image,scanline,(size_t) (row_bytes & 0x7FFF),
   1962         packed_scanline);
   1963       if (image->previous == (Image *) NULL)
   1964         {
   1965           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
   1966             image->rows);
   1967           if (status == MagickFalse)
   1968             break;
   1969         }
   1970     }
   1971   else
   1972     if (image_info->compression == JPEGCompression)
   1973       {
   1974         (void) ResetMagickMemory(scanline,0,row_bytes);
   1975         for (y=0; y < (ssize_t) image->rows; y++)
   1976           count+=EncodeImage(image,scanline,(size_t) (row_bytes & 0x7FFF),
   1977             packed_scanline);
   1978       }
   1979     else
   1980       {
   1981         register unsigned char
   1982           *blue,
   1983           *green,
   1984           *opacity,
   1985           *red;
   1986 
   1987         red=scanline;
   1988         green=scanline+image->columns;
   1989         blue=scanline+2*image->columns;
   1990         opacity=scanline+3*image->columns;
   1991         for (y=0; y < (ssize_t) image->rows; y++)
   1992         {
   1993           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
   1994           if (p == (const Quantum *) NULL)
   1995             break;
   1996           red=scanline;
   1997           green=scanline+image->columns;
   1998           blue=scanline+2*image->columns;
   1999           if (image->alpha_trait != UndefinedPixelTrait)
   2000             {
   2001               opacity=scanline;
   2002               red=scanline+image->columns;
   2003               green=scanline+2*image->columns;
   2004               blue=scanline+3*image->columns;
   2005             }
   2006           for (x=0; x < (ssize_t) image->columns; x++)
   2007           {
   2008             *red++=ScaleQuantumToChar(GetPixelRed(image,p));
   2009             *green++=ScaleQuantumToChar(GetPixelGreen(image,p));
   2010             *blue++=ScaleQuantumToChar(GetPixelBlue(image,p));
   2011             if (image->alpha_trait != UndefinedPixelTrait)
   2012               *opacity++=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p)));
   2013             p+=GetPixelChannels(image);
   2014           }
   2015           count+=EncodeImage(image,scanline,bytes_per_line,packed_scanline);
   2016           if (image->previous == (Image *) NULL)
   2017             {
   2018               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
   2019                 image->rows);
   2020               if (status == MagickFalse)
   2021                 break;
   2022             }
   2023         }
   2024       }
   2025   if ((count & 0x01) != 0)
   2026     (void) WriteBlobByte(image,'\0');
   2027   (void) WriteBlobMSBShort(image,PictEndOfPictureOp);
   2028   offset=TellBlob(image);
   2029   offset=SeekBlob(image,512,SEEK_SET);
   2030   (void) WriteBlobMSBShort(image,(unsigned short) offset);
   2031   scanline=(unsigned char *) RelinquishMagickMemory(scanline);
   2032   packed_scanline=(unsigned char *) RelinquishMagickMemory(packed_scanline);
   2033   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
   2034   (void) CloseBlob(image);
   2035   return(MagickTrue);
   2036 }
   2037