root / ImageMagick / trunk / coders / pict.c

Revision 12349, 68.1 kB (checked in by cristy, 3 weeks ago)
Line 
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%                                John Cristy                                  %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/color-private.h"
46#include "magick/colorspace.h"
47#include "magick/composite.h"
48#include "magick/constitute.h"
49#include "magick/exception.h"
50#include "magick/exception-private.h"
51#include "magick/image.h"
52#include "magick/image-private.h"
53#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
57#include "magick/monitor.h"
58#include "magick/monitor-private.h"
59#include "magick/profile.h"
60#include "magick/resource_.h"
61#include "magick/quantum-private.h"
62#include "magick/static.h"
63#include "magick/string_.h"
64#include "magick/module.h"
65#include "magick/transform.h"
66#include "magick/utility.h"
67
68/*
69  ImageMagick Macintosh PICT Methods.
70*/
71#define ReadPixmap(pixmap) \
72{ \
73  pixmap.version=(short) ReadBlobMSBShort(image); \
74  pixmap.pack_type=(short) ReadBlobMSBShort(image); \
75  pixmap.pack_size=ReadBlobMSBLong(image); \
76  pixmap.horizontal_resolution=1UL*ReadBlobMSBShort(image); \
77  (void) ReadBlobMSBShort(image); \
78  pixmap.vertical_resolution=1UL*ReadBlobMSBShort(image); \
79  (void) ReadBlobMSBShort(image); \
80  pixmap.pixel_type=(short) ReadBlobMSBShort(image); \
81  pixmap.bits_per_pixel=(short) ReadBlobMSBShort(image); \
82  pixmap.component_count=(short) ReadBlobMSBShort(image); \
83  pixmap.component_size=(short) ReadBlobMSBShort(image); \
84  pixmap.plane_bytes=ReadBlobMSBLong(image); \
85  pixmap.table=ReadBlobMSBLong(image); \
86  pixmap.reserved=ReadBlobMSBLong(image); \
87  if ((pixmap.bits_per_pixel <= 0) || (pixmap.bits_per_pixel > 32) || \
88      (pixmap.component_count <= 0) || (pixmap.component_count > 4) || \
89      (pixmap.component_size <= 0)) \
90    ThrowReaderException(CorruptImageError,"ImproperImageHeader"); \
91}
92
93#define ReadRectangle(image,rectangle) \
94{ \
95  rectangle.top=(short) ReadBlobMSBShort(image); \
96  rectangle.left=(short) ReadBlobMSBShort(image); \
97  rectangle.bottom=(short) ReadBlobMSBShort(image); \
98  rectangle.right=(short) ReadBlobMSBShort(image); \
99  if ((rectangle.left > rectangle.right) || \
100      (rectangle.top > rectangle.bottom)) \
101    ThrowReaderException(CorruptImageError,"ImproperImageHeader"); \
102}
103
104typedef struct _PICTCode
105{
106  const char
107    *name;
108
109  long
110    length;
111
112  const char
113    *description;
114} PICTCode;
115
116typedef struct _PICTPixmap
117{
118  short
119    version,
120    pack_type;
121
122  unsigned long
123    pack_size,
124    horizontal_resolution,
125    vertical_resolution;
126
127  short
128    pixel_type,
129    bits_per_pixel,
130    component_count,
131    component_size;
132
133  unsigned long
134    plane_bytes,
135    table,
136    reserved;
137} PICTPixmap;
138
139typedef struct _PICTRectangle
140{
141  short
142    top,
143    left,
144    bottom,
145    right;
146} PICTRectangle;
147
148static const PICTCode
149  codes[] =
150  {
151    /* 0x00 */ { "NOP", 0, "nop" },
152    /* 0x01 */ { "Clip", 0, "clip" },
153    /* 0x02 */ { "BkPat", 8, "background pattern" },
154    /* 0x03 */ { "TxFont", 2, "text font (word)" },
155    /* 0x04 */ { "TxFace", 1, "text face (byte)" },
156    /* 0x05 */ { "TxMode", 2, "text mode (word)" },
157    /* 0x06 */ { "SpExtra", 4, "space extra (fixed point)" },
158    /* 0x07 */ { "PnSize", 4, "pen size (point)" },
159    /* 0x08 */ { "PnMode", 2, "pen mode (word)" },
160    /* 0x09 */ { "PnPat", 8, "pen pattern" },
161    /* 0x0a */ { "FillPat", 8, "fill pattern" },
162    /* 0x0b */ { "OvSize", 4, "oval size (point)" },
163    /* 0x0c */ { "Origin", 4, "dh, dv (word)" },
164    /* 0x0d */ { "TxSize", 2, "text size (word)" },
165    /* 0x0e */ { "FgColor", 4, "foreground color (longword)" },
166    /* 0x0f */ { "BkColor", 4, "background color (longword)" },
167    /* 0x10 */ { "TxRatio", 8, "numerator (point), denominator (point)" },
168    /* 0x11 */ { "Version", 1, "version (byte)" },
169    /* 0x12 */ { "BkPixPat", 0, "color background pattern" },
170    /* 0x13 */ { "PnPixPat", 0, "color pen pattern" },
171    /* 0x14 */ { "FillPixPat", 0, "color fill pattern" },
172    /* 0x15 */ { "PnLocHFrac", 2, "fractional pen position" },
173    /* 0x16 */ { "ChExtra", 2, "extra for each character" },
174    /* 0x17 */ { "reserved", 0, "reserved for Apple use" },
175    /* 0x18 */ { "reserved", 0, "reserved for Apple use" },
176    /* 0x19 */ { "reserved", 0, "reserved for Apple use" },
177    /* 0x1a */ { "RGBFgCol", 6, "RGB foreColor" },
178    /* 0x1b */ { "RGBBkCol", 6, "RGB backColor" },
179    /* 0x1c */ { "HiliteMode", 0, "hilite mode flag" },
180    /* 0x1d */ { "HiliteColor", 6, "RGB hilite color" },
181    /* 0x1e */ { "DefHilite", 0, "Use default hilite color" },
182    /* 0x1f */ { "OpColor", 6, "RGB OpColor for arithmetic modes" },
183    /* 0x20 */ { "Line", 8, "pnLoc (point), newPt (point)" },
184    /* 0x21 */ { "LineFrom", 4, "newPt (point)" },
185    /* 0x22 */ { "ShortLine", 6, "pnLoc (point, dh, dv (-128 .. 127))" },
186    /* 0x23 */ { "ShortLineFrom", 2, "dh, dv (-128 .. 127)" },
187    /* 0x24 */ { "reserved", -1, "reserved for Apple use" },
188    /* 0x25 */ { "reserved", -1, "reserved for Apple use" },
189    /* 0x26 */ { "reserved", -1, "reserved for Apple use" },
190    /* 0x27 */ { "reserved", -1, "reserved for Apple use" },
191    /* 0x28 */ { "LongText", 0, "txLoc (point), count (0..255), text" },
192    /* 0x29 */ { "DHText", 0, "dh (0..255), count (0..255), text" },
193    /* 0x2a */ { "DVText", 0, "dv (0..255), count (0..255), text" },
194    /* 0x2b */ { "DHDVText", 0, "dh, dv (0..255), count (0..255), text" },
195    /* 0x2c */ { "reserved", -1, "reserved for Apple use" },
196    /* 0x2d */ { "reserved", -1, "reserved for Apple use" },
197    /* 0x2e */ { "reserved", -1, "reserved for Apple use" },
198    /* 0x2f */ { "reserved", -1, "reserved for Apple use" },
199    /* 0x30 */ { "frameRect", 8, "rect" },
200    /* 0x31 */ { "paintRect", 8, "rect" },
201    /* 0x32 */ { "eraseRect", 8, "rect" },
202    /* 0x33 */ { "invertRect", 8, "rect" },
203    /* 0x34 */ { "fillRect", 8, "rect" },
204    /* 0x35 */ { "reserved", 8, "reserved for Apple use" },
205    /* 0x36 */ { "reserved", 8, "reserved for Apple use" },
206    /* 0x37 */ { "reserved", 8, "reserved for Apple use" },
207    /* 0x38 */ { "frameSameRect", 0, "rect" },
208    /* 0x39 */ { "paintSameRect", 0, "rect" },
209    /* 0x3a */ { "eraseSameRect", 0, "rect" },
210    /* 0x3b */ { "invertSameRect", 0, "rect" },
211    /* 0x3c */ { "fillSameRect", 0, "rect" },
212    /* 0x3d */ { "reserved", 0, "reserved for Apple use" },
213    /* 0x3e */ { "reserved", 0, "reserved for Apple use" },
214    /* 0x3f */ { "reserved", 0, "reserved for Apple use" },
215    /* 0x40 */ { "frameRRect", 8, "rect" },
216    /* 0x41 */ { "paintRRect", 8, "rect" },
217    /* 0x42 */ { "eraseRRect", 8, "rect" },
218    /* 0x43 */ { "invertRRect", 8, "rect" },
219    /* 0x44 */ { "fillRRrect", 8, "rect" },
220    /* 0x45 */ { "reserved", 8, "reserved for Apple use" },
221    /* 0x46 */ { "reserved", 8, "reserved for Apple use" },
222    /* 0x47 */ { "reserved", 8, "reserved for Apple use" },
223    /* 0x48 */ { "frameSameRRect", 0, "rect" },
224    /* 0x49 */ { "paintSameRRect", 0, "rect" },
225    /* 0x4a */ { "eraseSameRRect", 0, "rect" },
226    /* 0x4b */ { "invertSameRRect", 0, "rect" },
227    /* 0x4c */ { "fillSameRRect", 0, "rect" },
228    /* 0x4d */ { "reserved", 0, "reserved for Apple use" },
229    /* 0x4e */ { "reserved", 0, "reserved for Apple use" },
230    /* 0x4f */ { "reserved", 0, "reserved for Apple use" },
231    /* 0x50 */ { "frameOval", 8, "rect" },
232    /* 0x51 */ { "paintOval", 8, "rect" },
233    /* 0x52 */ { "eraseOval", 8, "rect" },
234    /* 0x53 */ { "invertOval", 8, "rect" },
235    /* 0x54 */ { "fillOval", 8, "rect" },
236    /* 0x55 */ { "reserved", 8, "reserved for Apple use" },
237    /* 0x56 */ { "reserved", 8, "reserved for Apple use" },
238    /* 0x57 */ { "reserved", 8, "reserved for Apple use" },
239    /* 0x58 */ { "frameSameOval", 0, "rect" },
240    /* 0x59 */ { "paintSameOval", 0, "rect" },
241    /* 0x5a */ { "eraseSameOval", 0, "rect" },
242    /* 0x5b */ { "invertSameOval", 0, "rect" },
243    /* 0x5c */ { "fillSameOval", 0, "rect" },
244    /* 0x5d */ { "reserved", 0, "reserved for Apple use" },
245    /* 0x5e */ { "reserved", 0, "reserved for Apple use" },
246    /* 0x5f */ { "reserved", 0, "reserved for Apple use" },
247    /* 0x60 */ { "frameArc", 12, "rect, startAngle, arcAngle" },
248    /* 0x61 */ { "paintArc", 12, "rect, startAngle, arcAngle" },
249    /* 0x62 */ { "eraseArc", 12, "rect, startAngle, arcAngle" },
250    /* 0x63 */ { "invertArc", 12, "rect, startAngle, arcAngle" },
251    /* 0x64 */ { "fillArc", 12, "rect, startAngle, arcAngle" },
252    /* 0x65 */ { "reserved", 12, "reserved for Apple use" },
253    /* 0x66 */ { "reserved", 12, "reserved for Apple use" },
254    /* 0x67 */ { "reserved", 12, "reserved for Apple use" },
255    /* 0x68 */ { "frameSameArc", 4, "rect, startAngle, arcAngle" },
256    /* 0x69 */ { "paintSameArc", 4, "rect, startAngle, arcAngle" },
257    /* 0x6a */ { "eraseSameArc", 4, "rect, startAngle, arcAngle" },
258    /* 0x6b */ { "invertSameArc", 4, "rect, startAngle, arcAngle" },
259    /* 0x6c */ { "fillSameArc", 4, "rect, startAngle, arcAngle" },
260    /* 0x6d */ { "reserved", 4, "reserved for Apple use" },
261    /* 0x6e */ { "reserved", 4, "reserved for Apple use" },
262    /* 0x6f */ { "reserved", 4, "reserved for Apple use" },
263    /* 0x70 */ { "framePoly", 0, "poly" },
264    /* 0x71 */ { "paintPoly", 0, "poly" },
265    /* 0x72 */ { "erasePoly", 0, "poly" },
266    /* 0x73 */ { "invertPoly", 0, "poly" },
267    /* 0x74 */ { "fillPoly", 0, "poly" },
268    /* 0x75 */ { "reserved", 0, "reserved for Apple use" },
269    /* 0x76 */ { "reserved", 0, "reserved for Apple use" },
270    /* 0x77 */ { "reserved", 0, "reserved for Apple use" },
271    /* 0x78 */ { "frameSamePoly", 0, "poly (NYI)" },
272    /* 0x79 */ { "paintSamePoly", 0, "poly (NYI)" },
273    /* 0x7a */ { "eraseSamePoly", 0, "poly (NYI)" },
274    /* 0x7b */ { "invertSamePoly", 0, "poly (NYI)" },
275    /* 0x7c */ { "fillSamePoly", 0, "poly (NYI)" },
276    /* 0x7d */ { "reserved", 0, "reserved for Apple use" },
277    /* 0x7e */ { "reserved", 0, "reserved for Apple use" },
278    /* 0x7f */ { "reserved", 0, "reserved for Apple use" },
279    /* 0x80 */ { "frameRgn", 0, "region" },
280    /* 0x81 */ { "paintRgn", 0, "region" },
281    /* 0x82 */ { "eraseRgn", 0, "region" },
282    /* 0x83 */ { "invertRgn", 0, "region" },
283    /* 0x84 */ { "fillRgn", 0, "region" },
284    /* 0x85 */ { "reserved", 0, "reserved for Apple use" },
285    /* 0x86 */ { "reserved", 0, "reserved for Apple use" },
286    /* 0x87 */ { "reserved", 0, "reserved for Apple use" },
287    /* 0x88 */ { "frameSameRgn", 0, "region (NYI)" },
288    /* 0x89 */ { "paintSameRgn", 0, "region (NYI)" },
289    /* 0x8a */ { "eraseSameRgn", 0, "region (NYI)" },
290    /* 0x8b */ { "invertSameRgn", 0, "region (NYI)" },
291    /* 0x8c */ { "fillSameRgn", 0, "region (NYI)" },
292    /* 0x8d */ { "reserved", 0, "reserved for Apple use" },
293    /* 0x8e */ { "reserved", 0, "reserved for Apple use" },
294    /* 0x8f */ { "reserved", 0, "reserved for Apple use" },
295    /* 0x90 */ { "BitsRect", 0, "copybits, rect clipped" },
296    /* 0x91 */ { "BitsRgn", 0, "copybits, rgn clipped" },
297    /* 0x92 */ { "reserved", -1, "reserved for Apple use" },
298    /* 0x93 */ { "reserved", -1, "reserved for Apple use" },
299    /* 0x94 */ { "reserved", -1, "reserved for Apple use" },
300    /* 0x95 */ { "reserved", -1, "reserved for Apple use" },
301    /* 0x96 */ { "reserved", -1, "reserved for Apple use" },
302    /* 0x97 */ { "reserved", -1, "reserved for Apple use" },
303    /* 0x98 */ { "PackBitsRect", 0, "packed copybits, rect clipped" },
304    /* 0x99 */ { "PackBitsRgn", 0, "packed copybits, rgn clipped" },
305    /* 0x9a */ { "DirectBitsRect", 0, "PixMap, srcRect, dstRect, mode, PixData" },
306    /* 0x9b */ { "DirectBitsRgn", 0, "PixMap, srcRect, dstRect, mode, maskRgn, PixData" },
307    /* 0x9c */ { "reserved", -1, "reserved for Apple use" },
308    /* 0x9d */ { "reserved", -1, "reserved for Apple use" },
309    /* 0x9e */ { "reserved", -1, "reserved for Apple use" },
310    /* 0x9f */ { "reserved", -1, "reserved for Apple use" },
311    /* 0xa0 */ { "ShortComment", 2, "kind (word)" },
312    /* 0xa1 */ { "LongComment", 0, "kind (word), size (word), data" }
313  };
314
315/*
316  Forward declarations.
317*/
318static MagickBooleanType
319  WritePICTImage(const ImageInfo *,Image *);
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323%                                                                             %
324%                                                                             %
325%                                                                             %
326%   D e c o d e I m a g e                                                     %
327%                                                                             %
328%                                                                             %
329%                                                                             %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332%  DecodeImage decompresses an image via Macintosh pack bits decoding for
333%  Macintosh PICT images.
334%
335%  The format of the DecodeImage method is:
336%
337%      unsigned char *DecodeImage(Image *blob,Image *image,
338%        unsigned long bytes_per_line,const int bits_per_pixel,
339%        unsigned size_t extent)
340%
341%  A description of each parameter follows:
342%
343%    o image_info: the image info.
344%
345%    o blob,image: the address of a structure of type Image.
346%
347%    o bytes_per_line: This integer identifies the number of bytes in a
348%      scanline.
349%
350%    o bits_per_pixel: the number of bits in a pixel.
351%
352%    o extent: the number of pixels allocated.
353%
354*/
355
356static unsigned char *ExpandBuffer(unsigned char *pixels,
357  MagickSizeType *bytes_per_line,const unsigned int bits_per_pixel)
358{
359  register long
360    i;
361
362  register unsigned char
363    *p,
364    *q;
365
366  static unsigned char
367    scanline[8*256];
368
369  p=pixels;
370  q=scanline;
371  switch (bits_per_pixel)
372  {
373    case 8:
374    case 16:
375    case 32:
376      return(pixels);
377    case 4:
378    {
379      for (i=0; i < (long) *bytes_per_line; i++)
380      {
381        *q++=(*p >> 4) & 0xff;
382        *q++=(*p & 15);
383        p++;
384      }
385      *bytes_per_line*=2;
386      break;
387    }
388    case 2:
389    {
390      for (i=0; i < (long) *bytes_per_line; i++)
391      {
392        *q++=(*p >> 6) & 0x03;
393        *q++=(*p >> 4) & 0x03;
394        *q++=(*p >> 2) & 0x03;
395        *q++=(*p & 3);
396        p++;
397      }
398      *bytes_per_line*=4;
399      break;
400    }
401    case 1:
402    {
403      for (i=0; i < (long) *bytes_per_line; i++)
404      {
405        *q++=(*p >> 7) & 0x01;
406        *q++=(*p >> 6) & 0x01;
407        *q++=(*p >> 5) & 0x01;
408        *q++=(*p >> 4) & 0x01;
409        *q++=(*p >> 3) & 0x01;
410        *q++=(*p >> 2) & 0x01;
411        *q++=(*p >> 1) & 0x01;
412        *q++=(*p & 0x01);
413        p++;
414      }
415      *bytes_per_line*=8;
416      break;
417    }
418    default:
419      break;
420  }
421  return(scanline);
422}
423
424static unsigned char *DecodeImage(Image *blob,Image *image,
425  unsigned long bytes_per_line,const unsigned int bits_per_pixel,size_t *extent)
426{
427  long
428    j,
429    y;
430
431  MagickSizeType
432    number_pixels;
433
434  register long
435    i;
436
437  register unsigned char
438    *p,
439    *q;
440
441  size_t
442    length,
443    row_bytes;
444
445  ssize_t
446    count;
447
448  unsigned char
449    *pixels,
450    *scanline;
451
452  unsigned long
453    bytes_per_pixel,
454    scanline_length,
455    width;
456
457  /*
458    Determine pixel buffer size.
459  */
460  if (bits_per_pixel <= 8)
461    bytes_per_line&=0x7fff;
462  width=image->columns;
463  bytes_per_pixel=1;
464  if (bits_per_pixel == 16)
465    {
466      bytes_per_pixel=2;
467      width*=2;
468    }
469  else
470    if (bits_per_pixel == 32)
471      width*=image->matte ? 4 : 3;
472  if (bytes_per_line == 0)
473    bytes_per_line=width;
474  row_bytes=(size_t) (image->columns | 0x8000);
475  if (image->storage_class == DirectClass)
476    row_bytes=(size_t) ((4*image->columns) | 0x8000);
477  /*
478    Allocate pixel and scanline buffer.
479  */
480  pixels=(unsigned char *) AcquireQuantumMemory(image->rows,row_bytes*
481    sizeof(*pixels));
482  if (pixels == (unsigned char *) NULL)
483    return((unsigned char *) NULL);
484  *extent=row_bytes*image->rows*sizeof(*pixels);
485  (void) ResetMagickMemory(pixels,0,*extent);
486  scanline=(unsigned char *) AcquireQuantumMemory(row_bytes,sizeof(*scanline));
487  if (scanline == (unsigned char *) NULL)
488    return((unsigned char *) NULL);
489  if (bytes_per_line < 8)
490    {
491      /*
492        Pixels are already uncompressed.
493      */
494      for (y=0; y < (long) image->rows; y++)
495      {
496        q=pixels+y*width;
497        number_pixels=bytes_per_line;
498        count=ReadBlob(blob,(size_t) number_pixels,scanline);
499        p=ExpandBuffer(scanline,&number_pixels,bits_per_pixel);
500        if ((q+number_pixels) > (pixels+(*extent)))
501          {
502            (void) ThrowMagickException(&image->exception,GetMagickModule(),
503              CorruptImageError,"UnableToUncompressImage","`%s'",
504              image->filename);
505            break;
506          }
507        (void) CopyMagickMemory(q,p,(size_t) number_pixels);
508      }
509      scanline=(unsigned char *) RelinquishMagickMemory(scanline);
510      return(pixels);
511    }
512  /*
513    Uncompress RLE pixels into uncompressed pixel buffer.
514  */
515  for (y=0; y < (long) image->rows; y++)
516  {
517    q=pixels+y*width;
518    if (bytes_per_line > 200)
519      scanline_length=ReadBlobMSBShort(blob);
520    else
521      scanline_length=1UL*ReadBlobByte(blob);
522    if (scanline_length >= row_bytes)
523      {
524        (void) ThrowMagickException(&image->exception,GetMagickModule(),
525          CorruptImageError,"UnableToUncompressImage","`%s'",image->filename);
526        break;
527      }
528    count=ReadBlob(blob,scanline_length,scanline);
529    for (j=0; j < (long) scanline_length; )
530      if ((scanline[j] & 0x80) == 0)
531        {
532          length=(size_t) ((scanline[j] & 0xff)+1);
533          number_pixels=length*bytes_per_pixel;
534          p=ExpandBuffer(scanline+j+1,&number_pixels,bits_per_pixel);
535          if ((q-pixels+number_pixels) <= *extent)
536            (void) CopyMagickMemory(q,p,(size_t) number_pixels);
537          q+=number_pixels;
538          j+=(long) (length*bytes_per_pixel+1);
539        }
540      else
541        {
542          length=(size_t) (((scanline[j] ^ 0xff) & 0xff)+2);
543          number_pixels=bytes_per_pixel;
544          p=ExpandBuffer(scanline+j+1,&number_pixels,bits_per_pixel);
545          for (i=0; i < (long) length; i++)
546          {
547            if ((q-pixels+number_pixels) <= *extent)
548              (void) CopyMagickMemory(q,p,(size_t) number_pixels);
549            q+=number_pixels;
550          }
551          j+=bytes_per_pixel+1;
552        }
553  }
554  scanline=(unsigned char *) RelinquishMagickMemory(scanline);
555  return(pixels);
556}
557
558/*
559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560%                                                                             %
561%                                                                             %
562%                                                                             %
563%   E n c o d e I m a g e                                                     %
564%                                                                             %
565%                                                                             %
566%                                                                             %
567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
568%
569%  EncodeImage compresses an image via Macintosh pack bits encoding
570%  for Macintosh PICT images.
571%
572%  The format of the EncodeImage method is:
573%
574%      size_t EncodeImage(Image *image,const unsigned char *scanline,
575%        const unsigned long bytes_per_line,unsigned char *pixels)
576%
577%  A description of each parameter follows:
578%
579%    o image: the address of a structure of type Image.
580%
581%    o scanline: A pointer to an array of characters to pack.
582%
583%    o bytes_per_line: the number of bytes in a scanline.
584%
585%    o pixels: A pointer to an array of characters where the packed
586%      characters are stored.
587%
588%
589*/
590static size_t EncodeImage(Image *image,const unsigned char *scanline,
591  const unsigned long bytes_per_line,unsigned char *pixels)
592{
593#define MaxCount  128
594#define MaxPackbitsRunlength  128
595
596  long
597    count,
598    repeat_count,
599    runlength;
600
601  register const unsigned char
602    *p;
603
604  register long
605    i;
606
607  register unsigned char
608    *q;
609
610  size_t
611    length;
612
613  unsigned char
614    index;
615
616  /*
617    Pack scanline.
618  */
619  assert(image != (Image *) NULL);
620  assert(image->signature == MagickSignature);
621  if (image->debug != MagickFalse)
622    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
623  assert(scanline != (unsigned char *) NULL);
624  assert(pixels != (unsigned char *) NULL);
625  count=0;
626  runlength=0;
627  p=scanline+(bytes_per_line-1);
628  q=pixels;
629  index=(*p);
630  for (i=(long) bytes_per_line-1; i >= 0; i--)
631  {
632    if (index == *p)
633      runlength++;
634    else
635      {
636        if (runlength < 3)
637          while (runlength > 0)
638          {
639            *q++=(unsigned char) index;
640            runlength--;
641            count++;
642            if (count == MaxCount)
643              {
644                *q++=(unsigned char) (MaxCount-1);
645                count-=MaxCount;
646              }
647          }
648        else
649          {
650            if (count > 0)
651              *q++=(unsigned char) (count-1);
652            count=0;
653            while (runlength > 0)
654            {
655              repeat_count=runlength;
656              if (repeat_count > MaxPackbitsRunlength)
657                repeat_count=MaxPackbitsRunlength;
658              *q++=(unsigned char) index;
659              *q++=(unsigned char) (257-repeat_count);
660              runlength-=repeat_count;
661            }
662          }
663        runlength=1;
664      }
665    index=(*p);
666    p--;
667  }
668  if (runlength < 3)
669    while (runlength > 0)
670    {
671      *q++=(unsigned char) index;
672      runlength--;
673      count++;
674      if (count == MaxCount)
675        {
676          *q++=(unsigned char) (MaxCount-1);
677          count-=MaxCount;
678        }
679    }
680  else
681    {
682      if (count > 0)
683        *q++=(unsigned char) (count-1);
684      count=0;
685      while (runlength > 0)
686      {
687        repeat_count=runlength;
688        if (repeat_count > MaxPackbitsRunlength)
689          repeat_count=MaxPackbitsRunlength;
690        *q++=(unsigned char) index;
691        *q++=(unsigned char) (257-repeat_count);
692        runlength-=repeat_count;
693      }
694    }
695  if (count > 0)
696    *q++=(unsigned char) (count-1);
697  /*
698    Write the number of and the packed length.
699  */
700  length=(size_t) (q-pixels);
701  if (bytes_per_line > 200)
702    {
703      (void) WriteBlobMSBShort(image,(unsigned short) length);
704      length+=2;
705    }
706  else
707    {
708      (void) WriteBlobByte(image,(unsigned char) length);
709      length++;
710    }
711  while (q != pixels)
712  {
713    q--;
714    (void) WriteBlobByte(image,*q);
715  }
716  return(length);
717}
718
719/*
720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
721%                                                                             %
722%                                                                             %
723%                                                                             %
724%   I s P I C T                                                               %
725%                                                                             %
726%                                                                             %
727%                                                                             %
728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
729%
730%  IsPICT()() returns MagickTrue if the image format type, identified by the
731%  magick string, is PICT.
732%
733%  The format of the ReadPICTImage method is:
734%
735%      MagickBooleanType IsPICT(const unsigned char *magick,const size_t length)
736%
737%  A description of each parameter follows:
738%
739%    o magick: This string is generally the first few bytes of an image file
740%      or blob.
741%
742%    o length: Specifies the length of the magick string.
743%
744%
745*/
746static MagickBooleanType IsPICT(const unsigned char *magick,const size_t length)
747{
748  if (length < 528)
749    return(MagickFalse);
750  if (memcmp(magick+522,"\000\021\002\377\014\000",6) == 0)
751    return(MagickTrue);
752  return(MagickFalse);
753}
754
755#if !defined(macintosh)
756/*
757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758%                                                                             %
759%                                                                             %
760%                                                                             %
761%   R e a d P I C T I m a g e                                                 %
762%                                                                             %
763%                                                                             %
764%                                                                             %
765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766%
767%  ReadPICTImage() reads an Apple Macintosh QuickDraw/PICT image file
768%  and returns it.  It allocates the memory necessary for the new Image
769%  structure and returns a pointer to the new image.
770%
771%  The format of the ReadPICTImage method is:
772%
773%      Image *ReadPICTImage(const ImageInfo *image_info,
774%        ExceptionInfo *exception)
775%
776%  A description of each parameter follows:
777%
778%    o image_info: the image info.
779%
780%    o exception: return any errors or warnings in this structure.
781%
782*/
783
784static inline unsigned long MagickMax(const unsigned long x,
785  const unsigned long y)
786{
787  if (x > y)
788    return(x);
789  return(y);
790}
791
792static Image *ReadPICTImage(const ImageInfo *image_info,
793  ExceptionInfo *exception)
794{
795  char
796    geometry[MaxTextExtent];
797
798  Image
799    *image;
800
801  IndexPacket
802    index;
803
804  int
805    c,
806    code;
807
808  long
809    flags,
810    j,
811    version,
812    y;
813
814  MagickBooleanType
815    jpeg,
816    status;
817
818  PICTRectangle
819    frame;
820
821  PICTPixmap
822    pixmap;
823
824  register IndexPacket
825    *indexes;
826
827  register long
828    x;
829
830  register PixelPacket
831    *q;
832
833  register long
834    i;
835
836  size_t
837    extent,
838    length;
839
840  ssize_t
841    count;
842
843  StringInfo
844    *profile;
845
846  /*
847    Open image file.
848  */
849  assert(image_info != (const ImageInfo *) NULL);
850  assert(image_info->signature == MagickSignature);
851  if (image_info->debug != MagickFalse)
852    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
853      image_info->filename);
854  assert(exception != (ExceptionInfo *) NULL);
855  assert(exception->signature == MagickSignature);
856  image=AcquireImage(image_info);
857  image->depth=8;
858  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
859  if (status == MagickFalse)
860    {
861      image=DestroyImageList(image);
862      return((Image *) NULL);
863    }
864  /*
865    Read PICT header.
866  */
867  pixmap.bits_per_pixel=0;
868  pixmap.component_count=0;
869  for (i=0; i < 512; i++)
870    (void) ReadBlobByte(image);  /* skip header */
871  (void) ReadBlobMSBShort(image);  /* skip picture size */
872  ReadRectangle(image,frame);