Coverage Report

Created: 2025-06-13 06:50

/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginPICT.cpp
Line
Count
Source (jump to first uncovered line)
1
// ==========================================================
2
// Apple Macintosh QuickDraw/PICT Loader
3
//
4
// Design and implementation by
5
// - Amir Ebrahimi (amir@unity3d.com)
6
//
7
// Based on PICT loading code from paintlib (http://www.paintlib.de/paintlib/).
8
//
9
// Paintlib License:
10
// The paintlib source code and all documentation are copyright (c) 1996-2002 
11
// Ulrich von Zadow and other contributors.
12
//
13
// The paintlib source code is supplied "AS IS". Ulrich von Zadow and other 
14
// contributors disclaim all warranties, expressed or implied, including, without
15
// limitation, the warranties of merchantability and of fitness for any purpose. 
16
// The authors assume no liability for direct, indirect, incidental, special, 
17
// exemplary, or consequential damages, which may result from the use of paintlib, 
18
// even if advised of the possibility of such damage.
19
//
20
// Permission is hereby granted to use, copy, modify, and distribute this source 
21
// code, or portions hereof, for any purpose, without fee, subject to the following 
22
// restrictions:
23
//
24
// 1. The origin of this source code must not be misrepresented.
25
// 2. Altered versions must be plainly marked as such and must not be misrepresented
26
//    as being the original source.
27
// 3. This Copyright notice may not be removed or altered from any source or altered 
28
//    source distribution.
29
// 4. Executables containing paintlib or parts of it must state that the software 
30
//    "contains paintlib code. paintlib is copyright (c) 1996-2002 Ulrich von Zadow
31
//    and other contributors.". This notice must be displayed in at least one place
32
//    where the copyright for the software itself is displayed. The documentation must 
33
//    also contain this notice.
34
//
35
// Bug fixes were made to the original code to support version 2 PICT files
36
// properly.
37
// 
38
// Additional resources:
39
// http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-458.html
40
// http://www.fileformat.info/format/macpict/egff.htm
41
// 
42
// Notes (http://lists.apple.com/archives/java-dev/2006/Apr/msg00588.html):
43
// There are three main types of PICT files:
44
//  - Version 1
45
//  - Version 2
46
//  - Extended Version 2
47
//
48
// Some things to look out for:
49
//  - The bounds and target DPI are stored in a different place in all three.
50
//  - Some of the values are fixed-point shorts ( short / 65536f )
51
//  - Values are big endian 
52
//  - All of this may be *preceded* by a 512 byte header--sometimes it is
53
//    there, and sometimes it isn't. You just have to check for the magic
54
//    values in both places.
55
//
56
// This file is part of FreeImage 3
57
//
58
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
59
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
60
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
61
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
62
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
63
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
64
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
65
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
66
// THIS DISCLAIMER.
67
//
68
// Use at your own risk!
69
// ==========================================================
70
71
#include "FreeImage.h"
72
#include "Utilities.h"
73
74
// ==========================================================
75
// Plugin Interface
76
// ==========================================================
77
static int s_format_id;
78
79
static const int outputMessageSize = 256;
80
81
// ==========================================================
82
// Internal functions
83
// ==========================================================
84
85
static BYTE
86
0
Read8(FreeImageIO *io, fi_handle handle) {
87
0
  BYTE i = 0;
88
0
  io->read_proc(&i, 1, 1, handle);
89
0
  return i;
90
0
}
91
92
static WORD
93
0
Read16(FreeImageIO *io, fi_handle handle) {
94
  // reads a two-byte big-endian integer from the given file and returns its value.
95
  // assumes unsigned.
96
  
97
0
  unsigned hi = Read8(io, handle);
98
0
  unsigned lo = Read8(io, handle);
99
0
  return (WORD)(lo + (hi << 8));
100
0
}
101
102
static unsigned
103
0
Read32(FreeImageIO *io, fi_handle handle) {
104
  // reads a four-byte big-endian integer from the given file and returns its value.
105
  // assumes unsigned.
106
  
107
0
  unsigned b3 = Read8(io, handle);
108
0
  unsigned b2 = Read8(io, handle);
109
0
  unsigned b1 = Read8(io, handle);
110
0
  unsigned b0 = Read8(io, handle);
111
0
  return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
112
0
}
113
114
// ----------------------------------------------------------
115
116
struct OpDef
117
{
118
  const char * name;
119
  int    len;
120
  const char * description;
121
};
122
123
// for reserved opcodes
124
#define res(length) { "reserved", (length), "reserved for Apple use" }
125
#define RGB_LEN 6
126
0
#define WORD_LEN -1
127
#define NA 0
128
129
static OpDef optable[] =
130
{
131
/* 0x00 */  { "NOP",               0, "nop" },
132
/* 0x01 */  { "Clip",             NA, "clip" },
133
/* 0x02 */  { "BkPat",             8, "background pattern" },
134
/* 0x03 */  { "TxFont",            2, "text font (word)" },
135
/* 0x04 */  { "TxFace",            1, "text face (byte)" },
136
/* 0x05 */  { "TxMode",            2, "text mode (word)" },
137
/* 0x06 */  { "SpExtra",           4, "space extra (fixed point)" },
138
/* 0x07 */  { "PnSize",            4, "pen size (point)" },
139
/* 0x08 */  { "PnMode",            2, "pen mode (word)" },
140
/* 0x09 */  { "PnPat",             8, "pen pattern" },
141
/* 0x0a */  { "FillPat",           8, "fill pattern" },
142
/* 0x0b */  { "OvSize",            4, "oval size (point)" },
143
/* 0x0c */  { "Origin",            4, "dh, dv (word)" },
144
/* 0x0d */  { "TxSize",            2, "text size (word)" },
145
/* 0x0e */  { "FgColor",           4, "foreground color (longword)" },
146
/* 0x0f */  { "BkColor",           4, "background color (longword)" },
147
/* 0x10 */  { "TxRatio",           8, "numerator (point), denominator (point)" },
148
/* 0x11 */  { "Version",           1, "version (byte)" },
149
/* 0x12 */  { "BkPixPat",         NA, "color background pattern" },
150
/* 0x13 */  { "PnPixPat",         NA, "color pen pattern" },
151
/* 0x14 */  { "FillPixPat",       NA, "color fill pattern" },
152
/* 0x15 */  { "PnLocHFrac",        2, "fractional pen position" },
153
/* 0x16 */  { "ChExtra",           2, "extra for each character" },
154
/* 0x17 */  res(0),
155
/* 0x18 */  res(0),
156
/* 0x19 */  res(0),
157
/* 0x1a */  { "RGBFgCol",    RGB_LEN, "RGB foreColor" },
158
/* 0x1b */  { "RGBBkCol",    RGB_LEN, "RGB backColor" },
159
/* 0x1c */  { "HiliteMode",        0, "hilite mode flag" },
160
/* 0x1d */  { "HiliteColor", RGB_LEN, "RGB hilite color" },
161
/* 0x1e */  { "DefHilite",         0, "Use default hilite color" },
162
/* 0x1f */  { "OpColor",           6, "RGB OpColor for arithmetic modes" },
163
/* 0x20 */  { "Line",              8, "pnLoc (point), newPt (point)" },
164
/* 0x21 */  { "LineFrom",          4, "newPt (point)" },
165
/* 0x22 */  { "ShortLine",         6, "pnLoc (point, dh, dv (-128 .. 127))" },
166
/* 0x23 */  { "ShortLineFrom",     2, "dh, dv (-128 .. 127)" },
167
/* 0x24 */  res(WORD_LEN),
168
/* 0x25 */  res(WORD_LEN),
169
/* 0x26 */  res(WORD_LEN),
170
/* 0x27 */  res(WORD_LEN),
171
/* 0x28 */  { "LongText",         NA, "txLoc (point), count (0..255), text" },
172
/* 0x29 */  { "DHText",           NA, "dh (0..255), count (0..255), text" },
173
/* 0x2a */  { "DVText",           NA, "dv (0..255), count (0..255), text" },
174
/* 0x2b */  { "DHDVText",         NA, "dh, dv (0..255), count (0..255), text" },
175
/* 0x2c */  res(WORD_LEN),
176
/* 0x2d */  res(WORD_LEN),
177
/* 0x2e */  res(WORD_LEN),
178
/* 0x2f */  res(WORD_LEN),
179
/* 0x30 */  { "frameRect",         8, "rect" },
180
/* 0x31 */  { "paintRect",         8, "rect" },
181
/* 0x32 */  { "eraseRect",         8, "rect" },
182
/* 0x33 */  { "invertRect",        8, "rect" },
183
/* 0x34 */  { "fillRect",          8, "rect" },
184
/* 0x35 */  res(8),
185
/* 0x36 */  res(8),
186
/* 0x37 */  res(8),
187
/* 0x38 */  { "frameSameRect",     0, "rect" },
188
/* 0x39 */  { "paintSameRect",     0, "rect" },
189
/* 0x3a */  { "eraseSameRect",     0, "rect" },
190
/* 0x3b */  { "invertSameRect",    0, "rect" },
191
/* 0x3c */  { "fillSameRect",      0, "rect" },
192
/* 0x3d */  res(0),
193
/* 0x3e */  res(0),
194
/* 0x3f */  res(0),
195
/* 0x40 */  { "frameRRect",        8, "rect" },
196
/* 0x41 */  { "paintRRect",        8, "rect" },
197
/* 0x42 */  { "eraseRRect",        8, "rect" },
198
/* 0x43 */  { "invertRRect",       8, "rect" },
199
/* 0x44 */  { "fillRRrect",        8, "rect" },
200
/* 0x45 */  res(8),
201
/* 0x46 */  res(8),
202
/* 0x47 */  res(8),
203
/* 0x48 */  { "frameSameRRect",    0, "rect" },
204
/* 0x49 */  { "paintSameRRect",    0, "rect" },
205
/* 0x4a */  { "eraseSameRRect",    0, "rect" },
206
/* 0x4b */  { "invertSameRRect",   0, "rect" },
207
/* 0x4c */  { "fillSameRRect",     0, "rect" },
208
/* 0x4d */  res(0),
209
/* 0x4e */  res(0),
210
/* 0x4f */  res(0),
211
/* 0x50 */  { "frameOval",         8, "rect" },
212
/* 0x51 */  { "paintOval",         8, "rect" },
213
/* 0x52 */  { "eraseOval",         8, "rect" },
214
/* 0x53 */  { "invertOval",        8, "rect" },
215
/* 0x54 */  { "fillOval",          8, "rect" },
216
/* 0x55 */  res(8),
217
/* 0x56 */  res(8),
218
/* 0x57 */  res(8),
219
/* 0x58 */  { "frameSameOval",     0, "rect" },
220
/* 0x59 */  { "paintSameOval",     0, "rect" },
221
/* 0x5a */  { "eraseSameOval",     0, "rect" },
222
/* 0x5b */  { "invertSameOval",    0, "rect" },
223
/* 0x5c */  { "fillSameOval",      0, "rect" },
224
/* 0x5d */  res(0),
225
/* 0x5e */  res(0),
226
/* 0x5f */  res(0),
227
/* 0x60 */  { "frameArc",         12, "rect, startAngle, arcAngle" },
228
/* 0x61 */  { "paintArc",         12, "rect, startAngle, arcAngle" },
229
/* 0x62 */  { "eraseArc",         12, "rect, startAngle, arcAngle" },
230
/* 0x63 */  { "invertArc",        12, "rect, startAngle, arcAngle" },
231
/* 0x64 */  { "fillArc",          12, "rect, startAngle, arcAngle" },
232
/* 0x65 */  res(12),
233
/* 0x66 */  res(12),
234
/* 0x67 */  res(12),
235
/* 0x68 */  { "frameSameArc",      4, "rect, startAngle, arcAngle" },
236
/* 0x69 */  { "paintSameArc",      4, "rect, startAngle, arcAngle" },
237
/* 0x6a */  { "eraseSameArc",      4, "rect, startAngle, arcAngle" },
238
/* 0x6b */  { "invertSameArc",     4, "rect, startAngle, arcAngle" },
239
/* 0x6c */  { "fillSameArc",       4, "rect, startAngle, arcAngle" },
240
/* 0x6d */  res(4),
241
/* 0x6e */  res(4),
242
/* 0x6f */  res(4),
243
/* 0x70 */  { "framePoly",        NA, "poly" },
244
/* 0x71 */  { "paintPoly",        NA, "poly" },
245
/* 0x72 */  { "erasePoly",        NA, "poly" },
246
/* 0x73 */  { "invertPoly",       NA, "poly" },
247
/* 0x74 */  { "fillPoly",         NA, "poly" },
248
/* 0x75 */  res(NA),
249
/* 0x76 */  res(NA),
250
/* 0x77 */  res(NA),
251
/* 0x78 */  { "frameSamePoly",     0, "poly (NYI)" },
252
/* 0x79 */  { "paintSamePoly",     0, "poly (NYI)" },
253
/* 0x7a */  { "eraseSamePoly",     0, "poly (NYI)" },
254
/* 0x7b */  { "invertSamePoly",    0, "poly (NYI)" },
255
/* 0x7c */  { "fillSamePoly",      0, "poly (NYI)" },
256
/* 0x7d */  res(0),
257
/* 0x7e */  res(0),
258
/* 0x7f */  res(0),
259
/* 0x80 */  { "frameRgn",         NA, "region" },
260
/* 0x81 */  { "paintRgn",         NA, "region" },
261
/* 0x82 */  { "eraseRgn",         NA, "region" },
262
/* 0x83 */  { "invertRgn",        NA, "region" },
263
/* 0x84 */  { "fillRgn",          NA, "region" },
264
/* 0x85 */  res(NA),
265
/* 0x86 */  res(NA),
266
/* 0x87 */  res(NA),
267
/* 0x88 */  { "frameSameRgn",      0, "region (NYI)" },
268
/* 0x89 */  { "paintSameRgn",      0, "region (NYI)" },
269
/* 0x8a */  { "eraseSameRgn",      0, "region (NYI)" },
270
/* 0x8b */  { "invertSameRgn",     0, "region (NYI)" },
271
/* 0x8c */  { "fillSameRgn",       0, "region (NYI)" },
272
/* 0x8d */  res(0),
273
/* 0x8e */  res(0),
274
/* 0x8f */  res(0),
275
/* 0x90 */  { "BitsRect",         NA, "copybits, rect clipped" },
276
/* 0x91 */  { "BitsRgn",          NA, "copybits, rgn clipped" },
277
/* 0x92 */  res(WORD_LEN),
278
/* 0x93 */  res(WORD_LEN),
279
/* 0x94 */  res(WORD_LEN),
280
/* 0x95 */  res(WORD_LEN),
281
/* 0x96 */  res(WORD_LEN),
282
/* 0x97 */  res(WORD_LEN),
283
/* 0x98 */  { "PackBitsRect",     NA, "packed copybits, rect clipped" },
284
/* 0x99 */  { "PackBitsRgn",      NA, "packed copybits, rgn clipped" },
285
/* 0x9a */  { "Opcode_9A",        NA, "the mysterious opcode 9A" },
286
/* 0x9b */  res(WORD_LEN),
287
/* 0x9c */  res(WORD_LEN),
288
/* 0x9d */  res(WORD_LEN),
289
/* 0x9e */  res(WORD_LEN),
290
/* 0x9f */  res(WORD_LEN),
291
/* 0xa0 */  { "ShortComment",      2, "kind (word)" },
292
/* 0xa1 */  { "LongComment",      NA, "kind (word), size (word), data" }
293
};
294
295
// ----------------------------------------------------------
296
297
struct MacRect
298
{
299
  WORD top;
300
  WORD left;
301
  WORD bottom;
302
  WORD right;
303
};
304
305
struct MacpixMap
306
{
307
  // Ptr baseAddr              // Not used in file.
308
  // short rowBytes            // read in seperatly.
309
  struct MacRect Bounds;
310
  WORD version;
311
  WORD packType;
312
  LONG packSize;
313
  LONG hRes;
314
  LONG vRes;
315
  WORD pixelType;
316
  WORD pixelSize;
317
  WORD cmpCount;
318
  WORD cmpSize;
319
  LONG planeBytes;
320
  LONG pmTable;
321
  LONG pmReserved;
322
};
323
324
struct MacRGBColour
325
{
326
  WORD red;
327
  WORD green;
328
  WORD blue;
329
};
330
331
struct MacPoint
332
{
333
  WORD x;
334
  WORD y;
335
};
336
337
struct MacPattern // Klaube
338
{
339
  BYTE pix[64];
340
};
341
342
// ----------------------------------------------------------
343
344
static void 
345
0
ReadRect( FreeImageIO *io, fi_handle handle, MacRect* rect ) {
346
0
  rect->top = Read16( io, handle );
347
0
  rect->left = Read16( io, handle );
348
0
  rect->bottom = Read16( io, handle );
349
0
  rect->right = Read16( io, handle );
350
0
}
351
352
static void 
353
0
ReadPixmap( FreeImageIO *io, fi_handle handle, MacpixMap* pPixMap ) {
354
0
  pPixMap->version = Read16( io, handle );
355
0
  pPixMap->packType = Read16( io, handle );
356
0
  pPixMap->packSize = Read32( io, handle );
357
0
  pPixMap->hRes = Read16( io, handle );
358
0
  Read16( io, handle );
359
0
  pPixMap->vRes = Read16( io, handle );
360
0
  Read16( io, handle );
361
0
  pPixMap->pixelType = Read16( io, handle );
362
0
  pPixMap->pixelSize = Read16( io, handle );
363
0
  pPixMap->cmpCount = Read16( io, handle );
364
0
  pPixMap->cmpSize = Read16( io, handle );
365
0
  pPixMap->planeBytes = Read32( io, handle );
366
0
  pPixMap->pmTable = Read32( io, handle );
367
0
  pPixMap->pmReserved = Read32( io, handle );
368
0
}
369
370
/**
371
Reads a mac color table into a bitmap palette.
372
*/
373
static void 
374
0
ReadColorTable( FreeImageIO *io, fi_handle handle, WORD* pNumColors, RGBQUAD* pPal ) {
375
0
  LONG        ctSeed;
376
0
  WORD        ctFlags;
377
0
  WORD        val;
378
0
  int         i;
379
  
380
0
  ctSeed = Read32( io, handle );
381
0
  ctFlags = Read16( io, handle );
382
0
  WORD numColors = Read16( io, handle )+1;
383
0
  *pNumColors = numColors;
384
  
385
0
  for (i = 0; i < numColors; i++) {
386
0
    val = Read16( io, handle );
387
0
    if (ctFlags & 0x8000) {
388
      // The indicies in a device colour table are bogus and
389
      // usually == 0, so I assume we allocate up the list of
390
      // colours in order.
391
0
      val = (WORD)i;
392
0
    }
393
0
    if (val >= numColors) {
394
0
      throw "pixel value greater than color table size.";
395
0
    }
396
    // Mac colour tables contain 16-bit values for R, G, and B...
397
0
    pPal[val].rgbRed = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF));
398
0
    pPal[val].rgbGreen = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF));
399
0
    pPal[val].rgbBlue = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF));
400
0
  }
401
0
}
402
403
/**
404
skips unneeded packbits.
405
pixelSize == Source bits per pixel.
406
*/
407
static void 
408
0
SkipBits( FreeImageIO *io, fi_handle handle, MacRect* bounds, WORD rowBytes, int pixelSize ) {
409
0
  int    i;
410
0
  WORD   pixwidth;           // bytes per row when uncompressed.
411
  
412
0
  int height = bounds->bottom - bounds->top;
413
0
  int width = bounds->right - bounds->left;
414
  
415
  // High bit of rowBytes is flag.
416
0
  if (pixelSize <= 8) {
417
0
    rowBytes &= 0x7fff;
418
0
  }
419
0
  pixwidth = (WORD)width;
420
  
421
0
  if (pixelSize == 16) {
422
0
    pixwidth *= 2;
423
0
  }
424
0
  if (rowBytes == 0) {
425
0
    rowBytes = pixwidth;
426
0
  }
427
0
  if (rowBytes < 8) {
428
0
    io->seek_proc( handle, rowBytes*height, SEEK_CUR );
429
0
  }
430
0
  else {
431
0
    for (i = 0; i < height; i++) {
432
0
      int lineLen;            // length of source line in bytes.
433
0
      if (rowBytes > 250) {
434
0
        lineLen = Read16( io, handle );
435
0
      } else {
436
0
        lineLen = Read8( io, handle );
437
0
      }
438
0
      io->seek_proc( handle, lineLen, SEEK_CUR );
439
0
    }
440
0
  }
441
0
}
442
443
/**
444
Skip polygon or region
445
*/
446
static void 
447
0
SkipPolyOrRegion( FreeImageIO *io, fi_handle handle ) {
448
0
  WORD len = Read16( io, handle ) - 2;
449
0
  io->seek_proc(handle, len, SEEK_CUR); 
450
0
}
451
452
/**
453
Width in bytes for 8 bpp or less.
454
Width in pixels for 16 bpp.
455
Expands Width units to 32-bit pixel data.
456
*/
457
static void 
458
0
expandBuf( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst ) { 
459
0
  switch (bpp) {
460
0
    case 16:
461
0
      for ( int i=0; i<width; i++) {
462
0
        WORD src = Read16( io, handle );
463
0
        dst[ FI_RGBA_BLUE ] = (src & 31)*8;        // Blue
464
0
        dst[ FI_RGBA_GREEN ] = ((src >> 5) & 31)*8;   // Green
465
0
        dst[ FI_RGBA_RED ] = ((src >> 10) & 31)*8;    // Red
466
0
        dst[ FI_RGBA_ALPHA ] = 0xFF;          // Alpha
467
0
        dst += 4;
468
0
      }
469
0
      break;
470
0
    default:
471
0
      throw "Bad bits per pixel in expandBuf.";
472
0
  }
473
0
}
474
475
/**
476
Expands Width units to 8-bit pixel data.
477
Max. 8 bpp source format.
478
*/
479
static void 
480
expandBuf8( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst )
481
0
{
482
0
  switch (bpp) {
483
0
    case 8:
484
0
      io->read_proc( dst, width, 1, handle );
485
0
      break;
486
0
    case 4:
487
0
      for (int i = 0; i < width; i++) {
488
0
        WORD src = Read8( io, handle );
489
0
        *dst = (src >> 4) & 15;
490
0
        *(dst+1) = (src & 15);
491
0
        dst += 2;
492
0
      }
493
0
      if (width & 1) { // Odd Width?
494
0
        WORD src = Read8( io, handle );
495
0
        *dst = (src >> 4) & 15;
496
0
        dst++;
497
0
      }
498
0
      break;
499
0
    case 2:
500
0
      for (int i = 0; i < width; i++) {
501
0
        WORD src = Read8( io, handle );
502
0
        *dst = (src >> 6) & 3;
503
0
        *(dst+1) = (src >> 4) & 3;
504
0
        *(dst+2) = (src >> 2) & 3;
505
0
        *(dst+3) = (src & 3);
506
0
        dst += 4;
507
0
      }
508
0
      if (width & 3)  { // Check for leftover pixels
509
0
        for (int i = 6; i > 8 - (width & 3) * 2; i -= 2) {
510
0
          WORD src = Read8( io, handle );
511
0
          *dst = (src >> i) & 3;
512
0
          dst++;
513
0
        }
514
0
      }
515
0
      break;
516
0
    case 1:
517
0
      for (int i = 0; i < width; i++) {
518
0
        WORD src = Read8( io, handle );
519
0
        *dst = (src >> 7) & 1;
520
0
        *(dst+1) = (src >> 6) & 1;
521
0
        *(dst+2) = (src >> 5) & 1;
522
0
        *(dst+3) = (src >> 4) & 1;
523
0
        *(dst+4) = (src >> 3) & 1;
524
0
        *(dst+5) = (src >> 2) & 1;
525
0
        *(dst+6) = (src >> 1) & 1;
526
0
        *(dst+7) = (src  & 1);
527
0
        dst += 8;
528
0
      }
529
0
      if (width & 7) {  // Check for leftover pixels
530
0
        for (int i = 7; i > (8-width & 7); i--) {
531
0
          WORD src = Read8( io, handle );
532
0
          *dst = (src >> i) & 1;
533
0
          dst++;
534
0
        }
535
0
      }
536
0
      break;
537
0
    default:
538
0
      throw "Bad bits per pixel in expandBuf8.";
539
0
  }
540
0
}
541
542
static BYTE* 
543
0
UnpackPictRow( FreeImageIO *io, fi_handle handle, BYTE* pLineBuf, int width, int rowBytes, int srcBytes ) { 
544
545
0
  if (rowBytes < 8) { // Ah-ha!  The bits aren't actually packed.  This will be easy.
546
0
    io->read_proc( pLineBuf, rowBytes, 1, handle );
547
0
  }
548
0
  else {
549
0
    BYTE* pCurPixel = pLineBuf;
550
    
551
    // Unpack RLE. The data is packed bytewise.
552
0
    for (int j = 0; j < srcBytes; ) {
553
0
      BYTE FlagCounter = Read8( io, handle );
554
0
      if (FlagCounter & 0x80) {
555
0
        if (FlagCounter == 0x80) {
556
          // Special case: repeat value of 0.
557
          // Apple says ignore.
558
0
          j++;
559
0
        } else { 
560
          // Packed data.
561
0
          int len = ((FlagCounter ^ 255) & 255) + 2;          
562
0
          BYTE p = Read8( io, handle );
563
0
          memset( pCurPixel, p, len);
564
0
          pCurPixel += len;
565
0
          j += 2;
566
0
        }
567
0
      }
568
0
      else { 
569
        // Unpacked data
570
0
        int len = (FlagCounter & 255) + 1;
571
0
        io->read_proc( pCurPixel, len, 1, handle );
572
0
        pCurPixel += len;
573
0
        j += len + 1;
574
0
      }
575
0
    }
576
0
  }
577
  
578
0
  return pLineBuf;
579
0
}
580
581
/**
582
This routine decompresses BitsRects with a packType of 4 (and 32 bits per pixel). 
583
In this format, each line is separated into 8-bit-bitplanes and then compressed via RLE. 
584
To decode, the routine decompresses each line & then juggles the bytes around to get pixel-oriented data.
585
NumBitPlanes == 3 if RGB, 4 if RGBA
586
*/
587
static void 
588
0
Unpack32Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes, int numPlanes ) {
589
0
  int height = bounds->bottom - bounds->top;
590
0
  int width = bounds->right - bounds->left;
591
  
592
0
  if (rowBytes == 0) {
593
0
    rowBytes = (WORD)( width * 4 );
594
0
  }
595
  
596
0
  BYTE* pLineBuf = (BYTE*)malloc( rowBytes ); // Let's allocate enough for 4 bit planes
597
0
  if ( pLineBuf )  {
598
0
    try {
599
0
      for ( int i = 0; i < height; i++ ) { 
600
        // for each line do...
601
0
        int linelen;            // length of source line in bytes.
602
0
        if (rowBytes > 250) {
603
0
          linelen = Read16( io, handle );
604
0
        } else {
605
0
          linelen = Read8( io, handle);
606
0
        }
607
        
608
0
        BYTE* pBuf = UnpackPictRow( io, handle, pLineBuf, width, rowBytes, linelen );
609
        
610
        // Convert plane-oriented data into pixel-oriented data &
611
        // copy into destination bitmap.
612
0
        BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
613
        
614
0
        if ( numPlanes == 3 ) {
615
0
          for ( int j = 0; j < width; j++ ) { 
616
            // For each pixel in line...
617
0
            dst[ FI_RGBA_BLUE ] = (*(pBuf+width*2));     // Blue
618
0
            dst[ FI_RGBA_GREEN ] = (*(pBuf+width));       // Green
619
0
            dst[ FI_RGBA_RED ] = (*pBuf);             // Red
620
0
            dst[ FI_RGBA_ALPHA ] = (0xFF);
621
0
            dst += 4;
622
0
            pBuf++;
623
0
          }
624
0
        } else {
625
0
          for ( int j = 0; j < width; j++ ) { 
626
            // For each pixel in line...
627
0
            dst[ FI_RGBA_BLUE ] = (*(pBuf+width*3));     // Blue
628
0
            dst[ FI_RGBA_GREEN ] = (*(pBuf+width*2));     // Green
629
0
            dst[ FI_RGBA_RED ] = (*(pBuf+width));       // Red
630
0
            dst[ FI_RGBA_ALPHA ] = (*pBuf);
631
0
            dst += 4;
632
0
            pBuf++;
633
0
          }
634
0
        }
635
0
      }
636
0
    }
637
0
    catch( ... ) {
638
0
      free( pLineBuf );
639
0
      throw;
640
0
    }
641
0
  }
642
0
  free( pLineBuf );
643
0
}
644
645
/**
646
Decompression routine for 8 bpp. 
647
rowBytes is the number of bytes each source row would take if it were uncompressed.
648
This _isn't_ equal to the number of pixels in the row - it seems apple pads the data to a word boundary and then compresses it. 
649
Of course, we have to decompress the excess data and then throw it away.
650
*/
651
static void 
652
0
Unpack8Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes ) { 
653
0
  int height = bounds->bottom - bounds->top;
654
0
  int width = bounds->right - bounds->left;
655
  
656
  // High bit of rowBytes is flag.
657
0
  rowBytes &= 0x7fff;
658
  
659
0
  if (rowBytes == 0) {
660
0
    rowBytes = (WORD)width;
661
0
  }
662
  
663
0
  for ( int i = 0; i < height; i++ ) {
664
0
    int linelen;            // length of source line in bytes.
665
0
    if (rowBytes > 250) {
666
0
      linelen = Read16( io, handle );
667
0
    } else {
668
0
      linelen = Read8( io, handle );
669
0
    }
670
0
    BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);       
671
0
    dst = UnpackPictRow( io, handle, dst, width, rowBytes, linelen );
672
0
  }
673
0
}
674
675
/**
676
Decompression routine for everything but 8 & 32 bpp. 
677
This routine is slower than the two routines above since it has to deal with a lot of special cases :-(.
678
It's also a bit chaotic because of these special cases...
679
unpack8bits is basically a dumber version of unpackbits.
680
pixelSize == Source bits per pixel.
681
*/
682
static void 
683
0
UnpackBits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes, int pixelSize ) {
684
0
  WORD   pixwidth;           // bytes per row when uncompressed.
685
0
  int    pkpixsize;
686
0
  int    PixelPerRLEUnit;
687
688
0
  char outputMessage[ outputMessageSize ] = "";
689
  
690
0
  int height = bounds->bottom - bounds->top;
691
0
  int width = bounds->right - bounds->left;
692
  
693
  // High bit of rowBytes is flag.
694
0
  if (pixelSize <= 8) {
695
0
    rowBytes &= 0x7fff;
696
0
  }
697
  
698
0
  pixwidth = (WORD)width;
699
0
  pkpixsize = 1;          // RLE unit: one byte for everything...
700
0
  if (pixelSize == 16) {    // ...except 16 bpp.
701
0
    pkpixsize = 2;
702
0
    pixwidth *= 2;
703
0
  }
704
  
705
0
  if (rowBytes == 0) {
706
0
    rowBytes = pixwidth;
707
0
  }
708
  
709
0
  {
710
    // I allocate the temporary line buffer here. I allocate too
711
    // much memory to compensate for sloppy (& hence fast) decompression.
712
0
    switch (pixelSize) {
713
0
      case 1:
714
0
        PixelPerRLEUnit = 8;
715
0
        break;
716
0
      case 2:
717
0
        PixelPerRLEUnit = 4;
718
0
        break;
719
0
      case 4:
720
0
        PixelPerRLEUnit = 2;
721
0
        break;
722
0
      case 8:
723
0
        PixelPerRLEUnit = 1;
724
0
        break;
725
0
      case 16:
726
0
        PixelPerRLEUnit = 1;
727
0
        break;
728
0
      default:
729
0
        sprintf( outputMessage, "Illegal bpp value in unpackbits: %d\n", pixelSize );
730
0
        throw outputMessage;
731
0
    }
732
    
733
0
    if (rowBytes < 8) { 
734
      // ah-ha!  The bits aren't actually packed.  This will be easy.
735
0
      for ( int i = 0; i < height; i++ ) {
736
0
        BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
737
0
        if (pixelSize == 16) {
738
0
          expandBuf( io, handle, width, pixelSize, dst );
739
0
        } else {
740
0
          expandBuf8( io, handle, width, pixelSize, dst );
741
0
        }
742
0
      }
743
0
    }
744
0
    else {
745
0
      for ( int i = 0; i < height; i++ ) { 
746
        // For each line do...
747
0
        int    linelen;            // length of source line in bytes.
748
0
        if (rowBytes > 250) {
749
0
          linelen = Read16( io, handle );
750
0
        } else {
751
0
          linelen = Read8( io, handle );
752
0
        }
753
        
754
0
        BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
755
0
        BYTE FlagCounter;
756
        
757
        // Unpack RLE. The data is packed bytewise - except for
758
        // 16 bpp data, which is packed per pixel :-(.
759
0
        for ( int j = 0; j < linelen; ) {
760
0
          FlagCounter = Read8( io, handle );
761
0
          if (FlagCounter & 0x80) {
762
0
            if (FlagCounter == 0x80) {
763
              // Special case: repeat value of 0.
764
              // Apple says ignore.
765
0
              j++;
766
0
            }
767
0
            else { 
768
              // Packed data.
769
0
              int len = ((FlagCounter ^ 255) & 255) + 2;
770
              
771
              // This is slow for some formats...
772
0
              if (pixelSize == 16) {
773
0
                expandBuf( io, handle, 1, pixelSize, dst );
774
0
                for ( int k = 1; k < len; k++ ) { 
775
                  // Repeat the pixel len times.
776
0
                  memcpy( dst+(k*4*PixelPerRLEUnit), dst, 4*PixelPerRLEUnit);
777
0
                }
778
0
                dst += len*4*PixelPerRLEUnit;
779
0
              }
780
0
              else {
781
0
                expandBuf8( io, handle, 1, pixelSize, dst );
782
0
                for ( int k = 1; k < len; k++ ) { 
783
                  // Repeat the expanded byte len times.
784
0
                  memcpy( dst+(k*PixelPerRLEUnit), dst, PixelPerRLEUnit);
785
0
                }
786
0
                dst += len*PixelPerRLEUnit;
787
0
              }
788
0
              j += pkpixsize + 1;
789
0
            }
790
0
          }
791
0
          else { 
792
            // Unpacked data
793
0
            int len = (FlagCounter & 255) + 1;
794
0
            if (pixelSize == 16) {
795
0
              expandBuf( io, handle, len, pixelSize, dst );
796
0
              dst += len*4*PixelPerRLEUnit;
797
0
            }
798
0
            else {
799
0
              expandBuf8( io, handle, len, pixelSize, dst );
800
0
              dst += len*PixelPerRLEUnit;
801
0
            }
802
0
            j += ( len * pkpixsize ) + 1;
803
0
          }
804
0
        }
805
0
      }
806
0
    }
807
0
  }
808
0
}
809
810
static void 
811
0
DecodeOp9a( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacpixMap* pixMap ) {
812
  // Do the actual unpacking.
813
0
  switch ( pixMap->pixelSize ) {
814
0
    case 32:
815
0
      Unpack32Bits( io, handle, dib, &pixMap->Bounds, 0, pixMap->cmpCount );
816
0
      break;
817
0
    case 8:
818
0
      Unpack8Bits( io, handle, dib, &pixMap->Bounds, 0 );
819
0
      break;
820
0
    default:
821
0
      UnpackBits( io, handle, dib, &pixMap->Bounds, 0, pixMap->pixelSize );
822
0
  }
823
0
}
824
825
static void 
826
0
DecodeBitmap( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, BOOL isRegion, MacRect* bounds, WORD rowBytes ) {
827
0
  WORD mode = Read16( io, handle );
828
  
829
0
  if ( isRegion ) {
830
0
    SkipPolyOrRegion( io, handle );
831
0
  }
832
  
833
0
  RGBQUAD* pal = FreeImage_GetPalette( dib );
834
0
  if ( !pal ) {
835
0
    throw "No palette for bitmap!";
836
0
  }
837
  
838
0
  for (int i = 0; i < 2; i++) {
839
0
    unsigned char val = i ? 0xFF : 0x0;
840
0
    pal[i].rgbRed = val;
841
0
    pal[i].rgbGreen = val;
842
0
    pal[i].rgbBlue = val;
843
0
  }
844
  
845
0
  UnpackBits( io, handle, dib, bounds, rowBytes, 1 );
846
0
}
847
848
static void 
849
0
DecodePixmap( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, BOOL isRegion, MacpixMap* pixMap, WORD rowBytes ) {
850
  // Read mac colour table into windows palette.
851
0
  WORD numColors;    // Palette size.
852
0
  RGBQUAD ct[256];
853
  
854
0
  ReadColorTable( io, handle, &numColors, ct );
855
0
  if ( FreeImage_GetBPP( dib ) == 8 ) {
856
0
    RGBQUAD* pal = FreeImage_GetPalette( dib );
857
0
    if ( !pal ) {
858
0
      throw "No palette for bitmap!";
859
0
    }
860
    
861
0
    for (int i = 0; i < numColors; i++) {
862
0
      pal[i].rgbRed = ct[ i ].rgbRed;
863
0
      pal[i].rgbGreen = ct[ i ].rgbGreen;
864
0
      pal[i].rgbBlue = ct[ i ].rgbBlue;
865
0
    }
866
0
  }
867
  
868
  // Ignore source & destination rectangle as well as transfer mode.
869
0
  MacRect tempRect;
870
0
  ReadRect( io, handle, &tempRect );
871
0
  ReadRect( io, handle, &tempRect );
872
0
  WORD mode = Read16( io, handle );
873
  
874
0
  if ( isRegion) {
875
0
    SkipPolyOrRegion( io, handle );
876
0
  }
877
  
878
0
  switch ( pixMap->pixelSize ) {
879
0
    case 32:
880
0
      Unpack32Bits( io, handle, dib, &pixMap->Bounds, rowBytes, pixMap->cmpCount );
881
0
      break;
882
0
    case 8:
883
0
      Unpack8Bits( io, handle, dib, &pixMap->Bounds, rowBytes );
884
0
      break;
885
0
    default:
886
0
      UnpackBits( io, handle, dib, &pixMap->Bounds, rowBytes, pixMap->pixelSize );
887
0
  }
888
0
}
889
890
// ==========================================================
891
// Plugin Implementation
892
// ==========================================================
893
894
static const char * DLL_CALLCONV
895
2
Format() {
896
2
  return "PICT";
897
2
}
898
899
static const char * DLL_CALLCONV
900
0
Description() {
901
0
  return "Macintosh PICT";
902
0
}
903
904
static const char * DLL_CALLCONV
905
0
Extension() {
906
0
  return "pct,pict,pic";
907
0
}
908
909
static const char * DLL_CALLCONV
910
0
MimeType() {
911
0
  return "image/x-pict";
912
0
}
913
914
static BOOL DLL_CALLCONV
915
24.2k
Validate(FreeImageIO *io, fi_handle handle) {
916
24.2k
  if(io->seek_proc(handle, 522, SEEK_SET) == 0) {
917
24.2k
    BYTE pict_signature[] = { 0x00, 0x11, 0x02, 0xFF, 0x0C, 0X00 };
918
24.2k
    BYTE signature[6];
919
920
24.2k
    if(io->read_proc(signature, 1, sizeof(pict_signature), handle)) {
921
      // v1.0 files have 0x11 (version operator) followed by 0x01 (version number)
922
      // v2.0 files have 0x0011 (version operator) followed by 0x02ff (version number)
923
      //   and additionally 0x0c00 as a header opcode
924
      // Currently, we are only supporting v2.0
925
16.4k
      return (memcmp(pict_signature, signature, sizeof(pict_signature)) == 0);
926
16.4k
    } else {
927
7.79k
      return FALSE;
928
7.79k
    }
929
24.2k
  }
930
931
0
  return FALSE;
932
24.2k
}
933
934
static BOOL DLL_CALLCONV
935
0
SupportsExportDepth(int depth) {
936
0
  return FALSE;
937
0
}
938
939
static BOOL DLL_CALLCONV 
940
0
SupportsExportType(FREE_IMAGE_TYPE type) {
941
0
  return FALSE;
942
0
}
943
944
static BOOL DLL_CALLCONV
945
0
SupportsICCProfiles() {
946
0
  return FALSE;
947
0
}
948
949
/**
950
This plugin decodes macintosh PICT files with 1,2,4,8,16 and 32 bits per pixel as well as PICT/JPEG. 
951
If an alpha channel is present in a 32-bit-PICT, it is decoded as well. 
952
The PICT format is a general picture file format and can contain a lot of other elements besides bitmaps. 
953
These elements are ignored. 
954
*/
955
static FIBITMAP * DLL_CALLCONV
956
0
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
957
0
  char outputMessage[ outputMessageSize ] = "";
958
0
  FIBITMAP* dib = NULL;
959
0
  try {   
960
    // Skip empty 512 byte header.
961
0
    if ( !io->seek_proc(handle, 512, SEEK_CUR) == 0 )
962
0
      return NULL;
963
    
964
    // Read PICT header
965
0
    Read16( io, handle ); // Skip version 1 picture size
966
    
967
0
    MacRect frame;
968
0
    ReadRect( io, handle, &frame );
969
970
0
    BYTE b = 0;
971
0
    while ((b = Read8(io, handle)) == 0);
972
0
    if ( b != 0x11 ) {
973
0
      throw "invalid header: version number missing.";
974
0
    }
975
    
976
0
    int version = Read8( io, handle );
977
0
    if ( version == 2 && Read8( io, handle ) != 0xff ) {
978
0
      throw "invalid header: illegal version number.";
979
0
    }
980
    
981
0
    enum PICTType {none, op9a, jpeg, pixmap, bitmap};
982
0
    PICTType pictType = none;
983
    
984
0
    MacRect bounds;
985
0
    MacpixMap pixMap;
986
0
    int hRes = 0x480000; // in pixels/inch (72 by default == 0x480000 in fixed point)
987
0
    int vRes = 0x480000; // in pixels/inch (72 by default == 0x480000 in fixed point)
988
0
    WORD rowBytes = 0;
989
0
    BOOL isRegion = FALSE;
990
0
    BOOL done = FALSE;
991
0
    long currentPos = 0;
992
993
0
    while ( !done ) {
994
0
      WORD opcode = 0;
995
996
      // get the current stream position (used to avoid infinite loops)
997
0
      currentPos = io->tell_proc(handle);
998
      
999
0
      if ((version == 1) || ((io->tell_proc( handle ) % 2) != 0)) {
1000
        // align to word for version 2
1001
0
        opcode = Read8( io, handle );
1002
0
      }
1003
0
      if (version == 2) {
1004
0
        opcode = Read16( io, handle );
1005
0
      }
1006
      
1007
0
      if (opcode == 0xFF || opcode == 0xFFFF) {
1008
0
        done = TRUE;
1009
0
        throw "PICT contained only vector data!";
1010
0
      }
1011
0
      else if (opcode < 0xa2) {       
1012
0
        switch (opcode) {
1013
0
          case 0x01:
1014
0
          {
1015
            // skip clipping rectangle
1016
0
            MacRect clipRect;
1017
0
            WORD len = Read16( io, handle );
1018
1019
0
            if (len == 0x000a) { 
1020
              /* null rgn */
1021
0
              ReadRect( io, handle, &clipRect );
1022
0
            } else {
1023
0
              io->seek_proc(handle, len - 2, SEEK_CUR);
1024
0
            }
1025
0
            break;
1026
0
          }           
1027
0
          case 0x12:
1028
0
          case 0x13:
1029
0
          case 0x14:
1030
0
          {
1031
            // skip pattern definition
1032
0
            WORD       patType;
1033
0
            WORD       rowBytes;
1034
0
            MacpixMap  p;
1035
0
            WORD       numColors;
1036
            
1037
0
            patType = Read16( io, handle );
1038
            
1039
0
            switch( patType ) {
1040
0
              case 2:
1041
0
                io->seek_proc(handle, 8, SEEK_CUR);
1042
0
                io->seek_proc(handle, 5, SEEK_CUR);
1043
0
                break;
1044
0
              case 1:
1045
0
              {
1046
0
                io->seek_proc(handle, 8, SEEK_CUR);
1047
0
                rowBytes = Read16( io, handle );
1048
0
                ReadRect( io, handle, &p.Bounds );
1049
0
                ReadPixmap( io, handle, &p);
1050
                
1051
0
                RGBQUAD ct[256];
1052
0
                ReadColorTable(io, handle, &numColors, ct );
1053
0
                SkipBits( io, handle, &p.Bounds, rowBytes, p.pixelSize );
1054
0
                break;
1055
0
              }
1056
0
              default:
1057
0
                throw "Unknown pattern type.";
1058
0
            }
1059
            
1060
0
            break;
1061
0
          }
1062
0
          case 0x70:
1063
0
          case 0x71:
1064
0
          case 0x72:
1065
0
          case 0x73:
1066
0
          case 0x74:
1067
0
          case 0x75:
1068
0
          case 0x76:
1069
0
          case 0x77:
1070
0
          {
1071
0
            SkipPolyOrRegion( io, handle );
1072
0
            break;
1073
0
          }
1074
0
          case 0x90:
1075
0
          case 0x98:
1076
0
          {
1077
            // Bitmap/pixmap data clipped by a rectangle.
1078
0
            rowBytes = Read16( io, handle );    // Bytes per row in source when uncompressed.           
1079
0
            isRegion = FALSE;
1080
            
1081
0
            if ( rowBytes & 0x8000) {
1082
0
              pictType = pixmap;
1083
0
            } else {
1084
0
              pictType = bitmap;
1085
0
            }
1086
0
            done = TRUE;
1087
0
            break;
1088
0
          }
1089
0
          case 0x91:
1090
0
          case 0x99:
1091
0
          {
1092
            // Bitmap/pixmap data clipped by a region.
1093
0
            rowBytes = Read16( io, handle );    // Bytes per row in source when uncompressed.           
1094
0
            isRegion = TRUE;
1095
            
1096
0
            if ( rowBytes & 0x8000) {
1097
0
              pictType = pixmap;
1098
0
            } else {
1099
0
              pictType = bitmap;            
1100
0
            }
1101
0
            done = TRUE;
1102
0
            break;
1103
0
          }
1104
0
          case 0x9a:
1105
0
          {
1106
            // DirectBitsRect.
1107
0
            Read32( io, handle );           // Skip fake len and fake EOF.
1108
0
            Read16( io, handle );     // bogus row bytes.
1109
            
1110
            // Read in the PixMap fields.
1111
0
            ReadRect( io, handle, &pixMap.Bounds );
1112
0
            ReadPixmap( io, handle, &pixMap );
1113
            
1114
            // Ignore source & destination rectangle as well as transfer mode.
1115
0
            MacRect dummy;
1116
0
            ReadRect( io, handle, &dummy );
1117
0
            ReadRect( io, handle, &dummy );
1118
0
            WORD mode = Read16( io, handle );
1119
            
1120
0
            pictType=op9a;
1121
0
            done = TRUE;
1122
0
            break;
1123
0
          }
1124
0
          case 0xa1:
1125
0
          {
1126
            // long comment
1127
0
            WORD type;
1128
0
            WORD len;
1129
            
1130
0
            type = Read16( io, handle );
1131
0
            len = Read16( io, handle);
1132
0
            if (len > 0) {
1133
0
              io->seek_proc(handle, len, SEEK_CUR);
1134
0
            }
1135
0
            break;
1136
0
          }
1137
0
          default:
1138
            // No function => skip to next opcode
1139
0
            if (optable[opcode].len == WORD_LEN) {
1140
0
              WORD len = Read16( io, handle );
1141
0
              io->seek_proc(handle, len, SEEK_CUR);
1142
0
            } else {
1143
0
              io->seek_proc(handle, optable[opcode].len, SEEK_CUR);
1144
0
            }
1145
0
            break;
1146
0
        }
1147
0
      }
1148
0
      else if (opcode == 0xc00) {
1149
        // version 2 header (26 bytes)
1150
0
        WORD minorVersion = Read16( io, handle ); // always FFFE (-2) for extended version 2
1151
0
        Read16( io, handle );           // reserved
1152
0
        hRes = Read32( io, handle );        // original horizontal resolution in pixels/inch
1153
0
        vRes = Read32( io, handle );        // original horizontal resolution in pixels/inch
1154
0
        MacRect dummy;
1155
0
        ReadRect( io, handle, &dummy );       // frame bounds at original resolution
1156
0
        Read32( io, handle );           // reserved
1157
0
      }
1158
0
      else if (opcode == 0x8200) {
1159
        // jpeg
1160
0
        long opLen = Read32( io, handle );
1161
0
        BOOL found = FALSE;
1162
0
        int i = 0;
1163
        
1164
        // skip to JPEG header.
1165
0
        while ( !found && i < opLen ) {
1166
//          io->seek_proc( handle, 24, SEEK_CUR );
1167
//          MacRect dummy;
1168
//          ReadRect( io, handle, &dummy );
1169
//          io->seek_proc( handle, 122, SEEK_CUR );
1170
//          found = TRUE;
1171
0
          BYTE data[ 2 ];
1172
0
          if( io->read_proc( data, 2, 1, handle ) ) {
1173
0
            io->seek_proc( handle, -2, SEEK_CUR );
1174
            
1175
0
            if ( data[0] == 0xFF && data[1] == 0xD8 ) {
1176
0
              found = TRUE;
1177
0
            } else {
1178
0
              Read8( io, handle );
1179
0
              i++;
1180
0
            }
1181
0
          }
1182
0
        }
1183
        
1184
0
        if ( found ) {
1185
          // Pass the data to the JPEG decoder.
1186
0
          pictType = jpeg;
1187
0
        } else {
1188
0
          throw "PICT file contains unrecognized quicktime data.";
1189
0
        }
1190
0
        done = TRUE;
1191
0
      }
1192
0
      else if (opcode >= 0xa2 && opcode <= 0xaf) {
1193
        // reserved
1194
0
        WORD len = Read16( io, handle );
1195
0
        io->seek_proc(handle, len, SEEK_CUR);
1196
0
      }
1197
0
      else if ((opcode >= 0xb0 && opcode <= 0xcf) || (opcode >= 0x8000 && opcode <= 0x80ff)) {
1198
        // just a reserved opcode, no data
1199
0
      }
1200
0
      else if ((opcode >= 0xd0 && opcode <= 0xfe) || opcode >= 8100) {
1201
        // reserved
1202
0
        LONG len = Read32( io, handle );
1203
0
        io->seek_proc(handle, len, SEEK_CUR);
1204
0
      }
1205
0
      else if (opcode >= 0x100 && opcode <= 0x7fff) {
1206
        // reserved
1207
0
        io->seek_proc(handle, ((opcode >> 7) & 255), SEEK_CUR);       
1208
0
      }
1209
0
      else {
1210
0
        sprintf( outputMessage, "Can't handle opcode %x.\n", opcode );
1211
0
        throw outputMessage;
1212
0
      }
1213
1214
0
      if(currentPos == io->tell_proc(handle)) {
1215
        // we probaly reached the end of file as we can no longer move forward ... 
1216
0
        throw "Invalid PICT file";
1217
0
      }
1218
0
    }
1219
        
1220
0
    switch ( pictType ) {
1221
0
      case op9a:
1222
0
      {
1223
0
        bounds = pixMap.Bounds;
1224
0
        int width = bounds.right - bounds.left;
1225
0
        int height = bounds.bottom - bounds.top;
1226
        
1227
0
        if ( pixMap.pixelSize > 8 ) {
1228
0
          dib = FreeImage_Allocate( width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1229
0
        } else {
1230
0
          dib = FreeImage_Allocate( width, height, 8);
1231
0
        }
1232
0
        hRes = pixMap.hRes << 16;
1233
0
        vRes = pixMap.vRes << 16;       
1234
0
        break;
1235
0
      } 
1236
        
1237
0
      case jpeg:
1238
0
      {
1239
0
        dib = FreeImage_LoadFromHandle( FIF_JPEG, io, handle );         
1240
0
        break;
1241
0
      }
1242
1243
0
      case pixmap:
1244
0
      {
1245
        // Decode version 2 pixmap
1246
0
        ReadRect( io, handle, &pixMap.Bounds );
1247
0
        ReadPixmap( io, handle, &pixMap );
1248
        
1249
0
        bounds = pixMap.Bounds;
1250
0
        int width = bounds.right - bounds.left;
1251
0
        int height = bounds.bottom - bounds.top;
1252
1253
0
        if ( pixMap.pixelSize > 8 ) {
1254
0
          dib = FreeImage_Allocate( width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1255
0
        } else {
1256
0
          dib = FreeImage_Allocate( width, height, 8);
1257
0
        }
1258
0
        hRes = pixMap.hRes << 16;
1259
0
        vRes = pixMap.vRes << 16;       
1260
0
        break;
1261
0
      }
1262
        
1263
0
      case bitmap:
1264
0
      {
1265
        // Decode version 1 bitmap: 1 bpp.
1266
0
        MacRect srcRect;
1267
0
        MacRect dstRect;
1268
0
        WORD width;        // Width in pixels
1269
0
        WORD height;       // Height in pixels
1270
        
1271
0
        ReadRect( io, handle, &bounds );
1272
0
        ReadRect( io, handle, &srcRect );
1273
0
        ReadRect( io, handle, &dstRect );
1274
        
1275
0
        width = bounds.right - bounds.left;
1276
0
        height = bounds.bottom - bounds.top;
1277
        
1278
0
        dib = FreeImage_Allocate(width, height, 8);
1279
0
        break;
1280
0
      }     
1281
0
    }   
1282
    
1283
0
    if ( dib ) {
1284
      // need to convert resolution figures from fixed point, pixels/inch
1285
      // to floating point, pixels/meter.     
1286
0
      float hres_ppm = hRes * ((float)39.4 / (float)65536.0);
1287
0
      float vres_ppm = vRes * ((float)39.4 / (float)65536.0);   
1288
      
1289
0
      FreeImage_SetDotsPerMeterX( dib, (LONG)hres_ppm );
1290
0
      FreeImage_SetDotsPerMeterY( dib, (LONG)vres_ppm );      
1291
      
1292
0
      switch( pictType ) {
1293
0
        case op9a:
1294
0
          DecodeOp9a( io, handle, dib, &pixMap );
1295
0
          break;
1296
0
        case jpeg:
1297
          // Already decoded if the embedded format was valid.
1298
0
          break;
1299
0
        case pixmap:
1300
0
          DecodePixmap( io, handle, dib, isRegion, &pixMap, rowBytes );
1301
0
          break;
1302
0
        case bitmap:
1303
0
          DecodeBitmap( io, handle, dib, isRegion, &bounds, rowBytes );
1304
0
          break;
1305
0
        default:
1306
0
          throw "invalid pict type";
1307
0
      }     
1308
0
    }
1309
    
1310
0
    return dib;
1311
0
  } 
1312
0
  catch(const char *message) {
1313
0
    FreeImage_Unload( dib );
1314
0
    FreeImage_OutputMessageProc(s_format_id, message);
1315
0
  }
1316
1317
0
  return NULL;
1318
0
}
1319
1320
// ==========================================================
1321
//   Init
1322
// ==========================================================
1323
1324
void DLL_CALLCONV
1325
2
InitPICT(Plugin *plugin, int format_id) {
1326
2
  s_format_id = format_id;
1327
1328
2
  plugin->format_proc = Format;
1329
2
  plugin->description_proc = Description;
1330
2
  plugin->extension_proc = Extension;
1331
2
  plugin->regexpr_proc = NULL;
1332
2
  plugin->open_proc = NULL;
1333
2
  plugin->close_proc = NULL;
1334
2
  plugin->pagecount_proc = NULL;
1335
2
  plugin->pagecapability_proc = NULL;
1336
2
  plugin->load_proc = Load;
1337
2
  plugin->save_proc = NULL;
1338
2
  plugin->validate_proc = Validate;
1339
2
  plugin->mime_proc = MimeType;
1340
2
  plugin->supports_export_bpp_proc = SupportsExportDepth;
1341
2
  plugin->supports_export_type_proc = SupportsExportType;
1342
2
  plugin->supports_icc_profiles_proc = SupportsICCProfiles;
1343
2
}