| // ========================================================== |
| // Apple Macintosh QuickDraw/PICT Loader |
| // |
| // Design and implementation by |
| // - Amir Ebrahimi (amir@unity3d.com) |
| // |
| // Based on PICT loading code from paintlib (http://www.paintlib.de/paintlib/). |
| // |
| // Paintlib License: |
| // The paintlib source code and all documentation are copyright (c) 1996-2002 |
| // Ulrich von Zadow and other contributors. |
| // |
| // The paintlib source code is supplied "AS IS". Ulrich von Zadow and other |
| // contributors disclaim all warranties, expressed or implied, including, without |
| // limitation, the warranties of merchantability and of fitness for any purpose. |
| // The authors assume no liability for direct, indirect, incidental, special, |
| // exemplary, or consequential damages, which may result from the use of paintlib, |
| // even if advised of the possibility of such damage. |
| // |
| // Permission is hereby granted to use, copy, modify, and distribute this source |
| // code, or portions hereof, for any purpose, without fee, subject to the following |
| // restrictions: |
| // |
| // 1. The origin of this source code must not be misrepresented. |
| // 2. Altered versions must be plainly marked as such and must not be misrepresented |
| // as being the original source. |
| // 3. This Copyright notice may not be removed or altered from any source or altered |
| // source distribution. |
| // 4. Executables containing paintlib or parts of it must state that the software |
| // "contains paintlib code. paintlib is copyright (c) 1996-2002 Ulrich von Zadow |
| // and other contributors.". This notice must be displayed in at least one place |
| // where the copyright for the software itself is displayed. The documentation must |
| // also contain this notice. |
| // |
| // Bug fixes were made to the original code to support version 2 PICT files |
| // properly. |
| // |
| // Additional resources: |
| // http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-458.html |
| // http://www.fileformat.info/format/macpict/egff.htm |
| // |
| // Notes (http://lists.apple.com/archives/java-dev/2006/Apr/msg00588.html): |
| // There are three main types of PICT files: |
| // - Version 1 |
| // - Version 2 |
| // - Extended Version 2 |
| // |
| // Some things to look out for: |
| // - The bounds and target DPI are stored in a different place in all three. |
| // - Some of the values are fixed-point shorts ( short / 65536f ) |
| // - Values are big endian |
| // - All of this may be *preceded* by a 512 byte header--sometimes it is |
| // there, and sometimes it isn't. You just have to check for the magic |
| // values in both places. |
| // |
| // This file is part of FreeImage 3 |
| // |
| // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY |
| // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES |
| // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE |
| // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED |
| // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT |
| // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY |
| // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL |
| // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER |
| // THIS DISCLAIMER. |
| // |
| // Use at your own risk! |
| // ========================================================== |
| |
| #include "FreeImage.h" |
| #include "Utilities.h" |
| |
| // ========================================================== |
| // Plugin Interface |
| // ========================================================== |
| static int s_format_id; |
| |
| static const int outputMessageSize = 256; |
| |
| // ========================================================== |
| // Internal functions |
| // ========================================================== |
| |
| static BYTE |
| Read8(FreeImageIO *io, fi_handle handle) { |
| BYTE i = 0; |
| io->read_proc(&i, 1, 1, handle); |
| return i; |
| } |
| |
| static WORD |
| Read16(FreeImageIO *io, fi_handle handle) { |
| // reads a two-byte big-endian integer from the given file and returns its value. |
| // assumes unsigned. |
| |
| unsigned hi = Read8(io, handle); |
| unsigned lo = Read8(io, handle); |
| return (WORD)(lo + (hi << 8)); |
| } |
| |
| static unsigned |
| Read32(FreeImageIO *io, fi_handle handle) { |
| // reads a four-byte big-endian integer from the given file and returns its value. |
| // assumes unsigned. |
| |
| unsigned b3 = Read8(io, handle); |
| unsigned b2 = Read8(io, handle); |
| unsigned b1 = Read8(io, handle); |
| unsigned b0 = Read8(io, handle); |
| return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0; |
| } |
| |
| // ---------------------------------------------------------- |
| |
| struct OpDef |
| { |
| const char * name; |
| int len; |
| const char * description; |
| }; |
| |
| // for reserved opcodes |
| #define res(length) { "reserved", (length), "reserved for Apple use" } |
| #define RGB_LEN 6 |
| #define WORD_LEN -1 |
| #define NA 0 |
| |
| static OpDef optable[] = |
| { |
| /* 0x00 */ { "NOP", 0, "nop" }, |
| /* 0x01 */ { "Clip", NA, "clip" }, |
| /* 0x02 */ { "BkPat", 8, "background pattern" }, |
| /* 0x03 */ { "TxFont", 2, "text font (word)" }, |
| /* 0x04 */ { "TxFace", 1, "text face (byte)" }, |
| /* 0x05 */ { "TxMode", 2, "text mode (word)" }, |
| /* 0x06 */ { "SpExtra", 4, "space extra (fixed point)" }, |
| /* 0x07 */ { "PnSize", 4, "pen size (point)" }, |
| /* 0x08 */ { "PnMode", 2, "pen mode (word)" }, |
| /* 0x09 */ { "PnPat", 8, "pen pattern" }, |
| /* 0x0a */ { "FillPat", 8, "fill pattern" }, |
| /* 0x0b */ { "OvSize", 4, "oval size (point)" }, |
| /* 0x0c */ { "Origin", 4, "dh, dv (word)" }, |
| /* 0x0d */ { "TxSize", 2, "text size (word)" }, |
| /* 0x0e */ { "FgColor", 4, "foreground color (longword)" }, |
| /* 0x0f */ { "BkColor", 4, "background color (longword)" }, |
| /* 0x10 */ { "TxRatio", 8, "numerator (point), denominator (point)" }, |
| /* 0x11 */ { "Version", 1, "version (byte)" }, |
| /* 0x12 */ { "BkPixPat", NA, "color background pattern" }, |
| /* 0x13 */ { "PnPixPat", NA, "color pen pattern" }, |
| /* 0x14 */ { "FillPixPat", NA, "color fill pattern" }, |
| /* 0x15 */ { "PnLocHFrac", 2, "fractional pen position" }, |
| /* 0x16 */ { "ChExtra", 2, "extra for each character" }, |
| /* 0x17 */ res(0), |
| /* 0x18 */ res(0), |
| /* 0x19 */ res(0), |
| /* 0x1a */ { "RGBFgCol", RGB_LEN, "RGB foreColor" }, |
| /* 0x1b */ { "RGBBkCol", RGB_LEN, "RGB backColor" }, |
| /* 0x1c */ { "HiliteMode", 0, "hilite mode flag" }, |
| /* 0x1d */ { "HiliteColor", RGB_LEN, "RGB hilite color" }, |
| /* 0x1e */ { "DefHilite", 0, "Use default hilite color" }, |
| /* 0x1f */ { "OpColor", 6, "RGB OpColor for arithmetic modes" }, |
| /* 0x20 */ { "Line", 8, "pnLoc (point), newPt (point)" }, |
| /* 0x21 */ { "LineFrom", 4, "newPt (point)" }, |
| /* 0x22 */ { "ShortLine", 6, "pnLoc (point, dh, dv (-128 .. 127))" }, |
| /* 0x23 */ { "ShortLineFrom", 2, "dh, dv (-128 .. 127)" }, |
| /* 0x24 */ res(WORD_LEN), |
| /* 0x25 */ res(WORD_LEN), |
| /* 0x26 */ res(WORD_LEN), |
| /* 0x27 */ res(WORD_LEN), |
| /* 0x28 */ { "LongText", NA, "txLoc (point), count (0..255), text" }, |
| /* 0x29 */ { "DHText", NA, "dh (0..255), count (0..255), text" }, |
| /* 0x2a */ { "DVText", NA, "dv (0..255), count (0..255), text" }, |
| /* 0x2b */ { "DHDVText", NA, "dh, dv (0..255), count (0..255), text" }, |
| /* 0x2c */ res(WORD_LEN), |
| /* 0x2d */ res(WORD_LEN), |
| /* 0x2e */ res(WORD_LEN), |
| /* 0x2f */ res(WORD_LEN), |
| /* 0x30 */ { "frameRect", 8, "rect" }, |
| /* 0x31 */ { "paintRect", 8, "rect" }, |
| /* 0x32 */ { "eraseRect", 8, "rect" }, |
| /* 0x33 */ { "invertRect", 8, "rect" }, |
| /* 0x34 */ { "fillRect", 8, "rect" }, |
| /* 0x35 */ res(8), |
| /* 0x36 */ res(8), |
| /* 0x37 */ res(8), |
| /* 0x38 */ { "frameSameRect", 0, "rect" }, |
| /* 0x39 */ { "paintSameRect", 0, "rect" }, |
| /* 0x3a */ { "eraseSameRect", 0, "rect" }, |
| /* 0x3b */ { "invertSameRect", 0, "rect" }, |
| /* 0x3c */ { "fillSameRect", 0, "rect" }, |
| /* 0x3d */ res(0), |
| /* 0x3e */ res(0), |
| /* 0x3f */ res(0), |
| /* 0x40 */ { "frameRRect", 8, "rect" }, |
| /* 0x41 */ { "paintRRect", 8, "rect" }, |
| /* 0x42 */ { "eraseRRect", 8, "rect" }, |
| /* 0x43 */ { "invertRRect", 8, "rect" }, |
| /* 0x44 */ { "fillRRrect", 8, "rect" }, |
| /* 0x45 */ res(8), |
| /* 0x46 */ res(8), |
| /* 0x47 */ res(8), |
| /* 0x48 */ { "frameSameRRect", 0, "rect" }, |
| /* 0x49 */ { "paintSameRRect", 0, "rect" }, |
| /* 0x4a */ { "eraseSameRRect", 0, "rect" }, |
| /* 0x4b */ { "invertSameRRect", 0, "rect" }, |
| /* 0x4c */ { "fillSameRRect", 0, "rect" }, |
| /* 0x4d */ res(0), |
| /* 0x4e */ res(0), |
| /* 0x4f */ res(0), |
| /* 0x50 */ { "frameOval", 8, "rect" }, |
| /* 0x51 */ { "paintOval", 8, "rect" }, |
| /* 0x52 */ { "eraseOval", 8, "rect" }, |
| /* 0x53 */ { "invertOval", 8, "rect" }, |
| /* 0x54 */ { "fillOval", 8, "rect" }, |
| /* 0x55 */ res(8), |
| /* 0x56 */ res(8), |
| /* 0x57 */ res(8), |
| /* 0x58 */ { "frameSameOval", 0, "rect" }, |
| /* 0x59 */ { "paintSameOval", 0, "rect" }, |
| /* 0x5a */ { "eraseSameOval", 0, "rect" }, |
| /* 0x5b */ { "invertSameOval", 0, "rect" }, |
| /* 0x5c */ { "fillSameOval", 0, "rect" }, |
| /* 0x5d */ res(0), |
| /* 0x5e */ res(0), |
| /* 0x5f */ res(0), |
| /* 0x60 */ { "frameArc", 12, "rect, startAngle, arcAngle" }, |
| /* 0x61 */ { "paintArc", 12, "rect, startAngle, arcAngle" }, |
| /* 0x62 */ { "eraseArc", 12, "rect, startAngle, arcAngle" }, |
| /* 0x63 */ { "invertArc", 12, "rect, startAngle, arcAngle" }, |
| /* 0x64 */ { "fillArc", 12, "rect, startAngle, arcAngle" }, |
| /* 0x65 */ res(12), |
| /* 0x66 */ res(12), |
| /* 0x67 */ res(12), |
| /* 0x68 */ { "frameSameArc", 4, "rect, startAngle, arcAngle" }, |
| /* 0x69 */ { "paintSameArc", 4, "rect, startAngle, arcAngle" }, |
| /* 0x6a */ { "eraseSameArc", 4, "rect, startAngle, arcAngle" }, |
| /* 0x6b */ { "invertSameArc", 4, "rect, startAngle, arcAngle" }, |
| /* 0x6c */ { "fillSameArc", 4, "rect, startAngle, arcAngle" }, |
| /* 0x6d */ res(4), |
| /* 0x6e */ res(4), |
| /* 0x6f */ res(4), |
| /* 0x70 */ { "framePoly", NA, "poly" }, |
| /* 0x71 */ { "paintPoly", NA, "poly" }, |
| /* 0x72 */ { "erasePoly", NA, "poly" }, |
| /* 0x73 */ { "invertPoly", NA, "poly" }, |
| /* 0x74 */ { "fillPoly", NA, "poly" }, |
| /* 0x75 */ res(NA), |
| /* 0x76 */ res(NA), |
| /* 0x77 */ res(NA), |
| /* 0x78 */ { "frameSamePoly", 0, "poly (NYI)" }, |
| /* 0x79 */ { "paintSamePoly", 0, "poly (NYI)" }, |
| /* 0x7a */ { "eraseSamePoly", 0, "poly (NYI)" }, |
| /* 0x7b */ { "invertSamePoly", 0, "poly (NYI)" }, |
| /* 0x7c */ { "fillSamePoly", 0, "poly (NYI)" }, |
| /* 0x7d */ res(0), |
| /* 0x7e */ res(0), |
| /* 0x7f */ res(0), |
| /* 0x80 */ { "frameRgn", NA, "region" }, |
| /* 0x81 */ { "paintRgn", NA, "region" }, |
| /* 0x82 */ { "eraseRgn", NA, "region" }, |
| /* 0x83 */ { "invertRgn", NA, "region" }, |
| /* 0x84 */ { "fillRgn", NA, "region" }, |
| /* 0x85 */ res(NA), |
| /* 0x86 */ res(NA), |
| /* 0x87 */ res(NA), |
| /* 0x88 */ { "frameSameRgn", 0, "region (NYI)" }, |
| /* 0x89 */ { "paintSameRgn", 0, "region (NYI)" }, |
| /* 0x8a */ { "eraseSameRgn", 0, "region (NYI)" }, |
| /* 0x8b */ { "invertSameRgn", 0, "region (NYI)" }, |
| /* 0x8c */ { "fillSameRgn", 0, "region (NYI)" }, |
| /* 0x8d */ res(0), |
| /* 0x8e */ res(0), |
| /* 0x8f */ res(0), |
| /* 0x90 */ { "BitsRect", NA, "copybits, rect clipped" }, |
| /* 0x91 */ { "BitsRgn", NA, "copybits, rgn clipped" }, |
| /* 0x92 */ res(WORD_LEN), |
| /* 0x93 */ res(WORD_LEN), |
| /* 0x94 */ res(WORD_LEN), |
| /* 0x95 */ res(WORD_LEN), |
| /* 0x96 */ res(WORD_LEN), |
| /* 0x97 */ res(WORD_LEN), |
| /* 0x98 */ { "PackBitsRect", NA, "packed copybits, rect clipped" }, |
| /* 0x99 */ { "PackBitsRgn", NA, "packed copybits, rgn clipped" }, |
| /* 0x9a */ { "Opcode_9A", NA, "the mysterious opcode 9A" }, |
| /* 0x9b */ res(WORD_LEN), |
| /* 0x9c */ res(WORD_LEN), |
| /* 0x9d */ res(WORD_LEN), |
| /* 0x9e */ res(WORD_LEN), |
| /* 0x9f */ res(WORD_LEN), |
| /* 0xa0 */ { "ShortComment", 2, "kind (word)" }, |
| /* 0xa1 */ { "LongComment", NA, "kind (word), size (word), data" } |
| }; |
| |
| // ---------------------------------------------------------- |
| |
| struct MacRect |
| { |
| WORD top; |
| WORD left; |
| WORD bottom; |
| WORD right; |
| }; |
| |
| struct MacpixMap |
| { |
| // Ptr baseAddr // Not used in file. |
| // short rowBytes // read in seperatly. |
| struct MacRect Bounds; |
| WORD version; |
| WORD packType; |
| LONG packSize; |
| LONG hRes; |
| LONG vRes; |
| WORD pixelType; |
| WORD pixelSize; |
| WORD cmpCount; |
| WORD cmpSize; |
| LONG planeBytes; |
| LONG pmTable; |
| LONG pmReserved; |
| }; |
| |
| struct MacRGBColour |
| { |
| WORD red; |
| WORD green; |
| WORD blue; |
| }; |
| |
| struct MacPoint |
| { |
| WORD x; |
| WORD y; |
| }; |
| |
| struct MacPattern // Klaube |
| { |
| BYTE pix[64]; |
| }; |
| |
| // ---------------------------------------------------------- |
| |
| static void |
| ReadRect( FreeImageIO *io, fi_handle handle, MacRect* rect ) { |
| rect->top = Read16( io, handle ); |
| rect->left = Read16( io, handle ); |
| rect->bottom = Read16( io, handle ); |
| rect->right = Read16( io, handle ); |
| } |
| |
| static void |
| ReadPixmap( FreeImageIO *io, fi_handle handle, MacpixMap* pPixMap ) { |
| pPixMap->version = Read16( io, handle ); |
| pPixMap->packType = Read16( io, handle ); |
| pPixMap->packSize = Read32( io, handle ); |
| pPixMap->hRes = Read16( io, handle ); |
| Read16( io, handle ); |
| pPixMap->vRes = Read16( io, handle ); |
| Read16( io, handle ); |
| pPixMap->pixelType = Read16( io, handle ); |
| pPixMap->pixelSize = Read16( io, handle ); |
| pPixMap->cmpCount = Read16( io, handle ); |
| pPixMap->cmpSize = Read16( io, handle ); |
| pPixMap->planeBytes = Read32( io, handle ); |
| pPixMap->pmTable = Read32( io, handle ); |
| pPixMap->pmReserved = Read32( io, handle ); |
| } |
| |
| /** |
| Reads a mac color table into a bitmap palette. |
| */ |
| static void |
| ReadColorTable( FreeImageIO *io, fi_handle handle, WORD* pNumColors, RGBQUAD* pPal ) { |
| LONG ctSeed; |
| WORD ctFlags; |
| WORD val; |
| int i; |
| |
| ctSeed = Read32( io, handle ); |
| ctFlags = Read16( io, handle ); |
| WORD numColors = Read16( io, handle )+1; |
| *pNumColors = numColors; |
| |
| for (i = 0; i < numColors; i++) { |
| val = Read16( io, handle ); |
| if (ctFlags & 0x8000) { |
| // The indicies in a device colour table are bogus and |
| // usually == 0, so I assume we allocate up the list of |
| // colours in order. |
| val = (WORD)i; |
| } |
| if (val >= numColors) { |
| throw "pixel value greater than color table size."; |
| } |
| // Mac colour tables contain 16-bit values for R, G, and B... |
| pPal[val].rgbRed = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF)); |
| pPal[val].rgbGreen = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF)); |
| pPal[val].rgbBlue = ((BYTE) (((WORD) (Read16( io, handle )) >> 8) & 0xFF)); |
| } |
| } |
| |
| /** |
| skips unneeded packbits. |
| pixelSize == Source bits per pixel. |
| */ |
| static void |
| SkipBits( FreeImageIO *io, fi_handle handle, MacRect* bounds, WORD rowBytes, int pixelSize ) { |
| int i; |
| WORD pixwidth; // bytes per row when uncompressed. |
| |
| int height = bounds->bottom - bounds->top; |
| int width = bounds->right - bounds->left; |
| |
| // High bit of rowBytes is flag. |
| if (pixelSize <= 8) { |
| rowBytes &= 0x7fff; |
| } |
| pixwidth = (WORD)width; |
| |
| if (pixelSize == 16) { |
| pixwidth *= 2; |
| } |
| if (rowBytes == 0) { |
| rowBytes = pixwidth; |
| } |
| if (rowBytes < 8) { |
| io->seek_proc( handle, rowBytes*height, SEEK_CUR ); |
| } |
| else { |
| for (i = 0; i < height; i++) { |
| int lineLen; // length of source line in bytes. |
| if (rowBytes > 250) { |
| lineLen = Read16( io, handle ); |
| } else { |
| lineLen = Read8( io, handle ); |
| } |
| io->seek_proc( handle, lineLen, SEEK_CUR ); |
| } |
| } |
| } |
| |
| /** |
| Skip polygon or region |
| */ |
| static void |
| SkipPolyOrRegion( FreeImageIO *io, fi_handle handle ) { |
| WORD len = Read16( io, handle ) - 2; |
| io->seek_proc(handle, len, SEEK_CUR); |
| } |
| |
| /** |
| Width in bytes for 8 bpp or less. |
| Width in pixels for 16 bpp. |
| Expands Width units to 32-bit pixel data. |
| */ |
| static void |
| expandBuf( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst ) { |
| switch (bpp) { |
| case 16: |
| for ( int i=0; i<width; i++) { |
| WORD src = Read16( io, handle ); |
| dst[ FI_RGBA_BLUE ] = (src & 31)*8; // Blue |
| dst[ FI_RGBA_GREEN ] = ((src >> 5) & 31)*8; // Green |
| dst[ FI_RGBA_RED ] = ((src >> 10) & 31)*8; // Red |
| dst[ FI_RGBA_ALPHA ] = 0xFF; // Alpha |
| dst += 4; |
| } |
| break; |
| default: |
| throw "Bad bits per pixel in expandBuf."; |
| } |
| } |
| |
| /** |
| Expands Width units to 8-bit pixel data. |
| Max. 8 bpp source format. |
| */ |
| static void |
| expandBuf8( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst ) |
| { |
| switch (bpp) { |
| case 8: |
| io->read_proc( dst, width, 1, handle ); |
| break; |
| case 4: |
| for (int i = 0; i < width; i++) { |
| WORD src = Read8( io, handle ); |
| *dst = (src >> 4) & 15; |
| *(dst+1) = (src & 15); |
| dst += 2; |
| } |
| if (width & 1) { // Odd Width? |
| WORD src = Read8( io, handle ); |
| *dst = (src >> 4) & 15; |
| dst++; |
| } |
| break; |
| case 2: |
| for (int i = 0; i < width; i++) { |
| WORD src = Read8( io, handle ); |
| *dst = (src >> 6) & 3; |
| *(dst+1) = (src >> 4) & 3; |
| *(dst+2) = (src >> 2) & 3; |
| *(dst+3) = (src & 3); |
| dst += 4; |
| } |
| if (width & 3) { // Check for leftover pixels |
| for (int i = 6; i > 8 - (width & 3) * 2; i -= 2) { |
| WORD src = Read8( io, handle ); |
| *dst = (src >> i) & 3; |
| dst++; |
| } |
| } |
| break; |
| case 1: |
| for (int i = 0; i < width; i++) { |
| WORD src = Read8( io, handle ); |
| *dst = (src >> 7) & 1; |
| *(dst+1) = (src >> 6) & 1; |
| *(dst+2) = (src >> 5) & 1; |
| *(dst+3) = (src >> 4) & 1; |
| *(dst+4) = (src >> 3) & 1; |
| *(dst+5) = (src >> 2) & 1; |
| *(dst+6) = (src >> 1) & 1; |
| *(dst+7) = (src & 1); |
| dst += 8; |
| } |
| if (width & 7) { // Check for leftover pixels |
| for (int i = 7; i > (8-width & 7); i--) { |
| WORD src = Read8( io, handle ); |
| *dst = (src >> i) & 1; |
| dst++; |
| } |
| } |
| break; |
| default: |
| throw "Bad bits per pixel in expandBuf8."; |
| } |
| } |
| |
| static BYTE* |
| UnpackPictRow( FreeImageIO *io, fi_handle handle, BYTE* pLineBuf, int width, int rowBytes, int srcBytes ) { |
| |
| if (rowBytes < 8) { // Ah-ha! The bits aren't actually packed. This will be easy. |
| io->read_proc( pLineBuf, rowBytes, 1, handle ); |
| } |
| else { |
| BYTE* pCurPixel = pLineBuf; |
| |
| // Unpack RLE. The data is packed bytewise. |
| for (int j = 0; j < srcBytes; ) { |
| BYTE FlagCounter = Read8( io, handle ); |
| if (FlagCounter & 0x80) { |
| if (FlagCounter == 0x80) { |
| // Special case: repeat value of 0. |
| // Apple says ignore. |
| j++; |
| } else { |
| // Packed data. |
| int len = ((FlagCounter ^ 255) & 255) + 2; |
| BYTE p = Read8( io, handle ); |
| memset( pCurPixel, p, len); |
| pCurPixel += len; |
| j += 2; |
| } |
| } |
| else { |
| // Unpacked data |
| int len = (FlagCounter & 255) + 1; |
| io->read_proc( pCurPixel, len, 1, handle ); |
| pCurPixel += len; |
| j += len + 1; |
| } |
| } |
| } |
| |
| return pLineBuf; |
| } |
| |
| /** |
| This routine decompresses BitsRects with a packType of 4 (and 32 bits per pixel). |
| In this format, each line is separated into 8-bit-bitplanes and then compressed via RLE. |
| To decode, the routine decompresses each line & then juggles the bytes around to get pixel-oriented data. |
| NumBitPlanes == 3 if RGB, 4 if RGBA |
| */ |
| static void |
| Unpack32Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes, int numPlanes ) { |
| int height = bounds->bottom - bounds->top; |
| int width = bounds->right - bounds->left; |
| |
| if (rowBytes == 0) { |
| rowBytes = (WORD)( width * 4 ); |
| } |
| |
| BYTE* pLineBuf = (BYTE*)malloc( rowBytes ); // Let's allocate enough for 4 bit planes |
| if ( pLineBuf ) { |
| try { |
| for ( int i = 0; i < height; i++ ) { |
| // for each line do... |
| int linelen; // length of source line in bytes. |
| if (rowBytes > 250) { |
| linelen = Read16( io, handle ); |
| } else { |
| linelen = Read8( io, handle); |
| } |
| |
| BYTE* pBuf = UnpackPictRow( io, handle, pLineBuf, width, rowBytes, linelen ); |
| |
| // Convert plane-oriented data into pixel-oriented data & |
| // copy into destination bitmap. |
| BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i); |
| |
| if ( numPlanes == 3 ) { |
| for ( int j = 0; j < width; j++ ) { |
| // For each pixel in line... |
| dst[ FI_RGBA_BLUE ] = (*(pBuf+width*2)); // Blue |
| dst[ FI_RGBA_GREEN ] = (*(pBuf+width)); // Green |
| dst[ FI_RGBA_RED ] = (*pBuf); // Red |
| dst[ FI_RGBA_ALPHA ] = (0xFF); |
| dst += 4; |
| pBuf++; |
| } |
| } else { |
| for ( int j = 0; j < width; j++ ) { |
| // For each pixel in line... |
| dst[ FI_RGBA_BLUE ] = (*(pBuf+width*3)); // Blue |
| dst[ FI_RGBA_GREEN ] = (*(pBuf+width*2)); // Green |
| dst[ FI_RGBA_RED ] = (*(pBuf+width)); // Red |
| dst[ FI_RGBA_ALPHA ] = (*pBuf); |
| dst += 4; |
| pBuf++; |
| } |
| } |
| } |
| } |
| catch( ... ) { |
| free( pLineBuf ); |
| throw; |
| } |
| } |
| free( pLineBuf ); |
| } |
| |
| /** |
| Decompression routine for 8 bpp. |
| rowBytes is the number of bytes each source row would take if it were uncompressed. |
| 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. |
| Of course, we have to decompress the excess data and then throw it away. |
| */ |
| static void |
| Unpack8Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes ) { |
| int height = bounds->bottom - bounds->top; |
| int width = bounds->right - bounds->left; |
| |
| // High bit of rowBytes is flag. |
| rowBytes &= 0x7fff; |
| |
| if (rowBytes == 0) { |
| rowBytes = (WORD)width; |
| } |
| |
| for ( int i = 0; i < height; i++ ) { |
| int linelen; // length of source line in bytes. |
| if (rowBytes > 250) { |
| linelen = Read16( io, handle ); |
| } else { |
| linelen = Read8( io, handle ); |
| } |
| BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i); |
| dst = UnpackPictRow( io, handle, dst, width, rowBytes, linelen ); |
| } |
| } |
| |
| /** |
| Decompression routine for everything but 8 & 32 bpp. |
| This routine is slower than the two routines above since it has to deal with a lot of special cases :-(. |
| It's also a bit chaotic because of these special cases... |
| unpack8bits is basically a dumber version of unpackbits. |
| pixelSize == Source bits per pixel. |
| */ |
| static void |
| UnpackBits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, WORD rowBytes, int pixelSize ) { |
| WORD pixwidth; // bytes per row when uncompressed. |
| int pkpixsize; |
| int PixelPerRLEUnit; |
| |
| char outputMessage[ outputMessageSize ] = ""; |
| |
| int height = bounds->bottom - bounds->top; |
| int width = bounds->right - bounds->left; |
| |
| // High bit of rowBytes is flag. |
| if (pixelSize <= 8) { |
| rowBytes &= 0x7fff; |
| } |
| |
| pixwidth = (WORD)width; |
| pkpixsize = 1; // RLE unit: one byte for everything... |
| if (pixelSize == 16) { // ...except 16 bpp. |
| pkpixsize = 2; |
| pixwidth *= 2; |
| } |
| |
| if (rowBytes == 0) { |
| rowBytes = pixwidth; |
| } |
| |
| { |
| // I allocate the temporary line buffer here. I allocate too |
| // much memory to compensate for sloppy (& hence fast) decompression. |
| switch (pixelSize) { |
| case 1: |
| PixelPerRLEUnit = 8; |
| break; |
| case 2: |
| PixelPerRLEUnit = 4; |
| break; |
| case 4: |
| PixelPerRLEUnit = 2; |
| break; |
| case 8: |
| PixelPerRLEUnit = 1; |
| break; |
| case 16: |
| PixelPerRLEUnit = 1; |
| break; |
| default: |
| sprintf( outputMessage, "Illegal bpp value in unpackbits: %d\n", pixelSize ); |
| throw outputMessage; |
| } |
| |
| if (rowBytes < 8) { |
| // ah-ha! The bits aren't actually packed. This will be easy. |
| for ( int i = 0; i < height; i++ ) { |
| BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i); |
| if (pixelSize == 16) { |
| expandBuf( io, handle, width, pixelSize, dst ); |
| } else { |
| expandBuf8( io, handle, width, pixelSize, dst ); |
| } |
| } |
| } |
| else { |
| for ( int i = 0; i < height; i++ ) { |
| // For each line do... |
| int linelen; // length of source line in bytes. |
| if (rowBytes > 250) { |
| linelen = Read16( io, handle ); |
| } else { |
| linelen = Read8( io, handle ); |
| } |
| |
| BYTE* dst = (BYTE*)FreeImage_GetScanLine( dib, height - 1 - i); |
| BYTE FlagCounter; |
| |
| // Unpack RLE. The data is packed bytewise - except for |
| // 16 bpp data, which is packed per pixel :-(. |
| for ( int j = 0; j < linelen; ) { |
| FlagCounter = Read8( io, handle ); |
| if (FlagCounter & 0x80) { |
| if (FlagCounter == 0x80) { |
| // Special case: repeat value of 0. |
| // Apple says ignore. |
| j++; |
| } |
| else { |
| // Packed data. |
| int len = ((FlagCounter ^ 255) & 255) + 2; |
| |
| // This is slow for some formats... |
| if (pixelSize == 16) { |
| expandBuf( io, handle, 1, pixelSize, dst ); |
| for ( int k = 1; k < len; k++ ) { |
| // Repeat the pixel len times. |
| memcpy( dst+(k*4*PixelPerRLEUnit), dst, 4*PixelPerRLEUnit); |
| } |
| dst += len*4*PixelPerRLEUnit; |
| } |
| else { |
| expandBuf8( io, handle, 1, pixelSize, dst ); |
| for ( int k = 1; k < len; k++ ) { |
| // Repeat the expanded byte len times. |
| memcpy( dst+(k*PixelPerRLEUnit), dst, PixelPerRLEUnit); |
| } |
| dst += len*PixelPerRLEUnit; |
| } |
| j += pkpixsize + 1; |
| } |
| } |
| else { |
| // Unpacked data |
| int len = (FlagCounter & 255) + 1; |
| if (pixelSize == 16) { |
| expandBuf( io, handle, len, pixelSize, dst ); |
| dst += len*4*PixelPerRLEUnit; |
| } |
| else { |
| expandBuf8( io, handle, len, pixelSize, dst ); |
| dst += len*PixelPerRLEUnit; |
| } |
| j += ( len * pkpixsize ) + 1; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| static void |
| DecodeOp9a( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacpixMap* pixMap ) { |
| // Do the actual unpacking. |
| switch ( pixMap->pixelSize ) { |
| case 32: |
| Unpack32Bits( io, handle, dib, &pixMap->Bounds, 0, pixMap->cmpCount ); |
| break; |
| case 8: |
| Unpack8Bits( io, handle, dib, &pixMap->Bounds, 0 ); |
| break; |
| default: |
| UnpackBits( io, handle, dib, &pixMap->Bounds, 0, pixMap->pixelSize ); |
| } |
| } |
| |
| static void |
| DecodeBitmap( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, BOOL isRegion, MacRect* bounds, WORD rowBytes ) { |
| WORD mode = Read16( io, handle ); |
| |
| if ( isRegion ) { |
| SkipPolyOrRegion( io, handle ); |
| } |
| |
| RGBQUAD* pal = FreeImage_GetPalette( dib ); |
| if ( !pal ) { |
| throw "No palette for bitmap!"; |
| } |
| |
| for (int i = 0; i < 2; i++) { |
| unsigned char val = i ? 0xFF : 0x0; |
| pal[i].rgbRed = val; |
| pal[i].rgbGreen = val; |
| pal[i].rgbBlue = val; |
| } |
| |
| UnpackBits( io, handle, dib, bounds, rowBytes, 1 ); |
| } |
| |
| static void |
| DecodePixmap( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, BOOL isRegion, MacpixMap* pixMap, WORD rowBytes ) { |
| // Read mac colour table into windows palette. |
| WORD numColors; // Palette size. |
| RGBQUAD ct[256]; |
| |
| ReadColorTable( io, handle, &numColors, ct ); |
| if ( FreeImage_GetBPP( dib ) == 8 ) { |
| RGBQUAD* pal = FreeImage_GetPalette( dib ); |
| if ( !pal ) { |
| throw "No palette for bitmap!"; |
| } |
| |
| for (int i = 0; i < numColors; i++) { |
| pal[i].rgbRed = ct[ i ].rgbRed; |
| pal[i].rgbGreen = ct[ i ].rgbGreen; |
| pal[i].rgbBlue = ct[ i ].rgbBlue; |
| } |
| } |
| |
| // Ignore source & destination rectangle as well as transfer mode. |
| MacRect tempRect; |
| ReadRect( io, handle, &tempRect ); |
| ReadRect( io, handle, &tempRect ); |
| WORD mode = Read16( io, handle ); |
| |
| if ( isRegion) { |
| SkipPolyOrRegion( io, handle ); |
| } |
| |
| switch ( pixMap->pixelSize ) { |
| case 32: |
| Unpack32Bits( io, handle, dib, &pixMap->Bounds, rowBytes, pixMap->cmpCount ); |
| break; |
| case 8: |
| Unpack8Bits( io, handle, dib, &pixMap->Bounds, rowBytes ); |
| break; |
| default: |
| UnpackBits( io, handle, dib, &pixMap->Bounds, rowBytes, pixMap->pixelSize ); |
| } |
| } |
| |
| // ========================================================== |
| // Plugin Implementation |
| // ========================================================== |
| |
| static const char * DLL_CALLCONV |
| Format() { |
| return "PICT"; |
| } |
| |
| static const char * DLL_CALLCONV |
| Description() { |
| return "Macintosh PICT"; |
| } |
| |
| static const char * DLL_CALLCONV |
| Extension() { |
| return "pct,pict,pic"; |
| } |
| |
| static const char * DLL_CALLCONV |
| MimeType() { |
| return "image/x-pict"; |
| } |
| |
| static BOOL DLL_CALLCONV |
| Validate(FreeImageIO *io, fi_handle handle) { |
| if(io->seek_proc(handle, 522, SEEK_SET) == 0) { |
| BYTE pict_signature[] = { 0x00, 0x11, 0x02, 0xFF, 0x0C, 0X00 }; |
| BYTE signature[6]; |
| |
| if(io->read_proc(signature, 1, sizeof(pict_signature), handle)) { |
| // v1.0 files have 0x11 (version operator) followed by 0x01 (version number) |
| // v2.0 files have 0x0011 (version operator) followed by 0x02ff (version number) |
| // and additionally 0x0c00 as a header opcode |
| // Currently, we are only supporting v2.0 |
| return (memcmp(pict_signature, signature, sizeof(pict_signature)) == 0); |
| } else { |
| return FALSE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| static BOOL DLL_CALLCONV |
| SupportsExportDepth(int depth) { |
| return FALSE; |
| } |
| |
| static BOOL DLL_CALLCONV |
| SupportsExportType(FREE_IMAGE_TYPE type) { |
| return FALSE; |
| } |
| |
| static BOOL DLL_CALLCONV |
| SupportsICCProfiles() { |
| return FALSE; |
| } |
| |
| /** |
| This plugin decodes macintosh PICT files with 1,2,4,8,16 and 32 bits per pixel as well as PICT/JPEG. |
| If an alpha channel is present in a 32-bit-PICT, it is decoded as well. |
| The PICT format is a general picture file format and can contain a lot of other elements besides bitmaps. |
| These elements are ignored. |
| */ |
| static FIBITMAP * DLL_CALLCONV |
| Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { |
| char outputMessage[ outputMessageSize ] = ""; |
| FIBITMAP* dib = NULL; |
| try { |
| // Skip empty 512 byte header. |
| if ( !io->seek_proc(handle, 512, SEEK_CUR) == 0 ) |
| return NULL; |
| |
| // Read PICT header |
| Read16( io, handle ); // Skip version 1 picture size |
| |
| MacRect frame; |
| ReadRect( io, handle, &frame ); |
| |
| BYTE b = 0; |
| while ((b = Read8(io, handle)) == 0); |
| if ( b != 0x11 ) { |
| throw "invalid header: version number missing."; |
| } |
| |
| int version = Read8( io, handle ); |
| if ( version == 2 && Read8( io, handle ) != 0xff ) { |
| throw "invalid header: illegal version number."; |
| } |
| |
| enum PICTType {none, op9a, jpeg, pixmap, bitmap}; |
| PICTType pictType = none; |
| |
| MacRect bounds; |
| MacpixMap pixMap; |
| int hRes = 0x480000; // in pixels/inch (72 by default == 0x480000 in fixed point) |
| int vRes = 0x480000; // in pixels/inch (72 by default == 0x480000 in fixed point) |
| WORD rowBytes = 0; |
| BOOL isRegion = FALSE; |
| BOOL done = FALSE; |
| long currentPos = 0; |
| |
| while ( !done ) { |
| WORD opcode = 0; |
| |
| // get the current stream position (used to avoid infinite loops) |
| currentPos = io->tell_proc(handle); |
| |
| if ((version == 1) || ((io->tell_proc( handle ) % 2) != 0)) { |
| // align to word for version 2 |
| opcode = Read8( io, handle ); |
| } |
| if (version == 2) { |
| opcode = Read16( io, handle ); |
| } |
| |
| if (opcode == 0xFF || opcode == 0xFFFF) { |
| done = TRUE; |
| throw "PICT contained only vector data!"; |
| } |
| else if (opcode < 0xa2) { |
| switch (opcode) { |
| case 0x01: |
| { |
| // skip clipping rectangle |
| MacRect clipRect; |
| WORD len = Read16( io, handle ); |
| |
| if (len == 0x000a) { |
| /* null rgn */ |
| ReadRect( io, handle, &clipRect ); |
| } else { |
| io->seek_proc(handle, len - 2, SEEK_CUR); |
| } |
| break; |
| } |
| case 0x12: |
| case 0x13: |
| case 0x14: |
| { |
| // skip pattern definition |
| WORD patType; |
| WORD rowBytes; |
| MacpixMap p; |
| WORD numColors; |
| |
| patType = Read16( io, handle ); |
| |
| switch( patType ) { |
| case 2: |
| io->seek_proc(handle, 8, SEEK_CUR); |
| io->seek_proc(handle, 5, SEEK_CUR); |
| break; |
| case 1: |
| { |
| io->seek_proc(handle, 8, SEEK_CUR); |
| rowBytes = Read16( io, handle ); |
| ReadRect( io, handle, &p.Bounds ); |
| ReadPixmap( io, handle, &p); |
| |
| RGBQUAD ct[256]; |
| ReadColorTable(io, handle, &numColors, ct ); |
| SkipBits( io, handle, &p.Bounds, rowBytes, p.pixelSize ); |
| break; |
| } |
| default: |
| throw "Unknown pattern type."; |
| } |
| |
| break; |
| } |
| case 0x70: |
| case 0x71: |
| case 0x72: |
| case 0x73: |
| case 0x74: |
| case 0x75: |
| case 0x76: |
| case 0x77: |
| { |
| SkipPolyOrRegion( io, handle ); |
| break; |
| } |
| case 0x90: |
| case 0x98: |
| { |
| // Bitmap/pixmap data clipped by a rectangle. |
| rowBytes = Read16( io, handle ); // Bytes per row in source when uncompressed. |
| isRegion = FALSE; |
| |
| if ( rowBytes & 0x8000) { |
| pictType = pixmap; |
| } else { |
| pictType = bitmap; |
| } |
| done = TRUE; |
| break; |
| } |
| case 0x91: |
| case 0x99: |
| { |
| // Bitmap/pixmap data clipped by a region. |
| rowBytes = Read16( io, handle ); // Bytes per row in source when uncompressed. |
| isRegion = TRUE; |
| |
| if ( rowBytes & 0x8000) { |
| pictType = pixmap; |
| } else { |
| pictType = bitmap; |
| } |
| done = TRUE; |
| break; |
| } |
| case 0x9a: |
| { |
| // DirectBitsRect. |
| Read32( io, handle ); // Skip fake len and fake EOF. |
| Read16( io, handle ); // bogus row bytes. |
| |
| // Read in the PixMap fields. |
| ReadRect( io, handle, &pixMap.Bounds ); |
| ReadPixmap( io, handle, &pixMap ); |
| |
| // Ignore source & destination rectangle as well as transfer mode. |
| MacRect dummy; |
| ReadRect( io, handle, &dummy ); |
| ReadRect( io, handle, &dummy ); |
| WORD mode = Read16( io, handle ); |
| |
| pictType=op9a; |
| done = TRUE; |
| break; |
| } |
| case 0xa1: |
| { |
| // long comment |
| WORD type; |
| WORD len; |
| |
| type = Read16( io, handle ); |
| len = Read16( io, handle); |
| if (len > 0) { |
| io->seek_proc(handle, len, SEEK_CUR); |
| } |
| break; |
| } |
| default: |
| // No function => skip to next opcode |
| if (optable[opcode].len == WORD_LEN) { |
| WORD len = Read16( io, handle ); |
| io->seek_proc(handle, len, SEEK_CUR); |
| } else { |
| io->seek_proc(handle, optable[opcode].len, SEEK_CUR); |
| } |
| break; |
| } |
| } |
| else if (opcode == 0xc00) { |
| // version 2 header (26 bytes) |
| WORD minorVersion = Read16( io, handle ); // always FFFE (-2) for extended version 2 |
| Read16( io, handle ); // reserved |
| hRes = Read32( io, handle ); // original horizontal resolution in pixels/inch |
| vRes = Read32( io, handle ); // original horizontal resolution in pixels/inch |
| MacRect dummy; |
| ReadRect( io, handle, &dummy ); // frame bounds at original resolution |
| Read32( io, handle ); // reserved |
| } |
| else if (opcode == 0x8200) { |
| // jpeg |
| long opLen = Read32( io, handle ); |
| BOOL found = FALSE; |
| int i = 0; |
| |
| // skip to JPEG header. |
| while ( !found && i < opLen ) { |
| // io->seek_proc( handle, 24, SEEK_CUR ); |
| // MacRect dummy; |
| // ReadRect( io, handle, &dummy ); |
| // io->seek_proc( handle, 122, SEEK_CUR ); |
| // found = TRUE; |
| BYTE data[ 2 ]; |
| if( io->read_proc( data, 2, 1, handle ) ) { |
| io->seek_proc( handle, -2, SEEK_CUR ); |
| |
| if ( data[0] == 0xFF && data[1] == 0xD8 ) { |
| found = TRUE; |
| } else { |
| Read8( io, handle ); |
| i++; |
| } |
| } |
| } |
| |
| if ( found ) { |
| // Pass the data to the JPEG decoder. |
| pictType = jpeg; |
| } else { |
| throw "PICT file contains unrecognized quicktime data."; |
| } |
| done = TRUE; |
| } |
| else if (opcode >= 0xa2 && opcode <= 0xaf) { |
| // reserved |
| WORD len = Read16( io, handle ); |
| io->seek_proc(handle, len, SEEK_CUR); |
| } |
| else if ((opcode >= 0xb0 && opcode <= 0xcf) || (opcode >= 0x8000 && opcode <= 0x80ff)) { |
| // just a reserved opcode, no data |
| } |
| else if ((opcode >= 0xd0 && opcode <= 0xfe) || opcode >= 8100) { |
| // reserved |
| LONG len = Read32( io, handle ); |
| io->seek_proc(handle, len, SEEK_CUR); |
| } |
| else if (opcode >= 0x100 && opcode <= 0x7fff) { |
| // reserved |
| io->seek_proc(handle, ((opcode >> 7) & 255), SEEK_CUR); |
| } |
| else { |
| sprintf( outputMessage, "Can't handle opcode %x.\n", opcode ); |
| throw outputMessage; |
| } |
| |
| if(currentPos == io->tell_proc(handle)) { |
| // we probaly reached the end of file as we can no longer move forward ... |
| throw "Invalid PICT file"; |
| } |
| } |
| |
| switch ( pictType ) { |
| case op9a: |
| { |
| bounds = pixMap.Bounds; |
| int width = bounds.right - bounds.left; |
| int height = bounds.bottom - bounds.top; |
| |
| if ( pixMap.pixelSize > 8 ) { |
| dib = FreeImage_Allocate( width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); |
| } else { |
| dib = FreeImage_Allocate( width, height, 8); |
| } |
| hRes = pixMap.hRes << 16; |
| vRes = pixMap.vRes << 16; |
| break; |
| } |
| |
| case jpeg: |
| { |
| dib = FreeImage_LoadFromHandle( FIF_JPEG, io, handle ); |
| break; |
| } |
| |
| case pixmap: |
| { |
| // Decode version 2 pixmap |
| ReadRect( io, handle, &pixMap.Bounds ); |
| ReadPixmap( io, handle, &pixMap ); |
| |
| bounds = pixMap.Bounds; |
| int width = bounds.right - bounds.left; |
| int height = bounds.bottom - bounds.top; |
| |
| if ( pixMap.pixelSize > 8 ) { |
| dib = FreeImage_Allocate( width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); |
| } else { |
| dib = FreeImage_Allocate( width, height, 8); |
| } |
| hRes = pixMap.hRes << 16; |
| vRes = pixMap.vRes << 16; |
| break; |
| } |
| |
| case bitmap: |
| { |
| // Decode version 1 bitmap: 1 bpp. |
| MacRect srcRect; |
| MacRect dstRect; |
| WORD width; // Width in pixels |
| WORD height; // Height in pixels |
| |
| ReadRect( io, handle, &bounds ); |
| ReadRect( io, handle, &srcRect ); |
| ReadRect( io, handle, &dstRect ); |
| |
| width = bounds.right - bounds.left; |
| height = bounds.bottom - bounds.top; |
| |
| dib = FreeImage_Allocate(width, height, 8); |
| break; |
| } |
| } |
| |
| if ( dib ) { |
| // need to convert resolution figures from fixed point, pixels/inch |
| // to floating point, pixels/meter. |
| float hres_ppm = hRes * ((float)39.4 / (float)65536.0); |
| float vres_ppm = vRes * ((float)39.4 / (float)65536.0); |
| |
| FreeImage_SetDotsPerMeterX( dib, (LONG)hres_ppm ); |
| FreeImage_SetDotsPerMeterY( dib, (LONG)vres_ppm ); |
| |
| switch( pictType ) { |
| case op9a: |
| DecodeOp9a( io, handle, dib, &pixMap ); |
| break; |
| case jpeg: |
| // Already decoded if the embedded format was valid. |
| break; |
| case pixmap: |
| DecodePixmap( io, handle, dib, isRegion, &pixMap, rowBytes ); |
| break; |
| case bitmap: |
| DecodeBitmap( io, handle, dib, isRegion, &bounds, rowBytes ); |
| break; |
| default: |
| throw "invalid pict type"; |
| } |
| } |
| |
| return dib; |
| } |
| catch(const char *message) { |
| FreeImage_Unload( dib ); |
| FreeImage_OutputMessageProc(s_format_id, message); |
| } |
| |
| return NULL; |
| } |
| |
| // ========================================================== |
| // Init |
| // ========================================================== |
| |
| void DLL_CALLCONV |
| InitPICT(Plugin *plugin, int format_id) { |
| s_format_id = format_id; |
| |
| plugin->format_proc = Format; |
| plugin->description_proc = Description; |
| plugin->extension_proc = Extension; |
| plugin->regexpr_proc = NULL; |
| plugin->open_proc = NULL; |
| plugin->close_proc = NULL; |
| plugin->pagecount_proc = NULL; |
| plugin->pagecapability_proc = NULL; |
| plugin->load_proc = Load; |
| plugin->save_proc = NULL; |
| plugin->validate_proc = Validate; |
| plugin->mime_proc = MimeType; |
| plugin->supports_export_bpp_proc = SupportsExportDepth; |
| plugin->supports_export_type_proc = SupportsExportType; |
| plugin->supports_icc_profiles_proc = SupportsICCProfiles; |
| } |