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
Read8(FreeImageIO * io,fi_handle handle)86 Read8(FreeImageIO *io, fi_handle handle) {
87 BYTE i = 0;
88 io->read_proc(&i, 1, 1, handle);
89 return i;
90 }
91
92 static WORD
Read16(FreeImageIO * io,fi_handle handle)93 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 unsigned hi = Read8(io, handle);
98 unsigned lo = Read8(io, handle);
99 return (WORD)(lo + (hi << 8));
100 }
101
102 static unsigned
Read32(FreeImageIO * io,fi_handle handle)103 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 unsigned b3 = Read8(io, handle);
108 unsigned b2 = Read8(io, handle);
109 unsigned b1 = Read8(io, handle);
110 unsigned b0 = Read8(io, handle);
111 return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
112 }
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 #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
ReadRect(FreeImageIO * io,fi_handle handle,MacRect * rect)345 ReadRect( FreeImageIO *io, fi_handle handle, MacRect* rect ) {
346 rect->top = Read16( io, handle );
347 rect->left = Read16( io, handle );
348 rect->bottom = Read16( io, handle );
349 rect->right = Read16( io, handle );
350 }
351
352 static void
ReadPixmap(FreeImageIO * io,fi_handle handle,MacpixMap * pPixMap)353 ReadPixmap( FreeImageIO *io, fi_handle handle, MacpixMap* pPixMap ) {
354 pPixMap->version = Read16( io, handle );
355 pPixMap->packType = Read16( io, handle );
356 pPixMap->packSize = Read32( io, handle );
357 pPixMap->hRes = Read16( io, handle );
358 Read16( io, handle );
359 pPixMap->vRes = Read16( io, handle );
360 Read16( io, handle );
361 pPixMap->pixelType = Read16( io, handle );
362 pPixMap->pixelSize = Read16( io, handle );
363 pPixMap->cmpCount = Read16( io, handle );
364 pPixMap->cmpSize = Read16( io, handle );
365 pPixMap->planeBytes = Read32( io, handle );
366 pPixMap->pmTable = Read32( io, handle );
367 pPixMap->pmReserved = Read32( io, handle );
368 }
369
370 /**
371 Reads a mac color table into a bitmap palette.
372 */
373 static void
ReadColorTable(FreeImageIO * io,fi_handle handle,WORD * pNumColors,RGBQUAD * pPal)374 ReadColorTable( FreeImageIO *io, fi_handle handle, WORD* pNumColors, RGBQUAD* pPal ) {
375 LONG ctSeed;
376 WORD ctFlags;
377 WORD val;
378 int i;
379
380 ctSeed = Read32( io, handle );
381 ctFlags = Read16( io, handle );
382 WORD numColors = Read16( io, handle )+1;
383 *pNumColors = numColors;
384
385 for (i = 0; i < numColors; i++) {
386 val = Read16( io, handle );
387 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 val = (WORD)i;
392 }
393 if (val >= numColors) {
394 throw "pixel value greater than color table size.";
395 }
396 // Mac colour tables contain 16-bit values for R, G, and B...
397 pPal[val].rgbRed = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF));
398 pPal[val].rgbGreen = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF));
399 pPal[val].rgbBlue = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF));
400 }
401 }
402
403 /**
404 skips unneeded packbits.
405 pixelSize == Source bits per pixel.
406 */
407 static void
SkipBits(FreeImageIO * io,fi_handle handle,MacRect * bounds,WORD rowBytes,int pixelSize)408 SkipBits( FreeImageIO *io, fi_handle handle, MacRect* bounds, WORD rowBytes, int pixelSize ) {
409 int i;
410 WORD pixwidth; // bytes per row when uncompressed.
411
412 int height = bounds->bottom - bounds->top;
413 int width = bounds->right - bounds->left;
414
415 // High bit of rowBytes is flag.
416 if (pixelSize <= 8) {
417 rowBytes &= 0x7fff;
418 }
419 pixwidth = (WORD)width;
420
421 if (pixelSize == 16) {
422 pixwidth *= 2;
423 }
424 if (rowBytes == 0) {
425 rowBytes = pixwidth;
426 }
427 if (rowBytes < 8) {
428 io->seek_proc( handle, rowBytes*height, SEEK_CUR );
429 }
430 else {
431 for (i = 0; i < height; i++) {
432 int lineLen; // length of source line in bytes.
433 if (rowBytes > 250) {
434 lineLen = Read16( io, handle );
435 } else {
436 lineLen = Read8( io, handle );
437 }
438 io->seek_proc( handle, lineLen, SEEK_CUR );
439 }
440 }
441 }
442
443 /**
444 Skip polygon or region
445 */
446 static void
SkipPolyOrRegion(FreeImageIO * io,fi_handle handle)447 SkipPolyOrRegion( FreeImageIO *io, fi_handle handle ) {
448 WORD len = Read16( io, handle ) - 2;
449 io->seek_proc(handle, len, SEEK_CUR);
450 }
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
expandBuf(FreeImageIO * io,fi_handle handle,int width,int bpp,BYTE * dst)458 expandBuf( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst ) {
459 switch (bpp) {
460 case 16:
461 for ( int i=0; i<width; i++) {
462 WORD src = Read16( io, handle );
463 dst[ FI_RGBA_BLUE ] = (src & 31)*8; // Blue
464 dst[ FI_RGBA_GREEN ] = ((src >> 5) & 31)*8; // Green
465 dst[ FI_RGBA_RED ] = ((src >> 10) & 31)*8; // Red
466 dst[ FI_RGBA_ALPHA ] = 0xFF; // Alpha
467 dst += 4;
468 }
469 break;
470 default:
471 throw "Bad bits per pixel in expandBuf.";
472 }
473 }
474
475 /**
476 Expands Width units to 8-bit pixel data.
477 Max. 8 bpp source format.
478 */
479 static void
expandBuf8(FreeImageIO * io,fi_handle handle,int width,int bpp,BYTE * dst)480 expandBuf8( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst )
481 {
482 switch (bpp) {
483 case 8:
484 io->read_proc( dst, width, 1, handle );
485 break;
486 case 4:
487 for (int i = 0; i < width; i++) {
488 WORD src = Read8( io, handle );
489 *dst = (src >> 4) & 15;
490 *(dst+1) = (src & 15);
491 dst += 2;
492 }
493 if (width & 1) { // Odd Width?
494 WORD src = Read8( io, handle );
495 *dst = (src >> 4) & 15;
496 dst++;
497 }
498 break;
499 case 2:
500 for (int i = 0; i < width; i++) {
501 WORD src = Read8( io, handle );
502 *dst = (src >> 6) & 3;
503 *(dst+1) = (src >> 4) & 3;
504 *(dst+2) = (src >> 2) & 3;
505 *(dst+3) = (src & 3);
506 dst += 4;
507 }
508 if (width & 3) { // Check for leftover pixels
509 for (int i = 6; i > 8 - (width & 3) * 2; i -= 2) {
510 WORD src = Read8( io, handle );
511 *dst = (src >> i) & 3;
512 dst++;
513 }
514 }
515 break;
516 case 1:
517 for (int i = 0; i < width; i++) {
518 WORD src = Read8( io, handle );
519 *dst = (src >> 7) & 1;
520 *(dst+1) = (src >> 6) & 1;
521 *(dst+2) = (src >> 5) & 1;
522 *(dst+3) = (src >> 4) & 1;
523 *(dst+4) = (src >> 3) & 1;
524 *(dst+5) = (src >> 2) & 1;
525 *(dst+6) = (src >> 1) & 1;
526 *(dst+7) = (src & 1);
527 dst += 8;
528 }
529 if (width & 7) { // Check for leftover pixels
530 for (int i = 7; i > (8-width & 7); i--) {
531 WORD src = Read8( io, handle );
532 *dst = (src >> i) & 1;
533 dst++;
534 }
535 }
536 break;
537 default:
538 throw "Bad bits per pixel in expandBuf8.";
539 }
540 }
541
542 static BYTE*
UnpackPictRow(FreeImageIO * io,fi_handle handle,BYTE * pLineBuf,int width,int rowBytes,int srcBytes)543 UnpackPictRow( FreeImageIO *io, fi_handle handle, BYTE* pLineBuf, int width, int rowBytes, int srcBytes ) {
544
545 if (rowBytes < 8) { // Ah-ha! The bits aren't actually packed. This will be easy.
546 io->read_proc( pLineBuf, rowBytes, 1, handle );
547 }
548 else {
549 BYTE* pCurPixel = pLineBuf;
550
551 // Unpack RLE. The data is packed bytewise.
552 for (int j = 0; j < srcBytes; ) {
553 BYTE FlagCounter = Read8( io, handle );
554 if (FlagCounter & 0x80) {
555 if (FlagCounter == 0x80) {
556 // Special case: repeat value of 0.
557 // Apple says ignore.
558 j++;
559 } else {
560 // Packed data.
561 int len = ((FlagCounter ^ 255) & 255) + 2;
562 BYTE p = Read8( io, handle );
563 memset( pCurPixel, p, len);
564 pCurPixel += len;
565 j += 2;
566 }
567 }
568 else {
569 // Unpacked data
570 int len = (FlagCounter & 255) + 1;
571 io->read_proc( pCurPixel, len, 1, handle );
572 pCurPixel += len;
573 j += len + 1;
574 }
575 }
576 }
577
578 return pLineBuf;
579 }
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
Unpack32Bits(FreeImageIO * io,fi_handle handle,FIBITMAP * dib,MacRect * bounds,WORD rowBytes,int numPlanes)588 Unpack32Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes, int numPlanes ) {
589 int height = bounds->bottom - bounds->top;
590 int width = bounds->right - bounds->left;
591
592 if (rowBytes == 0) {
593 rowBytes = (WORD)( width * 4 );
594 }
595
596 BYTE* pLineBuf = (BYTE*)malloc( rowBytes ); // Let's allocate enough for 4 bit planes
597 if ( pLineBuf ) {
598 try {
599 for ( int i = 0; i < height; i++ ) {
600 // for each line do...
601 int linelen; // length of source line in bytes.
602 if (rowBytes > 250) {
603 linelen = Read16( io, handle );
604 } else {
605 linelen = Read8( io, handle);
606 }
607
608 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 BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
613
614 if ( numPlanes == 3 ) {
615 for ( int j = 0; j < width; j++ ) {
616 // For each pixel in line...
617 dst[ FI_RGBA_BLUE ] = (*(pBuf+width*2)); // Blue
618 dst[ FI_RGBA_GREEN ] = (*(pBuf+width)); // Green
619 dst[ FI_RGBA_RED ] = (*pBuf); // Red
620 dst[ FI_RGBA_ALPHA ] = (0xFF);
621 dst += 4;
622 pBuf++;
623 }
624 } else {
625 for ( int j = 0; j < width; j++ ) {
626 // For each pixel in line...
627 dst[ FI_RGBA_BLUE ] = (*(pBuf+width*3)); // Blue
628 dst[ FI_RGBA_GREEN ] = (*(pBuf+width*2)); // Green
629 dst[ FI_RGBA_RED ] = (*(pBuf+width)); // Red
630 dst[ FI_RGBA_ALPHA ] = (*pBuf);
631 dst += 4;
632 pBuf++;
633 }
634 }
635 }
636 }
637 catch( ... ) {
638 free( pLineBuf );
639 throw;
640 }
641 }
642 free( pLineBuf );
643 }
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
Unpack8Bits(FreeImageIO * io,fi_handle handle,FIBITMAP * dib,MacRect * bounds,WORD rowBytes)652 Unpack8Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes ) {
653 int height = bounds->bottom - bounds->top;
654 int width = bounds->right - bounds->left;
655
656 // High bit of rowBytes is flag.
657 rowBytes &= 0x7fff;
658
659 if (rowBytes == 0) {
660 rowBytes = (WORD)width;
661 }
662
663 for ( int i = 0; i < height; i++ ) {
664 int linelen; // length of source line in bytes.
665 if (rowBytes > 250) {
666 linelen = Read16( io, handle );
667 } else {
668 linelen = Read8( io, handle );
669 }
670 BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
671 dst = UnpackPictRow( io, handle, dst, width, rowBytes, linelen );
672 }
673 }
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
UnpackBits(FreeImageIO * io,fi_handle handle,FIBITMAP * dib,MacRect * bounds,WORD rowBytes,int pixelSize)683 UnpackBits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes, int pixelSize ) {
684 WORD pixwidth; // bytes per row when uncompressed.
685 int pkpixsize;
686 int PixelPerRLEUnit;
687
688 char outputMessage[ outputMessageSize ] = "";
689
690 int height = bounds->bottom - bounds->top;
691 int width = bounds->right - bounds->left;
692
693 // High bit of rowBytes is flag.
694 if (pixelSize <= 8) {
695 rowBytes &= 0x7fff;
696 }
697
698 pixwidth = (WORD)width;
699 pkpixsize = 1; // RLE unit: one byte for everything...
700 if (pixelSize == 16) { // ...except 16 bpp.
701 pkpixsize = 2;
702 pixwidth *= 2;
703 }
704
705 if (rowBytes == 0) {
706 rowBytes = pixwidth;
707 }
708
709 {
710 // I allocate the temporary line buffer here. I allocate too
711 // much memory to compensate for sloppy (& hence fast) decompression.
712 switch (pixelSize) {
713 case 1:
714 PixelPerRLEUnit = 8;
715 break;
716 case 2:
717 PixelPerRLEUnit = 4;
718 break;
719 case 4:
720 PixelPerRLEUnit = 2;
721 break;
722 case 8:
723 PixelPerRLEUnit = 1;
724 break;
725 case 16:
726 PixelPerRLEUnit = 1;
727 break;
728 default:
729 sprintf( outputMessage, "Illegal bpp value in unpackbits: %d\n", pixelSize );
730 throw outputMessage;
731 }
732
733 if (rowBytes < 8) {
734 // ah-ha! The bits aren't actually packed. This will be easy.
735 for ( int i = 0; i < height; i++ ) {
736 BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
737 if (pixelSize == 16) {
738 expandBuf( io, handle, width, pixelSize, dst );
739 } else {
740 expandBuf8( io, handle, width, pixelSize, dst );
741 }
742 }
743 }
744 else {
745 for ( int i = 0; i < height; i++ ) {
746 // For each line do...
747 int linelen; // length of source line in bytes.
748 if (rowBytes > 250) {
749 linelen = Read16( io, handle );
750 } else {
751 linelen = Read8( io, handle );
752 }
753
754 BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
755 BYTE FlagCounter;
756
757 // Unpack RLE. The data is packed bytewise - except for
758 // 16 bpp data, which is packed per pixel :-(.
759 for ( int j = 0; j < linelen; ) {
760 FlagCounter = Read8( io, handle );
761 if (FlagCounter & 0x80) {
762 if (FlagCounter == 0x80) {
763 // Special case: repeat value of 0.
764 // Apple says ignore.
765 j++;
766 }
767 else {
768 // Packed data.
769 int len = ((FlagCounter ^ 255) & 255) + 2;
770
771 // This is slow for some formats...
772 if (pixelSize == 16) {
773 expandBuf( io, handle, 1, pixelSize, dst );
774 for ( int k = 1; k < len; k++ ) {
775 // Repeat the pixel len times.
776 memcpy( dst+(k*4*PixelPerRLEUnit), dst, 4*PixelPerRLEUnit);
777 }
778 dst += len*4*PixelPerRLEUnit;
779 }
780 else {
781 expandBuf8( io, handle, 1, pixelSize, dst );
782 for ( int k = 1; k < len; k++ ) {
783 // Repeat the expanded byte len times.
784 memcpy( dst+(k*PixelPerRLEUnit), dst, PixelPerRLEUnit);
785 }
786 dst += len*PixelPerRLEUnit;
787 }
788 j += pkpixsize + 1;
789 }
790 }
791 else {
792 // Unpacked data
793 int len = (FlagCounter & 255) + 1;
794 if (pixelSize == 16) {
795 expandBuf( io, handle, len, pixelSize, dst );
796 dst += len*4*PixelPerRLEUnit;
797 }
798 else {
799 expandBuf8( io, handle, len, pixelSize, dst );
800 dst += len*PixelPerRLEUnit;
801 }
802 j += ( len * pkpixsize ) + 1;
803 }
804 }
805 }
806 }
807 }
808 }
809
810 static void
DecodeOp9a(FreeImageIO * io,fi_handle handle,FIBITMAP * dib,MacpixMap * pixMap)811 DecodeOp9a( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacpixMap* pixMap ) {
812 // Do the actual unpacking.
813 switch ( pixMap->pixelSize ) {
814 case 32:
815 Unpack32Bits( io, handle, dib, &pixMap->Bounds, 0, pixMap->cmpCount );
816 break;
817 case 8:
818 Unpack8Bits( io, handle, dib, &pixMap->Bounds, 0 );
819 break;
820 default:
821 UnpackBits( io, handle, dib, &pixMap->Bounds, 0, pixMap->pixelSize );
822 }
823 }
824
825 static void
DecodeBitmap(FreeImageIO * io,fi_handle handle,FIBITMAP * dib,BOOL isRegion,MacRect * bounds,WORD rowBytes)826 DecodeBitmap( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, BOOL isRegion, MacRect* bounds, WORD rowBytes ) {
827 WORD mode = Read16( io, handle );
828
829 if ( isRegion ) {
830 SkipPolyOrRegion( io, handle );
831 }
832
833 RGBQUAD* pal = FreeImage_GetPalette( dib );
834 if ( !pal ) {
835 throw "No palette for bitmap!";
836 }
837
838 for (int i = 0; i < 2; i++) {
839 unsigned char val = i ? 0xFF : 0x0;
840 pal[i].rgbRed = val;
841 pal[i].rgbGreen = val;
842 pal[i].rgbBlue = val;
843 }
844
845 UnpackBits( io, handle, dib, bounds, rowBytes, 1 );
846 }
847
848 static void
DecodePixmap(FreeImageIO * io,fi_handle handle,FIBITMAP * dib,BOOL isRegion,MacpixMap * pixMap,WORD rowBytes)849 DecodePixmap( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, BOOL isRegion, MacpixMap* pixMap, WORD rowBytes ) {
850 // Read mac colour table into windows palette.
851 WORD numColors; // Palette size.
852 RGBQUAD ct[256];
853
854 ReadColorTable( io, handle, &numColors, ct );
855 if ( FreeImage_GetBPP( dib ) == 8 ) {
856 RGBQUAD* pal = FreeImage_GetPalette( dib );
857 if ( !pal ) {
858 throw "No palette for bitmap!";
859 }
860
861 for (int i = 0; i < numColors; i++) {
862 pal[i].rgbRed = ct[ i ].rgbRed;
863 pal[i].rgbGreen = ct[ i ].rgbGreen;
864 pal[i].rgbBlue = ct[ i ].rgbBlue;
865 }
866 }
867
868 // Ignore source & destination rectangle as well as transfer mode.
869 MacRect tempRect;
870 ReadRect( io, handle, &tempRect );
871 ReadRect( io, handle, &tempRect );
872 WORD mode = Read16( io, handle );
873
874 if ( isRegion) {
875 SkipPolyOrRegion( io, handle );
876 }
877
878 switch ( pixMap->pixelSize ) {
879 case 32:
880 Unpack32Bits( io, handle, dib, &pixMap->Bounds, rowBytes, pixMap->cmpCount );
881 break;
882 case 8:
883 Unpack8Bits( io, handle, dib, &pixMap->Bounds, rowBytes );
884 break;
885 default:
886 UnpackBits( io, handle, dib, &pixMap->Bounds, rowBytes, pixMap->pixelSize );
887 }
888 }
889
890 // ==========================================================
891 // Plugin Implementation
892 // ==========================================================
893
894 static const char * DLL_CALLCONV
Format()895 Format() {
896 return "PICT";
897 }
898
899 static const char * DLL_CALLCONV
Description()900 Description() {
901 return "Macintosh PICT";
902 }
903
904 static const char * DLL_CALLCONV
Extension()905 Extension() {
906 return "pct,pict,pic";
907 }
908
909 static const char * DLL_CALLCONV
MimeType()910 MimeType() {
911 return "image/x-pict";
912 }
913
914 static BOOL DLL_CALLCONV
Validate(FreeImageIO * io,fi_handle handle)915 Validate(FreeImageIO *io, fi_handle handle) {
916 if(io->seek_proc(handle, 522, SEEK_SET) == 0) {
917 BYTE pict_signature[] = { 0x00, 0x11, 0x02, 0xFF, 0x0C, 0X00 };
918 BYTE signature[6];
919
920 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 return (memcmp(pict_signature, signature, sizeof(pict_signature)) == 0);
926 } else {
927 return FALSE;
928 }
929 }
930
931 return FALSE;
932 }
933
934 static BOOL DLL_CALLCONV
SupportsExportDepth(int depth)935 SupportsExportDepth(int depth) {
936 return FALSE;
937 }
938
939 static BOOL DLL_CALLCONV
SupportsExportType(FREE_IMAGE_TYPE type)940 SupportsExportType(FREE_IMAGE_TYPE type) {
941 return FALSE;
942 }
943
944 static BOOL DLL_CALLCONV
SupportsICCProfiles()945 SupportsICCProfiles() {
946 return FALSE;
947 }
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
Load(FreeImageIO * io,fi_handle handle,int page,int flags,void * data)956 Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
957 char outputMessage[ outputMessageSize ] = "";
958 FIBITMAP* dib = NULL;
959 try {
960 // Skip empty 512 byte header.
961 if ( !io->seek_proc(handle, 512, SEEK_CUR) == 0 )
962 return NULL;
963
964 // Read PICT header
965 Read16( io, handle ); // Skip version 1 picture size
966
967 MacRect frame;
968 ReadRect( io, handle, &frame );
969
970 BYTE b = 0;
971 while ((b = Read8(io, handle)) == 0);
972 if ( b != 0x11 ) {
973 throw "invalid header: version number missing.";
974 }
975
976 int version = Read8( io, handle );
977 if ( version == 2 && Read8( io, handle ) != 0xff ) {
978 throw "invalid header: illegal version number.";
979 }
980
981 enum PICTType {none, op9a, jpeg, pixmap, bitmap};
982 PICTType pictType = none;
983
984 MacRect bounds;
985 MacpixMap pixMap;
986 int hRes = 0x480000; // in pixels/inch (72 by default == 0x480000 in fixed point)
987 int vRes = 0x480000; // in pixels/inch (72 by default == 0x480000 in fixed point)
988 WORD rowBytes = 0;
989 BOOL isRegion = FALSE;
990 BOOL done = FALSE;
991 long currentPos = 0;
992
993 while ( !done ) {
994 WORD opcode = 0;
995
996 // get the current stream position (used to avoid infinite loops)
997 currentPos = io->tell_proc(handle);
998
999 if ((version == 1) || ((io->tell_proc( handle ) % 2) != 0)) {
1000 // align to word for version 2
1001 opcode = Read8( io, handle );
1002 }
1003 if (version == 2) {
1004 opcode = Read16( io, handle );
1005 }
1006
1007 if (opcode == 0xFF || opcode == 0xFFFF) {
1008 done = TRUE;
1009 throw "PICT contained only vector data!";
1010 }
1011 else if (opcode < 0xa2) {
1012 switch (opcode) {
1013 case 0x01:
1014 {
1015 // skip clipping rectangle
1016 MacRect clipRect;
1017 WORD len = Read16( io, handle );
1018
1019 if (len == 0x000a) {
1020 /* null rgn */
1021 ReadRect( io, handle, &clipRect );
1022 } else {
1023 io->seek_proc(handle, len - 2, SEEK_CUR);
1024 }
1025 break;
1026 }
1027 case 0x12:
1028 case 0x13:
1029 case 0x14:
1030 {
1031 // skip pattern definition
1032 WORD patType;
1033 WORD rowBytes;
1034 MacpixMap p;
1035 WORD numColors;
1036
1037 patType = Read16( io, handle );
1038
1039 switch( patType ) {
1040 case 2:
1041 io->seek_proc(handle, 8, SEEK_CUR);
1042 io->seek_proc(handle, 5, SEEK_CUR);
1043 break;
1044 case 1:
1045 {
1046 io->seek_proc(handle, 8, SEEK_CUR);
1047 rowBytes = Read16( io, handle );
1048 ReadRect( io, handle, &p.Bounds );
1049 ReadPixmap( io, handle, &p);
1050
1051 RGBQUAD ct[256];
1052 ReadColorTable(io, handle, &numColors, ct );
1053 SkipBits( io, handle, &p.Bounds, rowBytes, p.pixelSize );
1054 break;
1055 }
1056 default:
1057 throw "Unknown pattern type.";
1058 }
1059
1060 break;
1061 }
1062 case 0x70:
1063 case 0x71:
1064 case 0x72:
1065 case 0x73:
1066 case 0x74:
1067 case 0x75:
1068 case 0x76:
1069 case 0x77:
1070 {
1071 SkipPolyOrRegion( io, handle );
1072 break;
1073 }
1074 case 0x90:
1075 case 0x98:
1076 {
1077 // Bitmap/pixmap data clipped by a rectangle.
1078 rowBytes = Read16( io, handle ); // Bytes per row in source when uncompressed.
1079 isRegion = FALSE;
1080
1081 if ( rowBytes & 0x8000) {
1082 pictType = pixmap;
1083 } else {
1084 pictType = bitmap;
1085 }
1086 done = TRUE;
1087 break;
1088 }
1089 case 0x91:
1090 case 0x99:
1091 {
1092 // Bitmap/pixmap data clipped by a region.
1093 rowBytes = Read16( io, handle ); // Bytes per row in source when uncompressed.
1094 isRegion = TRUE;
1095
1096 if ( rowBytes & 0x8000) {
1097 pictType = pixmap;
1098 } else {
1099 pictType = bitmap;
1100 }
1101 done = TRUE;
1102 break;
1103 }
1104 case 0x9a:
1105 {
1106 // DirectBitsRect.
1107 Read32( io, handle ); // Skip fake len and fake EOF.
1108 Read16( io, handle ); // bogus row bytes.
1109
1110 // Read in the PixMap fields.
1111 ReadRect( io, handle, &pixMap.Bounds );
1112 ReadPixmap( io, handle, &pixMap );
1113
1114 // Ignore source & destination rectangle as well as transfer mode.
1115 MacRect dummy;
1116 ReadRect( io, handle, &dummy );
1117 ReadRect( io, handle, &dummy );
1118 WORD mode = Read16( io, handle );
1119
1120 pictType=op9a;
1121 done = TRUE;
1122 break;
1123 }
1124 case 0xa1:
1125 {
1126 // long comment
1127 WORD type;
1128 WORD len;
1129
1130 type = Read16( io, handle );
1131 len = Read16( io, handle);
1132 if (len > 0) {
1133 io->seek_proc(handle, len, SEEK_CUR);
1134 }
1135 break;
1136 }
1137 default:
1138 // No function => skip to next opcode
1139 if (optable[opcode].len == WORD_LEN) {
1140 WORD len = Read16( io, handle );
1141 io->seek_proc(handle, len, SEEK_CUR);
1142 } else {
1143 io->seek_proc(handle, optable[opcode].len, SEEK_CUR);
1144 }
1145 break;
1146 }
1147 }
1148 else if (opcode == 0xc00) {
1149 // version 2 header (26 bytes)
1150 WORD minorVersion = Read16( io, handle ); // always FFFE (-2) for extended version 2
1151 Read16( io, handle ); // reserved
1152 hRes = Read32( io, handle ); // original horizontal resolution in pixels/inch
1153 vRes = Read32( io, handle ); // original horizontal resolution in pixels/inch
1154 MacRect dummy;
1155 ReadRect( io, handle, &dummy ); // frame bounds at original resolution
1156 Read32( io, handle ); // reserved
1157 }
1158 else if (opcode == 0x8200) {
1159 // jpeg
1160 long opLen = Read32( io, handle );
1161 BOOL found = FALSE;
1162 int i = 0;
1163
1164 // skip to JPEG header.
1165 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 BYTE data[ 2 ];
1172 if( io->read_proc( data, 2, 1, handle ) ) {
1173 io->seek_proc( handle, -2, SEEK_CUR );
1174
1175 if ( data[0] == 0xFF && data[1] == 0xD8 ) {
1176 found = TRUE;
1177 } else {
1178 Read8( io, handle );
1179 i++;
1180 }
1181 }
1182 }
1183
1184 if ( found ) {
1185 // Pass the data to the JPEG decoder.
1186 pictType = jpeg;
1187 } else {
1188 throw "PICT file contains unrecognized quicktime data.";
1189 }
1190 done = TRUE;
1191 }
1192 else if (opcode >= 0xa2 && opcode <= 0xaf) {
1193 // reserved
1194 WORD len = Read16( io, handle );
1195 io->seek_proc(handle, len, SEEK_CUR);
1196 }
1197 else if ((opcode >= 0xb0 && opcode <= 0xcf) || (opcode >= 0x8000 && opcode <= 0x80ff)) {
1198 // just a reserved opcode, no data
1199 }
1200 else if ((opcode >= 0xd0 && opcode <= 0xfe) || opcode >= 8100) {
1201 // reserved
1202 LONG len = Read32( io, handle );
1203 io->seek_proc(handle, len, SEEK_CUR);
1204 }
1205 else if (opcode >= 0x100 && opcode <= 0x7fff) {
1206 // reserved
1207 io->seek_proc(handle, ((opcode >> 7) & 255), SEEK_CUR);
1208 }
1209 else {
1210 sprintf( outputMessage, "Can't handle opcode %x.\n", opcode );
1211 throw outputMessage;
1212 }
1213
1214 if(currentPos == io->tell_proc(handle)) {
1215 // we probaly reached the end of file as we can no longer move forward ...
1216 throw "Invalid PICT file";
1217 }
1218 }
1219
1220 switch ( pictType ) {
1221 case op9a:
1222 {
1223 bounds = pixMap.Bounds;
1224 int width = bounds.right - bounds.left;
1225 int height = bounds.bottom - bounds.top;
1226
1227 if ( pixMap.pixelSize > 8 ) {
1228 dib = FreeImage_Allocate( width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1229 } else {
1230 dib = FreeImage_Allocate( width, height, 8);
1231 }
1232 hRes = pixMap.hRes << 16;
1233 vRes = pixMap.vRes << 16;
1234 break;
1235 }
1236
1237 case jpeg:
1238 {
1239 dib = FreeImage_LoadFromHandle( FIF_JPEG, io, handle );
1240 break;
1241 }
1242
1243 case pixmap:
1244 {
1245 // Decode version 2 pixmap
1246 ReadRect( io, handle, &pixMap.Bounds );
1247 ReadPixmap( io, handle, &pixMap );
1248
1249 bounds = pixMap.Bounds;
1250 int width = bounds.right - bounds.left;
1251 int height = bounds.bottom - bounds.top;
1252
1253 if ( pixMap.pixelSize > 8 ) {
1254 dib = FreeImage_Allocate( width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1255 } else {
1256 dib = FreeImage_Allocate( width, height, 8);
1257 }
1258 hRes = pixMap.hRes << 16;
1259 vRes = pixMap.vRes << 16;
1260 break;
1261 }
1262
1263 case bitmap:
1264 {
1265 // Decode version 1 bitmap: 1 bpp.
1266 MacRect srcRect;
1267 MacRect dstRect;
1268 WORD width; // Width in pixels
1269 WORD height; // Height in pixels
1270
1271 ReadRect( io, handle, &bounds );
1272 ReadRect( io, handle, &srcRect );
1273 ReadRect( io, handle, &dstRect );
1274
1275 width = bounds.right - bounds.left;
1276 height = bounds.bottom - bounds.top;
1277
1278 dib = FreeImage_Allocate(width, height, 8);
1279 break;
1280 }
1281 }
1282
1283 if ( dib ) {
1284 // need to convert resolution figures from fixed point, pixels/inch
1285 // to floating point, pixels/meter.
1286 float hres_ppm = hRes * ((float)39.4 / (float)65536.0);
1287 float vres_ppm = vRes * ((float)39.4 / (float)65536.0);
1288
1289 FreeImage_SetDotsPerMeterX( dib, (LONG)hres_ppm );
1290 FreeImage_SetDotsPerMeterY( dib, (LONG)vres_ppm );
1291
1292 switch( pictType ) {
1293 case op9a:
1294 DecodeOp9a( io, handle, dib, &pixMap );
1295 break;
1296 case jpeg:
1297 // Already decoded if the embedded format was valid.
1298 break;
1299 case pixmap:
1300 DecodePixmap( io, handle, dib, isRegion, &pixMap, rowBytes );
1301 break;
1302 case bitmap:
1303 DecodeBitmap( io, handle, dib, isRegion, &bounds, rowBytes );
1304 break;
1305 default:
1306 throw "invalid pict type";
1307 }
1308 }
1309
1310 return dib;
1311 }
1312 catch(const char *message) {
1313 FreeImage_Unload( dib );
1314 FreeImage_OutputMessageProc(s_format_id, message);
1315 }
1316
1317 return NULL;
1318 }
1319
1320 // ==========================================================
1321 // Init
1322 // ==========================================================
1323
1324 void DLL_CALLCONV
InitPICT(Plugin * plugin,int format_id)1325 InitPICT(Plugin *plugin, int format_id) {
1326 s_format_id = format_id;
1327
1328 plugin->format_proc = Format;
1329 plugin->description_proc = Description;
1330 plugin->extension_proc = Extension;
1331 plugin->regexpr_proc = NULL;
1332 plugin->open_proc = NULL;
1333 plugin->close_proc = NULL;
1334 plugin->pagecount_proc = NULL;
1335 plugin->pagecapability_proc = NULL;
1336 plugin->load_proc = Load;
1337 plugin->save_proc = NULL;
1338 plugin->validate_proc = Validate;
1339 plugin->mime_proc = MimeType;
1340 plugin->supports_export_bpp_proc = SupportsExportDepth;
1341 plugin->supports_export_type_proc = SupportsExportType;
1342 plugin->supports_icc_profiles_proc = SupportsICCProfiles;
1343 }
1344