1
// ==========================================================
2
// Apple Macintosh QuickDraw/PICT Loader
4
// Design and implementation by
5
// - Amir Ebrahimi (amir@unity3d.com)
7
// Based on PICT loading code from paintlib (http://www.paintlib.de/paintlib/).
10
// The paintlib source code and all documentation are copyright (c) 1996-2002
11
// Ulrich von Zadow and other contributors.
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.
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
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.
35
// Bug fixes were made to the original code to support version 2 PICT files
38
// Additional resources:
39
// http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-458.html
40
// http://www.fileformat.info/format/macpict/egff.htm
42
// Notes (http://lists.apple.com/archives/java-dev/2006/Apr/msg00588.html):
43
// There are three main types of PICT files:
46
// - Extended Version 2
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.
56
// This file is part of FreeImage 3
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
68
// Use at your own risk!
69
// ==========================================================
71
#include "FreeImage.h"
72
#include "Utilities.h"
74
// ==========================================================
76
// ==========================================================
77
static int s_format_id;
79
static const int outputMessageSize = 256;
81
// ==========================================================
83
// ==========================================================
86
Read8(FreeImageIO *io, fi_handle handle) {
88
io->read_proc(&i, 1, 1, handle);
93
Read16(FreeImageIO *io, fi_handle handle) {
94
// reads a two-byte big-endian integer from the given file and returns its value.
97
unsigned hi = Read8(io, handle);
98
unsigned lo = Read8(io, handle);
99
return lo + (hi << 8);
103
Read32(FreeImageIO *io, fi_handle handle) {
104
// reads a four-byte big-endian integer from the given file and returns its value.
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;
114
// ----------------------------------------------------------
123
// for reserved opcodes
124
#define res(length) { "reserved", (length), "reserved for Apple use" }
129
static OpDef optable[] =
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" },
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" },
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" },
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" },
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" },
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" },
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" },
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" },
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" },
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" },
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)" },
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" },
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)" },
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" }
295
// ----------------------------------------------------------
307
// Ptr baseAddr // Not used in file.
308
// short rowBytes // read in seperatly.
309
struct MacRect Bounds;
337
struct MacPattern // Klaube
342
// ----------------------------------------------------------
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 );
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 );
371
Reads a mac color table into a bitmap palette.
374
ReadColorTable( FreeImageIO *io, fi_handle handle, WORD* pNumColors, RGBQUAD* pPal ) {
380
ctSeed = Read32( io, handle );
381
ctFlags = Read16( io, handle );
382
WORD numColors = Read16( io, handle )+1;
383
*pNumColors = numColors;
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
393
if (val >= numColors) {
394
throw "pixel value greater than color table size.";
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));
404
skips unneeded packbits.
405
pixelSize == Source bits per pixel.
408
SkipBits( FreeImageIO *io, fi_handle handle, MacRect* bounds, WORD rowBytes, int pixelSize ) {
410
WORD pixwidth; // bytes per row when uncompressed.
412
int height = bounds->bottom - bounds->top;
413
int width = bounds->right - bounds->left;
415
// High bit of rowBytes is flag.
416
if (pixelSize <= 8) {
421
if (pixelSize == 16) {
428
io->seek_proc( handle, rowBytes*height, SEEK_CUR );
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 );
436
lineLen = Read8( io, handle );
438
io->seek_proc( handle, lineLen, SEEK_CUR );
444
Skip polygon or region
447
SkipPolyOrRegion( FreeImageIO *io, fi_handle handle ) {
448
WORD len = Read16( io, handle ) - 2;
449
io->seek_proc(handle, len, SEEK_CUR);
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.
458
expandBuf( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst ) {
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
471
throw "Bad bits per pixel in expandBuf.";
476
Expands Width units to 8-bit pixel data.
477
Max. 8 bpp source format.
480
expandBuf8( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst )
484
io->read_proc( dst, width, 1, handle );
487
for (int i = 0; i < width; i++) {
488
WORD src = Read8( io, handle );
489
*dst = (src >> 4) & 15;
490
*(dst+1) = (src & 15);
493
if (width & 1) { // Odd Width?
494
WORD src = Read8( io, handle );
495
*dst = (src >> 4) & 15;
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);
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;
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);
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;
538
throw "Bad bits per pixel in expandBuf8.";
543
UnpackPictRow( FreeImageIO *io, fi_handle handle, BYTE* pLineBuf, int width, int rowBytes, int srcBytes ) {
544
if (rowBytes < 8) { // Ah-ha! The bits aren't actually packed. This will be easy.
545
io->read_proc( pLineBuf, rowBytes, 1, handle );
548
BYTE* pCurPixel = pLineBuf;
550
// Unpack RLE. The data is packed bytewise.
551
for (int j = 0; j < srcBytes; ) {
552
BYTE FlagCounter = Read8( io, handle );
553
if (FlagCounter & 0x80) {
554
if (FlagCounter == 0x80) {
555
// Special case: repeat value of 0.
556
// Apple says ignore.
560
int len = ((FlagCounter ^ 255) & 255) + 2;
561
BYTE p = Read8( io, handle );
562
memset( pCurPixel, p, len);
569
int len = (FlagCounter & 255) + 1;
570
io->read_proc( pCurPixel, len, 1, handle );
581
This routine decompresses BitsRects with a packType of 4 (and 32 bits per pixel).
582
In this format, each line is separated into 8-bit-bitplanes and then compressed via RLE.
583
To decode, the routine decompresses each line & then juggles the bytes around to get pixel-oriented data.
584
NumBitPlanes == 3 if RGB, 4 if RGBA
587
Unpack32Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes, int numPlanes ) {
588
int height = bounds->bottom - bounds->top;
589
int width = bounds->right - bounds->left;
595
BYTE* pLineBuf = (BYTE*)malloc( rowBytes ); // Let's allocate enough for 4 bit planes
598
for ( int i = 0; i < height; i++ ) {
599
// for each line do...
600
int linelen; // length of source line in bytes.
601
if (rowBytes > 250) {
602
linelen = Read16( io, handle );
604
linelen = Read8( io, handle);
607
BYTE* pBuf = UnpackPictRow( io, handle, pLineBuf, width, rowBytes, linelen );
609
// Convert plane-oriented data into pixel-oriented data &
610
// copy into destination bitmap.
611
BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
613
if ( numPlanes == 3 ) {
614
for ( int j = 0; j < width; j++ ) {
615
// For each pixel in line...
616
dst[ FI_RGBA_BLUE ] = (*(pBuf+width*2)); // Blue
617
dst[ FI_RGBA_GREEN ] = (*(pBuf+width)); // Green
618
dst[ FI_RGBA_RED ] = (*pBuf); // Red
619
dst[ FI_RGBA_ALPHA ] = (0xFF);
624
for ( int j = 0; j < width; j++ ) {
625
// For each pixel in line...
626
dst[ FI_RGBA_BLUE ] = (*(pBuf+width*3)); // Blue
627
dst[ FI_RGBA_GREEN ] = (*(pBuf+width*2)); // Green
628
dst[ FI_RGBA_RED ] = (*(pBuf+width)); // Red
629
dst[ FI_RGBA_ALPHA ] = (*pBuf);
645
Decompression routine for 8 bpp.
646
rowBytes is the number of bytes each source row would take if it were uncompressed.
647
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.
648
Of course, we have to decompress the excess data and then throw it away.
651
Unpack8Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes ) {
652
int height = bounds->bottom - bounds->top;
653
int width = bounds->right - bounds->left;
655
// High bit of rowBytes is flag.
662
for ( int i = 0; i < height; i++ ) {
663
int linelen; // length of source line in bytes.
664
if (rowBytes > 250) {
665
linelen = Read16( io, handle );
667
linelen = Read8( io, handle );
669
BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
670
dst = UnpackPictRow( io, handle, dst, width, rowBytes, linelen );
675
Decompression routine for everything but 8 & 32 bpp.
676
This routine is slower than the two routines above since it has to deal with a lot of special cases :-(.
677
It's also a bit chaotic because of these special cases...
678
unpack8bits is basically a dumber version of unpackbits.
679
pixelSize == Source bits per pixel.
682
UnpackBits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes, int pixelSize ) {
683
WORD pixwidth; // bytes per row when uncompressed.
687
char outputMessage[ outputMessageSize ] = "";
689
int height = bounds->bottom - bounds->top;
690
int width = bounds->right - bounds->left;
692
// High bit of rowBytes is flag.
693
if (pixelSize <= 8) {
698
pkpixsize = 1; // RLE unit: one byte for everything...
699
if (pixelSize == 16) { // ...except 16 bpp.
709
// I allocate the temporary line buffer here. I allocate too
710
// much memory to compensate for sloppy (& hence fast) decompression.
728
sprintf( outputMessage, "Illegal bpp value in unpackbits: %d\n", pixelSize );
733
// ah-ha! The bits aren't actually packed. This will be easy.
734
for ( int i = 0; i < height; i++ ) {
735
BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
736
if (pixelSize == 16) {
737
expandBuf( io, handle, width, pixelSize, dst );
739
expandBuf8( io, handle, width, pixelSize, dst );
744
for ( int i = 0; i < height; i++ ) {
745
// For each line do...
746
int linelen; // length of source line in bytes.
747
if (rowBytes > 250) {
748
linelen = Read16( io, handle );
750
linelen = Read8( io, handle );
753
BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i);
756
// Unpack RLE. The data is packed bytewise - except for
757
// 16 bpp data, which is packed per pixel :-(.
758
for ( int j = 0; j < linelen; ) {
759
FlagCounter = Read8( io, handle );
760
if (FlagCounter & 0x80) {
761
if (FlagCounter == 0x80) {
762
// Special case: repeat value of 0.
763
// Apple says ignore.
768
int len = ((FlagCounter ^ 255) & 255) + 2;
770
// This is slow for some formats...
771
if (pixelSize == 16) {
772
expandBuf( io, handle, 1, pixelSize, dst );
773
for ( int k = 1; k < len; k++ ) {
774
// Repeat the pixel len times.
775
memcpy( dst+(k*4*PixelPerRLEUnit), dst, 4*PixelPerRLEUnit);
777
dst += len*4*PixelPerRLEUnit;
780
expandBuf8( io, handle, 1, pixelSize, dst );
781
for ( int k = 1; k < len; k++ ) {
782
// Repeat the expanded byte len times.
783
memcpy( dst+(k*PixelPerRLEUnit), dst, PixelPerRLEUnit);
785
dst += len*PixelPerRLEUnit;
792
int len = (FlagCounter & 255) + 1;
793
if (pixelSize == 16) {
794
expandBuf( io, handle, len, pixelSize, dst );
795
dst += len*4*PixelPerRLEUnit;
798
expandBuf8( io, handle, len, pixelSize, dst );
799
dst += len*PixelPerRLEUnit;
801
j += ( len * pkpixsize ) + 1;
810
DecodeOp9a( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacpixMap* pixMap ) {
811
// Do the actual unpacking.
812
switch ( pixMap->pixelSize ) {
814
Unpack32Bits( io, handle, dib, &pixMap->Bounds, 0, pixMap->cmpCount );
817
Unpack8Bits( io, handle, dib, &pixMap->Bounds, 0 );
820
UnpackBits( io, handle, dib, &pixMap->Bounds, 0, pixMap->pixelSize );
825
DecodeBitmap( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, BOOL isRegion, MacRect* bounds, WORD rowBytes ) {
826
WORD mode = Read16( io, handle );
829
SkipPolyOrRegion( io, handle );
832
RGBQUAD* pal = FreeImage_GetPalette( dib );
834
throw "No palette for bitmap!";
837
for (int i = 0; i < 2; i++) {
838
unsigned char val = i ? 0xFF : 0x0;
840
pal[i].rgbGreen = val;
841
pal[i].rgbBlue = val;
844
UnpackBits( io, handle, dib, bounds, rowBytes, 1 );
848
DecodePixmap( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, BOOL isRegion, MacpixMap* pixMap, WORD rowBytes ) {
849
// Read mac colour table into windows palette.
850
WORD numColors; // Palette size.
853
ReadColorTable( io, handle, &numColors, ct );
854
if ( FreeImage_GetBPP( dib ) == 8 ) {
855
RGBQUAD* pal = FreeImage_GetPalette( dib );
857
throw "No palette for bitmap!";
860
for (int i = 0; i < numColors; i++) {
861
pal[i].rgbRed = ct[ i ].rgbRed;
862
pal[i].rgbGreen = ct[ i ].rgbGreen;
863
pal[i].rgbBlue = ct[ i ].rgbBlue;
867
// Ignore source & destination rectangle as well as transfer mode.
869
ReadRect( io, handle, &tempRect );
870
ReadRect( io, handle, &tempRect );
871
WORD mode = Read16( io, handle );
874
SkipPolyOrRegion( io, handle );
877
switch ( pixMap->pixelSize ) {
879
Unpack32Bits( io, handle, dib, &pixMap->Bounds, rowBytes, pixMap->cmpCount );
882
Unpack8Bits( io, handle, dib, &pixMap->Bounds, rowBytes );
885
UnpackBits( io, handle, dib, &pixMap->Bounds, rowBytes, pixMap->pixelSize );
889
// ==========================================================
890
// Plugin Implementation
891
// ==========================================================
893
static const char * DLL_CALLCONV
898
static const char * DLL_CALLCONV
900
return "Macintosh PICT";
903
static const char * DLL_CALLCONV
905
return "pct,pict,pic";
908
static const char * DLL_CALLCONV
910
return "image/x-pict";
913
static BOOL DLL_CALLCONV
914
Validate(FreeImageIO *io, fi_handle handle) {
915
if(io->seek_proc(handle, 522, SEEK_SET) == 0) {
916
BYTE pict_signature[] = { 0x00, 0x11, 0x02, 0xFF, 0x0C, 0X00 };
919
if(io->read_proc(signature, 1, sizeof(pict_signature), handle)) {
920
// v1.0 files have 0x11 (version operator) followed by 0x01 (version number)
921
// v2.0 files have 0x0011 (version operator) followed by 0x02ff (version number)
922
// and additionally 0x0c00 as a header opcode
923
// Currently, we are only supporting v2.0
924
return (memcmp(pict_signature, signature, sizeof(pict_signature)) == 0);
933
static BOOL DLL_CALLCONV
934
SupportsExportDepth(int depth) {
938
static BOOL DLL_CALLCONV
939
SupportsExportType(FREE_IMAGE_TYPE type) {
943
static BOOL DLL_CALLCONV
944
SupportsICCProfiles() {
949
This plugin decodes macintosh PICT files with 1,2,4,8,16 and 32 bits per pixel as well as PICT/JPEG.
950
If an alpha channel is present in a 32-bit-PICT, it is decoded as well.
951
The PICT format is a general picture file format and can contain a lot of other elements besides bitmaps.
952
These elements are ignored.
954
static FIBITMAP * DLL_CALLCONV
955
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
956
char outputMessage[ outputMessageSize ] = "";
957
FIBITMAP* dib = NULL;
959
// Skip empty 512 byte header.
960
if ( !io->seek_proc(handle, 512, SEEK_CUR) == 0 )
964
Read16( io, handle ); // Skip version 1 picture size
967
ReadRect( io, handle, &frame );
970
while ((b = Read8(io, handle)) == 0);
972
throw "invalid header: version number missing.";
975
int version = Read8( io, handle );
976
if ( version == 2 && Read8( io, handle ) != 0xff ) {
977
throw "invalid header: illegal version number.";
980
enum PICTType {none, op9a, jpeg, pixmap, bitmap};
981
PICTType pictType = none;
985
int hRes = 0x480000; // in pixels/inch (72 by default == 0x480000 in fixed point)
986
int vRes = 0x480000; // in pixels/inch (72 by default == 0x480000 in fixed point)
988
BOOL isRegion = FALSE;
993
if ((version == 1) || ((io->tell_proc( handle ) % 2) != 0)) {
994
// align to word for version 2
995
opcode = Read8( io, handle );
998
opcode = Read16( io, handle );
1001
if (opcode == 0xFF || opcode == 0xFFFF) {
1003
throw "PICT contained only vector data!";
1005
else if (opcode < 0xa2) {
1009
// skip clipping rectangle
1011
WORD len = Read16( io, handle );
1013
if (len == 0x000a) {
1015
ReadRect( io, handle, &clipRect );
1017
io->seek_proc(handle, len - 2, SEEK_CUR);
1025
// skip pattern definition
1031
patType = Read16( io, handle );
1035
io->seek_proc(handle, 8, SEEK_CUR);
1036
io->seek_proc(handle, 5, SEEK_CUR);
1040
io->seek_proc(handle, 8, SEEK_CUR);
1041
rowBytes = Read16( io, handle );
1042
ReadRect( io, handle, &p.Bounds );
1043
ReadPixmap( io, handle, &p);
1046
ReadColorTable(io, handle, &numColors, ct );
1047
SkipBits( io, handle, &p.Bounds, rowBytes, p.pixelSize );
1051
throw "Unknown pattern type.";
1065
SkipPolyOrRegion( io, handle );
1071
// Bitmap/pixmap data clipped by a rectangle.
1072
rowBytes = Read16( io, handle ); // Bytes per row in source when uncompressed.
1075
if ( rowBytes & 0x8000) {
1086
// Bitmap/pixmap data clipped by a region.
1087
rowBytes = Read16( io, handle ); // Bytes per row in source when uncompressed.
1090
if ( rowBytes & 0x8000) {
1101
Read32( io, handle ); // Skip fake len and fake EOF.
1102
Read16( io, handle ); // bogus row bytes.
1104
// Read in the PixMap fields.
1105
ReadRect( io, handle, &pixMap.Bounds );
1106
ReadPixmap( io, handle, &pixMap );
1108
// Ignore source & destination rectangle as well as transfer mode.
1110
ReadRect( io, handle, &dummy );
1111
ReadRect( io, handle, &dummy );
1112
WORD mode = Read16( io, handle );
1124
type = Read16( io, handle );
1125
len = Read16( io, handle);
1127
io->seek_proc(handle, len, SEEK_CUR);
1132
// No function => skip to next opcode
1133
if (optable[opcode].len == WORD_LEN) {
1134
WORD len = Read16( io, handle );
1135
io->seek_proc(handle, len, SEEK_CUR);
1137
io->seek_proc(handle, optable[opcode].len, SEEK_CUR);
1142
else if (opcode == 0xc00) {
1143
// version 2 header (26 bytes)
1144
WORD minorVersion = Read16( io, handle ); // always FFFE (-2) for extended version 2
1145
Read16( io, handle ); // reserved
1146
hRes = Read32( io, handle ); // original horizontal resolution in pixels/inch
1147
vRes = Read32( io, handle ); // original horizontal resolution in pixels/inch
1149
ReadRect( io, handle, &dummy ); // frame bounds at original resolution
1150
Read32( io, handle ); // reserved
1152
else if (opcode == 0x8200) {
1154
long opLen = Read32( io, handle );
1158
// skip to JPEG header.
1159
while ( !found && i < opLen ) {
1160
// io->seek_proc( handle, 24, SEEK_CUR );
1162
// ReadRect( io, handle, &dummy );
1163
// io->seek_proc( handle, 122, SEEK_CUR );
1166
if( io->read_proc( data, 2, 1, handle ) ) {
1167
io->seek_proc( handle, -2, SEEK_CUR );
1169
if ( data[0] == 0xFF && data[1] == 0xD8 ) {
1172
Read8( io, handle );
1179
// Pass the data to the JPEG decoder.
1182
throw "PICT file contains unrecognized quicktime data.";
1186
else if (opcode >= 0xa2 && opcode <= 0xaf) {
1188
WORD len = Read16( io, handle );
1189
io->seek_proc(handle, len, SEEK_CUR);
1191
else if ((opcode >= 0xb0 && opcode <= 0xcf) || (opcode >= 0x8000 && opcode <= 0x80ff)) {
1192
// just a reserved opcode, no data
1194
else if ((opcode >= 0xd0 && opcode <= 0xfe) || opcode >= 8100) {
1196
LONG len = Read32( io, handle );
1197
io->seek_proc(handle, len, SEEK_CUR);
1199
else if (opcode >= 0x100 && opcode <= 0x7fff) {
1201
io->seek_proc(handle, ((opcode >> 7) & 255), SEEK_CUR);
1204
sprintf( outputMessage, "Can't handle opcode %x.\n", opcode );
1205
throw outputMessage;
1209
switch ( pictType ) {
1212
bounds = pixMap.Bounds;
1213
int width = bounds.right - bounds.left;
1214
int height = bounds.bottom - bounds.top;
1216
if ( pixMap.pixelSize > 8 ) {
1217
dib = FreeImage_Allocate( width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1219
dib = FreeImage_Allocate( width, height, 8);
1221
hRes = pixMap.hRes << 16;
1222
vRes = pixMap.vRes << 16;
1228
dib = FreeImage_LoadFromHandle( FIF_JPEG, io, handle );
1234
// Decode version 2 pixmap
1235
ReadRect( io, handle, &pixMap.Bounds );
1236
ReadPixmap( io, handle, &pixMap );
1238
bounds = pixMap.Bounds;
1239
int width = bounds.right - bounds.left;
1240
int height = bounds.bottom - bounds.top;
1242
if ( pixMap.pixelSize > 8 ) {
1243
dib = FreeImage_Allocate( width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1245
dib = FreeImage_Allocate( width, height, 8);
1247
hRes = pixMap.hRes << 16;
1248
vRes = pixMap.vRes << 16;
1254
// Decode version 1 bitmap: 1 bpp.
1257
WORD width; // Width in pixels
1258
WORD height; // Height in pixels
1260
ReadRect( io, handle, &bounds );
1261
ReadRect( io, handle, &srcRect );
1262
ReadRect( io, handle, &dstRect );
1264
width = bounds.right - bounds.left;
1265
height = bounds.bottom - bounds.top;
1267
dib = FreeImage_Allocate(width, height, 8);
1273
// need to convert resolution figures from fixed point, pixels/inch
1274
// to floating point, pixels/meter.
1275
float hres_ppm = hRes * ((float)39.4 / (float)65536.0);
1276
float vres_ppm = vRes * ((float)39.4 / (float)65536.0);
1278
FreeImage_SetDotsPerMeterX( dib, (LONG)hres_ppm );
1279
FreeImage_SetDotsPerMeterY( dib, (LONG)vres_ppm );
1281
switch( pictType ) {
1283
DecodeOp9a( io, handle, dib, &pixMap );
1286
// Already decoded if the embedded format was valid.
1289
DecodePixmap( io, handle, dib, isRegion, &pixMap, rowBytes );
1292
DecodeBitmap( io, handle, dib, isRegion, &bounds, rowBytes );
1295
throw "invalid pict type";
1301
catch(const char *message) {
1302
FreeImage_Unload( dib );
1303
FreeImage_OutputMessageProc(s_format_id, message);
1309
// ==========================================================
1311
// ==========================================================
1314
InitPICT(Plugin *plugin, int format_id) {
1315
s_format_id = format_id;
1317
plugin->format_proc = Format;
1318
plugin->description_proc = Description;
1319
plugin->extension_proc = Extension;
1320
plugin->regexpr_proc = NULL;
1321
plugin->open_proc = NULL;
1322
plugin->close_proc = NULL;
1323
plugin->pagecount_proc = NULL;
1324
plugin->pagecapability_proc = NULL;
1325
plugin->load_proc = Load;
1326
plugin->save_proc = NULL;
1327
plugin->validate_proc = Validate;
1328
plugin->mime_proc = MimeType;
1329
plugin->supports_export_bpp_proc = SupportsExportDepth;
1330
plugin->supports_export_type_proc = SupportsExportType;
1331
plugin->supports_icc_profiles_proc = SupportsICCProfiles;