]> granicus.if.org Git - imagemagick/blob - coders/pict.c
(no commit message)
[imagemagick] / coders / pict.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                        PPPP   IIIII   CCCC  TTTTT                           %
7 %                        P   P    I    C        T                             %
8 %                        PPPP     I    C        T                             %
9 %                        P        I    C        T                             %
10 %                        P      IIIII   CCCC    T                             %
11 %                                                                             %
12 %                                                                             %
13 %               Read/Write Apple Macintosh QuickDraw/PICT Format              %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/color-private.h"
47 #include "MagickCore/colormap.h"
48 #include "MagickCore/colormap-private.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/colorspace-private.h"
51 #include "MagickCore/composite.h"
52 #include "MagickCore/constitute.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/image.h"
56 #include "MagickCore/image-private.h"
57 #include "MagickCore/list.h"
58 #include "MagickCore/log.h"
59 #include "MagickCore/magick.h"
60 #include "MagickCore/memory_.h"
61 #include "MagickCore/monitor.h"
62 #include "MagickCore/monitor-private.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/profile.h"
65 #include "MagickCore/resource_.h"
66 #include "MagickCore/quantum-private.h"
67 #include "MagickCore/static.h"
68 #include "MagickCore/string_.h"
69 #include "MagickCore/module.h"
70 #include "MagickCore/transform.h"
71 #include "MagickCore/utility.h"
72 \f
73 /*
74   ImageMagick Macintosh PICT Methods.
75 */
76 #define ReadPixmap(pixmap) \
77 { \
78   pixmap.version=(short) ReadBlobMSBShort(image); \
79   pixmap.pack_type=(short) ReadBlobMSBShort(image); \
80   pixmap.pack_size=ReadBlobMSBLong(image); \
81   pixmap.horizontal_resolution=1UL*ReadBlobMSBShort(image); \
82   (void) ReadBlobMSBShort(image); \
83   pixmap.vertical_resolution=1UL*ReadBlobMSBShort(image); \
84   (void) ReadBlobMSBShort(image); \
85   pixmap.pixel_type=(short) ReadBlobMSBShort(image); \
86   pixmap.bits_per_pixel=(short) ReadBlobMSBShort(image); \
87   pixmap.component_count=(short) ReadBlobMSBShort(image); \
88   pixmap.component_size=(short) ReadBlobMSBShort(image); \
89   pixmap.plane_bytes=ReadBlobMSBLong(image); \
90   pixmap.table=ReadBlobMSBLong(image); \
91   pixmap.reserved=ReadBlobMSBLong(image); \
92   if ((pixmap.bits_per_pixel <= 0) || (pixmap.bits_per_pixel > 32) || \
93       (pixmap.component_count <= 0) || (pixmap.component_count > 4) || \
94       (pixmap.component_size <= 0)) \
95     ThrowReaderException(CorruptImageError,"ImproperImageHeader"); \
96 }
97
98 #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         (void) TransformImageColorspace(image,tile_image->colorspace,exception);
1406         (void) CompositeImage(image,tile_image,CopyCompositeOp,MagickTrue,
1407           frame.left,frame.right,exception);
1408         image->compression=tile_image->compression;
1409         tile_image=DestroyImage(tile_image);
1410         continue;
1411       }
1412     if ((code == 0xff) || (code == 0xffff))
1413       break;
1414     if (((code >= 0xd0) && (code <= 0xfe)) ||
1415         ((code >= 0x8100) && (code <= 0xffff)))
1416       {
1417         /*
1418           Skip reserved.
1419         */
1420         length=ReadBlobMSBShort(image);
1421         for (i=0; i < (ssize_t) length; i++)
1422           (void) ReadBlobByte(image);
1423         continue;
1424       }
1425     if ((code >= 0x100) && (code <= 0x7fff))
1426       {
1427         /*
1428           Skip reserved.
1429         */
1430         length=(size_t) ((code >> 7) & 0xff);
1431         for (i=0; i < (ssize_t) length; i++)
1432           (void) ReadBlobByte(image);
1433         continue;
1434       }
1435   }
1436   (void) CloseBlob(image);
1437   return(GetFirstImageInList(image));
1438 }
1439 #endif
1440 \f
1441 /*
1442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1443 %                                                                             %
1444 %                                                                             %
1445 %                                                                             %
1446 %   R e g i s t e r P I C T I m a g e                                         %
1447 %                                                                             %
1448 %                                                                             %
1449 %                                                                             %
1450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1451 %
1452 %  RegisterPICTImage() adds attributes for the PICT image format to
1453 %  the list of supported formats.  The attributes include the image format
1454 %  tag, a method to read and/or write the format, whether the format
1455 %  supports the saving of more than one frame to the same file or blob,
1456 %  whether the format supports native in-memory I/O, and a brief
1457 %  description of the format.
1458 %
1459 %  The format of the RegisterPICTImage method is:
1460 %
1461 %      size_t RegisterPICTImage(void)
1462 %
1463 */
1464 ModuleExport size_t RegisterPICTImage(void)
1465 {
1466   MagickInfo
1467     *entry;
1468
1469   entry=SetMagickInfo("PCT");
1470   entry->decoder=(DecodeImageHandler *) ReadPICTImage;
1471   entry->encoder=(EncodeImageHandler *) WritePICTImage;
1472   entry->adjoin=MagickFalse;
1473   entry->seekable_stream=MagickTrue;
1474   entry->description=ConstantString("Apple Macintosh QuickDraw/PICT");
1475   entry->magick=(IsImageFormatHandler *) IsPICT;
1476   entry->module=ConstantString("PICT");
1477   (void) RegisterMagickInfo(entry);
1478   entry=SetMagickInfo("PICT");
1479   entry->decoder=(DecodeImageHandler *) ReadPICTImage;
1480   entry->encoder=(EncodeImageHandler *) WritePICTImage;
1481   entry->adjoin=MagickFalse;
1482   entry->seekable_stream=MagickTrue;
1483   entry->description=ConstantString("Apple Macintosh QuickDraw/PICT");
1484   entry->magick=(IsImageFormatHandler *) IsPICT;
1485   entry->module=ConstantString("PICT");
1486   (void) RegisterMagickInfo(entry);
1487   return(MagickImageCoderSignature);
1488 }
1489 \f
1490 /*
1491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1492 %                                                                             %
1493 %                                                                             %
1494 %                                                                             %
1495 %   U n r e g i s t e r P I C T I m a g e                                     %
1496 %                                                                             %
1497 %                                                                             %
1498 %                                                                             %
1499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1500 %
1501 %  UnregisterPICTImage() removes format registrations made by the
1502 %  PICT module from the list of supported formats.
1503 %
1504 %  The format of the UnregisterPICTImage method is:
1505 %
1506 %      UnregisterPICTImage(void)
1507 %
1508 */
1509 ModuleExport void UnregisterPICTImage(void)
1510 {
1511   (void) UnregisterMagickInfo("PCT");
1512   (void) UnregisterMagickInfo("PICT");
1513 }
1514 \f
1515 /*
1516 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1517 %                                                                             %
1518 %                                                                             %
1519 %                                                                             %
1520 %   W r i t e P I C T I m a g e                                               %
1521 %                                                                             %
1522 %                                                                             %
1523 %                                                                             %
1524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1525 %
1526 %  WritePICTImage() writes an image to a file in the Apple Macintosh
1527 %  QuickDraw/PICT image format.
1528 %
1529 %  The format of the WritePICTImage method is:
1530 %
1531 %      MagickBooleanType WritePICTImage(const ImageInfo *image_info,
1532 %        Image *image,ExceptionInfo *exception)
1533 %
1534 %  A description of each parameter follows.
1535 %
1536 %    o image_info: the image info.
1537 %
1538 %    o image:  The image.
1539 %
1540 %    o exception: return any errors or warnings in this structure.
1541 %
1542 */
1543 static MagickBooleanType WritePICTImage(const ImageInfo *image_info,
1544   Image *image,ExceptionInfo *exception)
1545 {
1546 #define MaxCount  128
1547 #define PictCropRegionOp  0x01
1548 #define PictEndOfPictureOp  0xff
1549 #define PictJPEGOp  0x8200
1550 #define PictInfoOp  0x0C00
1551 #define PictInfoSize  512
1552 #define PictPixmapOp  0x9A
1553 #define PictPICTOp  0x98
1554 #define PictVersion  0x11
1555
1556   const StringInfo
1557     *profile;
1558
1559   double
1560     x_resolution,
1561     y_resolution;
1562
1563   MagickBooleanType
1564     status;
1565
1566   MagickOffsetType
1567     offset;
1568
1569   PICTPixmap
1570     pixmap;
1571
1572   PICTRectangle
1573     bounds,
1574     crop_rectangle,
1575     destination_rectangle,
1576     frame_rectangle,
1577     size_rectangle,
1578     source_rectangle;
1579
1580   register const Quantum
1581     *p;
1582
1583   register ssize_t
1584     i,
1585     x;
1586
1587   size_t
1588     bytes_per_line,
1589     count,
1590     storage_class;
1591
1592   ssize_t
1593     y;
1594
1595   unsigned char
1596     *buffer,
1597     *packed_scanline,
1598     *scanline;
1599
1600   unsigned short
1601     base_address,
1602     row_bytes,
1603     transfer_mode;
1604
1605   /*
1606     Open output image file.
1607   */
1608   assert(image_info != (const ImageInfo *) NULL);
1609   assert(image_info->signature == MagickSignature);
1610   assert(image != (Image *) NULL);
1611   assert(image->signature == MagickSignature);
1612   if (image->debug != MagickFalse)
1613     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1614   if ((image->columns > 65535L) || (image->rows > 65535L))
1615     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1616   assert(exception != (ExceptionInfo *) NULL);
1617   assert(exception->signature == MagickSignature);
1618   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1619   if (status == MagickFalse)
1620     return(status);
1621   (void) TransformImageColorspace(image,sRGBColorspace,exception);
1622   /*
1623     Initialize image info.
1624   */
1625   size_rectangle.top=0;
1626   size_rectangle.left=0;
1627   size_rectangle.bottom=(short) image->rows;
1628   size_rectangle.right=(short) image->columns;
1629   frame_rectangle=size_rectangle;
1630   crop_rectangle=size_rectangle;
1631   source_rectangle=size_rectangle;
1632   destination_rectangle=size_rectangle;
1633   base_address=0xff;
1634   row_bytes=(unsigned short) (image->columns | 0x8000);
1635   bounds.top=0;
1636   bounds.left=0;
1637   bounds.bottom=(short) image->rows;
1638   bounds.right=(short) image->columns;
1639   pixmap.version=0;
1640   pixmap.pack_type=0;
1641   pixmap.pack_size=0;
1642   pixmap.pixel_type=0;
1643   pixmap.bits_per_pixel=8;
1644   pixmap.component_count=1;
1645   pixmap.component_size=8;
1646   pixmap.plane_bytes=0;
1647   pixmap.table=0;
1648   pixmap.reserved=0;
1649   transfer_mode=0;
1650   x_resolution=image->resolution.x != 0.0 ? image->resolution.x :
1651     DefaultResolution;
1652   y_resolution=image->resolution.y != 0.0 ? image->resolution.y :
1653     DefaultResolution;
1654   storage_class=image->storage_class;
1655   if (image_info->compression == JPEGCompression)
1656     storage_class=DirectClass;
1657   if ((storage_class == DirectClass) || (image->alpha_trait == BlendPixelTrait))
1658     {
1659       pixmap.component_count=image->alpha_trait ? 4 : 3;
1660       pixmap.pixel_type=16;
1661       pixmap.bits_per_pixel=32;
1662       pixmap.pack_type=0x04;
1663       transfer_mode=0x40;
1664       row_bytes=(unsigned short) ((4*image->columns) | 0x8000);
1665     }
1666   /*
1667     Allocate memory.
1668   */
1669   bytes_per_line=image->columns;
1670   if ((storage_class == DirectClass) || (image->alpha_trait == BlendPixelTrait))
1671     bytes_per_line*=image->alpha_trait ? 4 : 3;
1672   buffer=(unsigned char *) AcquireQuantumMemory(PictInfoSize,sizeof(*buffer));
1673   packed_scanline=(unsigned char *) AcquireQuantumMemory((size_t)
1674    (row_bytes+MaxCount),sizeof(*packed_scanline));
1675   scanline=(unsigned char *) AcquireQuantumMemory(row_bytes,sizeof(*scanline));
1676   if ((buffer == (unsigned char *) NULL) ||
1677       (packed_scanline == (unsigned char *) NULL) ||
1678       (scanline == (unsigned char *) NULL))
1679     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1680   (void) ResetMagickMemory(scanline,0,row_bytes);
1681   (void) ResetMagickMemory(packed_scanline,0,(size_t) (row_bytes+MaxCount));
1682   /*
1683     Write header, header size, size bounding box, version, and reserved.
1684   */
1685   (void) ResetMagickMemory(buffer,0,PictInfoSize);
1686   (void) WriteBlob(image,PictInfoSize,buffer);
1687   (void) WriteBlobMSBShort(image,0);
1688   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.top);
1689   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.left);
1690   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.bottom);
1691   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.right);
1692   (void) WriteBlobMSBShort(image,PictVersion);
1693   (void) WriteBlobMSBShort(image,0x02ff);  /* version #2 */
1694   (void) WriteBlobMSBShort(image,PictInfoOp);
1695   (void) WriteBlobMSBLong(image,0xFFFE0000UL);
1696   /*
1697     Write full size of the file, resolution, frame bounding box, and reserved.
1698   */
1699   (void) WriteBlobMSBShort(image,(unsigned short) x_resolution);
1700   (void) WriteBlobMSBShort(image,0x0000);
1701   (void) WriteBlobMSBShort(image,(unsigned short) y_resolution);
1702   (void) WriteBlobMSBShort(image,0x0000);
1703   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.top);
1704   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.left);
1705   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.bottom);
1706   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.right);
1707   (void) WriteBlobMSBLong(image,0x00000000L);
1708   profile=GetImageProfile(image,"iptc");
1709   if (profile != (StringInfo *) NULL)
1710     {
1711       (void) WriteBlobMSBShort(image,0xa1);
1712       (void) WriteBlobMSBShort(image,0x1f2);
1713       (void) WriteBlobMSBShort(image,(unsigned short)
1714         (GetStringInfoLength(profile)+4));
1715       (void) WriteBlobString(image,"8BIM");
1716       (void) WriteBlob(image,GetStringInfoLength(profile),
1717         GetStringInfoDatum(profile));
1718     }
1719   profile=GetImageProfile(image,"icc");
1720   if (profile != (StringInfo *) NULL)
1721     {
1722       (void) WriteBlobMSBShort(image,0xa1);
1723       (void) WriteBlobMSBShort(image,0xe0);
1724       (void) WriteBlobMSBShort(image,(unsigned short)
1725         (GetStringInfoLength(profile)+4));
1726       (void) WriteBlobMSBLong(image,0x00000000UL);
1727       (void) WriteBlob(image,GetStringInfoLength(profile),
1728         GetStringInfoDatum(profile));
1729       (void) WriteBlobMSBShort(image,0xa1);
1730       (void) WriteBlobMSBShort(image,0xe0);
1731       (void) WriteBlobMSBShort(image,4);
1732       (void) WriteBlobMSBLong(image,0x00000002UL);
1733     }
1734   /*
1735     Write crop region opcode and crop bounding box.
1736   */
1737   (void) WriteBlobMSBShort(image,PictCropRegionOp);
1738   (void) WriteBlobMSBShort(image,0xa);
1739   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.top);
1740   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.left);
1741   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.bottom);
1742   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.right);
1743   if (image_info->compression == JPEGCompression)
1744     {
1745       Image
1746         *jpeg_image;
1747
1748       ImageInfo
1749         *jpeg_info;
1750
1751       size_t
1752         length;
1753
1754       unsigned char
1755         *blob;
1756
1757       jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
1758       if (jpeg_image == (Image *) NULL)
1759         {
1760           (void) CloseBlob(image);
1761           return(MagickFalse);
1762         }
1763       jpeg_info=CloneImageInfo(image_info);
1764       (void) CopyMagickString(jpeg_info->magick,"JPEG",MaxTextExtent);
1765       length=0;
1766       blob=(unsigned char *) ImageToBlob(jpeg_info,jpeg_image,&length,
1767         exception);
1768       jpeg_info=DestroyImageInfo(jpeg_info);
1769       if (blob == (unsigned char *) NULL)
1770         return(MagickFalse);
1771       jpeg_image=DestroyImage(jpeg_image);
1772       (void) WriteBlobMSBShort(image,PictJPEGOp);
1773       (void) WriteBlobMSBLong(image,(unsigned int) length+154);
1774       (void) WriteBlobMSBShort(image,0x0000);
1775       (void) WriteBlobMSBLong(image,0x00010000UL);
1776       (void) WriteBlobMSBLong(image,0x00000000UL);
1777       (void) WriteBlobMSBLong(image,0x00000000UL);
1778       (void) WriteBlobMSBLong(image,0x00000000UL);
1779       (void) WriteBlobMSBLong(image,0x00010000UL);
1780       (void) WriteBlobMSBLong(image,0x00000000UL);
1781       (void) WriteBlobMSBLong(image,0x00000000UL);
1782       (void) WriteBlobMSBLong(image,0x00000000UL);
1783       (void) WriteBlobMSBLong(image,0x40000000UL);
1784       (void) WriteBlobMSBLong(image,0x00000000UL);
1785       (void) WriteBlobMSBLong(image,0x00000000UL);
1786       (void) WriteBlobMSBLong(image,0x00000000UL);
1787       (void) WriteBlobMSBLong(image,0x00400000UL);
1788       (void) WriteBlobMSBShort(image,0x0000);
1789       (void) WriteBlobMSBShort(image,(unsigned short) image->rows);
1790       (void) WriteBlobMSBShort(image,(unsigned short) image->columns);
1791       (void) WriteBlobMSBShort(image,0x0000);
1792       (void) WriteBlobMSBShort(image,768);
1793       (void) WriteBlobMSBShort(image,0x0000);
1794       (void) WriteBlobMSBLong(image,0x00000000UL);
1795       (void) WriteBlobMSBLong(image,0x00566A70UL);
1796       (void) WriteBlobMSBLong(image,0x65670000UL);
1797       (void) WriteBlobMSBLong(image,0x00000000UL);
1798       (void) WriteBlobMSBLong(image,0x00000001UL);
1799       (void) WriteBlobMSBLong(image,0x00016170UL);
1800       (void) WriteBlobMSBLong(image,0x706C0000UL);
1801       (void) WriteBlobMSBLong(image,0x00000000UL);
1802       (void) WriteBlobMSBShort(image,768);
1803       (void) WriteBlobMSBShort(image,(unsigned short) image->columns);
1804       (void) WriteBlobMSBShort(image,(unsigned short) image->rows);
1805       (void) WriteBlobMSBShort(image,(unsigned short) x_resolution);
1806       (void) WriteBlobMSBShort(image,0x0000);
1807       (void) WriteBlobMSBShort(image,(unsigned short) y_resolution);
1808       (void) WriteBlobMSBLong(image,0x00000000UL);
1809       (void) WriteBlobMSBLong(image,0x87AC0001UL);
1810       (void) WriteBlobMSBLong(image,0x0B466F74UL);
1811       (void) WriteBlobMSBLong(image,0x6F202D20UL);
1812       (void) WriteBlobMSBLong(image,0x4A504547UL);
1813       (void) WriteBlobMSBLong(image,0x00000000UL);
1814       (void) WriteBlobMSBLong(image,0x00000000UL);
1815       (void) WriteBlobMSBLong(image,0x00000000UL);
1816       (void) WriteBlobMSBLong(image,0x00000000UL);
1817       (void) WriteBlobMSBLong(image,0x00000000UL);
1818       (void) WriteBlobMSBLong(image,0x0018FFFFUL);
1819       (void) WriteBlob(image,length,blob);
1820       if ((length & 0x01) != 0)
1821         (void) WriteBlobByte(image,'\0');
1822       blob=(unsigned char *) RelinquishMagickMemory(blob);
1823     }
1824   /*
1825     Write picture opcode, row bytes, and picture bounding box, and version.
1826   */
1827   if (storage_class == PseudoClass)
1828     (void) WriteBlobMSBShort(image,PictPICTOp);
1829   else
1830     {
1831       (void) WriteBlobMSBShort(image,PictPixmapOp);
1832       (void) WriteBlobMSBLong(image,(size_t) base_address);
1833     }
1834   (void) WriteBlobMSBShort(image,(unsigned short) (row_bytes | 0x8000));
1835   (void) WriteBlobMSBShort(image,(unsigned short) bounds.top);
1836   (void) WriteBlobMSBShort(image,(unsigned short) bounds.left);
1837   (void) WriteBlobMSBShort(image,(unsigned short) bounds.bottom);
1838   (void) WriteBlobMSBShort(image,(unsigned short) bounds.right);
1839   /*
1840     Write pack type, pack size, resolution, pixel type, and pixel size.
1841   */
1842   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.version);
1843   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.pack_type);
1844   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.pack_size);
1845   (void) WriteBlobMSBShort(image,(unsigned short) (x_resolution+0.5));
1846   (void) WriteBlobMSBShort(image,0x0000);
1847   (void) WriteBlobMSBShort(image,(unsigned short) (y_resolution+0.5));
1848   (void) WriteBlobMSBShort(image,0x0000);
1849   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.pixel_type);
1850   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.bits_per_pixel);
1851   /*
1852     Write component count, size, plane bytes, table size, and reserved.
1853   */
1854   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.component_count);
1855   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.component_size);
1856   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.plane_bytes);
1857   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.table);
1858   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.reserved);
1859   if (storage_class == PseudoClass)
1860     {
1861       /*
1862         Write image colormap.
1863       */
1864       (void) WriteBlobMSBLong(image,0x00000000L);  /* color seed */
1865       (void) WriteBlobMSBShort(image,0L);  /* color flags */
1866       (void) WriteBlobMSBShort(image,(unsigned short) (image->colors-1));
1867       for (i=0; i < (ssize_t) image->colors; i++)
1868       {
1869         (void) WriteBlobMSBShort(image,(unsigned short) i);
1870         (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
1871           image->colormap[i].red));
1872         (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
1873           image->colormap[i].green));
1874         (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
1875           image->colormap[i].blue));
1876       }
1877     }
1878   /*
1879     Write source and destination rectangle.
1880   */
1881   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.top);
1882   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.left);
1883   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.bottom);
1884   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.right);
1885   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.top);
1886   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.left);
1887   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.bottom);
1888   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.right);
1889   (void) WriteBlobMSBShort(image,(unsigned short) transfer_mode);
1890   /*
1891     Write picture data.
1892   */
1893   count=0;
1894   if ((storage_class == PseudoClass) && (image->alpha_trait != BlendPixelTrait))
1895     for (y=0; y < (ssize_t) image->rows; y++)
1896     {
1897       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1898       if (p == (const Quantum *) NULL)
1899         break;
1900       for (x=0; x < (ssize_t) image->columns; x++)
1901       {
1902         scanline[x]=(unsigned char) GetPixelIndex(image,p);
1903         p+=GetPixelChannels(image);
1904       }
1905       count+=EncodeImage(image,scanline,(size_t) (row_bytes & 0x7FFF),
1906         packed_scanline);
1907       if (image->previous == (Image *) NULL)
1908         {
1909           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1910             image->rows);
1911           if (status == MagickFalse)
1912             break;
1913         }
1914     }
1915   else
1916     if (image_info->compression == JPEGCompression)
1917       {
1918         (void) ResetMagickMemory(scanline,0,row_bytes);
1919         for (y=0; y < (ssize_t) image->rows; y++)
1920           count+=EncodeImage(image,scanline,(size_t) (row_bytes & 0x7FFF),
1921             packed_scanline);
1922       }
1923     else
1924       {
1925         register unsigned char
1926           *blue,
1927           *green,
1928           *opacity,
1929           *red;
1930
1931         red=scanline;
1932         green=scanline+image->columns;
1933         blue=scanline+2*image->columns;
1934         opacity=scanline+3*image->columns;
1935         for (y=0; y < (ssize_t) image->rows; y++)
1936         {
1937           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1938           if (p == (const Quantum *) NULL)
1939             break;
1940           red=scanline;
1941           green=scanline+image->columns;
1942           blue=scanline+2*image->columns;
1943           if (image->alpha_trait == BlendPixelTrait)
1944             {
1945               opacity=scanline;
1946               red=scanline+image->columns;
1947               green=scanline+2*image->columns;
1948               blue=scanline+3*image->columns;
1949             }
1950           for (x=0; x < (ssize_t) image->columns; x++)
1951           {
1952             *red++=ScaleQuantumToChar(GetPixelRed(image,p));
1953             *green++=ScaleQuantumToChar(GetPixelGreen(image,p));
1954             *blue++=ScaleQuantumToChar(GetPixelBlue(image,p));
1955             if (image->alpha_trait == BlendPixelTrait)
1956               *opacity++=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p)));
1957             p+=GetPixelChannels(image);
1958           }
1959           count+=EncodeImage(image,scanline,bytes_per_line & 0x7FFF,
1960             packed_scanline);
1961           if (image->previous == (Image *) NULL)
1962             {
1963               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1964                 image->rows);
1965               if (status == MagickFalse)
1966                 break;
1967             }
1968         }
1969       }
1970   if ((count & 0x01) != 0)
1971     (void) WriteBlobByte(image,'\0');
1972   (void) WriteBlobMSBShort(image,PictEndOfPictureOp);
1973   offset=TellBlob(image);
1974   offset=SeekBlob(image,512,SEEK_SET);
1975   (void) WriteBlobMSBShort(image,(unsigned short) offset);
1976   scanline=(unsigned char *) RelinquishMagickMemory(scanline);
1977   packed_scanline=(unsigned char *) RelinquishMagickMemory(packed_scanline);
1978   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1979   (void) CloseBlob(image);
1980   return(MagickTrue);
1981 }