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