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