]> granicus.if.org Git - imagemagick/blob - coders/pict.c
fix ; same variable i is used in nexted loop (#866)
[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-2017 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) ResetMagickMemory(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   if (bytes_per_line < 8)
463     {
464       /*
465         Pixels are already uncompressed.
466       */
467       for (y=0; y < (ssize_t) image->rows; y++)
468       {
469         q=pixels+y*width*GetPixelChannels(image);;
470         number_pixels=bytes_per_line;
471         count=ReadBlob(blob,(size_t) number_pixels,scanline);
472         if (count != (ssize_t) number_pixels)
473           {
474             (void) ThrowMagickException(exception,GetMagickModule(),
475               CorruptImageError,"UnableToUncompressImage","`%s'",
476               image->filename);
477             break;
478           }
479         p=ExpandBuffer(scanline,&number_pixels,bits_per_pixel);
480         if ((q+number_pixels) > (pixels+(*extent)))
481           {
482             (void) ThrowMagickException(exception,GetMagickModule(),
483               CorruptImageError,"UnableToUncompressImage","`%s'",
484               image->filename);
485             break;
486           }
487         (void) CopyMagickMemory(q,p,(size_t) number_pixels);
488       }
489       scanline=(unsigned char *) RelinquishMagickMemory(scanline);
490       return(pixels);
491     }
492   /*
493     Uncompress RLE pixels into uncompressed pixel buffer.
494   */
495   for (y=0; y < (ssize_t) image->rows; y++)
496   {
497     q=pixels+y*width;
498     if (bytes_per_line > 200)
499       scanline_length=ReadBlobMSBShort(blob);
500     else
501       scanline_length=1UL*ReadBlobByte(blob);
502     if (scanline_length >= row_bytes)
503       {
504         (void) ThrowMagickException(exception,GetMagickModule(),
505           CorruptImageError,"UnableToUncompressImage","`%s'",image->filename);
506         break;
507       }
508     count=ReadBlob(blob,scanline_length,scanline);
509     if (count != (ssize_t) scanline_length)
510       {
511         (void) ThrowMagickException(exception,GetMagickModule(),
512           CorruptImageError,"UnableToUncompressImage","`%s'",image->filename);
513         break;
514       }
515     for (j=0; j < (ssize_t) scanline_length; )
516       if ((scanline[j] & 0x80) == 0)
517         {
518           length=(size_t) ((scanline[j] & 0xff)+1);
519           number_pixels=length*bytes_per_pixel;
520           p=ExpandBuffer(scanline+j+1,&number_pixels,bits_per_pixel);
521           if ((q-pixels+number_pixels) <= *extent)
522             (void) CopyMagickMemory(q,p,(size_t) number_pixels);
523           q+=number_pixels;
524           j+=(ssize_t) (length*bytes_per_pixel+1);
525         }
526       else
527         {
528           length=(size_t) (((scanline[j] ^ 0xff) & 0xff)+2);
529           number_pixels=bytes_per_pixel;
530           p=ExpandBuffer(scanline+j+1,&number_pixels,bits_per_pixel);
531           for (i=0; i < (ssize_t) length; i++)
532           {
533             if ((q-pixels+number_pixels) <= *extent)
534               (void) CopyMagickMemory(q,p,(size_t) number_pixels);
535             q+=number_pixels;
536           }
537           j+=(ssize_t) bytes_per_pixel+1;
538         }
539   }
540   scanline=(unsigned char *) RelinquishMagickMemory(scanline);
541   return(pixels);
542 }
543 \f
544 /*
545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546 %                                                                             %
547 %                                                                             %
548 %                                                                             %
549 %   E n c o d e I m a g e                                                     %
550 %                                                                             %
551 %                                                                             %
552 %                                                                             %
553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554 %
555 %  EncodeImage compresses an image via Macintosh pack bits encoding
556 %  for Macintosh PICT images.
557 %
558 %  The format of the EncodeImage method is:
559 %
560 %      size_t EncodeImage(Image *image,const unsigned char *scanline,
561 %        const size_t bytes_per_line,unsigned char *pixels)
562 %
563 %  A description of each parameter follows:
564 %
565 %    o image: the address of a structure of type Image.
566 %
567 %    o scanline: A pointer to an array of characters to pack.
568 %
569 %    o bytes_per_line: the number of bytes in a scanline.
570 %
571 %    o pixels: A pointer to an array of characters where the packed
572 %      characters are stored.
573 %
574 */
575 static size_t EncodeImage(Image *image,const unsigned char *scanline,
576   const size_t bytes_per_line,unsigned char *pixels)
577 {
578 #define MaxCount  128
579 #define MaxPackbitsRunlength  128
580
581   register const unsigned char
582     *p;
583
584   register ssize_t
585     i;
586
587   register unsigned char
588     *q;
589
590   size_t
591     length;
592
593   ssize_t
594     count,
595     repeat_count,
596     runlength;
597
598   unsigned char
599     index;
600
601   /*
602     Pack scanline.
603   */
604   assert(image != (Image *) NULL);
605   assert(image->signature == MagickCoreSignature);
606   if (image->debug != MagickFalse)
607     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
608   assert(scanline != (unsigned char *) NULL);
609   assert(pixels != (unsigned char *) NULL);
610   count=0;
611   runlength=0;
612   p=scanline+(bytes_per_line-1);
613   q=pixels;
614   index=(*p);
615   for (i=(ssize_t) bytes_per_line-1; i >= 0; i--)
616   {
617     if (index == *p)
618       runlength++;
619     else
620       {
621         if (runlength < 3)
622           while (runlength > 0)
623           {
624             *q++=(unsigned char) index;
625             runlength--;
626             count++;
627             if (count == MaxCount)
628               {
629                 *q++=(unsigned char) (MaxCount-1);
630                 count-=MaxCount;
631               }
632           }
633         else
634           {
635             if (count > 0)
636               *q++=(unsigned char) (count-1);
637             count=0;
638             while (runlength > 0)
639             {
640               repeat_count=runlength;
641               if (repeat_count > MaxPackbitsRunlength)
642                 repeat_count=MaxPackbitsRunlength;
643               *q++=(unsigned char) index;
644               *q++=(unsigned char) (257-repeat_count);
645               runlength-=repeat_count;
646             }
647           }
648         runlength=1;
649       }
650     index=(*p);
651     p--;
652   }
653   if (runlength < 3)
654     while (runlength > 0)
655     {
656       *q++=(unsigned char) index;
657       runlength--;
658       count++;
659       if (count == MaxCount)
660         {
661           *q++=(unsigned char) (MaxCount-1);
662           count-=MaxCount;
663         }
664     }
665   else
666     {
667       if (count > 0)
668         *q++=(unsigned char) (count-1);
669       count=0;
670       while (runlength > 0)
671       {
672         repeat_count=runlength;
673         if (repeat_count > MaxPackbitsRunlength)
674           repeat_count=MaxPackbitsRunlength;
675         *q++=(unsigned char) index;
676         *q++=(unsigned char) (257-repeat_count);
677         runlength-=repeat_count;
678       }
679     }
680   if (count > 0)
681     *q++=(unsigned char) (count-1);
682   /*
683     Write the number of and the packed length.
684   */
685   length=(size_t) (q-pixels);
686   if (bytes_per_line > 200)
687     {
688       (void) WriteBlobMSBShort(image,(unsigned short) length);
689       length+=2;
690     }
691   else
692     {
693       (void) WriteBlobByte(image,(unsigned char) length);
694       length++;
695     }
696   while (q != pixels)
697   {
698     q--;
699     (void) WriteBlobByte(image,*q);
700   }
701   return(length);
702 }
703 \f
704 /*
705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
706 %                                                                             %
707 %                                                                             %
708 %                                                                             %
709 %   I s P I C T                                                               %
710 %                                                                             %
711 %                                                                             %
712 %                                                                             %
713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
714 %
715 %  IsPICT()() returns MagickTrue if the image format type, identified by the
716 %  magick string, is PICT.
717 %
718 %  The format of the ReadPICTImage method is:
719 %
720 %      MagickBooleanType IsPICT(const unsigned char *magick,const size_t length)
721 %
722 %  A description of each parameter follows:
723 %
724 %    o magick: compare image format pattern against these bytes.
725 %
726 %    o length: Specifies the length of the magick string.
727 %
728 */
729 static MagickBooleanType IsPICT(const unsigned char *magick,const size_t length)
730 {
731   if (length < 12)
732     return(MagickFalse);
733   /*
734     Embedded OLE2 macintosh have "PICT" instead of 512 platform header.
735   */
736   if (memcmp(magick,"PICT",4) == 0)
737     return(MagickTrue);
738   if (length < 528)
739     return(MagickFalse);
740   if (memcmp(magick+522,"\000\021\002\377\014\000",6) == 0)
741     return(MagickTrue);
742   return(MagickFalse);
743 }
744 \f
745 #if !defined(macintosh)
746 /*
747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748 %                                                                             %
749 %                                                                             %
750 %                                                                             %
751 %   R e a d P I C T I m a g e                                                 %
752 %                                                                             %
753 %                                                                             %
754 %                                                                             %
755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
756 %
757 %  ReadPICTImage() reads an Apple Macintosh QuickDraw/PICT image file
758 %  and returns it.  It allocates the memory necessary for the new Image
759 %  structure and returns a pointer to the new image.
760 %
761 %  The format of the ReadPICTImage method is:
762 %
763 %      Image *ReadPICTImage(const ImageInfo *image_info,
764 %        ExceptionInfo *exception)
765 %
766 %  A description of each parameter follows:
767 %
768 %    o image_info: the image info.
769 %
770 %    o exception: return any errors or warnings in this structure.
771 %
772 */
773
774 static MagickBooleanType ReadPixmap(Image *image,PICTPixmap *pixmap)
775 {
776   pixmap->version=(short) ReadBlobMSBShort(image);
777   pixmap->pack_type=(short) ReadBlobMSBShort(image);
778   pixmap->pack_size=ReadBlobMSBLong(image);
779   pixmap->horizontal_resolution=1UL*ReadBlobMSBShort(image);
780   (void) ReadBlobMSBShort(image);
781   pixmap->vertical_resolution=1UL*ReadBlobMSBShort(image);
782   (void) ReadBlobMSBShort(image);
783   pixmap->pixel_type=(short) ReadBlobMSBShort(image);
784   pixmap->bits_per_pixel=(short) ReadBlobMSBShort(image);
785   pixmap->component_count=(short) ReadBlobMSBShort(image);
786   pixmap->component_size=(short) ReadBlobMSBShort(image);
787   pixmap->plane_bytes=ReadBlobMSBLong(image);
788   pixmap->table=ReadBlobMSBLong(image);
789   pixmap->reserved=ReadBlobMSBLong(image);
790   if ((EOFBlob(image) != MagickFalse) || (pixmap->bits_per_pixel <= 0) ||
791       (pixmap->bits_per_pixel > 32) || (pixmap->component_count <= 0) ||
792       (pixmap->component_count > 4) || (pixmap->component_size <= 0))
793     return(MagickFalse);
794   return(MagickTrue);
795 }
796
797 static MagickBooleanType ReadRectangle(Image *image,PICTRectangle *rectangle)
798 {
799   rectangle->top=(short) ReadBlobMSBShort(image);
800   rectangle->left=(short) ReadBlobMSBShort(image);
801   rectangle->bottom=(short) ReadBlobMSBShort(image);
802   rectangle->right=(short) ReadBlobMSBShort(image);
803   if ((EOFBlob(image) != MagickFalse) || (rectangle->left > rectangle->right) ||
804       (rectangle->top > rectangle->bottom))
805     return(MagickFalse);
806   return(MagickTrue);
807 }
808
809 static Image *ReadPICTImage(const ImageInfo *image_info,
810   ExceptionInfo *exception)
811 {
812   char
813     geometry[MagickPathExtent],
814     header_ole[4];
815
816   Image
817     *image;
818
819   int
820     c,
821     code;
822
823   MagickBooleanType
824     jpeg,
825     status;
826
827   PICTRectangle
828     frame;
829
830   PICTPixmap
831     pixmap;
832
833   Quantum
834     index;
835
836   register Quantum
837     *q;
838
839   register ssize_t
840     i,
841     x;
842
843   size_t
844     extent,
845     length;
846
847   ssize_t
848     count,
849     flags,
850     j,
851     version,
852     y;
853
854   StringInfo
855     *profile;
856
857   /*
858     Open image file.
859   */
860   assert(image_info != (const ImageInfo *) NULL);
861   assert(image_info->signature == MagickCoreSignature);
862   if (image_info->debug != MagickFalse)
863     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
864       image_info->filename);
865   assert(exception != (ExceptionInfo *) NULL);
866   assert(exception->signature == MagickCoreSignature);
867   image=AcquireImage(image_info,exception);
868   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
869   if (status == MagickFalse)
870     {
871       image=DestroyImageList(image);
872       return((Image *) NULL);
873     }
874   /*
875     Read PICT header.
876   */
877   pixmap.bits_per_pixel=0;
878   pixmap.component_count=0;
879   /*
880     Skip header : 512 for standard PICT and 4, ie "PICT" for OLE2.
881   */
882   header_ole[0]=ReadBlobByte(image);
883   header_ole[1]=ReadBlobByte(image);
884   header_ole[2]=ReadBlobByte(image);
885   header_ole[3]=ReadBlobByte(image);
886   if (!((header_ole[0] == 0x50) && (header_ole[1] == 0x49) &&
887       (header_ole[2] == 0x43) && (header_ole[3] == 0x54 )))
888     for (i=0; i < 508; i++)
889       if (ReadBlobByte(image) == EOF)
890         break;
891   (void) ReadBlobMSBShort(image);  /* skip picture size */
892   if (ReadRectangle(image,&frame) == MagickFalse)
893     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
894   while ((c=ReadBlobByte(image)) == 0) ;
895   if (c != 0x11)
896     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
897   version=ReadBlobByte(image);
898   if (version == 2)
899     {
900       c=ReadBlobByte(image);
901       if (c != 0xff)
902         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
903     }
904   else
905     if (version != 1)
906       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
907   if ((frame.left < 0) || (frame.right < 0) || (frame.top < 0) ||
908       (frame.bottom < 0) || (frame.left >= frame.right) ||
909       (frame.top >= frame.bottom))
910     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
911   /*
912     Create black canvas.
913   */
914   flags=0;
915   image->depth=8;
916   image->columns=1UL*(frame.right-frame.left);
917   image->rows=1UL*(frame.bottom-frame.top);
918   image->resolution.x=DefaultResolution;
919   image->resolution.y=DefaultResolution;
920   image->units=UndefinedResolution;
921   if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
922     if (image->scene >= (image_info->scene+image_info->number_scenes-1))
923       {
924         (void) CloseBlob(image);
925         return(GetFirstImageInList(image));
926       }
927   status=SetImageExtent(image,image->columns,image->rows,exception);
928   if (status == MagickFalse)
929     return(DestroyImageList(image));
930   /*
931     Interpret PICT opcodes.
932   */
933   jpeg=MagickFalse;
934   for (code=0; EOFBlob(image) == MagickFalse; )
935   {
936     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
937       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
938         break;
939     if ((version == 1) || ((TellBlob(image) % 2) != 0))
940       code=ReadBlobByte(image);
941     if (version == 2)
942       code=ReadBlobMSBSignedShort(image);
943     if (code < 0)
944       break;
945     if (code > 0xa1)
946       {
947         if (image->debug != MagickFalse)
948           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%04X:",code);
949       }
950     else
951       {
952         if (image->debug != MagickFalse)
953           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
954             "  %04X %s: %s",code,codes[code].name,codes[code].description);
955         switch (code)
956         {
957           case 0x01:
958           {
959             /*
960               Clipping rectangle.
961             */
962             length=ReadBlobMSBShort(image);
963             if (length != 0x000a)
964               {
965                 for (i=0; i < (ssize_t) (length-2); i++)
966                   if (ReadBlobByte(image) == EOF)
967                     break;
968                 break;
969               }
970             if (ReadRectangle(image,&frame) == MagickFalse)
971               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
972             if (((frame.left & 0x8000) != 0) || ((frame.top & 0x8000) != 0))
973               break;
974             image->columns=1UL*(frame.right-frame.left);
975             image->rows=1UL*(frame.bottom-frame.top);
976             status=SetImageExtent(image,image->columns,image->rows,exception);
977             if (status == MagickFalse)
978               return(DestroyImageList(image));
979             (void) SetImageBackgroundColor(image,exception);
980             break;
981           }
982           case 0x12:
983           case 0x13:
984           case 0x14:
985           {
986             ssize_t
987               pattern;
988
989             size_t
990               height,
991               width;
992
993             /*
994               Skip pattern definition.
995             */
996             pattern=1L*ReadBlobMSBShort(image);
997             for (i=0; i < 8; i++)
998               if (ReadBlobByte(image) == EOF)
999                 break;
1000             if (pattern == 2)
1001               {
1002                 for (i=0; i < 5; i++)
1003                   if (ReadBlobByte(image) == EOF)
1004                     break;
1005                 break;
1006               }
1007             if (pattern != 1)
1008               ThrowReaderException(CorruptImageError,"UnknownPatternType");
1009             length=ReadBlobMSBShort(image);
1010             if (ReadRectangle(image,&frame) == MagickFalse)
1011               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1012             if (ReadPixmap(image,&pixmap) == MagickFalse)
1013               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1014             image->depth=1UL*pixmap.component_size;
1015             image->resolution.x=1.0*pixmap.horizontal_resolution;
1016             image->resolution.y=1.0*pixmap.vertical_resolution;
1017             image->units=PixelsPerInchResolution;
1018             (void) ReadBlobMSBLong(image);
1019             flags=1L*ReadBlobMSBShort(image);
1020             length=ReadBlobMSBShort(image);
1021             for (i=0; i <= (ssize_t) length; i++)
1022               (void) ReadBlobMSBLong(image);
1023             width=1UL*(frame.bottom-frame.top);
1024             height=1UL*(frame.right-frame.left);
1025             if (pixmap.bits_per_pixel <= 8)
1026               length&=0x7fff;
1027             if (pixmap.bits_per_pixel == 16)
1028               width<<=1;
1029             if (length == 0)
1030               length=width;
1031             if (length < 8)
1032               {
1033                 for (i=0; i < (ssize_t) (length*height); i++)
1034                   if (ReadBlobByte(image) == EOF)
1035                     break;
1036               }
1037             else
1038               for (i=0; i < (int) height; i++)
1039                 if (length > 200)
1040                   {
1041                     for (j=0; j < (ssize_t) ReadBlobMSBShort(image); j++)
1042                       if (ReadBlobByte(image) == EOF)
1043                         break;
1044                   }
1045                 else
1046                   for (j=0; j < (ssize_t) ReadBlobByte(image); j++)
1047                     if (ReadBlobByte(image) == EOF)
1048                       break;
1049             break;
1050           }
1051           case 0x1b:
1052           {
1053             /*
1054               Initialize image background color.
1055             */
1056             image->background_color.red=(Quantum)
1057               ScaleShortToQuantum(ReadBlobMSBShort(image));
1058             image->background_color.green=(Quantum)
1059               ScaleShortToQuantum(ReadBlobMSBShort(image));
1060             image->background_color.blue=(Quantum)
1061               ScaleShortToQuantum(ReadBlobMSBShort(image));
1062             break;
1063           }
1064           case 0x70:
1065           case 0x71:
1066           case 0x72:
1067           case 0x73:
1068           case 0x74:
1069           case 0x75:
1070           case 0x76:
1071           case 0x77:
1072           {
1073             /*
1074               Skip polygon or region.
1075             */
1076             length=ReadBlobMSBShort(image);
1077             for (i=0; i < (ssize_t) (length-2); i++)
1078               if (ReadBlobByte(image) == EOF)
1079                 break;
1080             break;
1081           }
1082           case 0x90:
1083           case 0x91:
1084           case 0x98:
1085           case 0x99:
1086           case 0x9a:
1087           case 0x9b:
1088           {
1089             Image
1090               *tile_image;
1091
1092             PICTRectangle
1093               source,
1094               destination;
1095
1096             register unsigned char
1097               *p;
1098
1099             size_t
1100               j;
1101
1102             ssize_t
1103               bytes_per_line;
1104
1105             unsigned char
1106               *pixels;
1107
1108             /*
1109               Pixmap clipped by a rectangle.
1110             */
1111             bytes_per_line=0;
1112             if ((code != 0x9a) && (code != 0x9b))
1113               bytes_per_line=1L*ReadBlobMSBShort(image);
1114             else
1115               {
1116                 (void) ReadBlobMSBShort(image);
1117                 (void) ReadBlobMSBShort(image);
1118                 (void) ReadBlobMSBShort(image);
1119               }
1120             if (ReadRectangle(image,&frame) == MagickFalse)
1121               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1122             /*
1123               Initialize tile image.
1124             */
1125             tile_image=CloneImage(image,1UL*(frame.right-frame.left),
1126               1UL*(frame.bottom-frame.top),MagickTrue,exception);
1127             if (tile_image == (Image *) NULL)
1128               return((Image *) NULL);
1129             if ((code == 0x9a) || (code == 0x9b) ||
1130                 ((bytes_per_line & 0x8000) != 0))
1131               {
1132                 if (ReadPixmap(image,&pixmap) == MagickFalse)
1133                   {
1134                     tile_image=DestroyImage(tile_image);
1135                     ThrowReaderException(CorruptImageError,
1136                       "ImproperImageHeader");
1137                   }
1138                 tile_image->depth=1UL*pixmap.component_size;
1139                 tile_image->alpha_trait=pixmap.component_count == 4 ?
1140                   BlendPixelTrait : UndefinedPixelTrait;
1141                 tile_image->resolution.x=(double) pixmap.horizontal_resolution;
1142                 tile_image->resolution.y=(double) pixmap.vertical_resolution;
1143                 tile_image->units=PixelsPerInchResolution;
1144                 if (tile_image->alpha_trait != UndefinedPixelTrait)
1145                   image->alpha_trait=tile_image->alpha_trait;
1146               }
1147             if ((code != 0x9a) && (code != 0x9b))
1148               {
1149                 /*
1150                   Initialize colormap.
1151                 */
1152                 tile_image->colors=2;
1153                 if ((bytes_per_line & 0x8000) != 0)
1154                   {
1155                     (void) ReadBlobMSBLong(image);
1156                     flags=1L*ReadBlobMSBShort(image);
1157                     tile_image->colors=1UL*ReadBlobMSBShort(image)+1;
1158                   }
1159                 status=AcquireImageColormap(tile_image,tile_image->colors,
1160                   exception);
1161                 if (status == MagickFalse)
1162                   {
1163                     tile_image=DestroyImage(tile_image);
1164                     ThrowReaderException(ResourceLimitError,
1165                       "MemoryAllocationFailed");
1166                   }
1167                 if ((bytes_per_line & 0x8000) != 0)
1168                   {
1169                     for (i=0; i < (ssize_t) tile_image->colors; i++)
1170                     {
1171                       j=ReadBlobMSBShort(image) % tile_image->colors;
1172                       if ((flags & 0x8000) != 0)
1173                         j=(size_t) i;
1174                       tile_image->colormap[j].red=(Quantum)
1175                         ScaleShortToQuantum(ReadBlobMSBShort(image));
1176                       tile_image->colormap[j].green=(Quantum)
1177                         ScaleShortToQuantum(ReadBlobMSBShort(image));
1178                       tile_image->colormap[j].blue=(Quantum)
1179                         ScaleShortToQuantum(ReadBlobMSBShort(image));
1180                     }
1181                   }
1182                 else
1183                   {
1184                     for (i=0; i < (ssize_t) tile_image->colors; i++)
1185                     {
1186                       tile_image->colormap[i].red=(Quantum) (QuantumRange-
1187                         tile_image->colormap[i].red);
1188                       tile_image->colormap[i].green=(Quantum) (QuantumRange-
1189                         tile_image->colormap[i].green);
1190                       tile_image->colormap[i].blue=(Quantum) (QuantumRange-
1191                         tile_image->colormap[i].blue);
1192                     }
1193                   }
1194               }
1195             if (ReadRectangle(image,&source) == MagickFalse)
1196               {
1197                 tile_image=DestroyImage(tile_image);
1198                 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1199               }
1200             if (ReadRectangle(image,&destination) == MagickFalse)
1201               {
1202                 tile_image=DestroyImage(tile_image);
1203                 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1204               }
1205             (void) ReadBlobMSBShort(image);
1206             if ((code == 0x91) || (code == 0x99) || (code == 0x9b))
1207               {
1208                 /*
1209                   Skip region.
1210                 */
1211                 length=ReadBlobMSBShort(image);
1212                 for (i=0; i < (ssize_t) (length-2); i++)
1213                   if (ReadBlobByte(image) == EOF)
1214                     break;
1215               }
1216             if ((code != 0x9a) && (code != 0x9b) &&
1217                 (bytes_per_line & 0x8000) == 0)
1218               pixels=DecodeImage(image,tile_image,1UL*bytes_per_line,1,&extent,
1219                 exception);
1220             else
1221               pixels=DecodeImage(image,tile_image,1UL*bytes_per_line,1U*
1222                 pixmap.bits_per_pixel,&extent,exception);
1223             if (pixels == (unsigned char *) NULL)
1224               {
1225                 tile_image=DestroyImage(tile_image);
1226                 ThrowReaderException(ResourceLimitError,
1227                   "MemoryAllocationFailed");
1228               }
1229             /*
1230               Convert PICT tile image to pixel packets.
1231             */
1232             p=pixels;
1233             for (y=0; y < (ssize_t) tile_image->rows; y++)
1234             {
1235               if (p > (pixels+extent+image->columns))
1236                 {
1237                   tile_image=DestroyImage(tile_image);
1238                   ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
1239                 }
1240               q=QueueAuthenticPixels(tile_image,0,y,tile_image->columns,1,
1241                 exception);
1242               if (q == (Quantum *) NULL)
1243                 break;
1244               for (x=0; x < (ssize_t) tile_image->columns; x++)
1245               {
1246                 if (tile_image->storage_class == PseudoClass)
1247                   {
1248                     index=ConstrainColormapIndex(tile_image,*p,exception);
1249                     SetPixelIndex(tile_image,index,q);
1250                     SetPixelRed(tile_image,
1251                       tile_image->colormap[(ssize_t) index].red,q);
1252                     SetPixelGreen(tile_image,
1253                       tile_image->colormap[(ssize_t) index].green,q);
1254                     SetPixelBlue(tile_image,
1255                       tile_image->colormap[(ssize_t) index].blue,q);
1256                   }
1257                 else
1258                   {
1259                     if (pixmap.bits_per_pixel == 16)
1260                       {
1261                         i=(*p++);
1262                         j=(*p);
1263                         SetPixelRed(tile_image,ScaleCharToQuantum(
1264                           (unsigned char) ((i & 0x7c) << 1)),q);
1265                         SetPixelGreen(tile_image,ScaleCharToQuantum(
1266                           (unsigned char) (((i & 0x03) << 6) |
1267                           ((j & 0xe0) >> 2))),q);
1268                         SetPixelBlue(tile_image,ScaleCharToQuantum(
1269                           (unsigned char) ((j & 0x1f) << 3)),q);
1270                       }
1271                     else
1272                       if (tile_image->alpha_trait == UndefinedPixelTrait)
1273                         {
1274                           if (p > (pixels+extent+2*image->columns))
1275                             {
1276                               tile_image=DestroyImage(tile_image);
1277                               ThrowReaderException(CorruptImageError,
1278                                 "NotEnoughPixelData");
1279                             }
1280                           SetPixelRed(tile_image,ScaleCharToQuantum(*p),q);
1281                           SetPixelGreen(tile_image,ScaleCharToQuantum(
1282                             *(p+tile_image->columns)),q);
1283                           SetPixelBlue(tile_image,ScaleCharToQuantum(
1284                             *(p+2*tile_image->columns)),q);
1285                         }
1286                       else
1287                         {
1288                           if (p > (pixels+extent+3*image->columns))
1289                             {
1290                               tile_image=DestroyImage(tile_image);
1291                               ThrowReaderException(CorruptImageError,
1292                                 "NotEnoughPixelData");
1293                             }
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,y,tile_image->rows);
1316               if (status == MagickFalse)
1317                 break;
1318             }
1319             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1320             if (jpeg == MagickFalse)
1321               if ((code == 0x9a) || (code == 0x9b) ||
1322                   ((bytes_per_line & 0x8000) != 0))
1323                 (void) CompositeImage(image,tile_image,CopyCompositeOp,
1324                   MagickTrue,destination.left,destination.top,exception);
1325             tile_image=DestroyImage(tile_image);
1326             break;
1327           }
1328           case 0xa1:
1329           {
1330             unsigned char
1331               *info;
1332
1333             size_t
1334               type;
1335
1336             /*
1337               Comment.
1338             */
1339             type=ReadBlobMSBShort(image);
1340             length=ReadBlobMSBShort(image);
1341             if (length == 0)
1342               break;
1343             (void) ReadBlobMSBLong(image);
1344             length-=MagickMin(length,4);
1345             if (length == 0)
1346               break;
1347             info=(unsigned char *) AcquireQuantumMemory(length,sizeof(*info));
1348             if (info == (unsigned char *) NULL)
1349               break;
1350             count=ReadBlob(image,length,info);
1351             if (count != (ssize_t) length)
1352               {
1353                 info=(unsigned char *) RelinquishMagickMemory(info);
1354                 ThrowReaderException(ResourceLimitError,
1355                   "UnableToReadImageData");
1356               }
1357             switch (type)
1358             {
1359               case 0xe0:
1360               {
1361                 profile=BlobToStringInfo((const void *) NULL,length);
1362                 SetStringInfoDatum(profile,info);
1363                 status=SetImageProfile(image,"icc",profile,exception);
1364                 profile=DestroyStringInfo(profile);
1365                 if (status == MagickFalse)
1366                   {
1367                     info=(unsigned char *) RelinquishMagickMemory(info);
1368                     ThrowReaderException(ResourceLimitError,
1369                       "MemoryAllocationFailed");
1370                   }
1371                 break;
1372               }
1373               case 0x1f2:
1374               {
1375                 profile=BlobToStringInfo((const void *) NULL,length);
1376                 SetStringInfoDatum(profile,info);
1377                 status=SetImageProfile(image,"iptc",profile,exception);
1378                 if (status == MagickFalse)
1379                   {
1380                     info=(unsigned char *) RelinquishMagickMemory(info);
1381                     ThrowReaderException(ResourceLimitError,
1382                       "MemoryAllocationFailed");
1383                   }
1384                 profile=DestroyStringInfo(profile);
1385                 break;
1386               }
1387               default:
1388                 break;
1389             }
1390             info=(unsigned char *) RelinquishMagickMemory(info);
1391             break;
1392           }
1393           default:
1394           {
1395             /*
1396               Skip to next op code.
1397             */
1398             if (codes[code].length == -1)
1399               (void) ReadBlobMSBShort(image);
1400             else
1401               for (i=0; i < (ssize_t) codes[code].length; i++)
1402                 if (ReadBlobByte(image) == EOF)
1403                   break;
1404           }
1405         }
1406       }
1407     if (code == 0xc00)
1408       {
1409         /*
1410           Skip header.
1411         */
1412         for (i=0; i < 24; i++)
1413           if (ReadBlobByte(image) == EOF)
1414             break;
1415         continue;
1416       }
1417     if (((code >= 0xb0) && (code <= 0xcf)) ||
1418         ((code >= 0x8000) && (code <= 0x80ff)))
1419       continue;
1420     if (code == 0x8200)
1421       {
1422         FILE
1423           *file;
1424
1425         Image
1426           *tile_image;
1427
1428         ImageInfo
1429           *read_info;
1430
1431         int
1432           unique_file;
1433
1434         /*
1435           Embedded JPEG.
1436         */
1437         jpeg=MagickTrue;
1438         read_info=CloneImageInfo(image_info);
1439         SetImageInfoBlob(read_info,(void *) NULL,0);
1440         file=(FILE *) NULL;
1441         unique_file=AcquireUniqueFileResource(read_info->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                 ThrowReaderException(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(read_info->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           frame.left,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) ResetMagickMemory(scanline,0,row_bytes);
1772   (void) ResetMagickMemory(packed_scanline,0,(size_t) (row_bytes+MaxCount));
1773   /*
1774     Write header, header size, size bounding box, version, and reserved.
1775   */
1776   (void) ResetMagickMemory(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,0xFFFE0000UL);
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,0x00000000UL);
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,0x00000002UL);
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,0x00010000UL);
1867       (void) WriteBlobMSBLong(image,0x00000000UL);
1868       (void) WriteBlobMSBLong(image,0x00000000UL);
1869       (void) WriteBlobMSBLong(image,0x00000000UL);
1870       (void) WriteBlobMSBLong(image,0x00010000UL);
1871       (void) WriteBlobMSBLong(image,0x00000000UL);
1872       (void) WriteBlobMSBLong(image,0x00000000UL);
1873       (void) WriteBlobMSBLong(image,0x00000000UL);
1874       (void) WriteBlobMSBLong(image,0x40000000UL);
1875       (void) WriteBlobMSBLong(image,0x00000000UL);
1876       (void) WriteBlobMSBLong(image,0x00000000UL);
1877       (void) WriteBlobMSBLong(image,0x00000000UL);
1878       (void) WriteBlobMSBLong(image,0x00400000UL);
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,0x00000000UL);
1886       (void) WriteBlobMSBLong(image,0x00566A70UL);
1887       (void) WriteBlobMSBLong(image,0x65670000UL);
1888       (void) WriteBlobMSBLong(image,0x00000000UL);
1889       (void) WriteBlobMSBLong(image,0x00000001UL);
1890       (void) WriteBlobMSBLong(image,0x00016170UL);
1891       (void) WriteBlobMSBLong(image,0x706C0000UL);
1892       (void) WriteBlobMSBLong(image,0x00000000UL);
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,0x00000000UL);
1900       (void) WriteBlobMSBLong(image,0x87AC0001UL);
1901       (void) WriteBlobMSBLong(image,0x0B466F74UL);
1902       (void) WriteBlobMSBLong(image,0x6F202D20UL);
1903       (void) WriteBlobMSBLong(image,0x4A504547UL);
1904       (void) WriteBlobMSBLong(image,0x00000000UL);
1905       (void) WriteBlobMSBLong(image,0x00000000UL);
1906       (void) WriteBlobMSBLong(image,0x00000000UL);
1907       (void) WriteBlobMSBLong(image,0x00000000UL);
1908       (void) WriteBlobMSBLong(image,0x00000000UL);
1909       (void) WriteBlobMSBLong(image,0x0018FFFFUL);
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,(size_t) 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) ResetMagickMemory(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 }