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