Coverage Report

Created: 2026-01-20 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/pict.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2025 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                        PPPP   IIIII   CCCC  TTTTT                           %
15
%                        P   P    I    C        T                             %
16
%                        PPPP     I    C        T                             %
17
%                        P        I    C        T                             %
18
%                        P      IIIII   CCCC    T                             %
19
%                                                                             %
20
%                                                                             %
21
%              Read/Write Apple Macintosh QuickDraw/PICT Format.              %
22
%                                                                             %
23
%                                                                             %
24
%                              Software Design                                %
25
%                                John Cristy                                  %
26
%                                 July 1992                                   %
27
%                                                                             %
28
%                                                                             %
29
%                                                                             %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31
%
32
%
33
*/
34

35
/*
36
  Include declarations.
37
*/
38
#include "magick/studio.h"
39
#include "magick/blob.h"
40
#include "magick/colormap.h"
41
#include "magick/composite.h"
42
#include "magick/constitute.h"
43
#include "magick/log.h"
44
#include "magick/magick.h"
45
#include "magick/monitor.h"
46
#include "magick/pixel_cache.h"
47
#include "magick/profile.h"
48
#include "magick/tempfile.h"
49
#include "magick/transform.h"
50
#include "magick/utility.h"
51
#include "magick/static.h"
52

53
/*
54
  GraphicsMagick Macintosh PICT Methods.
55
*/
56
#define ReadPixmap(pixmap)                                             \
57
9.64k
  {                                                                    \
58
9.64k
  pixmap.version=ReadBlobMSBShort(image);                              \
59
9.64k
  pixmap.pack_type=ReadBlobMSBShort(image);                            \
60
9.64k
  pixmap.pack_size=ReadBlobMSBLong(image);                             \
61
9.64k
  pixmap.horizontal_resolution=ReadBlobMSBLong(image);                 \
62
9.64k
  pixmap.vertical_resolution=ReadBlobMSBLong(image);                   \
63
9.64k
  pixmap.pixel_type=ReadBlobMSBShort(image);                           \
64
9.64k
  pixmap.bits_per_pixel=ReadBlobMSBShort(image);                       \
65
9.64k
  pixmap.component_count=ReadBlobMSBShort(image);                      \
66
9.64k
  pixmap.component_size=ReadBlobMSBShort(image);                       \
67
9.64k
  pixmap.plane_bytes=ReadBlobMSBLong(image);                           \
68
9.64k
  pixmap.table=ReadBlobMSBLong(image);                                 \
69
9.64k
  pixmap.reserved=ReadBlobMSBLong(image);                              \
70
9.64k
  }
71
72
#define ValidatePixmap(pixmap) \
73
9.64k
  (!(EOFBlob(image) ||                                                 \
74
9.64k
     pixmap.bits_per_pixel <= 0 || pixmap.bits_per_pixel > 32 ||       \
75
9.64k
     pixmap.component_count <= 0 || pixmap.component_count > 4 ||      \
76
9.64k
     pixmap.component_size <= 0))
77
78
/*
79
  Read a PICT rectangle
80
*/
81
#define ReadRectangle(rectangle)                                       \
82
264k
  {                                                                    \
83
264k
  rectangle.top=ReadBlobMSBShort(image);                               \
84
264k
  rectangle.left=ReadBlobMSBShort(image);                              \
85
264k
  rectangle.bottom=ReadBlobMSBShort(image);                            \
86
264k
  rectangle.right=ReadBlobMSBShort(image);                             \
87
264k
  }
88
89
/*
90
  Return true if PICT rectangle is valid.
91
*/
92
#define ValidateRectangle(rectangle) \
93
264k
  ((!EOFBlob(image) && \
94
264k
    !((rectangle.bottom | rectangle.top | rectangle.right | rectangle.left ) & 0x8000) && \
95
264k
    !(rectangle.bottom < rectangle.top) && \
96
264k
    !(rectangle.right < rectangle.left)))
97
98
/*
99
  Issue a trace message with rectangle dimensions.
100
*/
101
#define TraceRectangle(image,rectangle)                         \
102
264k
  do                                                            \
103
264k
    {                                                           \
104
264k
      if (IsEventLogged(CoderEvent))                            \
105
264k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),     \
106
0
                              "%sRectangle: top %+d, bottom %+d, " \
107
0
                              "left %+d, right %+d",            \
108
0
                              EOFBlob(image) ? "EOF! " : "",    \
109
0
                              (int) frame.top,                  \
110
0
                              (int) frame.bottom,               \
111
0
                              (int) frame.left,                 \
112
0
                              (int) frame.right);               \
113
264k
    } while(0)
114
115
/*
116
  Issue a trace message with pixmap details
117
 */
118
#define TracePixMap(image,pixmap) \
119
10.1k
  do \
120
10.1k
    { \
121
10.1k
      if (IsEventLogged(CoderEvent))                                    \
122
10.1k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),             \
123
0
                              "PixMap:\n"                               \
124
0
                              "    version:                %u\n"        \
125
0
                              "    pack_type:              %u\n"    \
126
0
                              "    pack_size:              %u\n"        \
127
0
                              "    horizontal_resolution:  %u\n"        \
128
0
                              "    vertical_resolution:    %u\n"        \
129
0
                              "    pixel_type:             %u\n"        \
130
0
                              "    bits_per_pixel:         %u\n"        \
131
0
                              "    component_count:        %u\n"        \
132
0
                              "    component_size:         %u\n"        \
133
0
                              "    plane_bytes:            %u\n"        \
134
0
                              "    table:                  %u\n"        \
135
0
                              "    reserved:               %u",         \
136
0
                              (unsigned) pixmap.version,                \
137
0
                              (unsigned) pixmap.pack_type,              \
138
0
                              pixmap.pack_size,                         \
139
0
                              pixmap.horizontal_resolution,             \
140
0
                              pixmap.vertical_resolution,               \
141
0
                              (unsigned) pixmap.pixel_type,             \
142
0
                              (unsigned) pixmap.bits_per_pixel,         \
143
0
                              (unsigned) pixmap.component_count,        \
144
0
                              (unsigned) pixmap.component_size,         \
145
0
                              pixmap.plane_bytes,                       \
146
0
                              pixmap.table,                             \
147
0
                              pixmap.reserved);                         \
148
10.1k
    } while(0)
149
150
typedef struct _PICTPixmap
151
{
152
  magick_uint16_t
153
    version,
154
    pack_type; /* 0: default, 1: no packing, 2: 24-bit data, 3: RLE (16 bit) 4: RLE (32-bit) */
155
156
  magick_uint32_t
157
    pack_size,
158
    horizontal_resolution,
159
    vertical_resolution;
160
161
  magick_uint16_t
162
    pixel_type,
163
    bits_per_pixel,
164
    component_count,
165
    component_size;
166
167
  magick_uint32_t
168
    plane_bytes,
169
    table,
170
    reserved;
171
} PICTPixmap;
172
173
typedef struct _PICTRectangle
174
{
175
  magick_uint16_t
176
    top,
177
    left,
178
    bottom,
179
    right;
180
} PICTRectangle;
181
182
/* From https://developer.apple.com/library/archive/documentation/mac/QuickDraw/QuickDraw-461.html */
183
184
/* Code Lengths */
185
static const magick_int8_t code_lengths[]=
186
  {
187
    /* 0x00 */ 0,
188
    /* 0x01 */ 0,
189
    /* 0x02 */ 8,
190
    /* 0x03 */ 2,
191
    /* 0x04 */ 1,
192
    /* 0x05 */ 2,
193
    /* 0x06 */ 4,
194
    /* 0x07 */ 4,
195
    /* 0x08 */ 2,
196
    /* 0x09 */ 8,
197
    /* 0x0A */ 8,
198
    /* 0x0B */ 4,
199
    /* 0x0C */ 4,
200
    /* 0x0D */ 2,
201
    /* 0x0E */ 4,
202
    /* 0x0F */ 4,
203
    /* 0x10 */ 8,
204
    /* 0x11 */ 1,
205
    /* 0x12 */ 0,
206
    /* 0x13 */ 0,
207
    /* 0x14 */ 0,
208
    /* 0x15 */ 2,
209
    /* 0x16 */ 2,
210
    /* 0x17 */ 0,
211
    /* 0x18 */ 0,
212
    /* 0x19 */ 0,
213
    /* 0x1A */ 6,
214
    /* 0x1B */ 6,
215
    /* 0x1C */ 0,
216
    /* 0x1D */ 6,
217
    /* 0x1E */ 0,
218
    /* 0x1F */ 6,
219
    /* 0x20 */ 8,
220
    /* 0x21 */ 4,
221
    /* 0x22 */ 6,
222
    /* 0x23 */ 2,
223
    /* 0x24 */ -1,
224
    /* 0x25 */ -1,
225
    /* 0x26 */ -1,
226
    /* 0x27 */ -1,
227
    /* 0x28 */ 0,
228
    /* 0x29 */ 0,
229
    /* 0x2A */ 0,
230
    /* 0x2B */ 0,
231
    /* 0x2C */ -1,
232
    /* 0x2D */ -1,
233
    /* 0x2E */ -1,
234
    /* 0x2F */ -1,
235
    /* 0x30 */ 8,
236
    /* 0x31 */ 8,
237
    /* 0x32 */ 8,
238
    /* 0x33 */ 8,
239
    /* 0x34 */ 8,
240
    /* 0x35 */ 8,
241
    /* 0x36 */ 8,
242
    /* 0x37 */ 8,
243
    /* 0x38 */ 0,
244
    /* 0x39 */ 0,
245
    /* 0x3A */ 0,
246
    /* 0x3B */ 0,
247
    /* 0x3C */ 0,
248
    /* 0x3D */ 0,
249
    /* 0x3E */ 0,
250
    /* 0x3F */ 0,
251
    /* 0x40 */ 8,
252
    /* 0x41 */ 8,
253
    /* 0x42 */ 8,
254
    /* 0x43 */ 8,
255
    /* 0x44 */ 8,
256
    /* 0x45 */ 8,
257
    /* 0x46 */ 8,
258
    /* 0x47 */ 8,
259
    /* 0x48 */ 0,
260
    /* 0x49 */ 0,
261
    /* 0x4A */ 0,
262
    /* 0x4B */ 0,
263
    /* 0x4C */ 0,
264
    /* 0x4D */ 0,
265
    /* 0x4E */ 0,
266
    /* 0x4F */ 0,
267
    /* 0x50 */ 8,
268
    /* 0x51 */ 8,
269
    /* 0x52 */ 8,
270
    /* 0x53 */ 8,
271
    /* 0x54 */ 8,
272
    /* 0x55 */ 8,
273
    /* 0x56 */ 8,
274
    /* 0x57 */ 8,
275
    /* 0x58 */ 0,
276
    /* 0x59 */ 0,
277
    /* 0x5A */ 0,
278
    /* 0x5B */ 0,
279
    /* 0x5C */ 0,
280
    /* 0x5D */ 0,
281
    /* 0x5E */ 0,
282
    /* 0x5F */ 0,
283
    /* 0x60 */ 12,
284
    /* 0x61 */ 12,
285
    /* 0x62 */ 12,
286
    /* 0x63 */ 12,
287
    /* 0x64 */ 12,
288
    /* 0x65 */ 12,
289
    /* 0x66 */ 12,
290
    /* 0x67 */ 12,
291
    /* 0x68 */ 4,
292
    /* 0x69 */ 4,
293
    /* 0x6A */ 4,
294
    /* 0x6B */ 4,
295
    /* 0x6C */ 4,
296
    /* 0x6D */ 4,
297
    /* 0x6E */ 4,
298
    /* 0x6F */ 4,
299
    /* 0x70 */ 0,
300
    /* 0x71 */ 0,
301
    /* 0x72 */ 0,
302
    /* 0x73 */ 0,
303
    /* 0x74 */ 0,
304
    /* 0x75 */ 0,
305
    /* 0x76 */ 0,
306
    /* 0x77 */ 0,
307
    /* 0x78 */ 0,
308
    /* 0x79 */ 0,
309
    /* 0x7A */ 0,
310
    /* 0x7B */ 0,
311
    /* 0x7C */ 0,
312
    /* 0x7D */ 0,
313
    /* 0x7E */ 0,
314
    /* 0x7F */ 0,
315
    /* 0x80 */ 0,
316
    /* 0x81 */ 0,
317
    /* 0x82 */ 0,
318
    /* 0x83 */ 0,
319
    /* 0x84 */ 0,
320
    /* 0x85 */ 0,
321
    /* 0x86 */ 0,
322
    /* 0x87 */ 0,
323
    /* 0x88 */ 0,
324
    /* 0x89 */ 0,
325
    /* 0x8A */ 0,
326
    /* 0x8B */ 0,
327
    /* 0x8C */ 0,
328
    /* 0x8D */ 0,
329
    /* 0x8E */ 0,
330
    /* 0x8F */ 0,
331
    /* 0x90 */ 0,
332
    /* 0x91 */ 0,
333
    /* 0x92 */ -1,
334
    /* 0x93 */ -1,
335
    /* 0x94 */ -1,
336
    /* 0x95 */ -1,
337
    /* 0x96 */ -1,
338
    /* 0x97 */ -1,
339
    /* 0x98 */ 0,
340
    /* 0x99 */ 0,
341
    /* 0x9A */ 0,
342
    /* 0x9B */ 0,
343
    /* 0x9C */ -1,
344
    /* 0x9D */ -1,
345
    /* 0x9E */ -1,
346
    /* 0x9F */ -1,
347
    /* 0xA0 */ 2,
348
    /* 0xA1 */ 0
349
  };
350
351
/* Code names */
352
static const char code_names[] =
353
  /* 0x00 */ "NOP\0"
354
  /* 0x01 */ "ClipRgn\0"
355
  /* 0x02 */ "BkPat\0"
356
  /* 0x03 */ "TxFont\0"
357
  /* 0x04 */ "TxFace\0"
358
  /* 0x05 */ "TxMode\0"
359
  /* 0x06 */ "SpExtra\0"
360
  /* 0x07 */ "PnSize\0"
361
  /* 0x08 */ "PnMode\0"
362
  /* 0x09 */ "PnPat\0"
363
  /* 0x0A */ "FillPat\0"
364
  /* 0x0B */ "OvSize\0"
365
  /* 0x0C */ "Origin\0"
366
  /* 0x0D */ "TxSize\0"
367
  /* 0x0E */ "FgColor\0"
368
  /* 0x0F */ "BkColor\0"
369
  /* 0x10 */ "TxRatio\0"
370
  /* 0x11 */ "Version\0"
371
  /* 0x12 */ "BkPixPat\0"
372
  /* 0x13 */ "PnPixPat\0"
373
  /* 0x14 */ "FillPixPat\0"
374
  /* 0x15 */ "PnLocHFrac\0"
375
  /* 0x16 */ "ChExtra\0"
376
  /* 0x17 */ "reserved\0"
377
  /* 0x18 */ "reserved\0"
378
  /* 0x19 */ "reserved\0"
379
  /* 0x1A */ "RGBFgCol\0"
380
  /* 0x1B */ "RGBBkCol\0"
381
  /* 0x1C */ "HiliteMode\0"
382
  /* 0x1D */ "HiliteColor\0"
383
  /* 0x1E */ "DefHilite\0"
384
  /* 0x1F */ "OpColor\0"
385
  /* 0x20 */ "Line\0"
386
  /* 0x21 */ "LineFrom\0"
387
  /* 0x22 */ "ShortLine\0"
388
  /* 0x23 */ "ShortLineFrom\0"
389
  /* 0x24 */ "reserved\0"
390
  /* 0x25 */ "reserved\0"
391
  /* 0x26 */ "reserved\0"
392
  /* 0x27 */ "reserved\0"
393
  /* 0x28 */ "LongText\0"
394
  /* 0x29 */ "DHText\0"
395
  /* 0x2A */ "DVText\0"
396
  /* 0x2B */ "DHDVText\0"
397
  /* 0x2C */ "reserved\0"
398
  /* 0x2D */ "reserved\0"
399
  /* 0x2E */ "reserved\0"
400
  /* 0x2F */ "reserved\0"
401
  /* 0x30 */ "frameRect\0"
402
  /* 0x31 */ "paintRect\0"
403
  /* 0x32 */ "eraseRect\0"
404
  /* 0x33 */ "invertRect\0"
405
  /* 0x34 */ "fillRect\0"
406
  /* 0x35 */ "reserved\0"
407
  /* 0x36 */ "reserved\0"
408
  /* 0x37 */ "reserved\0"
409
  /* 0x38 */ "frameSameRect\0"
410
  /* 0x39 */ "paintSameRect\0"
411
  /* 0x3A */ "eraseSameRect\0"
412
  /* 0x3B */ "invertSameRect\0"
413
  /* 0x3C */ "fillSameRect\0"
414
  /* 0x3D */ "reserved\0"
415
  /* 0x3E */ "reserved\0"
416
  /* 0x3F */ "reserved\0"
417
  /* 0x40 */ "frameRRect\0"
418
  /* 0x41 */ "paintRRect\0"
419
  /* 0x42 */ "eraseRRect\0"
420
  /* 0x43 */ "invertRRect\0"
421
  /* 0x44 */ "fillRRrect\0"
422
  /* 0x45 */ "reserved\0"
423
  /* 0x46 */ "reserved\0"
424
  /* 0x47 */ "reserved\0"
425
  /* 0x48 */ "frameSameRRect\0"
426
  /* 0x49 */ "paintSameRRect\0"
427
  /* 0x4A */ "eraseSameRRect\0"
428
  /* 0x4B */ "invertSameRRect\0"
429
  /* 0x4C */ "fillSameRRect\0"
430
  /* 0x4D */ "reserved\0"
431
  /* 0x4E */ "reserved\0"
432
  /* 0x4F */ "reserved\0"
433
  /* 0x50 */ "frameOval\0"
434
  /* 0x51 */ "paintOval\0"
435
  /* 0x52 */ "eraseOval\0"
436
  /* 0x53 */ "invertOval\0"
437
  /* 0x54 */ "fillOval\0"
438
  /* 0x55 */ "reserved\0"
439
  /* 0x56 */ "reserved\0"
440
  /* 0x57 */ "reserved\0"
441
  /* 0x58 */ "frameSameOval\0"
442
  /* 0x59 */ "paintSameOval\0"
443
  /* 0x5A */ "eraseSameOval\0"
444
  /* 0x5B */ "invertSameOval\0"
445
  /* 0x5C */ "fillSameOval\0"
446
  /* 0x5D */ "reserved\0"
447
  /* 0x5E */ "reserved\0"
448
  /* 0x5F */ "reserved\0"
449
  /* 0x60 */ "frameArc\0"
450
  /* 0x61 */ "paintArc\0"
451
  /* 0x62 */ "eraseArc\0"
452
  /* 0x63 */ "invertArc\0"
453
  /* 0x64 */ "fillArc\0"
454
  /* 0x65 */ "reserved\0"
455
  /* 0x66 */ "reserved\0"
456
  /* 0x67 */ "reserved\0"
457
  /* 0x68 */ "frameSameArc\0"
458
  /* 0x69 */ "paintSameArc\0"
459
  /* 0x6A */ "eraseSameArc\0"
460
  /* 0x6B */ "invertSameArc\0"
461
  /* 0x6C */ "fillSameArc\0"
462
  /* 0x6D */ "reserved\0"
463
  /* 0x6E */ "reserved\0"
464
  /* 0x6F */ "reserved\0"
465
  /* 0x70 */ "framePoly\0"
466
  /* 0x71 */ "paintPoly\0"
467
  /* 0x72 */ "erasePoly\0"
468
  /* 0x73 */ "invertPoly\0"
469
  /* 0x74 */ "fillPoly\0"
470
  /* 0x75 */ "reserved\0"
471
  /* 0x76 */ "reserved\0"
472
  /* 0x77 */ "reserved\0"
473
  /* 0x78 */ "frameSamePoly\0"
474
  /* 0x79 */ "paintSamePoly\0"
475
  /* 0x7A */ "eraseSamePoly\0"
476
  /* 0x7B */ "invertSamePoly\0"
477
  /* 0x7C */ "fillSamePoly\0"
478
  /* 0x7D */ "reserved\0"
479
  /* 0x7E */ "reserved\0"
480
  /* 0x7F */ "reserved\0"
481
  /* 0x80 */ "frameRgn\0"
482
  /* 0x81 */ "paintRgn\0"
483
  /* 0x82 */ "eraseRgn\0"
484
  /* 0x83 */ "invertRgn\0"
485
  /* 0x84 */ "fillRgn\0"
486
  /* 0x85 */ "reserved\0"
487
  /* 0x86 */ "reserved\0"
488
  /* 0x87 */ "reserved\0"
489
  /* 0x88 */ "frameSameRgn\0"
490
  /* 0x89 */ "paintSameRgn\0"
491
  /* 0x8A */ "eraseSameRgn\0"
492
  /* 0x8B */ "invertSameRgn\0"
493
  /* 0x8C */ "fillSameRgn\0"
494
  /* 0x8D */ "reserved\0"
495
  /* 0x8E */ "reserved\0"
496
  /* 0x8F */ "reserved\0"
497
  /* 0x90 */ "BitsRect\0"
498
  /* 0x91 */ "BitsRgn\0"
499
  /* 0x92 */ "reserved\0"
500
  /* 0x93 */ "reserved\0"
501
  /* 0x94 */ "reserved\0"
502
  /* 0x95 */ "reserved\0"
503
  /* 0x96 */ "reserved\0"
504
  /* 0x97 */ "reserved\0"
505
  /* 0x98 */ "PackBitsRect\0"
506
  /* 0x99 */ "PackBitsRgn\0"
507
  /* 0x9A */ "DirectBitsRect\0"
508
  /* 0x9B */ "DirectBitsRgn\0"
509
  /* 0x9C */ "reserved\0"
510
  /* 0x9D */ "reserved\0"
511
  /* 0x9E */ "reserved\0"
512
  /* 0x9F */ "reserved\0"
513
  /* 0xA0 */ "ShortComment\0"
514
  /* 0xA1 */ "LongComment\0";
515
516
/* Code Descriptions */
517
static const char code_descriptions[] =
518
  /* 0x00 */ "nop\0"
519
  /* 0x01 */ "clip\0"
520
  /* 0x02 */ "background pattern\0"
521
  /* 0x03 */ "text font (word)\0"
522
  /* 0x04 */ "text face (byte)\0"
523
  /* 0x05 */ "text mode (word)\0"
524
  /* 0x06 */ "space extra (fixed point)\0"
525
  /* 0x07 */ "pen size (point)\0"
526
  /* 0x08 */ "pen mode (word)\0"
527
  /* 0x09 */ "pen pattern\0"
528
  /* 0x0A */ "fill pattern\0"
529
  /* 0x0B */ "oval size (point)\0"
530
  /* 0x0C */ "dh, dv (word)\0"
531
  /* 0x0D */ "text size (word)\0"
532
  /* 0x0E */ "foreground color (longword)\0"
533
  /* 0x0F */ "background color (longword)\0"
534
  /* 0x10 */ "numerator (point), denominator (point)\0"
535
  /* 0x11 */ "version (byte)\0"
536
  /* 0x12 */ "color background pattern\0"
537
  /* 0x13 */ "color pen pattern\0"
538
  /* 0x14 */ "color fill pattern\0"
539
  /* 0x15 */ "fractional pen position\0"
540
  /* 0x16 */ "extra for each character\0"
541
  /* 0x17 */ "reserved for Apple use\0"
542
  /* 0x18 */ "reserved for Apple use\0"
543
  /* 0x19 */ "reserved for Apple use\0"
544
  /* 0x1A */ "RGB foreColor\0"
545
  /* 0x1B */ "RGB backColor\0"
546
  /* 0x1C */ "hilite mode flag\0"
547
  /* 0x1D */ "RGB hilite color\0"
548
  /* 0x1E */ "Use default hilite color\0"
549
  /* 0x1F */ "RGB OpColor for arithmetic modes\0"
550
  /* 0x20 */ "pnLoc (point), newPt (point)\0"
551
  /* 0x21 */ "newPt (point)\0"
552
  /* 0x22 */ "pnLoc (point, dh, dv (-128 .. 127))\0"
553
  /* 0x23 */ "dh, dv (-128 .. 127)\0"
554
  /* 0x24 */ "reserved for Apple use\0"
555
  /* 0x25 */ "reserved for Apple use\0"
556
  /* 0x26 */ "reserved for Apple use\0"
557
  /* 0x27 */ "reserved for Apple use\0"
558
  /* 0x28 */ "txLoc (point), count (0..255), text\0"
559
  /* 0x29 */ "dh (0..255), count (0..255), text\0"
560
  /* 0x2A */ "dv (0..255), count (0..255), text\0"
561
  /* 0x2B */ "dh, dv (0..255), count (0..255), text\0"
562
  /* 0x2C */ "reserved for Apple use\0"
563
  /* 0x2D */ "reserved for Apple use\0"
564
  /* 0x2E */ "reserved for Apple use\0"
565
  /* 0x2F */ "reserved for Apple use\0"
566
  /* 0x30 */ "rect\0"
567
  /* 0x31 */ "rect\0"
568
  /* 0x32 */ "rect\0"
569
  /* 0x33 */ "rect\0"
570
  /* 0x34 */ "rect\0"
571
  /* 0x35 */ "reserved for Apple use\0"
572
  /* 0x36 */ "reserved for Apple use\0"
573
  /* 0x37 */ "reserved for Apple use\0"
574
  /* 0x38 */ "rect\0"
575
  /* 0x39 */ "rect\0"
576
  /* 0x3A */ "rect\0"
577
  /* 0x3B */ "rect\0"
578
  /* 0x3C */ "rect\0"
579
  /* 0x3D */ "reserved for Apple use\0"
580
  /* 0x3E */ "reserved for Apple use\0"
581
  /* 0x3F */ "reserved for Apple use\0"
582
  /* 0x40 */ "rect\0"
583
  /* 0x41 */ "rect\0"
584
  /* 0x42 */ "rect\0"
585
  /* 0x43 */ "rect\0"
586
  /* 0x44 */ "rect\0"
587
  /* 0x45 */ "reserved for Apple use\0"
588
  /* 0x46 */ "reserved for Apple use\0"
589
  /* 0x47 */ "reserved for Apple use\0"
590
  /* 0x48 */ "rect\0"
591
  /* 0x49 */ "rect\0"
592
  /* 0x4A */ "rect\0"
593
  /* 0x4B */ "rect\0"
594
  /* 0x4C */ "rect\0"
595
  /* 0x4D */ "reserved for Apple use\0"
596
  /* 0x4E */ "reserved for Apple use\0"
597
  /* 0x4F */ "reserved for Apple use\0"
598
  /* 0x50 */ "rect\0"
599
  /* 0x51 */ "rect\0"
600
  /* 0x52 */ "rect\0"
601
  /* 0x53 */ "rect\0"
602
  /* 0x54 */ "rect\0"
603
  /* 0x55 */ "reserved for Apple use\0"
604
  /* 0x56 */ "reserved for Apple use\0"
605
  /* 0x57 */ "reserved for Apple use\0"
606
  /* 0x58 */ "rect\0"
607
  /* 0x59 */ "rect\0"
608
  /* 0x5A */ "rect\0"
609
  /* 0x5B */ "rect\0"
610
  /* 0x5C */ "rect\0"
611
  /* 0x5D */ "reserved for Apple use\0"
612
  /* 0x5E */ "reserved for Apple use\0"
613
  /* 0x5F */ "reserved for Apple use\0"
614
  /* 0x60 */ "rect, startAngle, arcAngle\0"
615
  /* 0x61 */ "rect, startAngle, arcAngle\0"
616
  /* 0x62 */ "rect, startAngle, arcAngle\0"
617
  /* 0x63 */ "rect, startAngle, arcAngle\0"
618
  /* 0x64 */ "rect, startAngle, arcAngle\0"
619
  /* 0x65 */ "reserved for Apple use\0"
620
  /* 0x66 */ "reserved for Apple use\0"
621
  /* 0x67 */ "reserved for Apple use\0"
622
  /* 0x68 */ "rect, startAngle, arcAngle\0"
623
  /* 0x69 */ "rect, startAngle, arcAngle\0"
624
  /* 0x6A */ "rect, startAngle, arcAngle\0"
625
  /* 0x6B */ "rect, startAngle, arcAngle\0"
626
  /* 0x6C */ "rect, startAngle, arcAngle\0"
627
  /* 0x6D */ "reserved for Apple use\0"
628
  /* 0x6E */ "reserved for Apple use\0"
629
  /* 0x6F */ "reserved for Apple use\0"
630
  /* 0x70 */ "poly\0"
631
  /* 0x71 */ "poly\0"
632
  /* 0x72 */ "poly\0"
633
  /* 0x73 */ "poly\0"
634
  /* 0x74 */ "poly\0"
635
  /* 0x75 */ "reserved for Apple use\0"
636
  /* 0x76 */ "reserved for Apple use\0"
637
  /* 0x77 */ "reserved for Apple use\0"
638
  /* 0x78 */ "poly (NYI)\0"
639
  /* 0x79 */ "poly (NYI)\0"
640
  /* 0x7A */ "poly (NYI)\0"
641
  /* 0x7B */ "poly (NYI)\0"
642
  /* 0x7C */ "poly (NYI)\0"
643
  /* 0x7D */ "reserved for Apple use\0"
644
  /* 0x7E */ "reserved for Apple use\0"
645
  /* 0x7F */ "reserved for Apple use\0"
646
  /* 0x80 */ "region\0"
647
  /* 0x81 */ "region\0"
648
  /* 0x82 */ "region\0"
649
  /* 0x83 */ "region\0"
650
  /* 0x84 */ "region\0"
651
  /* 0x85 */ "reserved for Apple use\0"
652
  /* 0x86 */ "reserved for Apple use\0"
653
  /* 0x87 */ "reserved for Apple use\0"
654
  /* 0x88 */ "region (NYI)\0"
655
  /* 0x89 */ "region (NYI)\0"
656
  /* 0x8A */ "region (NYI)\0"
657
  /* 0x8B */ "region (NYI)\0"
658
  /* 0x8C */ "region (NYI)\0"
659
  /* 0x8D */ "reserved for Apple use\0"
660
  /* 0x8E */ "reserved for Apple use\0"
661
  /* 0x8F */ "reserved for Apple use\0"
662
  /* 0x90 */ "copybits, rect clipped\0"
663
  /* 0x91 */ "copybits, rgn clipped\0"
664
  /* 0x92 */ "reserved for Apple use\0"
665
  /* 0x93 */ "reserved for Apple use\0"
666
  /* 0x94 */ "reserved for Apple use\0"
667
  /* 0x95 */ "reserved for Apple use\0"
668
  /* 0x96 */ "reserved for Apple use\0"
669
  /* 0x97 */ "reserved for Apple use\0"
670
  /* 0x98 */ "packed copybits, rect clipped\0"
671
  /* 0x99 */ "packed copybits, rgn clipped\0"
672
  /* 0x9A */ "PixMap, srcRect, dstRect, mode, PixData\0"
673
  /* 0x9B */ "PixMap, srcRect, dstRect, mode, maskRgn, PixData\0"
674
  /* 0x9C */ "reserved for Apple use\0"
675
  /* 0x9D */ "reserved for Apple use\0"
676
  /* 0x9E */ "reserved for Apple use\0"
677
  /* 0x9F */ "reserved for Apple use\0"
678
  /* 0xA0 */ "kind (word)\0"
679
  /* 0xA1 */ "kind (word), size (word), data\0";
680
681
/*
682
  Forward declarations.
683
*/
684
static unsigned int
685
  WritePICTImage(const ImageInfo *,Image *);
686
687
static const char *lookup_string(const char *table, const size_t table_size, const unsigned int index)
688
0
{
689
0
    size_t count;
690
0
    const char *p = table;
691
0
    for (count = 0;
692
0
         (count < index) && (p < table+table_size-1);
693
0
         p++)
694
0
    {
695
0
        if (*p == '\0')
696
0
          count++;
697
0
    }
698
0
    return p;
699
0
}
700
701

702
/*
703
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
704
%                                                                             %
705
%                                                                             %
706
%                                                                             %
707
%   D e c o d e I m a g e                                                     %
708
%                                                                             %
709
%                                                                             %
710
%                                                                             %
711
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
712
%
713
%  Method DecodeImage decompresses an image via Macintosh pack bits
714
%  decoding for Macintosh PICT images.
715
%
716
%  The format of the DecodeImage method is:
717
%
718
%      unsigned char* DecodeImage(const ImageInfo *image_info,Image *blob,
719
%        Image *image,unsigned long bytes_per_line,const int bits_per_pixel)
720
%
721
%  A description of each parameter follows:
722
%
723
%    o status:  Method DecodeImage returns True if all the pixels are
724
%      uncompressed without error, otherwise False.
725
%
726
%    o image_info: Specifies a pointer to a ImageInfo structure.
727
%
728
%    o blob,image: The address of a structure of type Image.
729
%
730
%    o bytes_per_line: This integer identifies the number of bytes in a
731
%      scanline.
732
%
733
%    o bits_per_pixel: The number of bits in a pixel.
734
%
735
%
736
*/
737
738
static const unsigned char *ExpandBuffer(unsigned char *expand_buffer,
739
                                         const unsigned char * restrict pixels,
740
                                         unsigned long * restrict bytes_per_line,
741
                                         const unsigned int bits_per_pixel)
742
220k
{
743
220k
  register unsigned long
744
220k
    i;
745
746
220k
  register const unsigned char
747
220k
    *p;
748
749
220k
  register unsigned char
750
220k
    *q;
751
752
220k
  p=pixels;
753
220k
  q=expand_buffer;
754
220k
  switch (bits_per_pixel)
755
220k
  {
756
6.98k
    case 8:
757
9.01k
    case 16:
758
11.6k
    case 32:
759
11.6k
      return(pixels);
760
7.20k
    case 4:
761
7.20k
    {
762
19.1k
      for (i=0; i < *bytes_per_line; i++, p++)
763
11.9k
      {
764
11.9k
        *q++=(*p >> 4U) & 0xffU;
765
11.9k
        *q++=(*p & 15U);
766
11.9k
      }
767
7.20k
      *bytes_per_line*=2;
768
7.20k
      break;
769
9.01k
    }
770
42.8k
    case 2:
771
42.8k
    {
772
87.2k
      for (i=0; i < *bytes_per_line; i++, p++)
773
44.3k
      {
774
44.3k
        *q++=(*p >> 6U) & 0x03U;
775
44.3k
        *q++=(*p >> 4U) & 0x03U;
776
44.3k
        *q++=(*p >> 2U) & 0x03U;
777
44.3k
        *q++=(*p & 3U);
778
44.3k
      }
779
42.8k
      *bytes_per_line*=4;
780
42.8k
      break;
781
9.01k
    }
782
148k
    case 1:
783
148k
    {
784
473k
      for (i=0; i < *bytes_per_line; i++, p++)
785
324k
      {
786
324k
        *q++=(*p >> 7) & 0x01;
787
324k
        *q++=(*p >> 6) & 0x01;
788
324k
        *q++=(*p >> 5) & 0x01;
789
324k
        *q++=(*p >> 4) & 0x01;
790
324k
        *q++=(*p >> 3) & 0x01;
791
324k
        *q++=(*p >> 2) & 0x01;
792
324k
        *q++=(*p >> 1) & 0x01;
793
324k
        *q++=(*p & 0x01);
794
324k
      }
795
148k
      *bytes_per_line*=8;
796
148k
      break;
797
9.01k
    }
798
9.45k
    default:
799
9.45k
      break;
800
220k
  }
801
208k
  return(expand_buffer);
802
220k
}
803
804
static unsigned char *DecodeImage(const ImageInfo *image_info,
805
                                  Image *blob,Image *image,
806
                                  unsigned long bytes_per_line,
807
                                  const unsigned int bits_per_pixel)
808
27.1k
{
809
27.1k
  unsigned long
810
27.1k
    y;
811
812
27.1k
  register const unsigned char
813
27.1k
    *p;
814
815
27.1k
  register unsigned char
816
27.1k
    *q;
817
818
27.1k
  size_t
819
27.1k
    allocated_pixels,
820
27.1k
    scanline_alloc,
821
27.1k
    row_bytes;
822
823
27.1k
  unsigned char
824
27.1k
    expand_buffer[8*256],
825
27.1k
    *pixels = NULL,
826
27.1k
    *scanline = NULL;
827
828
27.1k
  unsigned long
829
27.1k
    number_pixels,
830
27.1k
    width;
831
832
27.1k
  magick_off_t
833
27.1k
    file_size;
834
835
27.1k
  unsigned int
836
27.1k
    bytes_per_pixel,
837
27.1k
    i,
838
27.1k
    j,
839
27.1k
    length,
840
27.1k
    scanline_length;
841
842
27.1k
  MagickBool
843
27.1k
    logging;
844
845
27.1k
  ARG_NOT_USED(image_info);
846
847
27.1k
  logging=IsEventLogged(CoderEvent);
848
849
  /*
850
    Determine pixel buffer size.
851
  */
852
27.1k
  if (bits_per_pixel <= 8)
853
23.8k
    bytes_per_line&=0x7fff;
854
27.1k
  width=image->columns;
855
27.1k
  bytes_per_pixel=1;
856
27.1k
  if (bits_per_pixel == 16)
857
1.17k
    {
858
1.17k
      bytes_per_pixel=2;
859
1.17k
      width*=2;
860
1.17k
    }
861
25.9k
  else
862
25.9k
    if (bits_per_pixel == 32)
863
858
      width*=image->matte ? 4 : 3;
864
27.1k
  if (bytes_per_line == 0)
865
12.6k
    bytes_per_line=width;
866
27.1k
  row_bytes=(size_t) (image->columns | 0x8000);
867
27.1k
  if (image->storage_class == DirectClass)
868
4.41k
    row_bytes=(size_t) ((4*image->columns) | 0x8000);
869
27.1k
  if (logging)
870
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
871
0
                          "DecodeImage: Using %lu bytes per line, %"
872
0
                          MAGICK_SIZE_T_F "u bytes per row",
873
0
                          bytes_per_line,
874
0
                          (MAGICK_SIZE_T) row_bytes);
875
  /*
876
    Validate allocation requests based on remaining file data
877
  */
878
27.1k
  if ((file_size = GetBlobSize(blob)) > 0)
879
27.1k
    {
880
27.1k
      magick_off_t
881
27.1k
        remaining;
882
883
27.1k
      remaining=file_size-TellBlob(blob);
884
885
27.1k
      if (remaining <= 0)
886
158
        {
887
158
          ThrowException(&image->exception,CorruptImageError,InsufficientImageDataInFile,
888
158
                         image->filename);
889
158
          goto decode_error_exit;
890
158
        }
891
26.9k
      else
892
26.9k
        {
893
26.9k
          double
894
26.9k
            ratio;
895
896
26.9k
          ratio = (((double) image->rows*bytes_per_line)/remaining);
897
898
26.9k
          if (logging)
899
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
900
0
                                  "Remaining: %" MAGICK_OFF_F "d, Ratio: %g",
901
0
                                  remaining, ratio);
902
903
26.9k
          if (ratio > (bytes_per_line < 8 ? 1.0 : 255.0))
904
47
            {
905
47
              if (logging)
906
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
907
0
                                      "Unreasonable file size "
908
0
                                      "(ratio of pixels to remaining file size %g)",
909
0
                                      ratio);
910
47
              ThrowException(&image->exception,CorruptImageError,InsufficientImageDataInFile,
911
47
                             image->filename);
912
47
              goto decode_error_exit;
913
47
            }
914
26.9k
        }
915
27.1k
    }
916
917
  /*
918
    Allocate pixel and scanline buffer.
919
  */
920
26.9k
  allocated_pixels=MagickArraySize(image->rows,row_bytes);
921
26.9k
  pixels=MagickAllocateResourceLimitedClearedMemory(unsigned char *,allocated_pixels);
922
26.9k
  if (pixels == (unsigned char *) NULL)
923
0
    {
924
0
      ThrowException(&image->exception,ResourceLimitError,MemoryAllocationFailed,
925
0
                     image->filename);
926
0
      goto decode_error_exit;
927
0
    }
928
  /* Use a worst-case allocation policy (because we can afford to) */
929
26.9k
  if (bytes_per_line < 8)
930
22.8k
    scanline_alloc = bytes_per_line;
931
4.04k
  else if (bytes_per_line <= 250)
932
3.36k
    scanline_alloc = 256U+256U; /* Allocate extra for RLE over-run */
933
688
  else
934
688
    scanline_alloc = 65536U+256U; /* Allocate extra for RLE over-run */
935
936
26.9k
  scanline=MagickAllocateResourceLimitedClearedMemory(unsigned char *,scanline_alloc);
937
26.9k
  if (scanline == (unsigned char *) NULL)
938
0
    {
939
0
      ThrowException(&image->exception,ResourceLimitError,MemoryAllocationFailed,
940
0
                     image->filename);
941
0
      goto decode_error_exit;
942
0
    }
943
26.9k
  (void) memset(expand_buffer,0,sizeof(expand_buffer));
944
26.9k
  if (bytes_per_line < 8)
945
22.8k
    {
946
      /*
947
        Pixels are already uncompressed.
948
      */
949
226k
      for (y=0; y < image->rows; y++)
950
203k
        {
951
203k
          q=pixels+(size_t)y*width;
952
203k
          number_pixels=bytes_per_line;
953
203k
          if (ReadBlob(blob,number_pixels,(char *) scanline) != number_pixels)
954
2
            {
955
2
              ThrowException(&image->exception,CorruptImageError,UnexpectedEndOfFile,
956
2
                             image->filename);
957
2
              goto decode_error_exit;
958
2
            }
959
203k
          p=ExpandBuffer(expand_buffer,scanline,&number_pixels,bits_per_pixel);
960
203k
          (void) memcpy(q,p,number_pixels);
961
203k
        }
962
22.8k
      MagickFreeResourceLimitedMemory(unsigned char *,scanline);
963
22.8k
      return(pixels);
964
22.8k
    }
965
  /*
966
    Uncompress RLE pixels into uncompressed pixel buffer.
967
  */
968
9.66k
  for (y=0; y < image->rows; y++)
969
5.81k
    {
970
5.81k
      q=pixels+(size_t)y*width;
971
      /*
972
        From page 119 of Inside Macintosh: Volume V
973
        (https://vintageapple.org/inside_o/pdf/Inside_Macintosh_Volume_V_1986.pdf):
974
975
        If rowBytes < 8, then data is unpacked
976
          data size = rowBytes*(bounds.bottom-bounds.top);
977
        if rowBytes >= then data is packed.
978
          Image contains (bounds.bottom-boutes.top) packed
979
          scanlines.
980
          Packed scanlines are produced by the PackBits
981
          routine.
982
          Each scanline consists of [byteCount] [data].
983
          If rowBytes > 250, then byteCount is a word,
984
            else it is a byte.
985
          end;
986
      */
987
#if 0
988
      /*
989
        Brutal implementation which cannot read files written by older
990
        IM/GM versions.
991
      */
992
      if (bytes_per_line > 250) /* Was 200 */
993
        scanline_length=ReadBlobMSBShort(blob);
994
      else
995
        scanline_length=ReadBlobByte(blob);
996
#else
997
      /* Intuit when byteCount must be a word */
998
5.81k
      if (bytes_per_line > 200)
999
1.11k
        {
1000
1.11k
          scanline_length=ReadBlobByte(blob);
1001
1.11k
          if (scanline_length == 0)
1002
659
            {
1003
659
              scanline_length <<= 8;
1004
659
              scanline_length |= ReadBlobByte(blob);
1005
659
            }
1006
1.11k
        }
1007
4.70k
      else
1008
4.70k
        {
1009
4.70k
          scanline_length=ReadBlobByte(blob);
1010
4.70k
        }
1011
5.81k
#endif
1012
#if 0
1013
      if (logging)
1014
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1015
                              "scanline_length = %u, "
1016
                              "scanline_alloc = %" MAGICK_SIZE_T_F "u",
1017
                              scanline_length, (MAGICK_SIZE_T)scanline_alloc);
1018
#endif
1019
5.81k
      if (scanline_length < 2)
1020
54
        {
1021
54
          if (logging)
1022
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1023
0
                                  "Scanline length %u < 2!",scanline_length);
1024
54
          ThrowException(&image->exception,CorruptImageError,UnableToUncompressImage,
1025
54
                         image->filename);
1026
54
          goto decode_error_exit;
1027
54
        }
1028
5.76k
      if (scanline_length > scanline_alloc)
1029
69
        {
1030
69
          if (logging)
1031
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1032
0
                                  "Scanline length %u exceeds allocation %" MAGICK_SIZE_T_F "u",
1033
0
                                  scanline_length, (MAGICK_SIZE_T)scanline_alloc);
1034
69
          ThrowException(&image->exception,CorruptImageError,UnableToUncompressImage,
1035
69
                         image->filename);
1036
69
          goto decode_error_exit;
1037
69
        }
1038
5.69k
      if (ReadBlob(blob,scanline_length,(char *) scanline) != scanline_length)
1039
75
        {
1040
75
          ThrowException(&image->exception,CorruptImageError,UnexpectedEndOfFile,
1041
75
                         "Scanline length too small!");
1042
75
          goto decode_error_exit;
1043
75
        }
1044
      #if 0
1045
      (void) memset(scanline+scanline_length,0,scanline_alloc-scanline_length); /* Zero remainder */
1046
      #endif
1047
22.4k
      for (j=0; j < scanline_length; )
1048
16.8k
        if ((scanline[j] & 0x80) == 0)
1049
13.7k
          {
1050
13.7k
            length=(scanline[j] & 0xff)+1;
1051
13.7k
            number_pixels=length*bytes_per_pixel;
1052
13.7k
            p=ExpandBuffer(expand_buffer,scanline+j+1,&number_pixels,bits_per_pixel);
1053
13.7k
            if (!((pixels+allocated_pixels)-number_pixels > q))
1054
2
              {
1055
2
                ThrowException(&image->exception,CorruptImageError,UnableToUncompressImage,
1056
2
                               "Decoded RLE pixels exceeds allocation!");
1057
2
                goto decode_error_exit;
1058
2
              }
1059
13.7k
            (void) memcpy(q,p,number_pixels);
1060
13.7k
            q+=number_pixels;
1061
13.7k
            j+=length*bytes_per_pixel+1;
1062
13.7k
          }
1063
3.03k
        else
1064
3.03k
          {
1065
3.03k
            length=((scanline[j]^0xff) & 0xff)+2;
1066
3.03k
            number_pixels=bytes_per_pixel;
1067
3.03k
            p=ExpandBuffer(expand_buffer,scanline+j+1,&number_pixels,bits_per_pixel);
1068
148k
            for (i=0; i < length; i++)
1069
145k
              {
1070
145k
                if (!((pixels+allocated_pixels)-number_pixels > q))
1071
3
                  {
1072
3
                    ThrowException(&image->exception,CorruptImageError,UnableToUncompressImage,
1073
3
                                   "Decoded RLE pixels exceeds allocation!");
1074
3
                    goto decode_error_exit;
1075
3
                  }
1076
145k
                (void) memcpy(q,p,number_pixels);
1077
145k
                q+=number_pixels;
1078
145k
              }
1079
3.03k
            j+=bytes_per_pixel+1;
1080
3.03k
          }
1081
5.62k
    }
1082
3.84k
  MagickFreeResourceLimitedMemory(unsigned char *,scanline);
1083
3.84k
  return (pixels);
1084
1085
410
 decode_error_exit:
1086
1087
410
  MagickFreeResourceLimitedMemory(unsigned char *,scanline);
1088
410
  MagickFreeResourceLimitedMemory(unsigned char *,pixels);
1089
410
  return (unsigned char *) NULL;
1090
4.04k
}
1091

1092
/*
1093
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094
%                                                                             %
1095
%                                                                             %
1096
%                                                                             %
1097
%   E n c o d e I m a g e                                                     %
1098
%                                                                             %
1099
%                                                                             %
1100
%                                                                             %
1101
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1102
%
1103
%  Method EncodeImage compresses an image via Macintosh pack bits encoding
1104
%  for Macintosh PICT images.
1105
%
1106
%  The format of the EncodeImage method is:
1107
%
1108
%      size_t EncodeImage(Image *image,const unsigned char *scanline,
1109
%        const unsigned long bytes_per_line,unsigned char *pixels)
1110
%
1111
%  A description of each parameter follows:
1112
%
1113
%    o status:  Method EncodeImage returns the number of encoded pixels.
1114
%
1115
%    o image: The address of a structure of type Image.
1116
%
1117
%    o scanline: A pointer to an array of characters to pack.
1118
%
1119
%    o bytes_per_line: The number of bytes in a scanline.
1120
%
1121
%    o pixels: A pointer to an array of characters where the packed
1122
%      characters are stored.
1123
%
1124
%
1125
*/
1126
static size_t EncodeImage(Image *image,const unsigned char *scanline,
1127
  const size_t bytes_per_line,unsigned char *pixels)
1128
233k
{
1129
233k
#define MaxCount  128U
1130
10.1M
#define MaxPackbitsRunlength  128
1131
1132
233k
  long
1133
233k
    count,
1134
233k
    repeat_count,
1135
233k
    runlength;
1136
1137
233k
  register const unsigned char
1138
233k
    *p;
1139
1140
233k
  register long
1141
233k
    i;
1142
1143
233k
  register unsigned char
1144
233k
    *q;
1145
1146
233k
  size_t
1147
233k
    length;
1148
1149
233k
  unsigned char
1150
233k
    index;
1151
1152
233k
  MagickBool
1153
233k
    logging;
1154
1155
233k
   logging=IsEventLogged(CoderEvent);
1156
1157
  /*
1158
    Pack scanline.
1159
  */
1160
233k
  assert(image != (Image *) NULL);
1161
233k
  assert(image->signature == MagickSignature);
1162
233k
  assert(scanline != (unsigned char *) NULL);
1163
233k
  assert(pixels != (unsigned char *) NULL);
1164
233k
#if 1
1165
233k
  if (logging)
1166
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1167
0
                          "EncodeImage: %lux%lu, matte=%s bytes_per_line=%zu",
1168
0
                          image->columns, image->rows,
1169
0
                          image->matte ? "True" : "False",
1170
0
                          bytes_per_line);
1171
233k
#endif
1172
233k
  count=0;
1173
233k
  runlength=0;
1174
233k
  p=scanline+(bytes_per_line-1);
1175
233k
  q=pixels;
1176
233k
  index=(*p);
1177
652M
  for (i=(long) bytes_per_line-1; i >= 0; i--)
1178
652M
  {
1179
652M
    if (index == *p)
1180
651M
      runlength++;
1181
109k
    else
1182
109k
      {
1183
109k
        if (runlength < 3)
1184
202k
          while (runlength > 0)
1185
108k
          {
1186
108k
            *q++=(unsigned char) index;
1187
108k
            runlength--;
1188
108k
            count++;
1189
108k
            if (count == MaxCount)
1190
477
              {
1191
477
                *q++=(unsigned char) (MaxCount-1);
1192
477
                count-=MaxCount;
1193
477
              }
1194
108k
          }
1195
16.0k
        else
1196
16.0k
          {
1197
16.0k
            if (count > 0)
1198
1.32k
              *q++=(unsigned char) (count-1);
1199
16.0k
            count=0;
1200
70.2k
            while (runlength > 0)
1201
54.2k
            {
1202
54.2k
              repeat_count=runlength;
1203
54.2k
              if (repeat_count > MaxPackbitsRunlength)
1204
38.1k
                repeat_count=MaxPackbitsRunlength;
1205
54.2k
              *q++=(unsigned char) index;
1206
54.2k
              *q++=(unsigned char) (257-repeat_count);
1207
54.2k
              runlength-=repeat_count;
1208
54.2k
            }
1209
16.0k
          }
1210
109k
        runlength=1;
1211
109k
      }
1212
652M
    index=(*p);
1213
652M
    p--;
1214
652M
  }
1215
233k
  if (runlength < 3)
1216
13.8k
    while (runlength > 0)
1217
8.92k
    {
1218
8.92k
      *q++=(unsigned char) index;
1219
8.92k
      runlength--;
1220
8.92k
      count++;
1221
8.92k
      if (count == MaxCount)
1222
99
        {
1223
99
          *q++=(unsigned char) (MaxCount-1);
1224
99
          count-=MaxCount;
1225
99
        }
1226
8.92k
    }
1227
228k
  else
1228
228k
    {
1229
228k
      if (count > 0)
1230
4.42k
        *q++=(unsigned char) (count-1);
1231
228k
      count=0;
1232
5.37M
      while (runlength > 0)
1233
5.15M
      {
1234
5.15M
        repeat_count=runlength;
1235
5.15M
        if (repeat_count > MaxPackbitsRunlength)
1236
4.92M
          repeat_count=MaxPackbitsRunlength;
1237
5.15M
        *q++=(unsigned char) index;
1238
5.15M
        *q++=(unsigned char) (257-repeat_count);
1239
5.15M
        runlength-=repeat_count;
1240
5.15M
      }
1241
228k
    }
1242
233k
  if (count > 0)
1243
4.82k
    *q++= (unsigned char) (count-1);
1244
  /*
1245
    Write the number of and the packed length.
1246
  */
1247
233k
  length=(q-pixels);
1248
233k
  if (bytes_per_line > 250)
1249
176k
    {
1250
176k
      (void) WriteBlobMSBShort(image,(magick_uint16_t) length);
1251
176k
      length+=2;
1252
176k
    }
1253
56.8k
  else
1254
56.8k
    {
1255
56.8k
      (void) WriteBlobByte(image,(magick_uint8_t) length);
1256
56.8k
      length++;
1257
56.8k
    }
1258
10.7M
  while (q != pixels)
1259
10.5M
  {
1260
10.5M
    q--;
1261
10.5M
    (void) WriteBlobByte(image,*q);
1262
10.5M
  }
1263
233k
  return(length);
1264
233k
}
1265

1266
/*
1267
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1268
%                                                                             %
1269
%                                                                             %
1270
%                                                                             %
1271
%   R e a d P I C T I m a g e                                                 %
1272
%                                                                             %
1273
%                                                                             %
1274
%                                                                             %
1275
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1276
%
1277
%  Method ReadPICTImage reads an Apple Macintosh QuickDraw/PICT image file
1278
%  and returns it.  It allocates the memory necessary for the new Image
1279
%  structure and returns a pointer to the new image.
1280
%
1281
%  The format of the ReadPICTImage method is:
1282
%
1283
%      Image *ReadPICTImage(const ImageInfo *image_info,
1284
%        ExceptionInfo *exception)
1285
%
1286
%  A description of each parameter follows:
1287
%
1288
%    o image:  Method ReadPICTImage returns a pointer to the image after
1289
%      reading.  A null image is returned if there is a memory shortage or
1290
%      if the image cannot be read.
1291
%
1292
%    o image_info: Specifies a pointer to a ImageInfo structure.
1293
%
1294
%    o exception: return any errors or warnings in this structure.
1295
%
1296
%
1297
*/
1298
156k
#define ThrowPICTReaderException(code_,reason_,image_) \
1299
156k
{ \
1300
156k
  if (clone_info) \
1301
156k
    DestroyImageInfo(clone_info); \
1302
156k
  if (tile_image) \
1303
156k
    DestroyImage(tile_image); \
1304
156k
  ThrowReaderException(code_,reason_,image_); \
1305
0
}
1306
1307
static Image *ReadPICTImage(const ImageInfo *image_info,
1308
  ExceptionInfo *exception)
1309
18.1k
{
1310
18.1k
  char
1311
18.1k
    geometry[MaxTextExtent];
1312
1313
18.1k
  Image
1314
18.1k
    *image = (Image *) NULL,
1315
18.1k
    *tile_image = (Image *) NULL;
1316
1317
18.1k
  ImageInfo
1318
18.1k
    *clone_info = (ImageInfo *) NULL;
1319
1320
18.1k
  IndexPacket
1321
18.1k
    index;
1322
1323
18.1k
  int
1324
18.1k
    c,
1325
18.1k
    version;
1326
1327
18.1k
  unsigned int
1328
18.1k
    code,
1329
18.1k
    flags;
1330
1331
18.1k
  long
1332
18.1k
    j,
1333
18.1k
    y;
1334
1335
18.1k
  PICTRectangle
1336
18.1k
    frame;
1337
1338
18.1k
  PICTPixmap
1339
18.1k
    pixmap;
1340
1341
18.1k
  register IndexPacket
1342
18.1k
    *indexes;
1343
1344
18.1k
  register long
1345
18.1k
    x;
1346
1347
18.1k
  register PixelPacket
1348
18.1k
    *q;
1349
1350
18.1k
  register long
1351
18.1k
    i;
1352
1353
18.1k
  size_t
1354
18.1k
    length;
1355
1356
18.1k
  magick_off_t
1357
18.1k
    file_size;
1358
1359
18.1k
  unsigned int
1360
18.1k
    jpeg,
1361
18.1k
    status;
1362
1363
18.1k
  MagickBool
1364
18.1k
    logging;
1365
1366
18.1k
   logging=IsEventLogged(CoderEvent);
1367
1368
  /*
1369
    Open image file.
1370
  */
1371
18.1k
  assert(image_info != (const ImageInfo *) NULL);
1372
18.1k
  assert(image_info->signature == MagickSignature);
1373
18.1k
  assert(exception != (ExceptionInfo *) NULL);
1374
18.1k
  assert(exception->signature == MagickSignature);
1375
18.1k
  image=AllocateImage(image_info);
1376
18.1k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1377
18.1k
  if (status == False)
1378
18.1k
    ThrowPICTReaderException(FileOpenError,UnableToOpenFile,image);
1379
18.1k
  file_size=GetBlobSize(image);
1380
  /*
1381
    Read PICT header.
1382
  */
1383
18.1k
  pixmap.bits_per_pixel=0;
1384
18.1k
  pixmap.component_count=0;
1385
9.31M
  for (i=0; i < 512; i++)
1386
9.29M
    (void) ReadBlobByte(image);  /* skip header */
1387
18.1k
  (void) ReadBlobMSBShort(image);  /* skip picture size */
1388
18.1k
  ReadRectangle(frame);
1389
18.1k
  TraceRectangle(image,frame);
1390
18.1k
  if (!ValidateRectangle(frame))
1391
16.2k
    ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1392
4.52M
  while ((c=ReadBlobByte(image)) == 0);
1393
16.2k
  if (c != 0x11)
1394
16.1k
    ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1395
16.1k
  version=ReadBlobByte(image);
1396
16.1k
  if (version == 2)
1397
12.4k
    {
1398
12.4k
      c=ReadBlobByte(image);
1399
12.4k
      if (c != 0xff)
1400
12.4k
        ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1401
12.4k
    }
1402
3.67k
  else
1403
3.67k
    if (version != 1)
1404
16.0k
      ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1405
  /*
1406
    Create black canvas.
1407
  */
1408
16.0k
  flags=0;
1409
16.0k
  image->depth=8;
1410
16.0k
  image->columns=frame.right-frame.left;
1411
16.0k
  image->rows=frame.bottom-frame.top;
1412
1413
16.0k
  if (logging)
1414
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1415
0
                          "Dimensions: %lux%lu",image->columns,image->rows);
1416
1417
16.0k
  if (CheckImagePixelLimits(image, exception) != MagickPass)
1418
15.8k
    ThrowPICTReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
1419
1420
15.8k
  SetRedSample(&image->background_color,0);
1421
15.8k
  SetGreenSample(&image->background_color,0);
1422
15.8k
  SetBlueSample(&image->background_color,0);
1423
15.8k
  SetOpacitySample(&image->background_color,OpaqueOpacity);
1424
15.8k
  if (SetImageEx(image,OpaqueOpacity,exception) != MagickPass)
1425
0
    {
1426
0
      CloseBlob(image);
1427
0
      DestroyImage(image);
1428
0
      return (Image *) NULL;
1429
0
    }
1430
1431
  /*
1432
    Interpret PICT opcodes.
1433
  */
1434
15.8k
  jpeg=False;
1435
20.6M
  for (code=0; EOFBlob(image) == False; )
1436
20.6M
  {
1437
20.6M
    if (image_info->ping && (image_info->subrange != 0))
1438
0
      if (image->scene >= (image_info->subimage+image_info->subrange-1))
1439
0
        break;
1440
20.6M
    if ((version == 1) || ((TellBlob(image) % 2) != 0))
1441
1.25M
      {
1442
1.25M
        if ((c=ReadBlobByte(image)) == EOF) /* returns int */
1443
682
          break;
1444
1.25M
        code=(unsigned int) c;
1445
1.25M
      }
1446
20.6M
    if (version == 2)
1447
19.5M
      code=ReadBlobMSBShort(image); /* returns magick_uint16_t */
1448
20.6M
    if (code > 0xa1)
1449
564k
      {
1450
564k
        if (logging)
1451
0
          {
1452
0
            if (0xff == code)
1453
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Code 0x%04X %.1024s: %.1024s",code,
1454
0
                                    "EndOfPicture","End of picture");
1455
0
            else /* Unknown code */
1456
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Code 0x%04X:",code);
1457
0
          }
1458
564k
      }
1459
20.0M
    else
1460
20.0M
      {
1461
20.0M
        if (logging)
1462
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Code 0x%04X %.1024s: %.1024s",code,
1463
0
                                lookup_string(code_names,sizeof(code_names),code),
1464
0
                                lookup_string(code_descriptions,sizeof(code_descriptions),code));
1465
20.0M
        switch (code)
1466
20.0M
        {
1467
19.4k
          case 0x01:
1468
19.4k
          {
1469
            /*
1470
              Clipping rectangle.
1471
            */
1472
19.4k
            length=ReadBlobMSBShort(image);
1473
19.4k
            if (length != 0x000a)
1474
12.3k
              {
1475
4.33M
                for (i=0; i < (long) (length-2); i++)
1476
4.31M
                  if (ReadBlobByte(image) == EOF)
1477
308
                    break;
1478
12.3k
                break;
1479
12.3k
              }
1480
7.08k
            ReadRectangle(frame);
1481
7.08k
            TraceRectangle(image,frame);
1482
7.08k
            if (!ValidateRectangle(frame))
1483
7.02k
              ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1484
7.02k
            if ((frame.left & 0x8000) || (frame.top & 0x8000))
1485
0
              break;
1486
7.02k
            image->columns=frame.right-frame.left;
1487
7.02k
            image->rows=frame.bottom-frame.top;
1488
7.02k
            if (CheckImagePixelLimits(image, exception) != MagickPass)
1489
6.99k
              ThrowPICTReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
1490
6.99k
            (void) SetImageEx(image,OpaqueOpacity,exception);
1491
6.99k
            break;
1492
7.02k
          }
1493
1.27k
          case 0x12:
1494
1.79k
          case 0x13:
1495
5.84k
          case 0x14:
1496
5.84k
          {
1497
5.84k
            long
1498
5.84k
              pattern;
1499
1500
5.84k
            unsigned long
1501
5.84k
              height,
1502
5.84k
              width;
1503
1504
            /*
1505
              Skip pattern definition.
1506
            */
1507
5.84k
            pattern=ReadBlobMSBShort(image);
1508
52.5k
            for (i=0; i < 8; i++)
1509
46.7k
              (void) ReadBlobByte(image);
1510
5.84k
            if (pattern == 2)
1511
2.34k
              {
1512
14.0k
                for (i=0; i < 5; i++)
1513
11.7k
                  (void) ReadBlobByte(image);
1514
2.34k
                break;
1515
2.34k
              }
1516
3.49k
            if (pattern != 1)
1517
101
              ThrowPICTReaderException(CorruptImageError,UnknownPatternType,
1518
3.49k
                image);
1519
3.39k
            length=ReadBlobMSBShort(image);
1520
3.39k
            ReadRectangle(frame);
1521
3.39k
            TraceRectangle(image,frame);
1522
3.39k
            if (!ValidateRectangle(frame))
1523
3.35k
              ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1524
3.35k
            ReadPixmap(pixmap);
1525
3.35k
            TracePixMap(image,pixmap);
1526
3.35k
            if (!ValidatePixmap(pixmap))
1527
3.27k
              ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1528
3.27k
            image->depth=pixmap.component_size;
1529
3.27k
            image->x_resolution=1.0*pixmap.horizontal_resolution;
1530
3.27k
            image->y_resolution=1.0*pixmap.vertical_resolution;
1531
3.27k
            if (logging)
1532
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1533
0
                                    "Depth %u, X resolution %g, Y resolution %g",
1534
0
                                    image->depth,
1535
0
                                    image->x_resolution, image->y_resolution);
1536
3.27k
            image->units=PixelsPerInchResolution;
1537
3.27k
            (void) ReadBlobMSBLong(image);
1538
3.27k
            flags=ReadBlobMSBShort(image);
1539
3.27k
            length=ReadBlobMSBShort(image);
1540
3.59M
            for (i=0; i <= (long) length; i++)
1541
3.59M
              (void) ReadBlobMSBLong(image);
1542
3.27k
            width=frame.bottom-frame.top;
1543
3.27k
            height=frame.right-frame.left;
1544
#if 0
1545
            image->depth=pixmap.bits_per_pixel <= 8 ? 8 : QuantumDepth;
1546
            if (pixmap.bits_per_pixel < 8)
1547
              image->depth=8;
1548
#endif
1549
3.27k
            if (pixmap.bits_per_pixel <= 8)
1550
1.59k
              length&=0x7fff;
1551
3.27k
            if (pixmap.bits_per_pixel == 16)
1552
529
              width<<=1;
1553
3.27k
            if (length == 0)
1554
2.43k
              length=width;
1555
3.27k
            if (length < 8)
1556
1.28k
              {
1557
120k
                for (i=0; i < (long) (length*height); i++)
1558
119k
                  if (ReadBlobByte(image) == EOF)
1559
58
                    break;
1560
1.28k
              }
1561
1.99k
            else
1562
1.99k
              {
1563
9.06M
                for (j=0; j < (int) height; j++)
1564
9.06M
                  {
1565
9.06M
                    if (EOFBlob(image))
1566
305
                      break;
1567
9.06M
                    if (length > 250)
1568
9.04M
                      {
1569
10.2M
                        for (j=0; j < ReadBlobMSBShort(image); j++)
1570
1.23M
                          if (ReadBlobByte(image) == EOF)
1571
40
                            break;
1572
9.04M
                      }
1573
19.9k
                    else
1574
19.9k
                      {
1575
29.9k
                        for (j=0; j < ReadBlobByte(image); j++)
1576
10.0k
                          if (ReadBlobByte(image) == EOF)
1577
26
                            break;
1578
19.9k
                      }
1579
9.06M
                  }
1580
1.99k
              }
1581
3.27k
            break;
1582
3.35k
          }
1583
1.18k
          case 0x1b:
1584
1.18k
          {
1585
            /*
1586
              Initialize image background color.
1587
            */
1588
1.18k
            image->background_color.red=(Quantum)
1589
1.18k
              ScaleShortToQuantum(ReadBlobMSBShort(image));
1590
1.18k
            image->background_color.green=(Quantum)
1591
1.18k
              ScaleShortToQuantum(ReadBlobMSBShort(image));
1592
1.18k
            image->background_color.blue=(Quantum)
1593
1.18k
              ScaleShortToQuantum(ReadBlobMSBShort(image));
1594
1.18k
            break;
1595
3.35k
          }
1596
879
          case 0x70:
1597
1.38k
          case 0x71:
1598
1.81k
          case 0x72:
1599
2.22k
          case 0x73:
1600
2.71k
          case 0x74:
1601
3.19k
          case 0x75:
1602
4.04k
          case 0x76:
1603
4.46k
          case 0x77:
1604
4.46k
          {
1605
            /*
1606
              Skip polygon or region.
1607
            */
1608
4.46k
            length=ReadBlobMSBShort(image);
1609
4.52M
            for (i=0; i < (long) (length-2); i++)
1610
4.52M
              if (ReadBlobByte(image) == EOF)
1611
107
                break;
1612
4.46k
            break;
1613
4.04k
          }
1614
1.52k
          case 0x90:
1615
7.43k
          case 0x91:
1616
18.8k
          case 0x98:
1617
23.4k
          case 0x99:
1618
25.6k
          case 0x9a:
1619
28.0k
          case 0x9b:
1620
28.0k
          {
1621
28.0k
            long
1622
28.0k
              bytes_per_line;
1623
1624
28.0k
            PICTRectangle
1625
28.0k
              source,
1626
28.0k
              destination;
1627
1628
28.0k
            register unsigned char
1629
28.0k
              *p;
1630
1631
28.0k
            size_t
1632
28.0k
              j;
1633
1634
28.0k
            unsigned char
1635
28.0k
              *pixels;
1636
1637
            /*
1638
              Pixmap clipped by a rectangle.
1639
            */
1640
28.0k
            bytes_per_line=0;
1641
28.0k
            if ((code != 0x9a) && (code != 0x9b))
1642
23.4k
              bytes_per_line=ReadBlobMSBShort(image);
1643
4.56k
            else
1644
4.56k
              {
1645
4.56k
                (void) ReadBlobMSBShort(image);
1646
4.56k
                (void) ReadBlobMSBShort(image);
1647
4.56k
                (void) ReadBlobMSBShort(image);
1648
4.56k
              }
1649
28.0k
            ReadRectangle(frame);
1650
28.0k
            TraceRectangle(image,frame);
1651
28.0k
            if (!ValidateRectangle(frame))
1652
27.8k
              ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1653
            /*
1654
              Initialize tile image.
1655
            */
1656
27.8k
            tile_image=CloneImage(image,frame.right-frame.left,
1657
27.8k
              frame.bottom-frame.top,True,exception);
1658
27.8k
            if (tile_image == (Image *) NULL)
1659
0
              {
1660
0
                DestroyImage(image);
1661
0
                return((Image *) NULL);
1662
0
              }
1663
27.8k
            DestroyBlob(tile_image);
1664
27.8k
            tile_image->blob=CloneBlobInfo((BlobInfo *) NULL);
1665
27.8k
            if ((code == 0x9a) || (code == 0x9b) || (bytes_per_line & 0x8000))
1666
6.28k
              {
1667
6.28k
                ReadPixmap(pixmap);
1668
6.28k
                TracePixMap(image,pixmap);
1669
6.28k
                if (!ValidatePixmap(pixmap))
1670
6.12k
                  ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1671
6.12k
                tile_image->matte=pixmap.component_count == 4;
1672
6.12k
              }
1673
27.7k
            if ((code != 0x9a) && (code != 0x9b))
1674
23.2k
              {
1675
                /*
1676
                  Initialize colormap.
1677
                */
1678
23.2k
                tile_image->colors=2;
1679
23.2k
                if (bytes_per_line & 0x8000)
1680
1.67k
                  {
1681
1.67k
                    (void) ReadBlobMSBLong(image);
1682
1.67k
                    flags=ReadBlobMSBShort(image);
1683
1.67k
                    tile_image->colors=ReadBlobMSBShort(image)+1;
1684
1.67k
                  }
1685
23.2k
                if (!AllocateImageColormap(tile_image,tile_image->colors))
1686
23.2k
                  ThrowPICTReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1687
23.2k
                if (logging)
1688
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1689
0
                  "Allocated tile image colormap with %u colors",tile_image->colors);
1690
23.2k
                if (bytes_per_line & 0x8000)
1691
1.67k
                  {
1692
362k
                    for (i=0; i < (long) tile_image->colors; i++)
1693
361k
                    {
1694
361k
                      j=ReadBlobMSBShort(image) % tile_image->colors;
1695
361k
                      if (flags & 0x8000)
1696
100k
                        j=i;
1697
361k
                      tile_image->colormap[j].red=(Quantum)
1698
361k
                        ScaleShortToQuantum(ReadBlobMSBShort(image));
1699
361k
                      tile_image->colormap[j].green=(Quantum)
1700
361k
                        ScaleShortToQuantum(ReadBlobMSBShort(image));
1701
361k
                      tile_image->colormap[j].blue=(Quantum)
1702
361k
                        ScaleShortToQuantum(ReadBlobMSBShort(image));
1703
361k
                      if (EOFBlob(image))
1704
102
                        break;
1705
361k
                    }
1706
1.67k
                  }
1707
21.5k
                else
1708
21.5k
                  {
1709
64.7k
                    for (i=0; i < (long) tile_image->colors; i++)
1710
43.1k
                    {
1711
43.1k
                      tile_image->colormap[i].red=(Quantum) (MaxRGB-
1712
43.1k
                        tile_image->colormap[i].red);
1713
43.1k
                      tile_image->colormap[i].green=(Quantum) (MaxRGB-
1714
43.1k
                        tile_image->colormap[i].green);
1715
43.1k
                      tile_image->colormap[i].blue=(Quantum) (MaxRGB-
1716
43.1k
                        tile_image->colormap[i].blue);
1717
43.1k
                    }
1718
21.5k
                  }
1719
23.2k
              }
1720
27.7k
            if (EOFBlob(image))
1721
27.6k
              ThrowPICTReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1722
27.6k
            ReadRectangle(source);
1723
27.6k
            TraceRectangle(image,source);
1724
27.6k
            if (!ValidateRectangle(source))
1725
27.2k
              ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1726
27.2k
            ReadRectangle(destination);
1727
27.2k
            TraceRectangle(image,destination);
1728
27.2k
            if (!ValidateRectangle(destination))
1729
27.1k
              ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1730
27.1k
            (void) ReadBlobMSBShort(image);
1731
27.1k
            if ((code == 0x91) || (code == 0x99) || (code == 0x9b))
1732
12.4k
              {
1733
                /*
1734
                  Skip region.
1735
                */
1736
12.4k
                length=ReadBlobMSBShort(image);
1737
248k
                for (i=0; i <= (long) (length-2); i++)
1738
235k
                  if (ReadBlobByte(image) == EOF)
1739
65
                    break;
1740
12.4k
              }
1741
27.1k
            if (CheckImagePixelLimits(tile_image, exception) != MagickPass)
1742
27.1k
              ThrowPICTReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
1743
27.1k
            if ((code != 0x9a) && (code != 0x9b) &&
1744
22.6k
                (bytes_per_line & 0x8000) == 0)
1745
21.1k
              pixels=DecodeImage(image_info,image,tile_image,bytes_per_line,1);
1746
5.96k
            else
1747
5.96k
              pixels=DecodeImage(image_info,image,tile_image,bytes_per_line,
1748
5.96k
                pixmap.bits_per_pixel);
1749
27.1k
            if (pixels == (unsigned char *) NULL)
1750
410
              {
1751
410
                CopyException(exception, &tile_image->exception);
1752
410
                ThrowPICTReaderException(ResourceLimitError,MemoryAllocationFailed,image)
1753
0
              }
1754
            /*
1755
              Convert PICT tile image to pixel packets.
1756
            */
1757
26.7k
            p=pixels;
1758
230k
            for (y=0; y < (long) tile_image->rows; y++)
1759
203k
            {
1760
203k
              q=SetImagePixelsEx(tile_image,0,y,tile_image->columns,1,&image->exception);
1761
203k
              if (q == (PixelPacket *) NULL)
1762
0
                break;
1763
203k
              indexes=AccessMutableIndexes(tile_image);
1764
11.1M
              for (x=0; x < (long) tile_image->columns; x++)
1765
10.9M
              {
1766
10.9M
                if (tile_image->storage_class == PseudoClass)
1767
10.8M
                  {
1768
10.8M
                    index=(IndexPacket) (*p);
1769
10.8M
                    VerifyColormapIndex(tile_image,index);
1770
10.8M
                    indexes[x]=index;
1771
10.8M
                    q->red=tile_image->colormap[index].red;
1772
10.8M
                    q->green=tile_image->colormap[index].green;
1773
10.8M
                    q->blue=tile_image->colormap[index].blue;
1774
10.8M
                  }
1775
134k
                else
1776
134k
                  {
1777
134k
                    if (pixmap.bits_per_pixel == 16)
1778
5.77k
                      {
1779
5.77k
                        i=(*p++);
1780
5.77k
                        j=(*p);
1781
5.77k
                        q->red=ScaleCharToQuantum((i & 0x7c) << 1);
1782
5.77k
                        q->green=ScaleCharToQuantum((((size_t)i & 0x03) << 6) |
1783
5.77k
                          (((size_t) j & 0xe0) >> 2));
1784
5.77k
                        q->blue=ScaleCharToQuantum((j & 0x1f) << 3);
1785
5.77k
                      }
1786
129k
                    else
1787
129k
                      {
1788
129k
                        if (!tile_image->matte)
1789
126k
                          {
1790
126k
                            q->red=ScaleCharToQuantum(*p);
1791
126k
                            q->green=
1792
126k
                              ScaleCharToQuantum(*(p+tile_image->columns));
1793
126k
                            q->blue=ScaleCharToQuantum(*(p+ (size_t)2*tile_image->columns));
1794
126k
                          }
1795
2.23k
                        else
1796
2.23k
                          {
1797
2.23k
                            q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*p));
1798
2.23k
                            q->red=ScaleCharToQuantum(*(p+tile_image->columns));
1799
2.23k
                            q->green=(Quantum)
1800
2.23k
                              ScaleCharToQuantum(*(p+ (size_t)2*tile_image->columns));
1801
2.23k
                            q->blue=
1802
2.23k
                              ScaleCharToQuantum(*(p+ (size_t)3*tile_image->columns));
1803
2.23k
                          }
1804
129k
                      }
1805
134k
                  }
1806
10.9M
                p++;
1807
10.9M
                q++;
1808
10.9M
              }
1809
203k
              if (!SyncImagePixelsEx(tile_image,&image->exception))
1810
0
                break;
1811
203k
              if ((tile_image->storage_class == DirectClass) &&
1812
61.5k
                  (pixmap.bits_per_pixel != 16))
1813
59.5k
                p+=((size_t) pixmap.component_count-1)*tile_image->columns;
1814
203k
              if (destination.bottom == (long) image->rows)
1815
106k
                if (QuantumTick(y,tile_image->rows))
1816
56.9k
                  if (!MagickMonitorFormatted(y,tile_image->rows,&image->exception,
1817
56.9k
                                              LoadImageText,image->filename,
1818
56.9k
                                              image->columns,image->rows))
1819
0
                    break;
1820
203k
            }
1821
26.7k
            MagickFreeResourceLimitedMemory(unsigned char *,pixels);
1822
26.7k
            if (tile_image->exception.severity > image->exception.severity)
1823
113
              CopyException(&image->exception,&tile_image->exception);
1824
26.7k
            if ((tile_image->exception.severity < ErrorException) && (jpeg == False))
1825
23.3k
              if ((code == 0x9a) || (code == 0x9b) ||
1826
18.9k
                  (bytes_per_line & 0x8000))
1827
5.17k
                {
1828
5.17k
                  if (logging)
1829
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1830
0
                                            "Composite tile: %lux%lu%+d%+d",
1831
0
                                            tile_image->columns, tile_image->rows,
1832
0
                                            destination.left, destination.top);
1833
5.17k
                  (void) CompositeImage(image,CopyCompositeOp,tile_image,
1834
5.17k
                                        destination.left,destination.top);
1835
5.17k
                }
1836
26.7k
            DestroyImage(tile_image);
1837
26.7k
            tile_image=(Image *) NULL;
1838
26.7k
            if (destination.bottom != (long) image->rows)
1839
23.4k
              if (!MagickMonitorFormatted(destination.bottom,image->rows,&image->exception,
1840
23.4k
                                          LoadImageText,image->filename,
1841
23.4k
                                          image->columns,image->rows))
1842
0
                break;
1843
26.7k
            break;
1844
26.7k
          }
1845
28.3k
          case 0xa1:
1846
28.3k
          {
1847
28.3k
            unsigned char
1848
28.3k
              *info;
1849
1850
28.3k
            unsigned int
1851
28.3k
              type;
1852
1853
            /*
1854
              Comment.
1855
            */
1856
28.3k
            type=ReadBlobMSBShort(image);
1857
28.3k
            length=ReadBlobMSBShort(image);
1858
28.3k
            if (length == 0)
1859
1.03k
              break;
1860
27.2k
            (void) ReadBlobMSBLong(image);
1861
27.2k
            length-=Min(4,length);
1862
27.2k
            if (length == 0)
1863
454
              break;
1864
26.8k
            info=MagickAllocateResourceLimitedMemory(unsigned char *,length);
1865
26.8k
            if (info == (unsigned char *) NULL)
1866
0
              break;
1867
26.8k
            (void) ReadBlob(image,length,info);
1868
26.8k
            switch (type)
1869
26.8k
            {
1870
3.24k
              case 0xe0:
1871
3.24k
              {
1872
3.24k
                if (length == 0)
1873
0
                  break;
1874
3.24k
                if (SetImageProfile(image,"ICM",info,length) == MagickFail)
1875
3.24k
                  ThrowPICTReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1876
3.24k
                MagickFreeResourceLimitedMemory(unsigned char *,info);
1877
3.24k
                break;
1878
3.24k
              }
1879
21.9k
              case 0x1f2:
1880
21.9k
              {
1881
21.9k
                if (length == 0)
1882
0
                  break;
1883
21.9k
                if (SetImageProfile(image,"IPTC",info,length) == MagickFail)
1884
21.9k
                  ThrowPICTReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1885
21.9k
                MagickFreeResourceLimitedMemory(unsigned char *,info);
1886
21.9k
                break;
1887
21.9k
              }
1888
1.61k
              default:
1889
1.61k
                break;
1890
26.8k
            }
1891
26.8k
            MagickFreeResourceLimitedMemory(unsigned char *,info);
1892
26.8k
            break;
1893
26.8k
          }
1894
20.0M
          default:
1895
20.0M
          {
1896
            /*
1897
              Skip to next op code.
1898
            */
1899
20.0M
            if (code_lengths[code] == -1)
1900
25.5k
              (void) ReadBlobMSBShort(image);
1901
19.9M
            else
1902
20.6M
              for (i=0; i < (long) code_lengths[code]; i++)
1903
670k
                if (ReadBlobByte(image) == EOF)
1904
323
                  break;
1905
20.0M
          }
1906
20.0M
        }
1907
20.0M
      }
1908
20.6M
    if (code == 0xc00)
1909
2.97k
      {
1910
        /*
1911
          Skip header.
1912
        */
1913
73.5k
        for (i=0; i < 24; i++)
1914
70.6k
          if (ReadBlobByte(image) == EOF)
1915
35
            break;
1916
2.97k
        continue;
1917
2.97k
      }
1918
20.6M
    if (((code >= 0xb0) && (code <= 0xcf)) ||
1919
20.6M
        ((code >= 0x8000) && (code <= 0x80ff)))
1920
11.1k
      continue;
1921
20.6M
    if (code == 0x8200)
1922
236k
      {
1923
        /*
1924
          Embedded JPEG.
1925
        */
1926
236k
        jpeg=True;
1927
236k
        length=ReadBlobMSBLong(image);
1928
236k
        if ((length > 154) && ((file_size <= 0) || ((size_t) (file_size-TellBlob(image)) > length)))
1929
152k
          {
1930
152k
            void
1931
152k
              *blob,
1932
152k
              *blob_alloc;
1933
1934
152k
            const size_t
1935
152k
              blob_alloc_size = length-154;
1936
1937
1.07M
            for (i=0; i < 6; i++)
1938
917k
              (void) ReadBlobMSBLong(image);
1939
152k
            ReadRectangle(frame);
1940
152k
            TraceRectangle(image,frame);
1941
152k
            if (!ValidateRectangle(frame))
1942
152k
              ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
1943
18.8M
            for (i=0; i < 122; i++)
1944
18.6M
              if (ReadBlobByte(image) == EOF)
1945
152k
                ThrowPICTReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1946
152k
            if ((blob_alloc=MagickAllocateResourceLimitedMemory(void *,blob_alloc_size)) == (void *) NULL)
1947
152k
              ThrowPICTReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1948
152k
            blob=blob_alloc;
1949
152k
            clone_info=CloneImageInfo(image_info);
1950
152k
            clone_info->blob=(_BlobInfoPtr_) NULL;
1951
152k
            clone_info->length=0;
1952
152k
            (void) strlcpy(clone_info->filename,"JPEG:",sizeof(clone_info->filename));
1953
152k
            if (ReadBlobZC(image,blob_alloc_size,&blob) != blob_alloc_size)
1954
16
              {
1955
16
                MagickFreeResourceLimitedMemory(void *,blob_alloc);
1956
16
                ThrowPICTReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1957
0
              }
1958
152k
            if (blob != blob_alloc)
1959
152k
              {
1960
152k
                if (logging)
1961
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1962
0
                                        "Tile Zero copy read.");
1963
152k
              }
1964
152k
            tile_image=BlobToImage(clone_info, blob, blob_alloc_size, &image->exception );
1965
152k
            DestroyImageInfo(clone_info);
1966
152k
            clone_info=(ImageInfo *) NULL;
1967
152k
            MagickFreeResourceLimitedMemory(void *,blob_alloc);
1968
152k
          }
1969
236k
        if (tile_image == (Image *) NULL)
1970
226k
          continue;
1971
9.34k
        if (logging)
1972
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1973
0
                                "Tile Dimensions: %lux%lu",
1974
0
                                tile_image->columns,tile_image->rows);
1975
9.34k
        if (logging)
1976
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1977
0
                                "Tile Resolution: %gx%g %s",
1978
0
                                tile_image->x_resolution,
1979
0
                                tile_image->y_resolution,
1980
0
                                tile_image->units == PixelsPerInchResolution ?
1981
0
                                "pixels/inch" :
1982
0
                                (tile_image->units == PixelsPerCentimeterResolution ?
1983
0
                                 "pixels/centimeter" :
1984
0
                                 "pixels"));
1985
9.34k
        FormatString(geometry,"%lux%lu",Max(image->columns,tile_image->columns),
1986
9.34k
          Max(image->rows,tile_image->rows));
1987
9.34k
        if (logging)
1988
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1989
0
                                "Tile Transform %lux%lu ==> %s",
1990
0
                                tile_image->columns,tile_image->rows,
1991
0
                                geometry);
1992
9.34k
        if (TransformImage(&tile_image,(char *) NULL,geometry) != MagickPass)
1993
0
          {
1994
0
            if (logging)
1995
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1996
0
                                    "Tile transform failed!");
1997
0
          }
1998
9.34k
        if (logging)
1999
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2000
0
                                "Tile Composite of %lux%lu on canvas %lux%lu at +%u,+%u",
2001
0
                                tile_image->columns,tile_image->rows,
2002
0
                                image->columns,image->rows,frame.left,frame.right);
2003
9.34k
        if (CompositeImage(image,CopyCompositeOp,tile_image,frame.left,
2004
9.34k
                           frame.right) != MagickPass)
2005
0
          {
2006
0
            if (logging)
2007
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2008
0
                                    "Tile composite failed!");
2009
0
          }
2010
9.34k
        image->compression=tile_image->compression;
2011
9.34k
        DestroyImage(tile_image);
2012
9.34k
        tile_image=(Image *) NULL;
2013
9.34k
        continue;
2014
236k
      }
2015
20.4M
    if ((code == 0xff) || (code == 0xffff))
2016
1.55k
      break;
2017
20.4M
    if (((code >= 0xd0) && (code <= 0xfe)) ||
2018
20.3M
        ((code >= 0x8100) && (code <= 0xffff)))
2019
82.4k
      {
2020
        /*
2021
          Skip reserved.
2022
        */
2023
82.4k
        length=ReadBlobMSBShort(image);
2024
31.5M
        for (i=0; i < (long) length; i++)
2025
31.4M
          if (ReadBlobByte(image) == EOF)
2026
1.59k
            break;
2027
82.4k
        continue;
2028
82.4k
      }
2029
20.3M
    if ((code >= 0x100) && (code <= 0x7fff))
2030
227k
      {
2031
        /*
2032
          Skip reserved.
2033
        */
2034
227k
        length=(code >> 7) & 0xff;
2035
14.6M
        for (i=0; i < (long) length; i++)
2036
14.3M
          if (ReadBlobByte(image) == EOF)
2037
2.73k
            break;
2038
227k
        continue;
2039
227k
      }
2040
20.3M
  }
2041
14.1k
  if (EOFBlob(image))
2042
12.5k
    ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
2043
14.1k
      image->filename);
2044
14.1k
  CloseBlob(image);
2045
14.1k
  StopTimer(&image->timer);
2046
14.1k
  return(image);
2047
15.8k
}
2048

2049
/*
2050
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2051
%                                                                             %
2052
%                                                                             %
2053
%                                                                             %
2054
%   R e g i s t e r P I C T I m a g e                                         %
2055
%                                                                             %
2056
%                                                                             %
2057
%                                                                             %
2058
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2059
%
2060
%  Method RegisterPICTImage adds attributes for the PICT image format to
2061
%  the list of supported formats.  The attributes include the image format
2062
%  tag, a method to read and/or write the format, whether the format
2063
%  supports the saving of more than one frame to the same file or blob,
2064
%  whether the format supports native in-memory I/O, and a brief
2065
%  description of the format.
2066
%
2067
%  The format of the RegisterPICTImage method is:
2068
%
2069
%      RegisterPICTImage(void)
2070
%
2071
*/
2072
ModuleExport void RegisterPICTImage(void)
2073
5
{
2074
5
  MagickInfo
2075
5
    *entry;
2076
2077
5
  entry=SetMagickInfo("PCT");
2078
5
  entry->decoder=(DecoderHandler) ReadPICTImage;
2079
5
  entry->encoder=(EncoderHandler) WritePICTImage;
2080
5
  entry->adjoin=False;
2081
5
  entry->description="Apple Macintosh QuickDraw/PICT";
2082
5
  entry->seekable_stream=MagickTrue;
2083
5
  entry->module="PICT";
2084
5
  (void) RegisterMagickInfo(entry);
2085
2086
5
  entry=SetMagickInfo("PICT");
2087
5
  entry->decoder=(DecoderHandler) ReadPICTImage;
2088
5
  entry->encoder=(EncoderHandler) WritePICTImage;
2089
5
  entry->adjoin=False;
2090
5
  entry->description="Apple Macintosh QuickDraw/PICT";
2091
5
  entry->seekable_stream=MagickTrue;
2092
5
  entry->module="PICT";
2093
5
  (void) RegisterMagickInfo(entry);
2094
5
}
2095

2096
/*
2097
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2098
%                                                                             %
2099
%                                                                             %
2100
%                                                                             %
2101
%   U n r e g i s t e r P I C T I m a g e                                     %
2102
%                                                                             %
2103
%                                                                             %
2104
%                                                                             %
2105
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2106
%
2107
%  Method UnregisterPICTImage removes format registrations made by the
2108
%  PICT module from the list of supported formats.
2109
%
2110
%  The format of the UnregisterPICTImage method is:
2111
%
2112
%      UnregisterPICTImage(void)
2113
%
2114
*/
2115
ModuleExport void UnregisterPICTImage(void)
2116
0
{
2117
0
  (void) UnregisterMagickInfo("PCT");
2118
0
  (void) UnregisterMagickInfo("PICT");
2119
0
}
2120

2121
/*
2122
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2123
%                                                                             %
2124
%                                                                             %
2125
%                                                                             %
2126
%   W r i t e P I C T I m a g e                                               %
2127
%                                                                             %
2128
%                                                                             %
2129
%                                                                             %
2130
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2131
%
2132
%  Method WritePICTImage writes an image to a file in the Apple Macintosh
2133
%  QuickDraw/PICT image format.
2134
%
2135
%  The format of the WritePICTImage method is:
2136
%
2137
%      unsigned int WritePICTImage(const ImageInfo *image_info,Image *image)
2138
%
2139
%  A description of each parameter follows.
2140
%
2141
%    o status: Method WritePICTImage return True if the image is written.
2142
%      False is returned is there is a memory shortage or if the image file
2143
%      fails to write.
2144
%
2145
%    o image_info: Specifies a pointer to a ImageInfo structure.
2146
%
2147
%    o image:  A pointer to an Image structure.
2148
%
2149
%
2150
*/
2151
#define LiberatePICTAllocations()                                       \
2152
0
  {                                                                     \
2153
0
    MagickFreeResourceLimitedMemory(unsigned char *,buffer);            \
2154
0
    MagickFreeResourceLimitedMemory(unsigned char *,packed_scanline);   \
2155
0
    MagickFreeResourceLimitedMemory(unsigned char *,scanline);          \
2156
0
  }
2157
#define ThrowPICTWriterException(code_,reason_,image_)  \
2158
0
  {                                                     \
2159
0
    LiberatePICTAllocations();                          \
2160
0
    ThrowWriterException(code_,reason_,image_);         \
2161
0
  }
2162
static unsigned int WritePICTImage(const ImageInfo *image_info,Image *image)
2163
487
{
2164
487
#define MaxCount  128U
2165
487
#define PictCropRegionOp  0x01
2166
487
#define PictEndOfPictureOp  0xff
2167
487
#define PictJPEGOp  0x8200
2168
487
#define PictInfoOp  0x0C00
2169
974
#define PictInfoSize  512
2170
487
#define PictPixmapOp  0x9A
2171
487
#define PictPICTOp  0x98
2172
487
#define PictVersion  0x11
2173
2174
487
  double
2175
487
    x_resolution = 72.0,
2176
487
    y_resolution = 72.0;
2177
2178
487
  long
2179
487
    y;
2180
2181
487
  ExtendedSignedIntegralType
2182
487
    offset;
2183
2184
487
  PICTPixmap
2185
487
    pixmap;
2186
2187
487
  PICTRectangle
2188
487
    bounds,
2189
487
    crop_rectangle,
2190
487
    destination_rectangle,
2191
487
    frame_rectangle,
2192
487
    size_rectangle,
2193
487
    source_rectangle;
2194
2195
487
  const unsigned char
2196
487
    *profile_info;
2197
2198
487
  size_t
2199
487
    profile_length;
2200
2201
487
  register const PixelPacket
2202
487
    *p;
2203
2204
487
  register const IndexPacket
2205
487
    *indexes;
2206
2207
487
  register long
2208
487
    i,
2209
487
    x;
2210
2211
487
  size_t
2212
487
    bytes_per_line,
2213
487
    count,
2214
487
    row_bytes;
2215
2216
487
  unsigned char
2217
487
    *buffer = (unsigned char *) NULL,
2218
487
    *packed_scanline = (unsigned char *) NULL,
2219
487
    *scanline = (unsigned char *) NULL;
2220
2221
487
  unsigned int
2222
487
    status;
2223
2224
487
  unsigned long
2225
487
    storage_class;
2226
2227
487
  unsigned short
2228
487
    base_address,
2229
487
    transfer_mode;
2230
2231
487
  MagickBool
2232
487
    logging;
2233
2234
487
  logging=IsEventLogged(CoderEvent);
2235
2236
  /*
2237
    Open output image file.
2238
  */
2239
487
  assert(image_info != (const ImageInfo *) NULL);
2240
487
  assert(image_info->signature == MagickSignature);
2241
487
  assert(image != (Image *) NULL);
2242
487
  assert(image->signature == MagickSignature);
2243
487
  if ((image->columns > 65535L) || (image->rows > 65535L))
2244
487
    ThrowPICTWriterException(ImageError,WidthOrHeightExceedsLimit,image);
2245
487
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2246
487
  if (status == False)
2247
487
    ThrowPICTWriterException(FileOpenError,UnableToOpenFile,image);
2248
487
  (void) TransformColorspace(image,RGBColorspace);
2249
  /*
2250
    Initialize image info.
2251
  */
2252
487
  size_rectangle.top=0;
2253
487
  size_rectangle.left=0;
2254
487
  size_rectangle.bottom=(short) image->rows;
2255
487
  size_rectangle.right=(short) image->columns;
2256
487
  frame_rectangle=size_rectangle;
2257
487
  crop_rectangle=size_rectangle;
2258
487
  source_rectangle=size_rectangle;
2259
487
  destination_rectangle=size_rectangle;
2260
487
  base_address=0xff;
2261
487
  row_bytes=(size_t) image->columns;
2262
487
  bounds.top=0;
2263
487
  bounds.left=0;
2264
487
  bounds.bottom=(short) image->rows;
2265
487
  bounds.right=(short) image->columns;
2266
487
  pixmap.version=0;
2267
487
  pixmap.pack_type=0;
2268
487
  pixmap.pack_size=0;
2269
487
  pixmap.horizontal_resolution=(unsigned int) x_resolution;
2270
487
  pixmap.vertical_resolution=(unsigned int) y_resolution;
2271
487
  pixmap.pixel_type=0;
2272
487
  pixmap.bits_per_pixel=8;
2273
487
  pixmap.component_count=1;
2274
487
  pixmap.component_size=8;
2275
487
  pixmap.plane_bytes=0;
2276
487
  pixmap.table=0;
2277
487
  pixmap.reserved=0;
2278
487
  transfer_mode=0;
2279
487
  if ((image->x_resolution > MagickEpsilon) &&
2280
12
      (image->y_resolution > MagickEpsilon))
2281
10
    {
2282
10
      x_resolution=image->x_resolution;
2283
10
      y_resolution=image->y_resolution;
2284
10
      if (image->units == PixelsPerCentimeterResolution)
2285
0
        {
2286
0
          x_resolution *= 2.54;
2287
0
          y_resolution *= 2.54;
2288
0
        }
2289
10
      x_resolution=ConstrainToRange(0.0,(double) 0xffff,x_resolution);
2290
10
      pixmap.horizontal_resolution=(unsigned int) x_resolution;
2291
10
      y_resolution=ConstrainToRange(0.0,(double) 0xffff,y_resolution);
2292
10
      pixmap.vertical_resolution=(unsigned int) y_resolution;
2293
10
    }
2294
487
  storage_class=image->storage_class;
2295
487
  if (image->compression == JPEGCompression)
2296
0
    storage_class=DirectClass;
2297
487
  if (storage_class == DirectClass)
2298
487
    {
2299
487
      pixmap.component_count=image->matte ? 4 : 3;
2300
487
      pixmap.pixel_type=16;
2301
487
      pixmap.bits_per_pixel=32;
2302
487
      pixmap.pack_type=0x04;
2303
487
      transfer_mode=0x40;
2304
487
      row_bytes=(size_t) 4*image->columns;
2305
487
    }
2306
487
  TracePixMap(image,pixmap);
2307
2308
  /*
2309
    Allocate memory.
2310
  */
2311
487
  bytes_per_line=(size_t) image->columns;
2312
487
  if (storage_class == DirectClass)
2313
487
    bytes_per_line = MagickArraySize(bytes_per_line, image->matte ? 4 : 3);
2314
487
  if (logging)
2315
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2316
0
                          "Bytes per line: %" MAGICK_SIZE_T_F "u bytes,"
2317
0
                          " Row bytes: %" MAGICK_SIZE_T_F "u bytes", bytes_per_line, row_bytes);
2318
487
  if ((row_bytes >= (size_t) SIZE_MAX/2) || (bytes_per_line == 0) ||
2319
487
      (bytes_per_line > 0x7FFFU) || ((row_bytes+MaxCount*2U) >= 0x7FFFU))
2320
487
    ThrowPICTWriterException(CoderError,UnsupportedNumberOfColumns,image);
2321
487
  buffer=MagickAllocateResourceLimitedMemory(unsigned char *,PictInfoSize);
2322
487
  packed_scanline=MagickAllocateResourceLimitedMemory(unsigned char *,(row_bytes+MaxCount*2U));
2323
487
  scanline=MagickAllocateResourceLimitedMemory(unsigned char *,row_bytes);
2324
487
  if ((buffer == (unsigned char *) NULL) ||
2325
487
      (packed_scanline == (unsigned char *) NULL) ||
2326
487
      (scanline == (unsigned char *) NULL))
2327
487
    ThrowPICTWriterException(ResourceLimitError,MemoryAllocationFailed,image);
2328
  /*
2329
    Write header, header size, size bounding box, version, and reserved.
2330
  */
2331
487
  (void) memset(buffer,0,PictInfoSize);
2332
487
  (void) WriteBlob(image,PictInfoSize,buffer);
2333
487
  (void) WriteBlobMSBShort(image,0);
2334
487
  (void) WriteBlobMSBShort(image,size_rectangle.top);
2335
487
  (void) WriteBlobMSBShort(image,size_rectangle.left);
2336
487
  (void) WriteBlobMSBShort(image,size_rectangle.bottom);
2337
487
  (void) WriteBlobMSBShort(image,size_rectangle.right);
2338
487
  (void) WriteBlobMSBShort(image,PictVersion);
2339
487
  (void) WriteBlobMSBShort(image,0x02ff);  /* version #2 */
2340
487
  (void) WriteBlobMSBShort(image,PictInfoOp);
2341
487
  (void) WriteBlobMSBLong(image,0xFFFE0000UL);
2342
  /*
2343
    Write full size of the file, resolution, frame bounding box, and reserved.
2344
  */
2345
  /* (void) WriteBlobMSBLong(image,pixmap.horizontal_resolution); */
2346
487
  (void) WriteBlobMSBShort(image,pixmap.horizontal_resolution & 0xFFFF);
2347
487
  (void) WriteBlobMSBShort(image,0x0000);
2348
  /* (void) WriteBlobMSBLong(image,pixmap.vertical_resolution); */
2349
487
  (void) WriteBlobMSBShort(image,pixmap.vertical_resolution & 0xFFFF);
2350
487
  (void) WriteBlobMSBShort(image,0x0000);
2351
487
  (void) WriteBlobMSBShort(image,frame_rectangle.top);
2352
487
  (void) WriteBlobMSBShort(image,frame_rectangle.left);
2353
487
  (void) WriteBlobMSBShort(image,frame_rectangle.bottom);
2354
487
  (void) WriteBlobMSBShort(image,frame_rectangle.right);
2355
487
  (void) WriteBlobMSBLong(image,0x00000000L);
2356
  /*
2357
    Output 8BIM profile.
2358
  */
2359
487
  profile_info=GetImageProfile(image,"8BIM",&profile_length);
2360
487
  if (profile_info != (unsigned char *) NULL)
2361
59
    {
2362
59
      (void) WriteBlobMSBShort(image,0xa1);
2363
59
      (void) WriteBlobMSBShort(image,0x1f2);
2364
59
      (void) WriteBlobMSBShort(image,(magick_uint16_t) profile_length+4);
2365
59
      (void) WriteBlobString(image,"8BIM");
2366
59
      (void) WriteBlob(image,profile_length,
2367
59
                       profile_info);
2368
59
    }
2369
  /*
2370
    Output ICM profile.
2371
  */
2372
487
  profile_info=GetImageProfile(image,"ICM",&profile_length);
2373
487
  if (profile_info != (unsigned char *) NULL)
2374
56
    {
2375
56
      (void) WriteBlobMSBShort(image,0xa1);
2376
56
      (void) WriteBlobMSBShort(image,0xe0);
2377
56
      (void) WriteBlobMSBShort(image,(magick_uint16_t) profile_length+4);
2378
56
      (void) WriteBlobMSBLong(image,0x00000000UL);
2379
56
      (void) WriteBlob(image,profile_length,
2380
56
                       profile_info);
2381
56
      (void) WriteBlobMSBShort(image,0xa1);
2382
56
      (void) WriteBlobMSBShort(image,0xe0);
2383
56
      (void) WriteBlobMSBShort(image,4);
2384
56
      (void) WriteBlobMSBLong(image,0x00000002UL);
2385
56
    }
2386
  /*
2387
    Write crop region opcode and crop bounding box.
2388
  */
2389
487
  (void) WriteBlobMSBShort(image,PictCropRegionOp);
2390
487
  (void) WriteBlobMSBShort(image,0xa);
2391
487
  (void) WriteBlobMSBShort(image,crop_rectangle.top);
2392
487
  (void) WriteBlobMSBShort(image,crop_rectangle.left);
2393
487
  (void) WriteBlobMSBShort(image,crop_rectangle.bottom);
2394
487
  (void) WriteBlobMSBShort(image,crop_rectangle.right);
2395
487
  if (image->compression == JPEGCompression)
2396
0
    {
2397
0
      Image
2398
0
        *jpeg_image;
2399
2400
0
      size_t
2401
0
        length;
2402
2403
0
      unsigned char
2404
0
        *blob;
2405
2406
0
      jpeg_image=CloneImage(image,0,0,True,&image->exception);
2407
0
      if (jpeg_image == (Image *) NULL)
2408
0
        {
2409
0
          LiberatePICTAllocations();
2410
0
          CloseBlob(image);
2411
0
          return (False);
2412
0
        }
2413
0
      DestroyBlob(jpeg_image);
2414
0
      jpeg_image->blob=CloneBlobInfo((BlobInfo *) NULL);
2415
0
      (void) strlcpy(jpeg_image->magick,"JPEG",sizeof(jpeg_image->magick));
2416
0
      blob=(unsigned char *) ImageToBlob(image_info,jpeg_image,&length,
2417
0
        &image->exception);
2418
0
      DestroyImage(jpeg_image);
2419
0
      if (blob == (unsigned char *) NULL)
2420
0
        {
2421
0
          LiberatePICTAllocations();
2422
0
          CloseBlob(image);
2423
0
          return(False);
2424
0
        }
2425
0
      (void) WriteBlobMSBShort(image,PictJPEGOp);
2426
0
      (void) WriteBlobMSBLong(image,(magick_uint16_t) length+154);
2427
0
      (void) WriteBlobMSBShort(image,0x0000);
2428
0
      (void) WriteBlobMSBLong(image,0x00010000UL);
2429
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2430
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2431
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2432
0
      (void) WriteBlobMSBLong(image,0x00010000UL);
2433
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2434
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2435
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2436
0
      (void) WriteBlobMSBLong(image,0x40000000UL);
2437
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2438
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2439
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2440
0
      (void) WriteBlobMSBLong(image,0x00400000UL);
2441
0
      (void) WriteBlobMSBShort(image,0x0000);
2442
0
      (void) WriteBlobMSBShort(image,image->rows);
2443
0
      (void) WriteBlobMSBShort(image,image->columns);
2444
0
      (void) WriteBlobMSBShort(image,0x0000);
2445
0
      (void) WriteBlobMSBShort(image,768);
2446
0
      (void) WriteBlobMSBShort(image,0x0000);
2447
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2448
0
      (void) WriteBlobMSBLong(image,0x00566A70UL);
2449
0
      (void) WriteBlobMSBLong(image,0x65670000UL);
2450
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2451
0
      (void) WriteBlobMSBLong(image,0x00000001UL);
2452
0
      (void) WriteBlobMSBLong(image,0x00016170UL);
2453
0
      (void) WriteBlobMSBLong(image,0x706C0000UL);
2454
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2455
0
      (void) WriteBlobMSBShort(image,768);
2456
0
      (void) WriteBlobMSBShort(image,image->columns);
2457
0
      (void) WriteBlobMSBShort(image,image->rows);
2458
0
      (void) WriteBlobMSBShort(image,(unsigned short) x_resolution);
2459
0
      (void) WriteBlobMSBShort(image,0x0000);
2460
0
      (void) WriteBlobMSBShort(image,(unsigned short) y_resolution);
2461
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2462
0
      (void) WriteBlobMSBLong(image,0x87AC0001UL);
2463
0
      (void) WriteBlobMSBLong(image,0x0B466F74UL);
2464
0
      (void) WriteBlobMSBLong(image,0x6F202D20UL);
2465
0
      (void) WriteBlobMSBLong(image,0x4A504547UL);
2466
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2467
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2468
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2469
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2470
0
      (void) WriteBlobMSBLong(image,0x00000000UL);
2471
0
      (void) WriteBlobMSBLong(image,0x0018FFFFUL);
2472
0
      (void) WriteBlob(image,length,blob);
2473
0
      if (length & 0x01)
2474
0
        (void) WriteBlobByte(image,'\0');
2475
0
      MagickFreeMemory(blob);
2476
0
    }
2477
  /*
2478
    Write picture opcode, row bytes, and picture bounding box, and version.
2479
  */
2480
487
  if (storage_class == PseudoClass)
2481
0
    (void) WriteBlobMSBShort(image,PictPICTOp);
2482
487
  else
2483
487
    {
2484
487
      (void) WriteBlobMSBShort(image,PictPixmapOp);
2485
487
      (void) WriteBlobMSBLong(image,(unsigned long) base_address);
2486
487
    }
2487
487
  (void) WriteBlobMSBShort(image,(unsigned short) (row_bytes | 0x8000));
2488
487
  (void) WriteBlobMSBShort(image,bounds.top);
2489
487
  (void) WriteBlobMSBShort(image,bounds.left);
2490
487
  (void) WriteBlobMSBShort(image,bounds.bottom);
2491
487
  (void) WriteBlobMSBShort(image,bounds.right);
2492
  /*
2493
    Write pack type, pack size, resolution, pixel type, and pixel size.
2494
  */
2495
487
  (void) WriteBlobMSBShort(image,pixmap.version);
2496
487
  (void) WriteBlobMSBShort(image,pixmap.pack_type);
2497
487
  (void) WriteBlobMSBLong(image,pixmap.pack_size);
2498
487
  (void) WriteBlobMSBShort(image,(unsigned short) x_resolution);
2499
487
  (void) WriteBlobMSBShort(image,0x0000);
2500
487
  (void) WriteBlobMSBShort(image,(unsigned short) y_resolution);
2501
487
  (void) WriteBlobMSBShort(image,0x0000);
2502
487
  (void) WriteBlobMSBShort(image,pixmap.pixel_type);
2503
487
  (void) WriteBlobMSBShort(image,pixmap.bits_per_pixel);
2504
  /*
2505
    Write component count, size, plane bytes, table size, and reserved.
2506
  */
2507
487
  (void) WriteBlobMSBShort(image,pixmap.component_count);
2508
487
  (void) WriteBlobMSBShort(image,pixmap.component_size);
2509
487
  (void) WriteBlobMSBLong(image,(unsigned long) pixmap.plane_bytes);
2510
487
  (void) WriteBlobMSBLong(image,(unsigned long) pixmap.table);
2511
487
  (void) WriteBlobMSBLong(image,(unsigned long) pixmap.reserved);
2512
487
  if (storage_class == PseudoClass)
2513
0
    {
2514
      /*
2515
        Write image colormap.
2516
      */
2517
0
      (void) WriteBlobMSBLong(image,0x00000000L);  /* color seed */
2518
0
      (void) WriteBlobMSBShort(image,0L);  /* color flags */
2519
0
      (void) WriteBlobMSBShort(image,(unsigned short) (image->colors-1));
2520
0
      for (i=0; i < (long) image->colors; i++)
2521
0
      {
2522
0
        (void) WriteBlobMSBShort(image,i);
2523
0
        (void) WriteBlobMSBShort(image,
2524
0
          ScaleQuantumToShort(image->colormap[i].red));
2525
0
        (void) WriteBlobMSBShort(image,
2526
0
          ScaleQuantumToShort(image->colormap[i].green));
2527
0
        (void) WriteBlobMSBShort(image,
2528
0
          ScaleQuantumToShort(image->colormap[i].blue));
2529
0
      }
2530
0
    }
2531
  /*
2532
    Write source and destination rectangle.
2533
  */
2534
487
  (void) WriteBlobMSBShort(image,source_rectangle.top);
2535
487
  (void) WriteBlobMSBShort(image,source_rectangle.left);
2536
487
  (void) WriteBlobMSBShort(image,source_rectangle.bottom);
2537
487
  (void) WriteBlobMSBShort(image,source_rectangle.right);
2538
487
  (void) WriteBlobMSBShort(image,destination_rectangle.top);
2539
487
  (void) WriteBlobMSBShort(image,destination_rectangle.left);
2540
487
  (void) WriteBlobMSBShort(image,destination_rectangle.bottom);
2541
487
  (void) WriteBlobMSBShort(image,destination_rectangle.right);
2542
487
  (void) WriteBlobMSBShort(image,transfer_mode);
2543
  /*
2544
    Write picture data.
2545
  */
2546
487
  count=0;
2547
487
  if (storage_class == PseudoClass)
2548
0
    for (y=0; y < (long) image->rows; y++)
2549
0
    {
2550
0
      p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2551
0
      if (p == (const PixelPacket *) NULL)
2552
0
        break;
2553
0
      indexes=AccessImmutableIndexes(image);
2554
0
      for (x=0; x < (long) image->columns; x++)
2555
0
        scanline[x]=indexes[x];
2556
0
      count+=EncodeImage(image,scanline,row_bytes & 0x7FFF,packed_scanline);
2557
0
      if (QuantumTick(y,image->rows))
2558
0
        if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2559
0
                                    SaveImageText,image->filename,
2560
0
                                    image->columns,image->rows))
2561
0
          break;
2562
0
    }
2563
487
  else
2564
487
    if (image->compression == JPEGCompression)
2565
0
      {
2566
0
        (void) memset(scanline,0,row_bytes);
2567
0
        for (y=0; y < (long) image->rows; y++)
2568
0
          count+=EncodeImage(image,scanline,row_bytes & 0x7FFF,packed_scanline);
2569
0
      }
2570
487
    else
2571
487
      {
2572
487
        register unsigned char
2573
487
          *blue,
2574
487
          *green,
2575
487
          *opacity,
2576
487
          *red;
2577
2578
487
        red=scanline;
2579
487
        green=scanline+image->columns;
2580
487
        blue=scanline+ (size_t)2*image->columns;
2581
487
        opacity=scanline+ (size_t)3*image->columns;
2582
234k
        for (y=0; y < (long) image->rows; y++)
2583
233k
        {
2584
233k
          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2585
233k
          if (p == (const PixelPacket *) NULL)
2586
0
            break;
2587
233k
          red=scanline;
2588
233k
          green=scanline+image->columns;
2589
233k
          blue=scanline+ (size_t)2*image->columns;
2590
233k
          if (image->matte)
2591
0
            {
2592
0
              opacity=scanline;
2593
0
              red=scanline+image->columns;
2594
0
              green=scanline+ (size_t)2*image->columns;
2595
0
              blue=scanline+ (size_t)3*image->columns;
2596
0
            }
2597
217M
          for (x=0; x < (long) image->columns; x++)
2598
217M
          {
2599
217M
            *red++=ScaleQuantumToChar(p->red);
2600
217M
            *green++=ScaleQuantumToChar(p->green);
2601
217M
            *blue++=ScaleQuantumToChar(p->blue);
2602
217M
            if (image->matte)
2603
0
              *opacity++=ScaleQuantumToChar(MaxRGB-p->opacity);
2604
217M
            p++;
2605
217M
          }
2606
233k
          count+=EncodeImage(image,scanline,bytes_per_line & 0x7FFF,packed_scanline);
2607
233k
          if (QuantumTick(y,image->rows))
2608
35.6k
            if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2609
35.6k
                                        SaveImageText,image->filename,
2610
35.6k
                                        image->columns,image->rows))
2611
0
              break;
2612
233k
        }
2613
487
      }
2614
487
  if (count & 0x1)
2615
180
    (void) WriteBlobByte(image,'\0');
2616
487
  (void) WriteBlobMSBShort(image,PictEndOfPictureOp);
2617
487
  offset=TellBlob(image);
2618
487
  (void) SeekBlob(image,512,SEEK_SET);
2619
487
  (void) WriteBlobMSBShort(image,(unsigned long) offset);
2620
487
  MagickFreeResourceLimitedMemory(unsigned char *,scanline);
2621
487
  MagickFreeResourceLimitedMemory(unsigned char *,packed_scanline);
2622
487
  MagickFreeResourceLimitedMemory(unsigned char *,buffer);
2623
487
  status &= CloseBlob(image);
2624
487
  return(status);
2625
487
}