/src/FreeImage/Source/FreeImage/PluginPNM.cpp
https://bitbucket.org/cabalistic/ogredeps/ · C++ · 831 lines · 558 code · 171 blank · 102 comment · 175 complexity · 7b0175fe43a3cbb02f30f193bf1a6a05 MD5 · raw file
- // ==========================================================
- // 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;
- }