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