diff options
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage/PluginPNM.cpp')
-rw-r--r-- | plugins/AdvaImg/src/FreeImage/PluginPNM.cpp | 831 |
1 files changed, 831 insertions, 0 deletions
diff --git a/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp b/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp new file mode 100644 index 0000000000..a30f858851 --- /dev/null +++ b/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp @@ -0,0 +1,831 @@ +// ========================================================== +// PNM (PPM, PGM, PBM) Loader and Writer +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@infonie.fr) +// +// 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" + +// ========================================================== +// Internal functions +// ========================================================== + +/** +Get an integer value from the actual position pointed by handle +*/ +static int +GetInt(FreeImageIO *io, fi_handle handle) { + char c = 0; + BOOL firstchar; + + // skip forward to start of next number + + if (!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + + while (1) { + // eat comments + + if (c == '#') { + // if we're at a comment, read to end of line + + firstchar = TRUE; + + while (1) { + if (!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + + if (firstchar && c == ' ') { + // loop off 1 sp after # + + firstchar = FALSE; + } else if (c == '\n') { + break; + } + } + } + + if (c >= '0' && c <='9') { + // we've found what we were looking for + + break; + } + + if (!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + } + + // we're at the start of a number, continue until we hit a non-number + + int i = 0; + + while (1) { + i = (i * 10) + (c - '0'); + + if (!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + + if (c < '0' || c > '9') + break; + } + + return i; +} + +/** +Read a WORD value taking into account the endianess issue +*/ +static inline WORD +ReadWord(FreeImageIO *io, fi_handle handle) { + WORD level = 0; + io->read_proc(&level, 2, 1, handle); +#ifndef FREEIMAGE_BIGENDIAN + SwapShort(&level); // PNM uses the big endian convention +#endif + return level; +} + +/** +Write a WORD value taking into account the endianess issue +*/ +static inline void +WriteWord(FreeImageIO *io, fi_handle handle, const WORD value) { + WORD level = value; +#ifndef FREEIMAGE_BIGENDIAN + SwapShort(&level); // PNM uses the big endian convention +#endif + io->write_proc(&level, 2, 1, handle); +} + + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "PNM"; +} + +static const char * DLL_CALLCONV +Description() { + return "Portable Network Media"; +} + +static const char * DLL_CALLCONV +Extension() { + return "pbm,pgm,ppm"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +static const char * DLL_CALLCONV +MimeType() { + return "image/freeimage-pnm"; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO *io, fi_handle handle) { + BYTE pbm_id1[] = { 0x50, 0x31 }; + BYTE pbm_id2[] = { 0x50, 0x34 }; + BYTE pgm_id1[] = { 0x50, 0x32 }; + BYTE pgm_id2[] = { 0x50, 0x35 }; + BYTE ppm_id1[] = { 0x50, 0x33 }; + BYTE ppm_id2[] = { 0x50, 0x36 }; + BYTE signature[2] = { 0, 0 }; + + io->read_proc(signature, 1, sizeof(pbm_id1), handle); + + if (memcmp(pbm_id1, signature, sizeof(pbm_id1)) == 0) + return TRUE; + + if (memcmp(pbm_id2, signature, sizeof(pbm_id2)) == 0) + return TRUE; + + if (memcmp(pgm_id1, signature, sizeof(pgm_id1)) == 0) + return TRUE; + + if (memcmp(pgm_id2, signature, sizeof(pgm_id2)) == 0) + return TRUE; + + if (memcmp(ppm_id1, signature, sizeof(ppm_id1)) == 0) + return TRUE; + + if (memcmp(ppm_id2, signature, sizeof(ppm_id2)) == 0) + return TRUE; + + return FALSE; +} + +static BOOL DLL_CALLCONV +SupportsExportDepth(int depth) { + return ( + (depth == 1) || + (depth == 8) || + (depth == 24) + ); +} + +static BOOL DLL_CALLCONV +SupportsExportType(FREE_IMAGE_TYPE type) { + return ( + (type == FIT_BITMAP) || + (type == FIT_UINT16) || + (type == FIT_RGB16) + ); +} + +static BOOL DLL_CALLCONV +SupportsNoPixels() { + return TRUE; +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { + char id_one = 0, id_two = 0; + int x, y; + FIBITMAP *dib = NULL; + RGBQUAD *pal; // pointer to dib palette + int i; + + if (!handle) { + return NULL; + } + + BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; + + try { + FREE_IMAGE_TYPE image_type = FIT_BITMAP; // standard image: 1-, 8-, 24-bit + + // Read the first two bytes of the file to determine the file format + // "P1" = ascii bitmap, "P2" = ascii greymap, "P3" = ascii pixmap, + // "P4" = raw bitmap, "P5" = raw greymap, "P6" = raw pixmap + + io->read_proc(&id_one, 1, 1, handle); + io->read_proc(&id_two, 1, 1, handle); + + if ((id_one != 'P') || (id_two < '1') || (id_two > '6')) { + // signature error + throw FI_MSG_ERROR_MAGIC_NUMBER; + } + + // Read the header information: width, height and the 'max' value if any + + int width = GetInt(io, handle); + int height = GetInt(io, handle); + int maxval = 1; + + if ((id_two == '2') || (id_two == '5') || (id_two == '3') || (id_two == '6')) { + maxval = GetInt(io, handle); + if ((maxval <= 0) || (maxval > 65535)) { + FreeImage_OutputMessageProc(s_format_id, "Invalid max value : %d", maxval); + throw (const char*)NULL; + } + } + + // Create a new DIB + + switch (id_two) { + case '1': + case '4': + // 1-bit + dib = FreeImage_AllocateHeader(header_only, width, height, 1); + break; + + case '2': + case '5': + if(maxval > 255) { + // 16-bit greyscale + image_type = FIT_UINT16; + dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height); + } else { + // 8-bit greyscale + dib = FreeImage_AllocateHeader(header_only, width, height, 8); + } + break; + + case '3': + case '6': + if(maxval > 255) { + // 48-bit RGB + image_type = FIT_RGB16; + dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height); + } else { + // 24-bit RGB + dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); + } + break; + } + + if (dib == NULL) { + throw FI_MSG_ERROR_DIB_MEMORY; + } + + // Build a greyscale palette if needed + + if(image_type == FIT_BITMAP) { + switch(id_two) { + case '1': + case '4': + pal = FreeImage_GetPalette(dib); + pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0; + pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; + break; + + case '2': + case '5': + pal = FreeImage_GetPalette(dib); + for (i = 0; i < 256; i++) { + pal[i].rgbRed = + pal[i].rgbGreen = + pal[i].rgbBlue = (BYTE)i; + } + break; + + default: + break; + } + } + + if(header_only) { + // header only mode + return dib; + } + + // Read the image... + + switch(id_two) { + case '1': + case '4': + // write the bitmap data + + if (id_two == '1') { // ASCII bitmap + for (y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + if (GetInt(io, handle) == 0) + bits[x >> 3] |= (0x80 >> (x & 0x7)); + else + bits[x >> 3] &= (0xFF7F >> (x & 0x7)); + } + } + } else { // Raw bitmap + int line = CalculateLine(width, 1); + + for (y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < line; x++) { + io->read_proc(&bits[x], 1, 1, handle); + + bits[x] = ~bits[x]; + } + } + } + + return dib; + + case '2': + case '5': + if(image_type == FIT_BITMAP) { + // write the bitmap data + + if(id_two == '2') { // ASCII greymap + int level = 0; + + for (y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + level = GetInt(io, handle); + bits[x] = (BYTE)((255 * level) / maxval); + } + } + } else { // Raw greymap + BYTE level = 0; + + for (y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + io->read_proc(&level, 1, 1, handle); + bits[x] = (BYTE)((255 * (int)level) / maxval); + } + } + } + } + else if(image_type == FIT_UINT16) { + // write the bitmap data + + if(id_two == '2') { // ASCII greymap + int level = 0; + + for (y = 0; y < height; y++) { + WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + level = GetInt(io, handle); + bits[x] = (WORD)((65535 * (double)level) / maxval); + } + } + } else { // Raw greymap + WORD level = 0; + + for (y = 0; y < height; y++) { + WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + level = ReadWord(io, handle); + bits[x] = (WORD)((65535 * (double)level) / maxval); + } + } + } + } + + return dib; + + case '3': + case '6': + if(image_type == FIT_BITMAP) { + // write the bitmap data + + if (id_two == '3') { // ASCII pixmap + int level = 0; + + for (y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + level = GetInt(io, handle); + bits[FI_RGBA_RED] = (BYTE)((255 * level) / maxval); // R + level = GetInt(io, handle); + bits[FI_RGBA_GREEN] = (BYTE)((255 * level) / maxval); // G + level = GetInt(io, handle); + bits[FI_RGBA_BLUE] = (BYTE)((255 * level) / maxval); // B + + bits += 3; + } + } + } else { // Raw pixmap + BYTE level = 0; + + for (y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + io->read_proc(&level, 1, 1, handle); + bits[FI_RGBA_RED] = (BYTE)((255 * (int)level) / maxval); // R + + io->read_proc(&level, 1, 1, handle); + bits[FI_RGBA_GREEN] = (BYTE)((255 * (int)level) / maxval); // G + + io->read_proc(&level, 1, 1, handle); + bits[FI_RGBA_BLUE] = (BYTE)((255 * (int)level) / maxval); // B + + bits += 3; + } + } + } + } + else if(image_type == FIT_RGB16) { + // write the bitmap data + + if (id_two == '3') { // ASCII pixmap + int level = 0; + + for (y = 0; y < height; y++) { + FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + level = GetInt(io, handle); + bits[x].red = (WORD)((65535 * (double)level) / maxval); // R + level = GetInt(io, handle); + bits[x].green = (WORD)((65535 * (double)level) / maxval); // G + level = GetInt(io, handle); + bits[x].blue = (WORD)((65535 * (double)level) / maxval); // B + } + } + } else { // Raw pixmap + WORD level = 0; + + for (y = 0; y < height; y++) { + FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + level = ReadWord(io, handle); + bits[x].red = (WORD)((65535 * (double)level) / maxval); // R + level = ReadWord(io, handle); + bits[x].green = (WORD)((65535 * (double)level) / maxval); // G + level = ReadWord(io, handle); + bits[x].blue = (WORD)((65535 * (double)level) / maxval); // B + } + } + } + } + + return dib; + } + + } catch (const char *text) { + if(dib) FreeImage_Unload(dib); + + if(NULL != text) { + switch(id_two) { + case '1': + case '4': + FreeImage_OutputMessageProc(s_format_id, text); + break; + + case '2': + case '5': + FreeImage_OutputMessageProc(s_format_id, text); + break; + + case '3': + case '6': + FreeImage_OutputMessageProc(s_format_id, text); + break; + } + } + } + + return NULL; +} + +static BOOL DLL_CALLCONV +Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { + // ---------------------------------------------------------- + // PNM Saving + // ---------------------------------------------------------- + // + // Output format : + // + // Bit depth flags file format + // ------------- -------------- ----------- + // 1-bit / pixel PNM_SAVE_ASCII PBM (P1) + // 1-bit / pixel PNM_SAVE_RAW PBM (P4) + // 8-bit / pixel PNM_SAVE_ASCII PGM (P2) + // 8-bit / pixel PNM_SAVE_RAW PGM (P5) + // 24-bit / pixel PNM_SAVE_ASCII PPM (P3) + // 24-bit / pixel PNM_SAVE_RAW PPM (P6) + // ---------------------------------------------------------- + + int x, y; + + char buffer[256]; // temporary buffer whose size should be enough for what we need + + if (!dib || !handle) return FALSE; + + FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); + + int bpp = FreeImage_GetBPP(dib); + int width = FreeImage_GetWidth(dib); + int height = FreeImage_GetHeight(dib); + + // Find the appropriate magic number for this file type + + int magic = 0; + int maxval = 255; + + switch(image_type) { + case FIT_BITMAP: + switch (bpp) { + case 1 : + magic = 1; // PBM file (B & W) + break; + case 8 : + magic = 2; // PGM file (Greyscale) + break; + + case 24 : + magic = 3; // PPM file (RGB) + break; + + default: + return FALSE; // Invalid bit depth + } + break; + + case FIT_UINT16: + magic = 2; // PGM file (Greyscale) + maxval = 65535; + break; + + case FIT_RGB16: + magic = 3; // PPM file (RGB) + maxval = 65535; + break; + + default: + return FALSE; + } + + + if (flags == PNM_SAVE_RAW) + magic += 3; + + // Write the header info + + sprintf(buffer, "P%d\n%d %d\n", magic, width, height); + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + + if (bpp != 1) { + sprintf(buffer, "%d\n", maxval); + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + } + + // Write the image data + /////////////////////// + + if(image_type == FIT_BITMAP) { + switch(bpp) { + case 24 : // 24-bit RGB, 3 bytes per pixel + { + if (flags == PNM_SAVE_RAW) { + for (y = 0; y < height; y++) { + // write the scanline to disc + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + io->write_proc(&bits[FI_RGBA_RED], 1, 1, handle); // R + io->write_proc(&bits[FI_RGBA_GREEN], 1, 1, handle); // G + io->write_proc(&bits[FI_RGBA_BLUE], 1, 1, handle); // B + + bits += 3; + } + } + } else { + int length = 0; + + for (y = 0; y < height; y++) { + // write the scanline to disc + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + sprintf(buffer, "%3d %3d %3d ", bits[FI_RGBA_RED], bits[FI_RGBA_GREEN], bits[FI_RGBA_BLUE]); + + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + + length += 12; + + if(length > 58) { + // No line should be longer than 70 characters + sprintf(buffer, "\n"); + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + length = 0; + } + + bits += 3; + } + } + + } + } + break; + + case 8: // 8-bit greyscale + { + if (flags == PNM_SAVE_RAW) { + for (y = 0; y < height; y++) { + // write the scanline to disc + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + io->write_proc(&bits[x], 1, 1, handle); + } + } + } else { + int length = 0; + + for (y = 0; y < height; y++) { + // write the scanline to disc + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + sprintf(buffer, "%3d ", bits[x]); + + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + + length += 4; + + if (length > 66) { + // No line should be longer than 70 characters + sprintf(buffer, "\n"); + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + length = 0; + } + } + } + } + } + break; + + case 1: // 1-bit B & W + { + int color; + + if (flags == PNM_SAVE_RAW) { + for(y = 0; y < height; y++) { + // write the scanline to disc + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for(x = 0; x < (int)FreeImage_GetLine(dib); x++) + io->write_proc(&bits[x], 1, 1, handle); + } + } else { + int length = 0; + + for (y = 0; y < height; y++) { + // write the scanline to disc + BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < (int)FreeImage_GetLine(dib) * 8; x++) { + color = (bits[x>>3] & (0x80 >> (x & 0x07))) != 0; + + sprintf(buffer, "%c ", color ? '1':'0'); + + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + + length += 2; + + if (length > 68) { + // No line should be longer than 70 characters + sprintf(buffer, "\n"); + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + length = 0; + } + } + } + } + } + + break; + } + } // if(FIT_BITMAP) + + else if(image_type == FIT_UINT16) { // 16-bit greyscale + if (flags == PNM_SAVE_RAW) { + for (y = 0; y < height; y++) { + // write the scanline to disc + WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + WriteWord(io, handle, bits[x]); + } + } + } else { + int length = 0; + + for (y = 0; y < height; y++) { + // write the scanline to disc + WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + sprintf(buffer, "%5d ", bits[x]); + + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + + length += 6; + + if (length > 64) { + // No line should be longer than 70 characters + sprintf(buffer, "\n"); + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + length = 0; + } + } + } + } + } + + else if(image_type == FIT_RGB16) { // 48-bit RGB + if (flags == PNM_SAVE_RAW) { + for (y = 0; y < height; y++) { + // write the scanline to disc + FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + WriteWord(io, handle, bits[x].red); // R + WriteWord(io, handle, bits[x].green); // G + WriteWord(io, handle, bits[x].blue); // B + } + } + } else { + int length = 0; + + for (y = 0; y < height; y++) { + // write the scanline to disc + FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y); + + for (x = 0; x < width; x++) { + sprintf(buffer, "%5d %5d %5d ", bits[x].red, bits[x].green, bits[x].blue); + + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + + length += 18; + + if(length > 52) { + // No line should be longer than 70 characters + sprintf(buffer, "\n"); + io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); + length = 0; + } + } + } + + } + } + + return TRUE; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitPNM(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 = Save; + 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; +} |