| // ========================================================== |
| // CUT Loader |
| // |
| // Design and implementation by |
| // - Floris van den Berg (flvdberg@wxs.nl) |
| // |
| // 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" |
| |
| // ---------------------------------------------------------- |
| // Constants + headers |
| // ---------------------------------------------------------- |
| |
| #ifdef _WIN32 |
| #pragma pack(push, 1) |
| #else |
| #pragma pack(1) |
| #endif |
| |
| typedef struct tagCUTHEADER { |
| WORD width; |
| WORD height; |
| LONG dummy; |
| } CUTHEADER; |
| |
| #ifdef _WIN32 |
| #pragma pack(pop) |
| #else |
| #pragma pack() |
| #endif |
| |
| // ========================================================== |
| // Plugin Interface |
| // ========================================================== |
| |
| static int s_format_id; |
| |
| // ========================================================== |
| // Plugin Implementation |
| // ========================================================== |
| |
| static const char * DLL_CALLCONV |
| Format() { |
| return "CUT"; |
| } |
| |
| static const char * DLL_CALLCONV |
| Description() { |
| return "Dr. Halo"; |
| } |
| |
| static const char * DLL_CALLCONV |
| Extension() { |
| return "cut"; |
| } |
| |
| static const char * DLL_CALLCONV |
| RegExpr() { |
| return NULL; |
| } |
| |
| static const char * DLL_CALLCONV |
| MimeType() { |
| return "image/x-cut"; |
| } |
| |
| static BOOL DLL_CALLCONV |
| Validate(FreeImageIO *io, fi_handle handle) { |
| 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 |
| SupportsNoPixels() { |
| return TRUE; |
| } |
| |
| // ---------------------------------------------------------- |
| |
| static FIBITMAP * DLL_CALLCONV |
| Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { |
| FIBITMAP *dib = NULL; |
| |
| if(!handle) { |
| return NULL; |
| } |
| |
| try { |
| CUTHEADER header; |
| |
| BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; |
| |
| // read the cut header |
| |
| if(io->read_proc(&header, 1, sizeof(CUTHEADER), handle) != sizeof(CUTHEADER)) { |
| throw FI_MSG_ERROR_PARSING; |
| } |
| |
| #ifdef FREEIMAGE_BIGENDIAN |
| SwapShort((WORD *)&header.width); |
| SwapShort((WORD *)&header.height); |
| #endif |
| |
| if ((header.width == 0) || (header.height == 0)) { |
| return NULL; |
| } |
| |
| // allocate a new bitmap |
| |
| dib = FreeImage_AllocateHeader(header_only, header.width, header.height, 8); |
| |
| if (dib == NULL) { |
| throw FI_MSG_ERROR_DIB_MEMORY; |
| } |
| |
| // stuff it with a palette |
| |
| RGBQUAD *palette = FreeImage_GetPalette(dib); |
| |
| for (int j = 0; j < 256; ++j) { |
| palette[j].rgbBlue = palette[j].rgbGreen = palette[j].rgbRed = (BYTE)j; |
| } |
| |
| if(header_only) { |
| // header only mode |
| return dib; |
| } |
| |
| // unpack the RLE bitmap bits |
| |
| BYTE *bits = FreeImage_GetScanLine(dib, header.height - 1); |
| |
| unsigned i = 0, k = 0; |
| unsigned pitch = FreeImage_GetPitch(dib); |
| unsigned size = header.width * header.height; |
| BYTE count = 0, run = 0; |
| |
| while (i < size) { |
| if(io->read_proc(&count, 1, sizeof(BYTE), handle) != 1) { |
| throw FI_MSG_ERROR_PARSING; |
| } |
| |
| if (count == 0) { |
| k = 0; |
| bits -= pitch; |
| |
| // paint shop pro adds two useless bytes here... |
| |
| io->read_proc(&count, 1, sizeof(BYTE), handle); |
| io->read_proc(&count, 1, sizeof(BYTE), handle); |
| |
| continue; |
| } |
| |
| if (count & 0x80) { |
| count &= ~(0x80); |
| |
| if(io->read_proc(&run, 1, sizeof(BYTE), handle) != 1) { |
| throw FI_MSG_ERROR_PARSING; |
| } |
| |
| if(k + count <= header.width) { |
| memset(bits + k, run, count); |
| } else { |
| throw FI_MSG_ERROR_PARSING; |
| } |
| } else { |
| if(k + count <= header.width) { |
| if(io->read_proc(&bits[k], count, sizeof(BYTE), handle) != 1) { |
| throw FI_MSG_ERROR_PARSING; |
| } |
| } else { |
| throw FI_MSG_ERROR_PARSING; |
| } |
| } |
| |
| k += count; |
| i += count; |
| } |
| |
| return dib; |
| |
| } catch(const char* text) { |
| if(dib) { |
| FreeImage_Unload(dib); |
| } |
| FreeImage_OutputMessageProc(s_format_id, text); |
| return NULL; |
| } |
| } |
| |
| // ========================================================== |
| // Init |
| // ========================================================== |
| |
| void DLL_CALLCONV |
| InitCUT(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 = RegExpr; |
| 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 = NULL; |
| plugin->supports_no_pixels_proc = SupportsNoPixels; |
| } |