Ejemplo n.º 1
0
FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
	if(handle == NULL) 
		return NULL;
	
	bool header_only = (_fi_flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
	
	WORD nCompression = 0;
	io->read_proc(&nCompression, sizeof(nCompression), 1, handle);
	
#ifndef FREEIMAGE_BIGENDIAN
	SwapShort(&nCompression);
#endif
	
	if((nCompression != PSDP_COMPRESSION_NONE && nCompression != PSDP_COMPRESSION_RLE))	{
		FreeImage_OutputMessageProc(_fi_format_id, "Unsupported compression %d", nCompression);
		return NULL;
	}
	
	const unsigned nWidth = _headerInfo._Width;
	const unsigned nHeight = _headerInfo._Height;
	const unsigned nChannels = _headerInfo._Channels;
	const unsigned depth = _headerInfo._BitsPerChannel;
	const unsigned bytes = (depth == 1) ? 1 : depth / 8;
		
	// channel(plane) line (BYTE aligned)
	const unsigned lineSize = (_headerInfo._BitsPerChannel == 1) ? (nWidth + 7) / 8 : nWidth * bytes;
	
	if(nCompression == PSDP_COMPRESSION_RLE && depth > 16) {
		FreeImage_OutputMessageProc(_fi_format_id, "Unsupported RLE with depth %d", depth);
		return NULL;
	}
	
	// build output buffer
	
	FIBITMAP* bitmap = NULL;
	unsigned dstCh = 0;
	
	short mode = _headerInfo._ColourMode;
	
	if(mode == PSDP_MULTICHANNEL && nChannels < 3) {
		// CM 
		mode = PSDP_GRAYSCALE; // C as gray, M as extra channel
	}
		
	bool needPalette = false;
	switch (mode) {
		case PSDP_BITMAP:
		case PSDP_DUOTONE:	
		case PSDP_INDEXED:
		case PSDP_GRAYSCALE:
			dstCh = 1;
			switch(depth) {
				case 16:
				bitmap = FreeImage_AllocateHeaderT(header_only, FIT_UINT16, nWidth, nHeight, depth*dstCh);
				break;
				case 32:
				bitmap = FreeImage_AllocateHeaderT(header_only, FIT_FLOAT, nWidth, nHeight, depth*dstCh);
				break;
				default: // 1-, 8-
				needPalette = true;
				bitmap = FreeImage_AllocateHeader(header_only, nWidth, nHeight, depth*dstCh);
				break;
			}
			break;
		case PSDP_RGB:	
		case PSDP_LAB:		
		case PSDP_CMYK	:
		case PSDP_MULTICHANNEL	:
			// force PSDP_MULTICHANNEL CMY as CMYK
			dstCh = (mode == PSDP_MULTICHANNEL && !header_only) ? 4 : MIN<unsigned>(nChannels, 4);
			if(dstCh < 3) {
				throw "Invalid number of channels";
			}

			switch(depth) {
				case 16:
				bitmap = FreeImage_AllocateHeaderT(header_only, dstCh < 4 ? FIT_RGB16 : FIT_RGBA16, nWidth, nHeight, depth*dstCh);
				break;
				case 32:
				bitmap = FreeImage_AllocateHeaderT(header_only, dstCh < 4 ? FIT_RGBF : FIT_RGBAF, nWidth, nHeight, depth*dstCh);
				break;
				default:
				bitmap = FreeImage_AllocateHeader(header_only, nWidth, nHeight, depth*dstCh);
				break;
			}
			break;
		default:
			throw "Unsupported color mode";
			break;
	}
	if(!bitmap) {
		throw FI_MSG_ERROR_DIB_MEMORY;
	}

	// write thumbnail
	FreeImage_SetThumbnail(bitmap, _thumbnail.getDib());
		
	// @todo Add some metadata model
		
	if(header_only) {
		return bitmap;
	}
	
	// Load pixels data

	const unsigned dstChannels = dstCh;
	
	const unsigned dstBpp =  (depth == 1) ? 1 : FreeImage_GetBPP(bitmap)/8;
	const unsigned dstLineSize = FreeImage_GetPitch(bitmap);	
	BYTE* const dst_first_line = FreeImage_GetScanLine(bitmap, nHeight - 1);//<*** flipped
	
	BYTE* line_start = new BYTE[lineSize]; //< fileline cache

	switch ( nCompression ) {
		case PSDP_COMPRESSION_NONE: // raw data	
		{			
			for(unsigned c = 0; c < nChannels; c++) {
				if(c >= dstChannels) {
					// @todo write extra channels
					break; 
				}
					
				const unsigned channelOffset = c * bytes;
				
				BYTE* dst_line_start = dst_first_line;
				for(unsigned h = 0; h < nHeight; ++h, dst_line_start -= dstLineSize) {//<*** flipped

					io->read_proc(line_start, lineSize, 1, handle);
					
					for (BYTE *line = line_start, *dst_line = dst_line_start; line < line_start + lineSize; 
						line += bytes, dst_line += dstBpp) {
#ifdef FREEIMAGE_BIGENDIAN
							memcpy(dst_line + channelOffset, line, bytes);
#else
						// reverse copy bytes
						for (unsigned b = 0; b < bytes; ++b) {
							dst_line[channelOffset + b] = line[(bytes-1) - b];
						}
#endif // FREEIMAGE_BIGENDIAN
					}
				} //< h
			}//< ch
			
			SAFE_DELETE_ARRAY(line_start);
					
		}
		break;
		
		case PSDP_COMPRESSION_RLE: // RLE compression	
		{			
									
			// The RLE-compressed data is preceeded by a 2-byte line size for each row in the data,
			// store an array of these

			// later use this array as WORD rleLineSizeList[nChannels][nHeight];
			WORD *rleLineSizeList = new (std::nothrow) WORD[nChannels*nHeight];

			if(!rleLineSizeList) {
				FreeImage_Unload(bitmap);
				SAFE_DELETE_ARRAY(line_start);
				throw std::bad_alloc();
			}	
			
			io->read_proc(rleLineSizeList, 2, nChannels * nHeight, handle);
			
			WORD largestRLELine = 0;
			for(unsigned ch = 0; ch < nChannels; ++ch) {
				for(unsigned h = 0; h < nHeight; ++h) {
					const unsigned index = ch * nHeight + h;

#ifndef FREEIMAGE_BIGENDIAN 
					SwapShort(&rleLineSizeList[index]);
#endif
					if(largestRLELine < rleLineSizeList[index]) {
						largestRLELine = rleLineSizeList[index];
					}
				}
			}

			BYTE* rle_line_start = new (std::nothrow) BYTE[largestRLELine];
			if(!rle_line_start) {
				FreeImage_Unload(bitmap);
				SAFE_DELETE_ARRAY(line_start);
				SAFE_DELETE_ARRAY(rleLineSizeList);
				throw std::bad_alloc();
			}
			
			// Read the RLE data (assume 8-bit)
			
			const BYTE* const line_end = line_start + lineSize;

			for (unsigned ch = 0; ch < nChannels; ch++) {
				const unsigned channelOffset = ch * bytes;
				
				BYTE* dst_line_start = dst_first_line;
				for(unsigned h = 0; h < nHeight; ++h, dst_line_start -= dstLineSize) {//<*** flipped
					const unsigned index = ch * nHeight + h;
					
					// - read and uncompress line -
					
					const WORD rleLineSize = rleLineSizeList[index];
					
					io->read_proc(rle_line_start, rleLineSize, 1, handle);
					
					for (BYTE* rle_line = rle_line_start, *line = line_start; 
						rle_line < rle_line_start + rleLineSize, line < line_end;) {

						int len = *rle_line++;
						
						// NOTE len is signed byte in PackBits RLE
						
						if ( len < 128 ) { //<- MSB is not set
							// uncompressed packet
							
							// (len + 1) bytes of data are copied
							
							++len;
							
							// assert we don't write beyound eol
							memcpy(line, rle_line, line + len > line_end ? line_end - line : len);
							line += len;
							rle_line += len;
						}
						else if ( len > 128 ) { //< MSB is set
						
							// RLE compressed packet
							
							// One byte of data is repeated (–len + 1) times
							
							len ^= 0xFF; // same as (-len + 1) & 0xFF 
							len += 2;    //

							// assert we don't write beyound eol
							memset(line, *rle_line++, line + len > line_end ? line_end - line : len);							
							line += len;

						}
						else if ( 128 == len ) {
							// Do nothing
						}
					}//< rle_line
					
					// - write line to destination -
					
					if(ch >= dstChannels) {
						// @todo write to extra channels
						break; 
					}
						
					// byte by byte copy a single channel to pixel
					for (BYTE *line = line_start, *dst_line = dst_line_start; line < line_start + lineSize; 
						line += bytes, dst_line += dstBpp) {

#ifdef FREEIMAGE_BIGENDIAN
							memcpy(dst_line + channelOffset, line, bytes);
#else
							// reverse copy bytes
							for (unsigned b = 0; b < bytes; ++b) {
								dst_line[channelOffset + b] = line[(bytes-1) - b];							
							}
#endif // FREEIMAGE_BIGENDIAN
					}	
				}//< h
			}//< ch
			
			SAFE_DELETE_ARRAY(line_start);
			SAFE_DELETE_ARRAY(rleLineSizeList);
			SAFE_DELETE_ARRAY(rle_line_start);
		}
		break;
		
		case 2: // ZIP without prediction, no specification
			break;
			
		case 3: // ZIP with prediction, no specification
			break;
			
		default: // Unknown format
			break;
		
	}
	
	// --- Further process the bitmap ---
	
	if((mode == PSDP_CMYK || mode == PSDP_MULTICHANNEL)) {	
		// CMYK values are "inverted", invert them back		

		if(mode == PSDP_MULTICHANNEL) {
			invertColor(bitmap);
		} else {
			FreeImage_Invert(bitmap);
		}

		if((_fi_flags & PSD_CMYK) == PSD_CMYK) {
			// keep as CMYK

			if(mode == PSDP_MULTICHANNEL) {
				//### we force CMY to be CMYK, but CMY has no ICC. 
				// Create empty profile and add the flag.
				FreeImage_CreateICCProfile(bitmap, NULL, 0);
				FreeImage_GetICCProfile(bitmap)->flags |= FIICC_COLOR_IS_CMYK;
			}
		}
		else { 
			// convert to RGB
			
			ConvertCMYKtoRGBA(bitmap);
			
			// The ICC Profile is no longer valid
			_iccProfile.clear();
			
			// remove the pending A if not present in source 
			if(nChannels == 4 || nChannels == 3 ) {
				FIBITMAP* t = RemoveAlphaChannel(bitmap);
				if(t) {
					FreeImage_Unload(bitmap);
					bitmap = t;
				} // else: silently fail
			}
		}
	}
	else if ( mode == PSDP_LAB && !((_fi_flags & PSD_LAB) == PSD_LAB)) {
		ConvertLABtoRGB(bitmap);
	}
	else {
		if (needPalette && FreeImage_GetPalette(bitmap)) {
			
			if(mode == PSDP_BITMAP) {
				CREATE_GREYSCALE_PALETTE_REVERSE(FreeImage_GetPalette(bitmap), 2);
			}
			else if(mode == PSDP_INDEXED) {
				if(!_colourModeData._plColourData || _colourModeData._Length != 768 || _ColourCount < 0) {
					FreeImage_OutputMessageProc(_fi_format_id, "Indexed image has no palette. Using the default grayscale one.");
				} else {
					_colourModeData.FillPalette(bitmap);
				}
			}
			// GRAYSCALE, DUOTONE - use default grayscale palette
		}
		
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
		if(FreeImage_GetImageType(bitmap) == FIT_BITMAP) {
			SwapRedBlue32(bitmap);
		}
#endif
	}
	
	return bitmap;
} 
Ejemplo n.º 2
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
    FIBITMAP *dib = NULL;
    BYTE *bits;           // Pointer to dib data
    RGBQUAD *pal;         // Pointer to dib palette
    BYTE *line = NULL;    // PCX raster line
    BYTE *ReadBuf = NULL; // buffer;
    BOOL bIsRLE;          // True if the file is run-length encoded

    if(!handle) {
        return NULL;
    }

    BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

    try {
        // check PCX identifier

        long start_pos = io->tell_proc(handle);
        BOOL validated = pcx_validate(io, handle);
        io->seek_proc(handle, start_pos, SEEK_SET);
        if(!validated) {
            throw FI_MSG_ERROR_MAGIC_NUMBER;
        }

        // process the header

        PCXHEADER header;

        if(io->read_proc(&header, sizeof(PCXHEADER), 1, handle) != 1) {
            throw FI_MSG_ERROR_PARSING;
        }
#ifdef FREEIMAGE_BIGENDIAN
        SwapHeader(&header);
#endif

        // allocate a new DIB

        unsigned width = header.window[2] - header.window[0] + 1;
        unsigned height = header.window[3] - header.window[1] + 1;
        unsigned bitcount = header.bpp * header.planes;

        if (bitcount == 24) {
            dib = FreeImage_AllocateHeader(header_only, width, height, bitcount, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
        } else {
            dib = FreeImage_AllocateHeader(header_only, width, height, bitcount);
        }

        // if the dib couldn't be allocated, throw an error

        if (!dib) {
            throw FI_MSG_ERROR_DIB_MEMORY;
        }

        // metrics handling code

        FreeImage_SetDotsPerMeterX(dib, (unsigned) (((float)header.hdpi) / 0.0254000 + 0.5));
        FreeImage_SetDotsPerMeterY(dib, (unsigned) (((float)header.vdpi) / 0.0254000 + 0.5));

        // Set up the palette if needed
        // ----------------------------

        switch(bitcount) {
        case 1:
        {
            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 4:
        {
            pal = FreeImage_GetPalette(dib);

            BYTE *pColormap = &header.color_map[0];

            for (int i = 0; i < 16; i++) {
                pal[i].rgbRed   = pColormap[0];
                pal[i].rgbGreen = pColormap[1];
                pal[i].rgbBlue  = pColormap[2];
                pColormap += 3;
            }

            break;
        }

        case 8:
        {
            BYTE palette_id;

            io->seek_proc(handle, -769L, SEEK_END);
            io->read_proc(&palette_id, 1, 1, handle);

            if (palette_id == 0x0C) {
                BYTE *cmap = (BYTE*)malloc(768 * sizeof(BYTE));
                io->read_proc(cmap, 768, 1, handle);

                pal = FreeImage_GetPalette(dib);
                BYTE *pColormap = &cmap[0];

                for(int i = 0; i < 256; i++) {
                    pal[i].rgbRed   = pColormap[0];
                    pal[i].rgbGreen = pColormap[1];
                    pal[i].rgbBlue  = pColormap[2];
                    pColormap += 3;
                }

                free(cmap);
            }

            // wrong palette ID, perhaps a gray scale is needed ?

            else if (header.palette_info == 2) {
                pal = FreeImage_GetPalette(dib);

                for(int i = 0; i < 256; i++) {
                    pal[i].rgbRed   = (BYTE)i;
                    pal[i].rgbGreen = (BYTE)i;
                    pal[i].rgbBlue  = (BYTE)i;
                }
            }

            io->seek_proc(handle, (long)sizeof(PCXHEADER), SEEK_SET);
        }
        break;
        }

        if(header_only) {
            // header only mode
            return dib;
        }

        // calculate the line length for the PCX and the DIB

        // length of raster line in bytes
        unsigned linelength = header.bytes_per_line * header.planes;
        // length of DIB line (rounded to DWORD) in bytes
        unsigned pitch = FreeImage_GetPitch(dib);

        // run-length encoding ?

        bIsRLE = (header.encoding == 1) ? TRUE : FALSE;

        // load image data
        // ---------------

        line = (BYTE*)malloc(linelength * sizeof(BYTE));
        if(!line) throw FI_MSG_ERROR_MEMORY;

        ReadBuf = (BYTE*)malloc(IO_BUF_SIZE * sizeof(BYTE));
        if(!ReadBuf) throw FI_MSG_ERROR_MEMORY;

        bits = FreeImage_GetScanLine(dib, height - 1);

        int ReadPos = IO_BUF_SIZE;

        if ((header.planes == 1) && ((header.bpp == 1) || (header.bpp == 8))) {
            BYTE skip;
            unsigned written;

            for (unsigned y = 0; y < height; y++) {
                written = readline(*io, handle, bits, linelength, bIsRLE, ReadBuf, &ReadPos);

                // skip trailing garbage at the end of the scanline

                for (unsigned count = written; count < linelength; count++) {
                    if (ReadPos < IO_BUF_SIZE) {
                        ReadPos++;
                    } else {
                        io->read_proc(&skip, sizeof(BYTE), 1, handle);
                    }
                }

                bits -= pitch;
            }
        } else if ((header.planes == 4) && (header.bpp == 1)) {
            BYTE bit,  mask, skip;
            unsigned index;
            BYTE *buffer;
            unsigned x, y, written;

            buffer = (BYTE*)malloc(width * sizeof(BYTE));
            if(!buffer) throw FI_MSG_ERROR_MEMORY;

            for (y = 0; y < height; y++) {
                written = readline(*io, handle, line, linelength, bIsRLE, ReadBuf, &ReadPos);

                // build a nibble using the 4 planes

                memset(buffer, 0, width * sizeof(BYTE));

                for(int plane = 0; plane < 4; plane++) {
                    bit = (BYTE)(1 << plane);

                    for (x = 0; x < width; x++) {
                        index = (unsigned)((x / 8) + plane * header.bytes_per_line);
                        mask = (BYTE)(0x80 >> (x & 0x07));
                        buffer[x] |= (line[index] & mask) ? bit : 0;
                    }
                }

                // then write the DIB row

                for (x = 0; x < width / 2; x++) {
                    bits[x] = (buffer[2*x] << 4) | buffer[2*x+1];
                }

                // skip trailing garbage at the end of the scanline

                for (unsigned count = written; count < linelength; count++) {
                    if (ReadPos < IO_BUF_SIZE) {
                        ReadPos++;
                    } else {
                        io->read_proc(&skip, sizeof(BYTE), 1, handle);
                    }
                }

                bits -= pitch;
            }

            free(buffer);

        } else if((header.planes == 3) && (header.bpp == 8)) {
            BYTE *pline;

            for (unsigned y = 0; y < height; y++) {
                readline(*io, handle, line, linelength, bIsRLE, ReadBuf, &ReadPos);

                // convert the plane stream to BGR (RRRRGGGGBBBB -> BGRBGRBGRBGR)
                // well, now with the FI_RGBA_x macros, on BIGENDIAN we convert to RGB

                pline = line;
                unsigned x;

                for (x = 0; x < width; x++) {
                    bits[x * 3 + FI_RGBA_RED] = pline[x];
                }
                pline += header.bytes_per_line;

                for (x = 0; x < width; x++) {
                    bits[x * 3 + FI_RGBA_GREEN] = pline[x];
                }
                pline += header.bytes_per_line;

                for (x = 0; x < width; x++) {
                    bits[x * 3 + FI_RGBA_BLUE] = pline[x];
                }
                pline += header.bytes_per_line;

                bits -= pitch;
            }
        } else {
            throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
        }

        free(line);
        free(ReadBuf);

        return dib;

    } catch (const char *text) {
Ejemplo n.º 3
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	png_structp png_ptr = NULL;
	png_infop info_ptr;
	png_uint_32 width, height;
	png_colorp png_palette = NULL;
	int color_type, palette_entries = 0;
	int bit_depth, pixel_depth;		// pixel_depth = bit_depth * channels

	FIBITMAP *dib = NULL;
	RGBQUAD *palette = NULL;		// pointer to dib palette
	png_bytepp  row_pointers = NULL;
	int i;

    fi_ioStructure fio;
    fio.s_handle = handle;
	fio.s_io = io;
    
	if (handle) {
		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

		try {		
			// check to see if the file is in fact a PNG file

			BYTE png_check[PNG_BYTES_TO_CHECK];

			io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle);

			if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) {
				return NULL;	// Bad signature
			}
			
			// create the chunk manage structure

			png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler);

			if (!png_ptr) {
				return NULL;			
			}

			// create the info structure

		    info_ptr = png_create_info_struct(png_ptr);

			if (!info_ptr) {
				png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
				return NULL;
			}

			// init the IO

			png_set_read_fn(png_ptr, &fio, _ReadProc);

            if (setjmp(png_jmpbuf(png_ptr))) {
				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
				return NULL;
			}

			// because we have already read the signature...

			png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

			// read the IHDR chunk

			png_read_info(png_ptr, info_ptr);
			png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);

			pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr);

			// get image data type (assume standard image type)

			FREE_IMAGE_TYPE image_type = FIT_BITMAP;
			if (bit_depth == 16) {
				if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) {
					image_type = FIT_UINT16;
				} 
				else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) {
					image_type = FIT_RGB16;
				} 
				else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
					image_type = FIT_RGBA16;
				} else {
					// tell libpng to strip 16 bit/color files down to 8 bits/color
					png_set_strip_16(png_ptr);
					bit_depth = 8;
				}
			}

#ifndef FREEIMAGE_BIGENDIAN
			if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
				// turn on 16 bit byte swapping
				png_set_swap(png_ptr);
			}
#endif						

			// set some additional flags

			switch(color_type) {
				case PNG_COLOR_TYPE_RGB:
				case PNG_COLOR_TYPE_RGB_ALPHA:
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
					// flip the RGB pixels to BGR (or RGBA to BGRA)

					if(image_type == FIT_BITMAP) {
						png_set_bgr(png_ptr);
					}
#endif
					break;

				case PNG_COLOR_TYPE_PALETTE:
					// expand palette images to the full 8 bits from 2 bits/pixel

					if (pixel_depth == 2) {
						png_set_packing(png_ptr);
						pixel_depth = 8;
					}					

					break;

				case PNG_COLOR_TYPE_GRAY:
					// expand grayscale images to the full 8 bits from 2 bits/pixel
					// but *do not* expand fully transparent palette entries to a full alpha channel

					if (pixel_depth == 2) {
						png_set_expand_gray_1_2_4_to_8(png_ptr);
						pixel_depth = 8;
					}

					break;

				case PNG_COLOR_TYPE_GRAY_ALPHA:
					// expand 8-bit greyscale + 8-bit alpha to 32-bit

					png_set_gray_to_rgb(png_ptr);
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
					// flip the RGBA pixels to BGRA

					png_set_bgr(png_ptr);
#endif
					pixel_depth = 32;

					break;

				default:
					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			// unlike the example in the libpng documentation, we have *no* idea where
			// this file may have come from--so if it doesn't have a file gamma, don't
			// do any correction ("do no harm")

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
				double gamma = 0;
				double screen_gamma = 2.2;

				if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) {
					png_set_gamma(png_ptr, screen_gamma, gamma);
				}
			}

			// all transformations have been registered; now update info_ptr data

			png_read_update_info(png_ptr, info_ptr);

			// color type may have changed, due to our transformations

			color_type = png_get_color_type(png_ptr,info_ptr);

			// create a DIB and write the bitmap header
			// set up the DIB palette, if needed

			switch (color_type) {
				case PNG_COLOR_TYPE_RGB:
					png_set_invert_alpha(png_ptr);

					if(image_type == FIT_BITMAP) {
						dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					} else {
						dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
					}
					break;

				case PNG_COLOR_TYPE_RGB_ALPHA:
					if(image_type == FIT_BITMAP) {
						dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					} else {
						dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
					}
					break;

				case PNG_COLOR_TYPE_PALETTE:
					dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth);

					png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries);

					palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib));
					palette = FreeImage_GetPalette(dib);

					// store the palette

					for (i = 0; i < palette_entries; i++) {
						palette[i].rgbRed   = png_palette[i].red;
						palette[i].rgbGreen = png_palette[i].green;
						palette[i].rgbBlue  = png_palette[i].blue;
					}
					break;

				case PNG_COLOR_TYPE_GRAY:
					dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);

					if(pixel_depth <= 8) {
						palette = FreeImage_GetPalette(dib);
						palette_entries = 1 << pixel_depth;

						for (i = 0; i < palette_entries; i++) {
							palette[i].rgbRed   =
							palette[i].rgbGreen =
							palette[i].rgbBlue  = (BYTE)((i * 255) / (palette_entries - 1));
						}
					}
					break;

				default:
					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			// store the transparency table

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
				// array of alpha (transparency) entries for palette
				png_bytep trans_alpha = NULL;
				// number of transparent entries
				int num_trans = 0;						
				// graylevel or color sample values of the single transparent color for non-paletted images
				png_color_16p trans_color = NULL;

				png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);

				if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) {
					// single transparent color
					if (trans_color->gray < palette_entries) { 
						BYTE table[256]; 
						memset(table, 0xFF, palette_entries); 
						table[trans_color->gray] = 0; 
						FreeImage_SetTransparencyTable(dib, table, palette_entries); 
					}
				} else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) {
					// transparency table
					FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
				}
			}

			// store the background color 

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
				// Get the background color to draw transparent and alpha images over.
				// Note that even if the PNG file supplies a background, you are not required to
				// use it - you should use the (solid) application background if it has one.

				png_color_16p image_background = NULL;
				RGBQUAD rgbBkColor;

				if (png_get_bKGD(png_ptr, info_ptr, &image_background)) {
					rgbBkColor.rgbRed      = (BYTE)image_background->red;
					rgbBkColor.rgbGreen    = (BYTE)image_background->green;
					rgbBkColor.rgbBlue     = (BYTE)image_background->blue;
					rgbBkColor.rgbReserved = 0;

					FreeImage_SetBackgroundColor(dib, &rgbBkColor);
				}
			}

			// get physical resolution

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
				png_uint_32 res_x, res_y;
				
				// we'll overload this var and use 0 to mean no phys data,
				// since if it's not in meters we can't use it anyway

				int res_unit_type = PNG_RESOLUTION_UNKNOWN;

				png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type);

				if (res_unit_type == PNG_RESOLUTION_METER) {
					FreeImage_SetDotsPerMeterX(dib, res_x);
					FreeImage_SetDotsPerMeterY(dib, res_y);
				}
			}

			// get possible ICC profile

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
				png_charp profile_name = NULL;
				png_bytep profile_data = NULL;
				png_uint_32 profile_length = 0;
				int  compression_type;

				png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length);

				// copy ICC profile data (must be done after FreeImage_AllocateHeader)

				FreeImage_CreateICCProfile(dib, profile_data, profile_length);
			}

			// --- header only mode => clean-up and return

			if (header_only) {
				// get possible metadata (it can be located both before and after the image data)
				ReadMetadata(png_ptr, info_ptr, dib);
				if (png_ptr) {
					// clean up after the read, and free any memory allocated - REQUIRED
					png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
				}
				return dib;
			}

			// set the individual row_pointers to point at the correct offsets

			row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep));

			if (!row_pointers) {
				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
				FreeImage_Unload(dib);
				return NULL;
			}

			// read in the bitmap bits via the pointer table
			// allow loading of PNG with minor errors (such as images with several IDAT chunks)

			for (png_uint_32 k = 0; k < height; k++) {
				row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k);			
			}

			png_set_benign_errors(png_ptr, 1);
			png_read_image(png_ptr, row_pointers);

			// check if the bitmap contains transparency, if so enable it in the header

			if (FreeImage_GetBPP(dib) == 32) {
				if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
					FreeImage_SetTransparent(dib, TRUE);
				} else {
					FreeImage_SetTransparent(dib, FALSE);
				}
			}
				
			// cleanup

			if (row_pointers) {
				free(row_pointers);
				row_pointers = NULL;
			}

			// read the rest of the file, getting any additional chunks in info_ptr

			png_read_end(png_ptr, info_ptr);

			// get possible metadata (it can be located both before and after the image data)

			ReadMetadata(png_ptr, info_ptr, dib);

			if (png_ptr) {
				// clean up after the read, and free any memory allocated - REQUIRED
				png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			}

			return dib;

		} catch (const char *text) {
			if (png_ptr) {
				png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			}
			if (row_pointers) {
				free(row_pointers);
			}
			if (dib) {
				FreeImage_Unload(dib);			
			}
			FreeImage_OutputMessageProc(s_format_id, text);
			
			return NULL;
		}
	}			

	return NULL;
}
Ejemplo n.º 4
0
/**
Decode a WebP image and returns a FIBITMAP image
@param webp_image Raw WebP image
@param flags FreeImage load flags
@return Returns a dib if successfull, returns NULL otherwise
*/
static FIBITMAP *
DecodeImage(WebPData *webp_image, int flags) {
	FIBITMAP *dib = NULL;

	const uint8_t* data = webp_image->bytes;	// raw image data
	const size_t data_size = webp_image->size;	// raw image size

    VP8StatusCode webp_status = VP8_STATUS_OK;

	BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

	// Main object storing the configuration for advanced decoding
	WebPDecoderConfig decoder_config;
	// Output buffer
	WebPDecBuffer* const output_buffer = &decoder_config.output;
	// Features gathered from the bitstream
	WebPBitstreamFeatures* const bitstream = &decoder_config.input;

	try {
		// Initialize the configuration as empty
		// This function must always be called first, unless WebPGetFeatures() is to be called
		if(!WebPInitDecoderConfig(&decoder_config)) {
			throw "Library version mismatch";
		}

		// Retrieve features from the bitstream
		// The bitstream structure is filled with information gathered from the bitstream
		webp_status = WebPGetFeatures(data, data_size, bitstream);
		if(webp_status != VP8_STATUS_OK) {
			throw FI_MSG_ERROR_PARSING;
		}

		// Allocate output dib

		unsigned bpp = bitstream->has_alpha ? 32 : 24;	
		unsigned width = (unsigned)bitstream->width;
		unsigned height = (unsigned)bitstream->height;

		dib = FreeImage_AllocateHeader(header_only, width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
		if(!dib) {
			throw FI_MSG_ERROR_DIB_MEMORY;
		}

		if(header_only) {
			WebPFreeDecBuffer(output_buffer);
			return dib;
		}

		// --- Set decoding options ---

		// use multi-threaded decoding
		decoder_config.options.use_threads = 1;
		// set output color space
		output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR;

		// ---

		// decode the input stream, taking 'config' into account. 
		
		webp_status = WebPDecode(data, data_size, &decoder_config);
		if(webp_status != VP8_STATUS_OK) {
			throw FI_MSG_ERROR_PARSING;
		}

		// fill the dib with the decoded data

		const BYTE *src_bitmap = output_buffer->u.RGBA.rgba;
		const unsigned src_pitch = (unsigned)output_buffer->u.RGBA.stride;

		switch(bpp) {
			case 24:
				for(unsigned y = 0; y < height; y++) {
					const BYTE *src_bits = src_bitmap + y * src_pitch;						
					BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, height-1-y);
					for(unsigned x = 0; x < width; x++) {
						dst_bits[FI_RGBA_BLUE]	= src_bits[0];	// B
						dst_bits[FI_RGBA_GREEN]	= src_bits[1];	// G
						dst_bits[FI_RGBA_RED]	= src_bits[2];	// R
						src_bits += 3;
						dst_bits += 3;
					}
				}
				break;
			case 32:
				for(unsigned y = 0; y < height; y++) {
					const BYTE *src_bits = src_bitmap + y * src_pitch;						
					BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, height-1-y);
					for(unsigned x = 0; x < width; x++) {
						dst_bits[FI_RGBA_BLUE]	= src_bits[0];	// B
						dst_bits[FI_RGBA_GREEN]	= src_bits[1];	// G
						dst_bits[FI_RGBA_RED]	= src_bits[2];	// R
						dst_bits[FI_RGBA_ALPHA]	= src_bits[3];	// A
						src_bits += 4;
						dst_bits += 4;
					}
				}
				break;
		}

		// Free the decoder
		WebPFreeDecBuffer(output_buffer);

		return dib;

	} catch (const char *text) {
		if(dib) {
			FreeImage_Unload(dib);
		}
		WebPFreeDecBuffer(output_buffer);

		if(NULL != text) {
			FreeImage_OutputMessageProc(s_format_id, text);
		}

		return NULL;
	}
}
Ejemplo n.º 5
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	SUNHEADER header;	// Sun file header
	WORD linelength;	// Length of raster line in bytes
	WORD fill;			// Number of fill bytes per raster line
	BOOL rle;			// TRUE if RLE file
	BOOL isRGB;			// TRUE if file type is RT_FORMAT_RGB
	BYTE fillchar;

	FIBITMAP *dib = NULL;
	BYTE *bits;			// Pointer to dib data
	WORD x, y;

	if(!handle) {
		return NULL;
	}

	BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

	try {
		// Read SUN raster header

		io->read_proc(&header, sizeof(SUNHEADER), 1, handle);

#ifndef FREEIMAGE_BIGENDIAN
		// SUN rasterfiles are big endian only

		SwapLong(&header.magic);
		SwapLong(&header.width);
		SwapLong(&header.height);
		SwapLong(&header.depth);
		SwapLong(&header.length);
		SwapLong(&header.type);
		SwapLong(&header.maptype);
		SwapLong(&header.maplength);
#endif

		// Verify SUN identifier

		if (header.magic != RAS_MAGIC) {
			throw FI_MSG_ERROR_MAGIC_NUMBER;
		}

		// Allocate a new DIB

		switch(header.depth) {
			case 1:
			case 8:
				dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth);
				break;

			case 24:
				dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
				break;

			case 32:
				dib = FreeImage_AllocateHeader(header_only, header.width, header.height, header.depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
				break;
		}

		if (dib == NULL) {
			throw FI_MSG_ERROR_DIB_MEMORY;
		}

		// Check the file format

		rle = FALSE;
		isRGB = FALSE;

		switch(header.type) {
			case RT_OLD:
			case RT_STANDARD:
			case RT_FORMAT_TIFF: // I don't even know what these format are...
			case RT_FORMAT_IFF: //The TIFF and IFF format types indicate that the raster
				//file was originally converted from either of these file formats.
				//so lets at least try to process them as RT_STANDARD
				break;

			case RT_BYTE_ENCODED:
				rle = TRUE;
				break;

			case RT_FORMAT_RGB:
				isRGB = TRUE;
				break;

			default:
				throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
		}

		// set up the colormap if needed

		switch(header.maptype) {
			case RMT_NONE :
			{				
				if (header.depth < 24) {
					// Create linear color ramp

					RGBQUAD *pal = FreeImage_GetPalette(dib);

					int numcolors = 1 << header.depth;

					for (int i = 0; i < numcolors; i++) {
						pal[i].rgbRed	= (BYTE)((255 * i) / (numcolors - 1));
						pal[i].rgbGreen = (BYTE)((255 * i) / (numcolors - 1));
						pal[i].rgbBlue	= (BYTE)((255 * i) / (numcolors - 1));
					}
				}

				break;
			}

			case RMT_EQUAL_RGB:
			{
				BYTE *r, *g, *b;

				// Read SUN raster colormap

				int numcolors = 1 << header.depth;
				if((DWORD)(3 * numcolors) > header.maplength) {
					// some RAS may have less colors than the full palette
					numcolors = header.maplength / 3;
				} else {
					throw "Invalid palette";
				}

				r = (BYTE*)malloc(3 * numcolors * sizeof(BYTE));
				g = r + numcolors;
				b = g + numcolors;

				RGBQUAD *pal = FreeImage_GetPalette(dib);

				io->read_proc(r, 3 * numcolors, 1, handle);

				for (int i = 0; i < numcolors; i++) {
					pal[i].rgbRed	= r[i];
					pal[i].rgbGreen = g[i];
					pal[i].rgbBlue	= b[i];
				}

				free(r);
				break;
			}

			case RMT_RAW:
			{
				BYTE *colormap;

				// Read (skip) SUN raster colormap.

				colormap = (BYTE *)malloc(header.maplength * sizeof(BYTE));

				io->read_proc(colormap, header.maplength, 1, handle);

				free(colormap);
				break;
			}
		}

		if(header_only) {
			// header only mode
			return dib;
		}

		// Calculate the line + pitch
		// Each row is multiple of 16 bits (2 bytes).

		if (header.depth == 1) {
			linelength = (WORD)((header.width / 8) + (header.width % 8 ? 1 : 0));
		} else {
			linelength = (WORD)header.width;
		}

		fill = (linelength % 2) ? 1 : 0;

		unsigned pitch = FreeImage_GetPitch(dib);

		// Read the image data
		
		switch(header.depth) {
			case 1:
			case 8:
			{
				bits = FreeImage_GetBits(dib) + (header.height - 1) * pitch;

				for (y = 0; y < header.height; y++) {
					ReadData(io, handle, bits, linelength, rle);

					bits -= pitch;

					if (fill) {
						ReadData(io, handle, &fillchar, fill, rle);
					}
				}

				break;
			}

			case 24:
			{
				BYTE *buf, *bp;

				buf = (BYTE*)malloc(header.width * 3);

				for (y = 0; y < header.height; y++) {
					bits = FreeImage_GetBits(dib) + (header.height - 1 - y) * pitch;

					ReadData(io, handle, buf, header.width * 3, rle);

					bp = buf;

					if (isRGB) {
						for (x = 0; x < header.width; x++) {
							bits[FI_RGBA_RED] = *(bp++);	// red
							bits[FI_RGBA_GREEN] = *(bp++);	// green
							bits[FI_RGBA_BLUE] = *(bp++);	// blue

							bits += 3;
						}
					} else {
						for (x = 0; x < header.width; x++) {
							bits[FI_RGBA_RED] = *(bp + 2);	// red
							bits[FI_RGBA_GREEN] = *(bp + 1);// green
							bits[FI_RGBA_BLUE] = *bp;       // blue

							bits += 3; bp += 3;
						}
					}

					if (fill) {
						ReadData(io, handle, &fillchar, fill, rle);
					}
				}

				free(buf);
				break;
			}

			case 32:
			{
				BYTE *buf, *bp;

				buf = (BYTE*)malloc(header.width * 4);

				for (y = 0; y < header.height; y++) {
					bits = FreeImage_GetBits(dib) + (header.height - 1 - y) * pitch;

					ReadData(io, handle, buf, header.width * 4, rle);

					bp = buf;

					if (isRGB) {
						for (x = 0; x < header.width; x++) {
							bits[FI_RGBA_ALPHA] = *(bp++);	// alpha
							bits[FI_RGBA_RED] = *(bp++);	// red
							bits[FI_RGBA_GREEN] = *(bp++);	// green
							bits[FI_RGBA_BLUE] = *(bp++);	// blue

							bits += 4;
						}
					}
					else {
						for (x = 0; x < header.width; x++) {
							bits[FI_RGBA_RED] = *(bp + 3);	// red
							bits[FI_RGBA_GREEN] = *(bp + 2); // green
							bits[FI_RGBA_BLUE] = *(bp + 1);	// blue
							bits[FI_RGBA_ALPHA] = *bp;		// alpha

							bits += 4;
							bp += 4;
						}
					}

					if (fill) {
						ReadData(io, handle, &fillchar, fill, rle);
					}
				}

				free(buf);
				break;
			}
		}
		
		return dib;

	} catch (const char *text) {
		if(dib) {
			FreeImage_Unload(dib);
		}
		FreeImage_OutputMessageProc(s_format_id, text);
	}

	return NULL;
}
Ejemplo n.º 6
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	FIBITMAP *dib = NULL;
	unsigned width;
	unsigned height;
	const unsigned bpp = 24;
	int scan_line_add   = 1;
	int start_scan_line = 0;
	
	BYTE *y1 = NULL, *y2 = NULL, *cbcr = NULL;

	BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

	// to make absolute seeks possible we store the current position in the file
	
	long offset_in_file = io->tell_proc(handle);
	long seek = 0;

	// decide which bitmap in the cabinet to load

	switch (flags) {
		case PCD_BASEDIV4 :
			seek = 0x2000;
			width = 192;
			height = 128;
			break;

		case PCD_BASEDIV16 :
			seek = 0xB800;
			width = 384;
			height = 256;
			break;

		default :
			seek = 0x30000;
			width = 768;
			height = 512;
			break;
	}

	try {
		// allocate the dib and write out the header
		dib = FreeImage_AllocateHeader(header_only, width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
		if(!dib) throw FI_MSG_ERROR_DIB_MEMORY;

		if(header_only) {
			return dib;
		}

		// check if the PCD is bottom-up

		if (VerticalOrientation(io, handle)) {
			scan_line_add = -1;
			start_scan_line = height - 1;		
		}

		// temporary stuff to load PCD

		BYTE *y1 = (BYTE*)malloc(width * sizeof(BYTE));
		BYTE *y2 = (BYTE*)malloc(width * sizeof(BYTE));
		BYTE *cbcr = (BYTE*)malloc(width * sizeof(BYTE));
		if(!y1 || !y2 || !cbcr) throw FI_MSG_ERROR_MEMORY;

		BYTE *yl[] = { y1, y2 };

		// seek to the part where the bitmap data begins

		io->seek_proc(handle, offset_in_file, SEEK_SET);
		io->seek_proc(handle, seek, SEEK_CUR);

		// read the data

		for (unsigned y = 0; y < height / 2; y++) {
			io->read_proc(y1, width, 1, handle);
			io->read_proc(y2, width, 1, handle);
			io->read_proc(cbcr, width, 1, handle);

			for (int i = 0; i < 2; i++) {
				BYTE *bits = FreeImage_GetScanLine(dib, start_scan_line);
				for (unsigned x = 0; x < width; x++) {
					int r, g, b;

					YUV2RGB(yl[i][x], cbcr[x / 2], cbcr[(width / 2) + (x / 2)], r, g, b);

					bits[FI_RGBA_BLUE]  = (BYTE)b;
					bits[FI_RGBA_GREEN] = (BYTE)g;
					bits[FI_RGBA_RED]   = (BYTE)r;
					bits += 3;
				}

				start_scan_line += scan_line_add;
			}
		}

		free(cbcr);
		free(y2);
		free(y1);

		return dib;

	} catch(const char *text) {
		if(dib) FreeImage_Unload(dib);
		if(cbcr) free(cbcr);
		if(y2) free(y2);
		if(y1) free(y1);

		FreeImage_OutputMessageProc(s_format_id, text);

		return NULL;
	}
}
Ejemplo n.º 7
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	char msg[256];
    FIBITMAP *dib = NULL;

    if (!handle) return NULL;

    try {
		char *str;
		
		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
		
		//find the starting brace
		if( !FindChar(io, handle,'{') )
			throw "Could not find starting brace";

		//read info string
		str = ReadString(io, handle);
		if(!str)
			throw "Error reading info string";

		int width, height, colors, cpp;
		if( sscanf(str, "%d %d %d %d", &width, &height, &colors, &cpp) != 4 ) {
			free(str);
			throw "Improperly formed info string";
		}
		free(str);

        if (colors > 256) {
			dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
		} else {
			dib = FreeImage_AllocateHeader(header_only, width, height, 8);
		}

		//build a map of color chars to rgb values
		std::map<std::string,FILE_RGBA> rawpal; //will store index in Alpha if 8bpp
		for(int i = 0; i < colors; i++ ) {
			FILE_RGBA rgba;

			str = ReadString(io, handle);
			if(!str)
				throw "Error reading color strings";

			std::string chrs(str,cpp); //create a string for the color chars using the first cpp chars
			char *keys = str + cpp; //the color keys for these chars start after the first cpp chars

			//translate all the tabs to spaces
			char *tmp = keys;
			while( strchr(tmp,'\t') ) {
				tmp = strchr(tmp,'\t');
				*tmp++ = ' ';
			}

			//prefer the color visual
			if( strstr(keys," c ") ) {
				char *clr = strstr(keys," c ") + 3;
				while( *clr == ' ' ) clr++; //find the start of the hex rgb value
				if( *clr == '#' ) {
					int red = 0, green = 0, blue = 0, n;
					clr++;
					//end string at first space, if any found
					if( strchr(clr,' ') )
						*(strchr(clr,' ')) = '\0';
					//parse hex color, it can be #rgb #rrggbb #rrrgggbbb or #rrrrggggbbbb
					switch( strlen(clr) ) {
						case 3:	n = sscanf(clr,"%01x%01x%01x",&red,&green,&blue);
							red |= (red << 4);
							green |= (green << 4);
							blue |= (blue << 4);
							break;
						case 6:	n = sscanf(clr,"%02x%02x%02x",&red,&green,&blue);
							break;
						case 9:	n = sscanf(clr,"%03x%03x%03x",&red,&green,&blue);
							red >>= 4;
							green >>= 4;
							blue >>= 4;
							break;
						case 12: n = sscanf(clr,"%04x%04x%04x",&red,&green,&blue);
							red >>= 8;
							green >>= 8;
							blue >>= 8;
							break;
						default:
							n = 0;
							break;
					}
					if( n != 3 ) {
						free(str);
						throw "Improperly formed hex color value";
					}
					rgba.r = (BYTE)red;
					rgba.g = (BYTE)green;
					rgba.b = (BYTE)blue;
				} else if( !strncmp(clr,"None",4) || !strncmp(clr,"none",4) ) {
					rgba.r = rgba.g = rgba.b = 0xFF;
				} else {
					char *tmp = clr;

					//scan forward for each space, if its " x " or " xx " end the string there
					//this means its probably some other visual data beyond that point and not
					//part of the color name.  How many named color end with a 1 or 2 character
					//word? Probably none in our list at least.
					while( (tmp = strchr(tmp,' ')) != NULL ) {
						if( tmp[1] != ' ' ) {
							if( (tmp[2] == ' ') || (tmp[2] != ' ' && tmp[3] == ' ') ) {
								tmp[0] = '\0';
								break;
							}
						}
						tmp++;
					}

					//remove any trailing spaces
					tmp = clr+strlen(clr)-1;
					while( *tmp == ' ' ) {
						*tmp = '\0';
						tmp--;
					}

					if (!FreeImage_LookupX11Color(clr,  &rgba.r, &rgba.g, &rgba.b)) {
						sprintf(msg, "Unknown color name '%s'", str);
						free(str);
						throw msg;
					}
				}
			} else {
Ejemplo n.º 8
0
/**
Convert a OpenJPEG image to a FIBITMAP
@param format_id Plugin ID
@param image OpenJPEG image
@param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP
@return Returns the converted image if successful, returns NULL otherwise
*/
FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image, BOOL header_only) {
	FIBITMAP *dib = NULL;

	try {
		// compute image width and height

		//int w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
		int wr = image->comps[0].w;
		int wrr = int_ceildivpow2(image->comps[0].w, image->comps[0].factor);
		
		//int h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
		//int hr = image->comps[0].h;
		int hrr = int_ceildivpow2(image->comps[0].h, image->comps[0].factor);

		// check the number of components

		int numcomps = image->numcomps;

		BOOL bIsValid = TRUE;
		for(int c = 0; c < numcomps - 1; c++) {
			if(	(image->comps[c].dx == image->comps[c+1].dx) && 
				(image->comps[c].dy == image->comps[c+1].dy) &&
				(image->comps[c].prec == image->comps[c+1].prec) ) {
				continue;
			} else {
				bIsValid = FALSE;
				break;
			}
		}
		bIsValid &= ((numcomps == 1) || (numcomps == 3) || (numcomps == 4));
		if(!bIsValid) {
			if(numcomps) {
				FreeImage_OutputMessageProc(format_id, "Warning: image contains %d greyscale components. Only the first will be loaded.\n", numcomps);
				numcomps = 1;
			} else {
				// unknown type
				throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}
		}

		// create a new DIB

		if(image->comps[0].prec <= 8) {
			switch(numcomps) {
				case 1:
					dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 8);
					break;
				case 3:
					dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					break;
				case 4:
					dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					break;
			}
		} else if(image->comps[0].prec <= 16) {
			switch(numcomps) {
				case 1:
					dib = FreeImage_AllocateHeaderT(header_only, FIT_UINT16, wrr, hrr);
					break;
				case 3:
					dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, wrr, hrr);
					break;
				case 4:
					dib = FreeImage_AllocateHeaderT(header_only, FIT_RGBA16, wrr, hrr);
					break;
			}
		} else {
			throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
		}
		if(!dib) {
			throw FI_MSG_ERROR_DIB_MEMORY;
		}

		// "header only" FIBITMAP ?
		if(header_only) {
			return dib;
		}
		
		if(image->comps[0].prec <= 8) {
			if(numcomps == 1) {
				// 8-bit greyscale
				// ----------------------------------------------------------

				// build a greyscale palette
				
				RGBQUAD *pal = FreeImage_GetPalette(dib);
				for (int i = 0; i < 256; i++) {
					pal[i].rgbRed	= (BYTE)i;
					pal[i].rgbGreen = (BYTE)i;
					pal[i].rgbBlue	= (BYTE)i;
				}

				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int index = image->comps[0].data[pixel_pos];
						index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);

						bits[x] = (BYTE)index;

						pixel_count++;
					}
				}
			}
			else if(numcomps == 3) {

				// 24-bit RGB
				// ----------------------------------------------------------	
				
				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int r = image->comps[0].data[pixel_pos];
						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
						
						int g = image->comps[1].data[pixel_pos];
						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
						
						int b = image->comps[2].data[pixel_pos];
						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);

						bits[FI_RGBA_RED]   = (BYTE)r;
						bits[FI_RGBA_GREEN] = (BYTE)g;
						bits[FI_RGBA_BLUE]  = (BYTE)b;
						bits += 3;

						pixel_count++;
					}
				}
			}
			else if(numcomps == 4) {

				// 32-bit RGBA
				// ----------------------------------------------------------	
				
				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int r = image->comps[0].data[pixel_pos];
						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
						
						int g = image->comps[1].data[pixel_pos];
						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
						
						int b = image->comps[2].data[pixel_pos];
						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);

						int a = image->comps[3].data[pixel_pos];
						a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);

						bits[FI_RGBA_RED]   = (BYTE)r;
						bits[FI_RGBA_GREEN] = (BYTE)g;
						bits[FI_RGBA_BLUE]  = (BYTE)b;
						bits[FI_RGBA_ALPHA] = (BYTE)a;
						bits += 4;

						pixel_count++;
					}
				}
			}
		}
		else if(image->comps[0].prec <= 16) {
			if(numcomps == 1) {
				// 16-bit greyscale
				// ----------------------------------------------------------

				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					WORD *bits = (WORD*)FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int index = image->comps[0].data[pixel_pos];
						index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);

						bits[x] = (WORD)index;

						pixel_count++;
					}
				}
			}
			else if(numcomps == 3) {

				// 48-bit RGB
				// ----------------------------------------------------------	
				
				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int r = image->comps[0].data[pixel_pos];
						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
						
						int g = image->comps[1].data[pixel_pos];
						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
						
						int b = image->comps[2].data[pixel_pos];
						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);

						bits[x].red   = (WORD)r;
						bits[x].green = (WORD)g;
						bits[x].blue  = (WORD)b;

						pixel_count++;
					}
				}
			}
			else if(numcomps == 4) {

				// 64-bit RGBA
				// ----------------------------------------------------------	
				
				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int r = image->comps[0].data[pixel_pos];
						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
						
						int g = image->comps[1].data[pixel_pos];
						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
						
						int b = image->comps[2].data[pixel_pos];
						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);

						int a = image->comps[3].data[pixel_pos];
						a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);

						bits[x].red   = (WORD)r;
						bits[x].green = (WORD)g;
						bits[x].blue  = (WORD)b;
						bits[x].alpha = (WORD)a;

						pixel_count++;
					}
				}
			}
		}

		return dib;

	} catch(const char *text) {
		if(dib) FreeImage_Unload(dib);
		FreeImage_OutputMessageProc(format_id, text);
		return NULL;
	}

}