• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-2019 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://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 
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 
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 
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 
ExpandBuffer(const unsigned char * magick_restrict pixels,const unsigned int bits_per_pixel,MagickSizeType * bytes_per_line)328 static const unsigned char *ExpandBuffer(const unsigned char *magick_restrict pixels,
329   const unsigned int bits_per_pixel,MagickSizeType *bytes_per_line)
330 {
331   register const unsigned char
332     *p;
333 
334   register ssize_t
335     i;
336 
337   register unsigned char
338     *q;
339 
340   static unsigned char
341     scanline[8*256];
342 
343   p=pixels;
344   q=scanline;
345   switch (bits_per_pixel)
346   {
347     case 8:
348     case 16:
349     case 32:
350       return(pixels);
351     case 4:
352     {
353       for (i=0; i < (ssize_t) *bytes_per_line; i++)
354       {
355         *q++=(*p >> 4) & 0xff;
356         *q++=(*p & 15);
357         p++;
358       }
359       *bytes_per_line*=2;
360       break;
361     }
362     case 2:
363     {
364       for (i=0; i < (ssize_t) *bytes_per_line; i++)
365       {
366         *q++=(*p >> 6) & 0x03;
367         *q++=(*p >> 4) & 0x03;
368         *q++=(*p >> 2) & 0x03;
369         *q++=(*p & 3);
370         p++;
371       }
372       *bytes_per_line*=4;
373       break;
374     }
375     case 1:
376     {
377       for (i=0; i < (ssize_t) *bytes_per_line; i++)
378       {
379         *q++=(*p >> 7) & 0x01;
380         *q++=(*p >> 6) & 0x01;
381         *q++=(*p >> 5) & 0x01;
382         *q++=(*p >> 4) & 0x01;
383         *q++=(*p >> 3) & 0x01;
384         *q++=(*p >> 2) & 0x01;
385         *q++=(*p >> 1) & 0x01;
386         *q++=(*p & 0x01);
387         p++;
388       }
389       *bytes_per_line*=8;
390       break;
391     }
392     default:
393       break;
394   }
395   return(scanline);
396 }
397 
DecodeImage(Image * blob,Image * image,size_t bytes_per_line,const unsigned int bits_per_pixel,size_t * extent)398 static unsigned char *DecodeImage(Image *blob,Image *image,
399   size_t bytes_per_line,const unsigned int bits_per_pixel,size_t *extent)
400 {
401   MagickBooleanType
402     status;
403 
404   MagickSizeType
405     number_pixels;
406 
407   register const unsigned char
408     *p;
409 
410   register ssize_t
411     i;
412 
413   register unsigned char
414     *q;
415 
416   size_t
417     bytes_per_pixel,
418     length,
419     row_bytes,
420     scanline_length,
421     width;
422 
423   ssize_t
424     count,
425     j,
426     y;
427 
428   unsigned char
429     *pixels,
430     *scanline;
431 
432   /*
433     Determine pixel buffer size.
434   */
435   if (bits_per_pixel <= 8)
436     bytes_per_line&=0x7fff;
437   width=image->columns;
438   bytes_per_pixel=1;
439   if (bits_per_pixel == 16)
440     {
441       bytes_per_pixel=2;
442       width*=2;
443     }
444   else
445     if (bits_per_pixel == 32)
446       width*=image->alpha_trait ? 4 : 3;
447   if (bytes_per_line == 0)
448     bytes_per_line=width;
449   row_bytes=(size_t) (image->columns | 0x8000);
450   if (image->storage_class == DirectClass)
451     row_bytes=(size_t) ((4*image->columns) | 0x8000);
452   /*
453     Allocate pixel and scanline buffer.
454   */
455   pixels=(unsigned char *) AcquireQuantumMemory(image->rows,row_bytes*
456     sizeof(*pixels));
457   if (pixels == (unsigned char *) NULL)
458     return((unsigned char *) NULL);
459   *extent=row_bytes*image->rows*sizeof(*pixels);
460   (void) memset(pixels,0,*extent);
461   scanline=(unsigned char *) AcquireQuantumMemory(row_bytes,2*
462     sizeof(*scanline));
463   if (scanline == (unsigned char *) NULL)
464     {
465       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
466       return((unsigned char *) NULL);
467     }
468   (void) memset(scanline,0,2*row_bytes*sizeof(*scanline));
469   status=MagickTrue;
470   if (bytes_per_line < 8)
471     {
472       /*
473         Pixels are already uncompressed.
474       */
475       for (y=0; y < (ssize_t) image->rows; y++)
476       {
477         q=pixels+y*width*GetPixelChannels(image);
478         number_pixels=bytes_per_line;
479         count=ReadBlob(blob,(size_t) number_pixels,scanline);
480         if (count != (ssize_t) number_pixels)
481           {
482             status=MagickFalse;
483             break;
484           }
485         p=ExpandBuffer(scanline,bits_per_pixel,&number_pixels);
486         if ((q+number_pixels) > (pixels+(*extent)))
487           {
488             status=MagickFalse;
489             break;
490           }
491         (void) memcpy(q,p,(size_t) number_pixels);
492       }
493       scanline=(unsigned char *) RelinquishMagickMemory(scanline);
494       if (status == MagickFalse)
495         pixels=(unsigned char *) RelinquishMagickMemory(pixels);
496       return(pixels);
497     }
498   /*
499     Uncompress RLE pixels into uncompressed pixel buffer.
500   */
501   for (y=0; y < (ssize_t) image->rows; y++)
502   {
503     q=pixels+y*width;
504     if (bytes_per_line > 200)
505       scanline_length=ReadBlobMSBShort(blob);
506     else
507       scanline_length=(size_t) ReadBlobByte(blob);
508     if ((scanline_length >= row_bytes) || (scanline_length == 0))
509       {
510         status=MagickFalse;
511         break;
512       }
513     count=ReadBlob(blob,scanline_length,scanline);
514     if (count != (ssize_t) scanline_length)
515       {
516         status=MagickFalse;
517         break;
518       }
519     for (j=0; j < (ssize_t) scanline_length; )
520       if ((scanline[j] & 0x80) == 0)
521         {
522           length=(size_t) ((scanline[j] & 0xff)+1);
523           number_pixels=length*bytes_per_pixel;
524           p=ExpandBuffer(scanline+j+1,bits_per_pixel,&number_pixels);
525           if ((q-pixels+number_pixels) <= *extent)
526             (void) memcpy(q,p,(size_t) number_pixels);
527           q+=number_pixels;
528           j+=(ssize_t) (length*bytes_per_pixel+1);
529         }
530       else
531         {
532           length=(size_t) (((scanline[j] ^ 0xff) & 0xff)+2);
533           number_pixels=bytes_per_pixel;
534           p=ExpandBuffer(scanline+j+1,bits_per_pixel,&number_pixels);
535           for (i=0; i < (ssize_t) length; i++)
536           {
537             if ((q-pixels+number_pixels) <= *extent)
538               (void) memcpy(q,p,(size_t) number_pixels);
539             q+=number_pixels;
540           }
541           j+=(ssize_t) bytes_per_pixel+1;
542         }
543   }
544   scanline=(unsigned char *) RelinquishMagickMemory(scanline);
545   if (status == MagickFalse)
546     pixels=(unsigned char *) RelinquishMagickMemory(pixels);
547   return(pixels);
548 }
549 
550 /*
551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
552 %                                                                             %
553 %                                                                             %
554 %                                                                             %
555 %   E n c o d e I m a g e                                                     %
556 %                                                                             %
557 %                                                                             %
558 %                                                                             %
559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560 %
561 %  EncodeImage compresses an image via Macintosh pack bits encoding
562 %  for Macintosh PICT images.
563 %
564 %  The format of the EncodeImage method is:
565 %
566 %      size_t EncodeImage(Image *image,const unsigned char *scanline,
567 %        const size_t bytes_per_line,unsigned char *pixels)
568 %
569 %  A description of each parameter follows:
570 %
571 %    o image: the address of a structure of type Image.
572 %
573 %    o scanline: A pointer to an array of characters to pack.
574 %
575 %    o bytes_per_line: the number of bytes in a scanline.
576 %
577 %    o pixels: A pointer to an array of characters where the packed
578 %      characters are stored.
579 %
580 */
EncodeImage(Image * image,const unsigned char * scanline,const size_t bytes_per_line,unsigned char * pixels)581 static size_t EncodeImage(Image *image,const unsigned char *scanline,
582   const size_t bytes_per_line,unsigned char *pixels)
583 {
584 #define MaxCount  128
585 #define MaxPackbitsRunlength  128
586 
587   register const unsigned char
588     *p;
589 
590   register ssize_t
591     i;
592 
593   register unsigned char
594     *q;
595 
596   size_t
597     length;
598 
599   ssize_t
600     count,
601     repeat_count,
602     runlength;
603 
604   unsigned char
605     index;
606 
607   /*
608     Pack scanline.
609   */
610   assert(image != (Image *) NULL);
611   assert(image->signature == MagickCoreSignature);
612   if (image->debug != MagickFalse)
613     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
614   assert(scanline != (unsigned char *) NULL);
615   assert(pixels != (unsigned char *) NULL);
616   count=0;
617   runlength=0;
618   p=scanline+(bytes_per_line-1);
619   q=pixels;
620   index=(*p);
621   for (i=(ssize_t) bytes_per_line-1; i >= 0; i--)
622   {
623     if (index == *p)
624       runlength++;
625     else
626       {
627         if (runlength < 3)
628           while (runlength > 0)
629           {
630             *q++=(unsigned char) index;
631             runlength--;
632             count++;
633             if (count == MaxCount)
634               {
635                 *q++=(unsigned char) (MaxCount-1);
636                 count-=MaxCount;
637               }
638           }
639         else
640           {
641             if (count > 0)
642               *q++=(unsigned char) (count-1);
643             count=0;
644             while (runlength > 0)
645             {
646               repeat_count=runlength;
647               if (repeat_count > MaxPackbitsRunlength)
648                 repeat_count=MaxPackbitsRunlength;
649               *q++=(unsigned char) index;
650               *q++=(unsigned char) (257-repeat_count);
651               runlength-=repeat_count;
652             }
653           }
654         runlength=1;
655       }
656     index=(*p);
657     p--;
658   }
659   if (runlength < 3)
660     while (runlength > 0)
661     {
662       *q++=(unsigned char) index;
663       runlength--;
664       count++;
665       if (count == MaxCount)
666         {
667           *q++=(unsigned char) (MaxCount-1);
668           count-=MaxCount;
669         }
670     }
671   else
672     {
673       if (count > 0)
674         *q++=(unsigned char) (count-1);
675       count=0;
676       while (runlength > 0)
677       {
678         repeat_count=runlength;
679         if (repeat_count > MaxPackbitsRunlength)
680           repeat_count=MaxPackbitsRunlength;
681         *q++=(unsigned char) index;
682         *q++=(unsigned char) (257-repeat_count);
683         runlength-=repeat_count;
684       }
685     }
686   if (count > 0)
687     *q++=(unsigned char) (count-1);
688   /*
689     Write the number of and the packed length.
690   */
691   length=(size_t) (q-pixels);
692   if (bytes_per_line > 200)
693     {
694       (void) WriteBlobMSBShort(image,(unsigned short) length);
695       length+=2;
696     }
697   else
698     {
699       (void) WriteBlobByte(image,(unsigned char) length);
700       length++;
701     }
702   while (q != pixels)
703   {
704     q--;
705     (void) WriteBlobByte(image,*q);
706   }
707   return(length);
708 }
709 
710 /*
711 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
712 %                                                                             %
713 %                                                                             %
714 %                                                                             %
715 %   I s P I C T                                                               %
716 %                                                                             %
717 %                                                                             %
718 %                                                                             %
719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720 %
721 %  IsPICT()() returns MagickTrue if the image format type, identified by the
722 %  magick string, is PICT.
723 %
724 %  The format of the ReadPICTImage method is:
725 %
726 %      MagickBooleanType IsPICT(const unsigned char *magick,const size_t length)
727 %
728 %  A description of each parameter follows:
729 %
730 %    o magick: compare image format pattern against these bytes.
731 %
732 %    o length: Specifies the length of the magick string.
733 %
734 */
IsPICT(const unsigned char * magick,const size_t length)735 static MagickBooleanType IsPICT(const unsigned char *magick,const size_t length)
736 {
737   if (length < 12)
738     return(MagickFalse);
739   /*
740     Embedded OLE2 macintosh have "PICT" instead of 512 platform header.
741   */
742   if (memcmp(magick,"PICT",4) == 0)
743     return(MagickTrue);
744   if (length < 528)
745     return(MagickFalse);
746   if (memcmp(magick+522,"\000\021\002\377\014\000",6) == 0)
747     return(MagickTrue);
748   return(MagickFalse);
749 }
750 
751 #if !defined(macintosh)
752 /*
753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
754 %                                                                             %
755 %                                                                             %
756 %                                                                             %
757 %   R e a d P I C T I m a g e                                                 %
758 %                                                                             %
759 %                                                                             %
760 %                                                                             %
761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
762 %
763 %  ReadPICTImage() reads an Apple Macintosh QuickDraw/PICT image file
764 %  and returns it.  It allocates the memory necessary for the new Image
765 %  structure and returns a pointer to the new image.
766 %
767 %  The format of the ReadPICTImage method is:
768 %
769 %      Image *ReadPICTImage(const ImageInfo *image_info,
770 %        ExceptionInfo *exception)
771 %
772 %  A description of each parameter follows:
773 %
774 %    o image_info: the image info.
775 %
776 %    o exception: return any errors or warnings in this structure.
777 %
778 */
779 
ReadPixmap(Image * image,PICTPixmap * pixmap)780 static MagickBooleanType ReadPixmap(Image *image,PICTPixmap *pixmap)
781 {
782   pixmap->version=(short) ReadBlobMSBShort(image);
783   pixmap->pack_type=(short) ReadBlobMSBShort(image);
784   pixmap->pack_size=ReadBlobMSBLong(image);
785   pixmap->horizontal_resolution=1UL*ReadBlobMSBShort(image);
786   (void) ReadBlobMSBShort(image);
787   pixmap->vertical_resolution=1UL*ReadBlobMSBShort(image);
788   (void) ReadBlobMSBShort(image);
789   pixmap->pixel_type=(short) ReadBlobMSBShort(image);
790   pixmap->bits_per_pixel=(short) ReadBlobMSBShort(image);
791   pixmap->component_count=(short) ReadBlobMSBShort(image);
792   pixmap->component_size=(short) ReadBlobMSBShort(image);
793   pixmap->plane_bytes=ReadBlobMSBLong(image);
794   pixmap->table=ReadBlobMSBLong(image);
795   pixmap->reserved=ReadBlobMSBLong(image);
796   if ((EOFBlob(image) != MagickFalse) || (pixmap->bits_per_pixel <= 0) ||
797       (pixmap->bits_per_pixel > 32) || (pixmap->component_count <= 0) ||
798       (pixmap->component_count > 4) || (pixmap->component_size <= 0))
799     return(MagickFalse);
800   return(MagickTrue);
801 }
802 
ReadRectangle(Image * image,PICTRectangle * rectangle)803 static MagickBooleanType ReadRectangle(Image *image,PICTRectangle *rectangle)
804 {
805   rectangle->top=(short) ReadBlobMSBShort(image);
806   rectangle->left=(short) ReadBlobMSBShort(image);
807   rectangle->bottom=(short) ReadBlobMSBShort(image);
808   rectangle->right=(short) ReadBlobMSBShort(image);
809   if ((EOFBlob(image) != MagickFalse) ||
810       ((rectangle->bottom-rectangle->top) <= 0) ||
811       ((rectangle->right-rectangle->left) <= 0))
812     return(MagickFalse);
813   return(MagickTrue);
814 }
815 
ReadPICTImage(const ImageInfo * image_info,ExceptionInfo * exception)816 static Image *ReadPICTImage(const ImageInfo *image_info,
817   ExceptionInfo *exception)
818 {
819 #define ThrowPICTException(exception,message) \
820 { \
821   if (tile_image != (Image *) NULL) \
822     tile_image=DestroyImage(tile_image); \
823   if (read_info != (ImageInfo *) NULL) \
824     read_info=DestroyImageInfo(read_info); \
825   ThrowReaderException((exception),(message)); \
826 }
827 
828   char
829     geometry[MagickPathExtent],
830     header_ole[4];
831 
832   Image
833     *image,
834     *tile_image;
835 
836   ImageInfo
837     *read_info;
838 
839   int
840     c,
841     code;
842 
843   MagickBooleanType
844     jpeg,
845     status;
846 
847   PICTRectangle
848     frame;
849 
850   PICTPixmap
851     pixmap;
852 
853   Quantum
854     index;
855 
856   register Quantum
857     *q;
858 
859   register ssize_t
860     i,
861     x;
862 
863   size_t
864     extent,
865     length;
866 
867   ssize_t
868     count,
869     flags,
870     j,
871     version,
872     y;
873 
874   StringInfo
875     *profile;
876 
877   /*
878     Open image file.
879   */
880   assert(image_info != (const ImageInfo *) NULL);
881   assert(image_info->signature == MagickCoreSignature);
882   if (image_info->debug != MagickFalse)
883     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
884       image_info->filename);
885   assert(exception != (ExceptionInfo *) NULL);
886   assert(exception->signature == MagickCoreSignature);
887   image=AcquireImage(image_info,exception);
888   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
889   if (status == MagickFalse)
890     {
891       image=DestroyImageList(image);
892       return((Image *) NULL);
893     }
894   /*
895     Read PICT header.
896   */
897   read_info=(ImageInfo *) NULL;
898   tile_image=(Image *) NULL;
899   pixmap.bits_per_pixel=0;
900   pixmap.component_count=0;
901   /*
902     Skip header : 512 for standard PICT and 4, ie "PICT" for OLE2.
903   */
904   header_ole[0]=ReadBlobByte(image);
905   header_ole[1]=ReadBlobByte(image);
906   header_ole[2]=ReadBlobByte(image);
907   header_ole[3]=ReadBlobByte(image);
908   if (!((header_ole[0] == 0x50) && (header_ole[1] == 0x49) &&
909       (header_ole[2] == 0x43) && (header_ole[3] == 0x54 )))
910     for (i=0; i < 508; i++)
911       if (ReadBlobByte(image) == EOF)
912         break;
913   (void) ReadBlobMSBShort(image);  /* skip picture size */
914   if (ReadRectangle(image,&frame) == MagickFalse)
915     ThrowPICTException(CorruptImageError,"ImproperImageHeader");
916   while ((c=ReadBlobByte(image)) == 0) ;
917   if (c != 0x11)
918     ThrowPICTException(CorruptImageError,"ImproperImageHeader");
919   version=(ssize_t) ReadBlobByte(image);
920   if (version == 2)
921     {
922       c=ReadBlobByte(image);
923       if (c != 0xff)
924         ThrowPICTException(CorruptImageError,"ImproperImageHeader");
925     }
926   else
927     if (version != 1)
928       ThrowPICTException(CorruptImageError,"ImproperImageHeader");
929   if ((frame.left < 0) || (frame.right < 0) || (frame.top < 0) ||
930       (frame.bottom < 0) || (frame.left >= frame.right) ||
931       (frame.top >= frame.bottom))
932     ThrowPICTException(CorruptImageError,"ImproperImageHeader");
933   /*
934     Create black canvas.
935   */
936   flags=0;
937   image->depth=8;
938   image->columns=(size_t) (frame.right-frame.left);
939   image->rows=(size_t) (frame.bottom-frame.top);
940   image->resolution.x=DefaultResolution;
941   image->resolution.y=DefaultResolution;
942   image->units=UndefinedResolution;
943   if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
944     if (image->scene >= (image_info->scene+image_info->number_scenes-1))
945       {
946         (void) CloseBlob(image);
947         return(GetFirstImageInList(image));
948       }
949   status=SetImageExtent(image,image->columns,image->rows,exception);
950   if (status != MagickFalse)
951     status=ResetImagePixels(image,exception);
952   if (status == MagickFalse)
953     return(DestroyImageList(image));
954   /*
955     Interpret PICT opcodes.
956   */
957   jpeg=MagickFalse;
958   for (code=0; EOFBlob(image) == MagickFalse; )
959   {
960     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
961       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
962         break;
963     if ((version == 1) || ((TellBlob(image) % 2) != 0))
964       code=ReadBlobByte(image);
965     if (version == 2)
966       code=ReadBlobMSBSignedShort(image);
967     if (code < 0)
968       break;
969     if (code == 0)
970       continue;
971     if (code > 0xa1)
972       {
973         if (image->debug != MagickFalse)
974           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%04X:",code);
975       }
976     else
977       {
978         if (image->debug != MagickFalse)
979           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
980             "  %04X %s: %s",code,codes[code].name,codes[code].description);
981         switch (code)
982         {
983           case 0x01:
984           {
985             /*
986               Clipping rectangle.
987             */
988             length=ReadBlobMSBShort(image);
989             if ((MagickSizeType) length > GetBlobSize(image))
990               ThrowPICTException(CorruptImageError,
991                 "InsufficientImageDataInFile");
992             if (length != 0x000a)
993               {
994                 for (i=0; i < (ssize_t) (length-2); i++)
995                   if (ReadBlobByte(image) == EOF)
996                     break;
997                 break;
998               }
999             if (ReadRectangle(image,&frame) == MagickFalse)
1000               ThrowPICTException(CorruptImageError,"ImproperImageHeader");
1001             if (((frame.left & 0x8000) != 0) || ((frame.top & 0x8000) != 0))
1002               break;
1003             image->columns=(size_t) (frame.right-frame.left);
1004             image->rows=(size_t) (frame.bottom-frame.top);
1005             status=SetImageExtent(image,image->columns,image->rows,exception);
1006             if (status != MagickFalse)
1007               status=ResetImagePixels(image,exception);
1008             if (status == MagickFalse)
1009               return(DestroyImageList(image));
1010             break;
1011           }
1012           case 0x12:
1013           case 0x13:
1014           case 0x14:
1015           {
1016             ssize_t
1017               pattern;
1018 
1019             size_t
1020               height,
1021               width;
1022 
1023             /*
1024               Skip pattern definition.
1025             */
1026             pattern=(ssize_t) ReadBlobMSBShort(image);
1027             for (i=0; i < 8; i++)
1028               if (ReadBlobByte(image) == EOF)
1029                 break;
1030             if (pattern == 2)
1031               {
1032                 for (i=0; i < 5; i++)
1033                   if (ReadBlobByte(image) == EOF)
1034                     break;
1035                 break;
1036               }
1037             if (pattern != 1)
1038               ThrowPICTException(CorruptImageError,"UnknownPatternType");
1039             length=ReadBlobMSBShort(image);
1040             if ((MagickSizeType) length > GetBlobSize(image))
1041               ThrowPICTException(CorruptImageError,
1042                 "InsufficientImageDataInFile");
1043             if (ReadRectangle(image,&frame) == MagickFalse)
1044               ThrowPICTException(CorruptImageError,"ImproperImageHeader");
1045             if (ReadPixmap(image,&pixmap) == MagickFalse)
1046               ThrowPICTException(CorruptImageError,"ImproperImageHeader");
1047             image->depth=(size_t) pixmap.component_size;
1048             image->resolution.x=1.0*pixmap.horizontal_resolution;
1049             image->resolution.y=1.0*pixmap.vertical_resolution;
1050             image->units=PixelsPerInchResolution;
1051             (void) ReadBlobMSBLong(image);
1052             flags=(ssize_t) ReadBlobMSBShort(image);
1053             length=ReadBlobMSBShort(image);
1054             if ((MagickSizeType) length > GetBlobSize(image))
1055               ThrowPICTException(CorruptImageError,
1056                 "InsufficientImageDataInFile");
1057             for (i=0; i <= (ssize_t) length; i++)
1058               (void) ReadBlobMSBLong(image);
1059             width=(size_t) (frame.bottom-frame.top);
1060             height=(size_t) (frame.right-frame.left);
1061             if (pixmap.bits_per_pixel <= 8)
1062               length&=0x7fff;
1063             if (pixmap.bits_per_pixel == 16)
1064               width<<=1;
1065             if (length == 0)
1066               length=width;
1067             if (length < 8)
1068               {
1069                 for (i=0; i < (ssize_t) (length*height); i++)
1070                   if (ReadBlobByte(image) == EOF)
1071                     break;
1072               }
1073             else
1074               for (i=0; i < (ssize_t) height; i++)
1075               {
1076                 if (EOFBlob(image) != MagickFalse)
1077                   break;
1078                 if (length > 200)
1079                   {
1080                     for (j=0; j < (ssize_t) ReadBlobMSBShort(image); j++)
1081                       if (ReadBlobByte(image) == EOF)
1082                         break;
1083                   }
1084                 else
1085                   for (j=0; j < (ssize_t) ReadBlobByte(image); j++)
1086                     if (ReadBlobByte(image) == EOF)
1087                       break;
1088               }
1089             break;
1090           }
1091           case 0x1b:
1092           {
1093             /*
1094               Initialize image background color.
1095             */
1096             image->background_color.red=(Quantum)
1097               ScaleShortToQuantum(ReadBlobMSBShort(image));
1098             image->background_color.green=(Quantum)
1099               ScaleShortToQuantum(ReadBlobMSBShort(image));
1100             image->background_color.blue=(Quantum)
1101               ScaleShortToQuantum(ReadBlobMSBShort(image));
1102             break;
1103           }
1104           case 0x70:
1105           case 0x71:
1106           case 0x72:
1107           case 0x73:
1108           case 0x74:
1109           case 0x75:
1110           case 0x76:
1111           case 0x77:
1112           {
1113             /*
1114               Skip polygon or region.
1115             */
1116             length=ReadBlobMSBShort(image);
1117             if ((MagickSizeType) length > GetBlobSize(image))
1118               ThrowPICTException(CorruptImageError,
1119                 "InsufficientImageDataInFile");
1120             for (i=0; i < (ssize_t) (length-2); i++)
1121               if (ReadBlobByte(image) == EOF)
1122                 break;
1123             break;
1124           }
1125           case 0x90:
1126           case 0x91:
1127           case 0x98:
1128           case 0x99:
1129           case 0x9a:
1130           case 0x9b:
1131           {
1132             PICTRectangle
1133               source,
1134               destination;
1135 
1136             register unsigned char
1137               *p;
1138 
1139             size_t
1140               j;
1141 
1142             ssize_t
1143               bytes_per_line;
1144 
1145             unsigned char
1146               *pixels;
1147 
1148             /*
1149               Pixmap clipped by a rectangle.
1150             */
1151             bytes_per_line=0;
1152             if ((code != 0x9a) && (code != 0x9b))
1153               bytes_per_line=(ssize_t) ReadBlobMSBShort(image);
1154             else
1155               {
1156                 (void) ReadBlobMSBShort(image);
1157                 (void) ReadBlobMSBShort(image);
1158                 (void) ReadBlobMSBShort(image);
1159               }
1160             if (ReadRectangle(image,&frame) == MagickFalse)
1161               ThrowPICTException(CorruptImageError,"ImproperImageHeader");
1162             /*
1163               Initialize tile image.
1164             */
1165             tile_image=CloneImage(image,(size_t) (frame.right-frame.left),
1166               (size_t) (frame.bottom-frame.top),MagickTrue,exception);
1167             if (tile_image == (Image *) NULL)
1168               ThrowPICTException(CorruptImageError,"ImproperImageHeader");
1169             if ((code == 0x9a) || (code == 0x9b) ||
1170                 ((bytes_per_line & 0x8000) != 0))
1171               {
1172                 if (ReadPixmap(image,&pixmap) == MagickFalse)
1173                   ThrowPICTException(CorruptImageError,"ImproperImageHeader");
1174                 tile_image->depth=(size_t) pixmap.component_size;
1175                 tile_image->alpha_trait=pixmap.component_count == 4 ?
1176                   BlendPixelTrait : UndefinedPixelTrait;
1177                 tile_image->resolution.x=(double) pixmap.horizontal_resolution;
1178                 tile_image->resolution.y=(double) pixmap.vertical_resolution;
1179                 tile_image->units=PixelsPerInchResolution;
1180                 if (tile_image->alpha_trait != UndefinedPixelTrait)
1181                   (void) SetImageAlpha(tile_image,OpaqueAlpha,exception);
1182               }
1183             if ((code != 0x9a) && (code != 0x9b))
1184               {
1185                 /*
1186                   Initialize colormap.
1187                 */
1188                 tile_image->colors=2;
1189                 if ((bytes_per_line & 0x8000) != 0)
1190                   {
1191                     (void) ReadBlobMSBLong(image);
1192                     flags=(ssize_t) ReadBlobMSBShort(image);
1193                     tile_image->colors=1UL*ReadBlobMSBShort(image)+1;
1194                   }
1195                 status=AcquireImageColormap(tile_image,tile_image->colors,
1196                   exception);
1197                 if (status == MagickFalse)
1198                   ThrowPICTException(ResourceLimitError,
1199                     "MemoryAllocationFailed");
1200                 if ((bytes_per_line & 0x8000) != 0)
1201                   {
1202                     for (i=0; i < (ssize_t) tile_image->colors; i++)
1203                     {
1204                       j=ReadBlobMSBShort(image) % tile_image->colors;
1205                       if ((flags & 0x8000) != 0)
1206                         j=(size_t) i;
1207                       tile_image->colormap[j].red=(Quantum)
1208                         ScaleShortToQuantum(ReadBlobMSBShort(image));
1209                       tile_image->colormap[j].green=(Quantum)
1210                         ScaleShortToQuantum(ReadBlobMSBShort(image));
1211                       tile_image->colormap[j].blue=(Quantum)
1212                         ScaleShortToQuantum(ReadBlobMSBShort(image));
1213                     }
1214                   }
1215                 else
1216                   {
1217                     for (i=0; i < (ssize_t) tile_image->colors; i++)
1218                     {
1219                       tile_image->colormap[i].red=(Quantum) (QuantumRange-
1220                         tile_image->colormap[i].red);
1221                       tile_image->colormap[i].green=(Quantum) (QuantumRange-
1222                         tile_image->colormap[i].green);
1223                       tile_image->colormap[i].blue=(Quantum) (QuantumRange-
1224                         tile_image->colormap[i].blue);
1225                     }
1226                   }
1227               }
1228             if (EOFBlob(image) != MagickFalse)
1229               ThrowPICTException(CorruptImageError,
1230                 "InsufficientImageDataInFile");
1231             if (ReadRectangle(image,&source) == MagickFalse)
1232               ThrowPICTException(CorruptImageError,"ImproperImageHeader");
1233             if (ReadRectangle(image,&destination) == MagickFalse)
1234               ThrowPICTException(CorruptImageError,"ImproperImageHeader");
1235             (void) ReadBlobMSBShort(image);
1236             if ((code == 0x91) || (code == 0x99) || (code == 0x9b))
1237               {
1238                 /*
1239                   Skip region.
1240                 */
1241                 length=ReadBlobMSBShort(image);
1242                 if ((MagickSizeType) length > GetBlobSize(image))
1243                   ThrowPICTException(CorruptImageError,
1244                     "InsufficientImageDataInFile");
1245                 for (i=0; i < (ssize_t) (length-2); i++)
1246                   if (ReadBlobByte(image) == EOF)
1247                     break;
1248               }
1249             if ((code != 0x9a) && (code != 0x9b) &&
1250                 (bytes_per_line & 0x8000) == 0)
1251               pixels=DecodeImage(image,tile_image,(size_t) bytes_per_line,1,
1252                 &extent);
1253             else
1254               pixels=DecodeImage(image,tile_image,(size_t) bytes_per_line,
1255                 (unsigned int) pixmap.bits_per_pixel,&extent);
1256             if (pixels == (unsigned char *) NULL)
1257               ThrowPICTException(CorruptImageError,"UnableToUncompressImage");
1258             /*
1259               Convert PICT tile image to pixel packets.
1260             */
1261             p=pixels;
1262             for (y=0; y < (ssize_t) tile_image->rows; y++)
1263             {
1264               if (p > (pixels+extent+image->columns))
1265                 {
1266                   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1267                   ThrowPICTException(CorruptImageError,"NotEnoughPixelData");
1268                 }
1269               q=QueueAuthenticPixels(tile_image,0,y,tile_image->columns,1,
1270                 exception);
1271               if (q == (Quantum *) NULL)
1272                 break;
1273               for (x=0; x < (ssize_t) tile_image->columns; x++)
1274               {
1275                 if (tile_image->storage_class == PseudoClass)
1276                   {
1277                     index=(Quantum) ConstrainColormapIndex(tile_image,(ssize_t)
1278                       *p,exception);
1279                     SetPixelIndex(tile_image,index,q);
1280                     SetPixelRed(tile_image,
1281                       tile_image->colormap[(ssize_t) index].red,q);
1282                     SetPixelGreen(tile_image,
1283                       tile_image->colormap[(ssize_t) index].green,q);
1284                     SetPixelBlue(tile_image,
1285                       tile_image->colormap[(ssize_t) index].blue,q);
1286                   }
1287                 else
1288                   {
1289                     if (pixmap.bits_per_pixel == 16)
1290                       {
1291                         i=(ssize_t) (*p++);
1292                         j=(size_t) (*p);
1293                         SetPixelRed(tile_image,ScaleCharToQuantum(
1294                           (unsigned char) ((i & 0x7c) << 1)),q);
1295                         SetPixelGreen(tile_image,ScaleCharToQuantum(
1296                           (unsigned char) (((i & 0x03) << 6) |
1297                           ((j & 0xe0) >> 2))),q);
1298                         SetPixelBlue(tile_image,ScaleCharToQuantum(
1299                           (unsigned char) ((j & 0x1f) << 3)),q);
1300                       }
1301                     else
1302                       if (tile_image->alpha_trait == UndefinedPixelTrait)
1303                         {
1304                           if (p > (pixels+extent+2*image->columns))
1305                             ThrowPICTException(CorruptImageError,
1306                               "NotEnoughPixelData");
1307                           SetPixelRed(tile_image,ScaleCharToQuantum(*p),q);
1308                           SetPixelGreen(tile_image,ScaleCharToQuantum(
1309                             *(p+tile_image->columns)),q);
1310                           SetPixelBlue(tile_image,ScaleCharToQuantum(
1311                             *(p+2*tile_image->columns)),q);
1312                         }
1313                       else
1314                         {
1315                           if (p > (pixels+extent+3*image->columns))
1316                             ThrowPICTException(CorruptImageError,
1317                               "NotEnoughPixelData");
1318                           SetPixelAlpha(tile_image,ScaleCharToQuantum(*p),q);
1319                           SetPixelRed(tile_image,ScaleCharToQuantum(
1320                             *(p+tile_image->columns)),q);
1321                           SetPixelGreen(tile_image,ScaleCharToQuantum(
1322                             *(p+2*tile_image->columns)),q);
1323                           SetPixelBlue(tile_image,ScaleCharToQuantum(
1324                             *(p+3*tile_image->columns)),q);
1325                         }
1326                   }
1327                 p++;
1328                 q+=GetPixelChannels(tile_image);
1329               }
1330               if (SyncAuthenticPixels(tile_image,exception) == MagickFalse)
1331                 break;
1332               if ((tile_image->storage_class == DirectClass) &&
1333                   (pixmap.bits_per_pixel != 16))
1334                 {
1335                   p+=(pixmap.component_count-1)*tile_image->columns;
1336                   if (p < pixels)
1337                     break;
1338                 }
1339               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1340                 tile_image->rows);
1341               if (status == MagickFalse)
1342                 break;
1343             }
1344             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1345             if ((jpeg == MagickFalse) && (EOFBlob(image) == MagickFalse))
1346               if ((code == 0x9a) || (code == 0x9b) ||
1347                   ((bytes_per_line & 0x8000) != 0))
1348                 (void) CompositeImage(image,tile_image,CopyCompositeOp,
1349                   MagickTrue,(ssize_t) destination.left,(ssize_t)
1350                   destination.top,exception);
1351             tile_image=DestroyImage(tile_image);
1352             break;
1353           }
1354           case 0xa1:
1355           {
1356             unsigned char
1357               *info;
1358 
1359             size_t
1360               type;
1361 
1362             /*
1363               Comment.
1364             */
1365             type=ReadBlobMSBShort(image);
1366             length=ReadBlobMSBShort(image);
1367             if ((MagickSizeType) length > GetBlobSize(image))
1368               ThrowPICTException(CorruptImageError,
1369                 "InsufficientImageDataInFile");
1370             if (length == 0)
1371               break;
1372             (void) ReadBlobMSBLong(image);
1373             length-=MagickMin(length,4);
1374             if (length == 0)
1375               break;
1376             info=(unsigned char *) AcquireQuantumMemory(length,sizeof(*info));
1377             if (info == (unsigned char *) NULL)
1378               break;
1379             count=ReadBlob(image,length,info);
1380             if (count != (ssize_t) length)
1381               {
1382                 info=(unsigned char *) RelinquishMagickMemory(info);
1383                 ThrowPICTException(ResourceLimitError,"UnableToReadImageData");
1384               }
1385             switch (type)
1386             {
1387               case 0xe0:
1388               {
1389                 profile=BlobToStringInfo((const void *) NULL,length);
1390                 SetStringInfoDatum(profile,info);
1391                 status=SetImageProfile(image,"icc",profile,exception);
1392                 profile=DestroyStringInfo(profile);
1393                 if (status == MagickFalse)
1394                   {
1395                     info=(unsigned char *) RelinquishMagickMemory(info);
1396                     ThrowPICTException(ResourceLimitError,
1397                       "MemoryAllocationFailed");
1398                   }
1399                 break;
1400               }
1401               case 0x1f2:
1402               {
1403                 profile=BlobToStringInfo((const void *) NULL,length);
1404                 SetStringInfoDatum(profile,info);
1405                 status=SetImageProfile(image,"iptc",profile,exception);
1406                 if (status == MagickFalse)
1407                   {
1408                     info=(unsigned char *) RelinquishMagickMemory(info);
1409                     ThrowPICTException(ResourceLimitError,
1410                       "MemoryAllocationFailed");
1411                   }
1412                 profile=DestroyStringInfo(profile);
1413                 break;
1414               }
1415               default:
1416                 break;
1417             }
1418             info=(unsigned char *) RelinquishMagickMemory(info);
1419             break;
1420           }
1421           default:
1422           {
1423             /*
1424               Skip to next op code.
1425             */
1426             if (codes[code].length == -1)
1427               (void) ReadBlobMSBShort(image);
1428             else
1429               for (i=0; i < (ssize_t) codes[code].length; i++)
1430                 if (ReadBlobByte(image) == EOF)
1431                   break;
1432           }
1433         }
1434       }
1435     if (code == 0xc00)
1436       {
1437         /*
1438           Skip header.
1439         */
1440         for (i=0; i < 24; i++)
1441           if (ReadBlobByte(image) == EOF)
1442             break;
1443         continue;
1444       }
1445     if (((code >= 0xb0) && (code <= 0xcf)) ||
1446         ((code >= 0x8000) && (code <= 0x80ff)))
1447       continue;
1448     if (code == 0x8200)
1449       {
1450         char
1451           filename[MaxTextExtent];
1452 
1453         FILE
1454           *file;
1455 
1456         int
1457           unique_file;
1458 
1459         /*
1460           Embedded JPEG.
1461         */
1462         jpeg=MagickTrue;
1463         read_info=CloneImageInfo(image_info);
1464         SetImageInfoBlob(read_info,(void *) NULL,0);
1465         file=(FILE *) NULL;
1466         unique_file=AcquireUniqueFileResource(filename);
1467         (void) FormatLocaleString(read_info->filename,MaxTextExtent,"jpeg:%s",
1468           filename);
1469         if (unique_file != -1)
1470           file=fdopen(unique_file,"wb");
1471         if ((unique_file == -1) || (file == (FILE *) NULL))
1472           {
1473             (void) RelinquishUniqueFileResource(read_info->filename);
1474             (void) CopyMagickString(image->filename,read_info->filename,
1475               MagickPathExtent);
1476             ThrowPICTException(FileOpenError,"UnableToCreateTemporaryFile");
1477           }
1478         length=ReadBlobMSBLong(image);
1479         if ((MagickSizeType) length > GetBlobSize(image))
1480           ThrowPICTException(CorruptImageError,
1481             "InsufficientImageDataInFile");
1482         if (length > 154)
1483           {
1484             for (i=0; i < 6; i++)
1485               (void) ReadBlobMSBLong(image);
1486             if (ReadRectangle(image,&frame) == MagickFalse)
1487               {
1488                 (void) fclose(file);
1489                 (void) RelinquishUniqueFileResource(read_info->filename);
1490                 ThrowPICTException(CorruptImageError,"ImproperImageHeader");
1491               }
1492             for (i=0; i < 122; i++)
1493               if (ReadBlobByte(image) == EOF)
1494                 break;
1495             for (i=0; i < (ssize_t) (length-154); i++)
1496             {
1497               c=ReadBlobByte(image);
1498               if (c == EOF)
1499                 break;
1500               if (fputc(c,file) != c)
1501                 break;
1502             }
1503           }
1504         (void) fclose(file);
1505         (void) close(unique_file);
1506         tile_image=ReadImage(read_info,exception);
1507         (void) RelinquishUniqueFileResource(filename);
1508         read_info=DestroyImageInfo(read_info);
1509         if (tile_image == (Image *) NULL)
1510           continue;
1511         (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g",
1512           (double) MagickMax(image->columns,tile_image->columns),
1513           (double) MagickMax(image->rows,tile_image->rows));
1514         (void) SetImageExtent(image,
1515           MagickMax(image->columns,tile_image->columns),
1516           MagickMax(image->rows,tile_image->rows),exception);
1517         (void) TransformImageColorspace(image,tile_image->colorspace,exception);
1518         (void) CompositeImage(image,tile_image,CopyCompositeOp,MagickTrue,
1519           (ssize_t) frame.left,(ssize_t) frame.right,exception);
1520         image->compression=tile_image->compression;
1521         tile_image=DestroyImage(tile_image);
1522         continue;
1523       }
1524     if ((code == 0xff) || (code == 0xffff))
1525       break;
1526     if (((code >= 0xd0) && (code <= 0xfe)) ||
1527         ((code >= 0x8100) && (code <= 0xffff)))
1528       {
1529         /*
1530           Skip reserved.
1531         */
1532         length=ReadBlobMSBShort(image);
1533         if ((MagickSizeType) length > GetBlobSize(image))
1534           ThrowPICTException(CorruptImageError,
1535             "InsufficientImageDataInFile");
1536         for (i=0; i < (ssize_t) length; i++)
1537           if (ReadBlobByte(image) == EOF)
1538             break;
1539         continue;
1540       }
1541     if ((code >= 0x100) && (code <= 0x7fff))
1542       {
1543         /*
1544           Skip reserved.
1545         */
1546         length=(size_t) ((code >> 7) & 0xff);
1547         if ((MagickSizeType) length > GetBlobSize(image))
1548           ThrowPICTException(CorruptImageError,
1549             "InsufficientImageDataInFile");
1550         for (i=0; i < (ssize_t) length; i++)
1551           if (ReadBlobByte(image) == EOF)
1552             break;
1553         continue;
1554       }
1555   }
1556   (void) CloseBlob(image);
1557   return(GetFirstImageInList(image));
1558 }
1559 #endif
1560 
1561 /*
1562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1563 %                                                                             %
1564 %                                                                             %
1565 %                                                                             %
1566 %   R e g i s t e r P I C T I m a g e                                         %
1567 %                                                                             %
1568 %                                                                             %
1569 %                                                                             %
1570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1571 %
1572 %  RegisterPICTImage() adds attributes for the PICT image format to
1573 %  the list of supported formats.  The attributes include the image format
1574 %  tag, a method to read and/or write the format, whether the format
1575 %  supports the saving of more than one frame to the same file or blob,
1576 %  whether the format supports native in-memory I/O, and a brief
1577 %  description of the format.
1578 %
1579 %  The format of the RegisterPICTImage method is:
1580 %
1581 %      size_t RegisterPICTImage(void)
1582 %
1583 */
RegisterPICTImage(void)1584 ModuleExport size_t RegisterPICTImage(void)
1585 {
1586   MagickInfo
1587     *entry;
1588 
1589   entry=AcquireMagickInfo("PICT","PCT","Apple Macintosh QuickDraw/PICT");
1590   entry->decoder=(DecodeImageHandler *) ReadPICTImage;
1591   entry->encoder=(EncodeImageHandler *) WritePICTImage;
1592   entry->flags^=CoderAdjoinFlag;
1593   entry->flags|=CoderEncoderSeekableStreamFlag;
1594   entry->magick=(IsImageFormatHandler *) IsPICT;
1595   (void) RegisterMagickInfo(entry);
1596   entry=AcquireMagickInfo("PICT","PICT","Apple Macintosh QuickDraw/PICT");
1597   entry->decoder=(DecodeImageHandler *) ReadPICTImage;
1598   entry->encoder=(EncodeImageHandler *) WritePICTImage;
1599   entry->flags^=CoderAdjoinFlag;
1600   entry->flags|=CoderEncoderSeekableStreamFlag;
1601   entry->magick=(IsImageFormatHandler *) IsPICT;
1602   (void) RegisterMagickInfo(entry);
1603   return(MagickImageCoderSignature);
1604 }
1605 
1606 /*
1607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1608 %                                                                             %
1609 %                                                                             %
1610 %                                                                             %
1611 %   U n r e g i s t e r P I C T I m a g e                                     %
1612 %                                                                             %
1613 %                                                                             %
1614 %                                                                             %
1615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1616 %
1617 %  UnregisterPICTImage() removes format registrations made by the
1618 %  PICT module from the list of supported formats.
1619 %
1620 %  The format of the UnregisterPICTImage method is:
1621 %
1622 %      UnregisterPICTImage(void)
1623 %
1624 */
UnregisterPICTImage(void)1625 ModuleExport void UnregisterPICTImage(void)
1626 {
1627   (void) UnregisterMagickInfo("PCT");
1628   (void) UnregisterMagickInfo("PICT");
1629 }
1630 
1631 /*
1632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 %                                                                             %
1634 %                                                                             %
1635 %                                                                             %
1636 %   W r i t e P I C T I m a g e                                               %
1637 %                                                                             %
1638 %                                                                             %
1639 %                                                                             %
1640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1641 %
1642 %  WritePICTImage() writes an image to a file in the Apple Macintosh
1643 %  QuickDraw/PICT image format.
1644 %
1645 %  The format of the WritePICTImage method is:
1646 %
1647 %      MagickBooleanType WritePICTImage(const ImageInfo *image_info,
1648 %        Image *image,ExceptionInfo *exception)
1649 %
1650 %  A description of each parameter follows.
1651 %
1652 %    o image_info: the image info.
1653 %
1654 %    o image:  The image.
1655 %
1656 %    o exception: return any errors or warnings in this structure.
1657 %
1658 */
WritePICTImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)1659 static MagickBooleanType WritePICTImage(const ImageInfo *image_info,
1660   Image *image,ExceptionInfo *exception)
1661 {
1662 #define MaxCount  128
1663 #define PictCropRegionOp  0x01
1664 #define PictEndOfPictureOp  0xff
1665 #define PictJPEGOp  0x8200
1666 #define PictInfoOp  0x0C00
1667 #define PictInfoSize  512
1668 #define PictPixmapOp  0x9A
1669 #define PictPICTOp  0x98
1670 #define PictVersion  0x11
1671 
1672   const StringInfo
1673     *profile;
1674 
1675   double
1676     x_resolution,
1677     y_resolution;
1678 
1679   MagickBooleanType
1680     status;
1681 
1682   MagickOffsetType
1683     offset;
1684 
1685   PICTPixmap
1686     pixmap;
1687 
1688   PICTRectangle
1689     bounds,
1690     crop_rectangle,
1691     destination_rectangle,
1692     frame_rectangle,
1693     size_rectangle,
1694     source_rectangle;
1695 
1696   register const Quantum
1697     *p;
1698 
1699   register ssize_t
1700     i,
1701     x;
1702 
1703   size_t
1704     bytes_per_line,
1705     count,
1706     row_bytes,
1707     storage_class;
1708 
1709   ssize_t
1710     y;
1711 
1712   unsigned char
1713     *buffer,
1714     *packed_scanline,
1715     *scanline;
1716 
1717   unsigned short
1718     base_address,
1719     transfer_mode;
1720 
1721   /*
1722     Open output image file.
1723   */
1724   assert(image_info != (const ImageInfo *) NULL);
1725   assert(image_info->signature == MagickCoreSignature);
1726   assert(image != (Image *) NULL);
1727   assert(image->signature == MagickCoreSignature);
1728   if (image->debug != MagickFalse)
1729     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1730   if ((image->columns > 65535L) || (image->rows > 65535L))
1731     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1732   assert(exception != (ExceptionInfo *) NULL);
1733   assert(exception->signature == MagickCoreSignature);
1734   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1735   if (status == MagickFalse)
1736     return(status);
1737   (void) TransformImageColorspace(image,sRGBColorspace,exception);
1738   /*
1739     Initialize image info.
1740   */
1741   size_rectangle.top=0;
1742   size_rectangle.left=0;
1743   size_rectangle.bottom=(short) image->rows;
1744   size_rectangle.right=(short) image->columns;
1745   frame_rectangle=size_rectangle;
1746   crop_rectangle=size_rectangle;
1747   source_rectangle=size_rectangle;
1748   destination_rectangle=size_rectangle;
1749   base_address=0xff;
1750   row_bytes=image->columns;
1751   bounds.top=0;
1752   bounds.left=0;
1753   bounds.bottom=(short) image->rows;
1754   bounds.right=(short) image->columns;
1755   pixmap.version=0;
1756   pixmap.pack_type=0;
1757   pixmap.pack_size=0;
1758   pixmap.pixel_type=0;
1759   pixmap.bits_per_pixel=8;
1760   pixmap.component_count=1;
1761   pixmap.component_size=8;
1762   pixmap.plane_bytes=0;
1763   pixmap.table=0;
1764   pixmap.reserved=0;
1765   transfer_mode=0;
1766   x_resolution=image->resolution.x != 0.0 ? image->resolution.x :
1767     DefaultResolution;
1768   y_resolution=image->resolution.y != 0.0 ? image->resolution.y :
1769     DefaultResolution;
1770   storage_class=image->storage_class;
1771   if (image_info->compression == JPEGCompression)
1772     storage_class=DirectClass;
1773   if (storage_class == DirectClass)
1774     {
1775       pixmap.component_count=image->alpha_trait != UndefinedPixelTrait ? 4 : 3;
1776       pixmap.pixel_type=16;
1777       pixmap.bits_per_pixel=32;
1778       pixmap.pack_type=0x04;
1779       transfer_mode=0x40;
1780       row_bytes=4*image->columns;
1781     }
1782   /*
1783     Allocate memory.
1784   */
1785   bytes_per_line=image->columns;
1786   if (storage_class == DirectClass)
1787     bytes_per_line*=image->alpha_trait != UndefinedPixelTrait ? 4 : 3;
1788   buffer=(unsigned char *) AcquireQuantumMemory(PictInfoSize,sizeof(*buffer));
1789   packed_scanline=(unsigned char *) AcquireQuantumMemory((size_t)
1790    (row_bytes+2*MaxCount),sizeof(*packed_scanline));
1791   scanline=(unsigned char *) AcquireQuantumMemory(row_bytes,sizeof(*scanline));
1792   if ((buffer == (unsigned char *) NULL) ||
1793       (packed_scanline == (unsigned char *) NULL) ||
1794       (scanline == (unsigned char *) NULL))
1795     {
1796       if (scanline != (unsigned char *) NULL)
1797         scanline=(unsigned char *) RelinquishMagickMemory(scanline);
1798       if (packed_scanline != (unsigned char *) NULL)
1799         packed_scanline=(unsigned char *) RelinquishMagickMemory(
1800           packed_scanline);
1801       if (buffer != (unsigned char *) NULL)
1802         buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1803       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1804     }
1805   (void) memset(scanline,0,row_bytes);
1806   (void) memset(packed_scanline,0,(size_t) (row_bytes+2*MaxCount)*
1807     sizeof(*packed_scanline));
1808   /*
1809     Write header, header size, size bounding box, version, and reserved.
1810   */
1811   (void) memset(buffer,0,PictInfoSize);
1812   (void) WriteBlob(image,PictInfoSize,buffer);
1813   (void) WriteBlobMSBShort(image,0);
1814   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.top);
1815   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.left);
1816   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.bottom);
1817   (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.right);
1818   (void) WriteBlobMSBShort(image,PictVersion);
1819   (void) WriteBlobMSBShort(image,0x02ff);  /* version #2 */
1820   (void) WriteBlobMSBShort(image,PictInfoOp);
1821   (void) WriteBlobMSBLong(image,0xFFFE0000U);
1822   /*
1823     Write full size of the file, resolution, frame bounding box, and reserved.
1824   */
1825   (void) WriteBlobMSBShort(image,(unsigned short) x_resolution);
1826   (void) WriteBlobMSBShort(image,0x0000);
1827   (void) WriteBlobMSBShort(image,(unsigned short) y_resolution);
1828   (void) WriteBlobMSBShort(image,0x0000);
1829   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.top);
1830   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.left);
1831   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.bottom);
1832   (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.right);
1833   (void) WriteBlobMSBLong(image,0x00000000L);
1834   profile=GetImageProfile(image,"iptc");
1835   if (profile != (StringInfo *) NULL)
1836     {
1837       (void) WriteBlobMSBShort(image,0xa1);
1838       (void) WriteBlobMSBShort(image,0x1f2);
1839       (void) WriteBlobMSBShort(image,(unsigned short)
1840         (GetStringInfoLength(profile)+4));
1841       (void) WriteBlobString(image,"8BIM");
1842       (void) WriteBlob(image,GetStringInfoLength(profile),
1843         GetStringInfoDatum(profile));
1844     }
1845   profile=GetImageProfile(image,"icc");
1846   if (profile != (StringInfo *) NULL)
1847     {
1848       (void) WriteBlobMSBShort(image,0xa1);
1849       (void) WriteBlobMSBShort(image,0xe0);
1850       (void) WriteBlobMSBShort(image,(unsigned short)
1851         (GetStringInfoLength(profile)+4));
1852       (void) WriteBlobMSBLong(image,0x00000000U);
1853       (void) WriteBlob(image,GetStringInfoLength(profile),
1854         GetStringInfoDatum(profile));
1855       (void) WriteBlobMSBShort(image,0xa1);
1856       (void) WriteBlobMSBShort(image,0xe0);
1857       (void) WriteBlobMSBShort(image,4);
1858       (void) WriteBlobMSBLong(image,0x00000002U);
1859     }
1860   /*
1861     Write crop region opcode and crop bounding box.
1862   */
1863   (void) WriteBlobMSBShort(image,PictCropRegionOp);
1864   (void) WriteBlobMSBShort(image,0xa);
1865   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.top);
1866   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.left);
1867   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.bottom);
1868   (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.right);
1869   if (image_info->compression == JPEGCompression)
1870     {
1871       Image
1872         *jpeg_image;
1873 
1874       ImageInfo
1875         *jpeg_info;
1876 
1877       size_t
1878         length;
1879 
1880       unsigned char
1881         *blob;
1882 
1883       jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
1884       if (jpeg_image == (Image *) NULL)
1885         {
1886           (void) CloseBlob(image);
1887           return(MagickFalse);
1888         }
1889       jpeg_info=CloneImageInfo(image_info);
1890       (void) CopyMagickString(jpeg_info->magick,"JPEG",MagickPathExtent);
1891       length=0;
1892       blob=(unsigned char *) ImageToBlob(jpeg_info,jpeg_image,&length,
1893         exception);
1894       jpeg_info=DestroyImageInfo(jpeg_info);
1895       if (blob == (unsigned char *) NULL)
1896         return(MagickFalse);
1897       jpeg_image=DestroyImage(jpeg_image);
1898       (void) WriteBlobMSBShort(image,PictJPEGOp);
1899       (void) WriteBlobMSBLong(image,(unsigned int) length+154);
1900       (void) WriteBlobMSBShort(image,0x0000);
1901       (void) WriteBlobMSBLong(image,0x00010000U);
1902       (void) WriteBlobMSBLong(image,0x00000000U);
1903       (void) WriteBlobMSBLong(image,0x00000000U);
1904       (void) WriteBlobMSBLong(image,0x00000000U);
1905       (void) WriteBlobMSBLong(image,0x00010000U);
1906       (void) WriteBlobMSBLong(image,0x00000000U);
1907       (void) WriteBlobMSBLong(image,0x00000000U);
1908       (void) WriteBlobMSBLong(image,0x00000000U);
1909       (void) WriteBlobMSBLong(image,0x40000000U);
1910       (void) WriteBlobMSBLong(image,0x00000000U);
1911       (void) WriteBlobMSBLong(image,0x00000000U);
1912       (void) WriteBlobMSBLong(image,0x00000000U);
1913       (void) WriteBlobMSBLong(image,0x00400000U);
1914       (void) WriteBlobMSBShort(image,0x0000);
1915       (void) WriteBlobMSBShort(image,(unsigned short) image->rows);
1916       (void) WriteBlobMSBShort(image,(unsigned short) image->columns);
1917       (void) WriteBlobMSBShort(image,0x0000);
1918       (void) WriteBlobMSBShort(image,768);
1919       (void) WriteBlobMSBShort(image,0x0000);
1920       (void) WriteBlobMSBLong(image,0x00000000U);
1921       (void) WriteBlobMSBLong(image,0x00566A70U);
1922       (void) WriteBlobMSBLong(image,0x65670000U);
1923       (void) WriteBlobMSBLong(image,0x00000000U);
1924       (void) WriteBlobMSBLong(image,0x00000001U);
1925       (void) WriteBlobMSBLong(image,0x00016170U);
1926       (void) WriteBlobMSBLong(image,0x706C0000U);
1927       (void) WriteBlobMSBLong(image,0x00000000U);
1928       (void) WriteBlobMSBShort(image,768);
1929       (void) WriteBlobMSBShort(image,(unsigned short) image->columns);
1930       (void) WriteBlobMSBShort(image,(unsigned short) image->rows);
1931       (void) WriteBlobMSBShort(image,(unsigned short) x_resolution);
1932       (void) WriteBlobMSBShort(image,0x0000);
1933       (void) WriteBlobMSBShort(image,(unsigned short) y_resolution);
1934       (void) WriteBlobMSBShort(image,0x0000);
1935       (void) WriteBlobMSBLong(image,(unsigned int) length);
1936       (void) WriteBlobMSBShort(image,0x0001);
1937       (void) WriteBlobMSBLong(image,0x0B466F74U);
1938       (void) WriteBlobMSBLong(image,0x6F202D20U);
1939       (void) WriteBlobMSBLong(image,0x4A504547U);
1940       (void) WriteBlobMSBLong(image,0x00000000U);
1941       (void) WriteBlobMSBLong(image,0x00000000U);
1942       (void) WriteBlobMSBLong(image,0x00000000U);
1943       (void) WriteBlobMSBLong(image,0x00000000U);
1944       (void) WriteBlobMSBLong(image,0x00000000U);
1945       (void) WriteBlobMSBLong(image,0x0018FFFFU);
1946       (void) WriteBlob(image,length,blob);
1947       if ((length & 0x01) != 0)
1948         (void) WriteBlobByte(image,'\0');
1949       blob=(unsigned char *) RelinquishMagickMemory(blob);
1950     }
1951   /*
1952     Write picture opcode, row bytes, and picture bounding box, and version.
1953   */
1954   if (storage_class == PseudoClass)
1955     (void) WriteBlobMSBShort(image,PictPICTOp);
1956   else
1957     {
1958       (void) WriteBlobMSBShort(image,PictPixmapOp);
1959       (void) WriteBlobMSBLong(image,(unsigned int) base_address);
1960     }
1961   (void) WriteBlobMSBShort(image,(unsigned short) (row_bytes | 0x8000));
1962   (void) WriteBlobMSBShort(image,(unsigned short) bounds.top);
1963   (void) WriteBlobMSBShort(image,(unsigned short) bounds.left);
1964   (void) WriteBlobMSBShort(image,(unsigned short) bounds.bottom);
1965   (void) WriteBlobMSBShort(image,(unsigned short) bounds.right);
1966   /*
1967     Write pack type, pack size, resolution, pixel type, and pixel size.
1968   */
1969   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.version);
1970   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.pack_type);
1971   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.pack_size);
1972   (void) WriteBlobMSBShort(image,(unsigned short) (x_resolution+0.5));
1973   (void) WriteBlobMSBShort(image,0x0000);
1974   (void) WriteBlobMSBShort(image,(unsigned short) (y_resolution+0.5));
1975   (void) WriteBlobMSBShort(image,0x0000);
1976   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.pixel_type);
1977   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.bits_per_pixel);
1978   /*
1979     Write component count, size, plane bytes, table size, and reserved.
1980   */
1981   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.component_count);
1982   (void) WriteBlobMSBShort(image,(unsigned short) pixmap.component_size);
1983   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.plane_bytes);
1984   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.table);
1985   (void) WriteBlobMSBLong(image,(unsigned int) pixmap.reserved);
1986   if (storage_class == PseudoClass)
1987     {
1988       /*
1989         Write image colormap.
1990       */
1991       (void) WriteBlobMSBLong(image,0x00000000L);  /* color seed */
1992       (void) WriteBlobMSBShort(image,0L);  /* color flags */
1993       (void) WriteBlobMSBShort(image,(unsigned short) (image->colors-1));
1994       for (i=0; i < (ssize_t) image->colors; i++)
1995       {
1996         (void) WriteBlobMSBShort(image,(unsigned short) i);
1997         (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
1998           image->colormap[i].red));
1999         (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
2000           image->colormap[i].green));
2001         (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
2002           image->colormap[i].blue));
2003       }
2004     }
2005   /*
2006     Write source and destination rectangle.
2007   */
2008   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.top);
2009   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.left);
2010   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.bottom);
2011   (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.right);
2012   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.top);
2013   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.left);
2014   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.bottom);
2015   (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.right);
2016   (void) WriteBlobMSBShort(image,(unsigned short) transfer_mode);
2017   /*
2018     Write picture data.
2019   */
2020   count=0;
2021   if (storage_class == PseudoClass)
2022     for (y=0; y < (ssize_t) image->rows; y++)
2023     {
2024       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2025       if (p == (const Quantum *) NULL)
2026         break;
2027       for (x=0; x < (ssize_t) image->columns; x++)
2028       {
2029         scanline[x]=(unsigned char) GetPixelIndex(image,p);
2030         p+=GetPixelChannels(image);
2031       }
2032       count+=EncodeImage(image,scanline,(size_t) (row_bytes & 0x7FFF),
2033         packed_scanline);
2034       if (image->previous == (Image *) NULL)
2035         {
2036           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2037             image->rows);
2038           if (status == MagickFalse)
2039             break;
2040         }
2041     }
2042   else
2043     if (image_info->compression == JPEGCompression)
2044       {
2045         (void) memset(scanline,0,row_bytes);
2046         for (y=0; y < (ssize_t) image->rows; y++)
2047           count+=EncodeImage(image,scanline,(size_t) (row_bytes & 0x7FFF),
2048             packed_scanline);
2049       }
2050     else
2051       {
2052         register unsigned char
2053           *blue,
2054           *green,
2055           *opacity,
2056           *red;
2057 
2058         red=scanline;
2059         green=scanline+image->columns;
2060         blue=scanline+2*image->columns;
2061         opacity=scanline+3*image->columns;
2062         for (y=0; y < (ssize_t) image->rows; y++)
2063         {
2064           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2065           if (p == (const Quantum *) NULL)
2066             break;
2067           red=scanline;
2068           green=scanline+image->columns;
2069           blue=scanline+2*image->columns;
2070           if (image->alpha_trait != UndefinedPixelTrait)
2071             {
2072               opacity=scanline;
2073               red=scanline+image->columns;
2074               green=scanline+2*image->columns;
2075               blue=scanline+3*image->columns;
2076             }
2077           for (x=0; x < (ssize_t) image->columns; x++)
2078           {
2079             *red++=ScaleQuantumToChar(GetPixelRed(image,p));
2080             *green++=ScaleQuantumToChar(GetPixelGreen(image,p));
2081             *blue++=ScaleQuantumToChar(GetPixelBlue(image,p));
2082             if (image->alpha_trait != UndefinedPixelTrait)
2083               *opacity++=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p)));
2084             p+=GetPixelChannels(image);
2085           }
2086           count+=EncodeImage(image,scanline,bytes_per_line,packed_scanline);
2087           if (image->previous == (Image *) NULL)
2088             {
2089               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2090                 image->rows);
2091               if (status == MagickFalse)
2092                 break;
2093             }
2094         }
2095       }
2096   if ((count & 0x01) != 0)
2097     (void) WriteBlobByte(image,'\0');
2098   (void) WriteBlobMSBShort(image,PictEndOfPictureOp);
2099   offset=TellBlob(image);
2100   offset=SeekBlob(image,512,SEEK_SET);
2101   (void) WriteBlobMSBShort(image,(unsigned short) offset);
2102   scanline=(unsigned char *) RelinquishMagickMemory(scanline);
2103   packed_scanline=(unsigned char *) RelinquishMagickMemory(packed_scanline);
2104   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
2105   (void) CloseBlob(image);
2106   return(MagickTrue);
2107 }
2108