/** @brief Fills a FIT_BITMAP image with the specified color.

 This function does the dirty work for FreeImage_FillBackground for FIT_BITMAP
 images.
 @param dib The image to be filled.
 @param color The color, the specified image should be filled with.
 @param options Options that affect the color search process for palletized images.
 @return Returns TRUE on success, FALSE otherwise. This function fails if any of
 the dib and color is NULL or the provided image is not a FIT_BITMAP image.
 */
static BOOL
FillBackgroundBitmap(FIBITMAP *dib, const RGBQUAD *color, int options) {

	if ((!dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
		return FALSE;;
	}
	
	if (!color) {
		return FALSE;
	}
	
	const RGBQUAD *color_intl = color;
	unsigned bpp = FreeImage_GetBPP(dib);
	unsigned width = FreeImage_GetWidth(dib);
	unsigned height = FreeImage_GetHeight(dib);
	
	FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
	
	// get a pointer to the first scanline (bottom line)
	BYTE *src_bits = FreeImage_GetScanLine(dib, 0);
	BYTE *dst_bits = src_bits;	
	
	BOOL supports_alpha = ((bpp >= 24) || ((bpp == 8) && (color_type != FIC_PALETTE)));
	
	// Check for RGBA case if bitmap supports alpha 
	// blending (8-bit greyscale, 24- or 32-bit images)
	if (supports_alpha && (options & FI_COLOR_IS_RGBA_COLOR)) {
		
		if (color->rgbReserved == 0) {
			// the fill color is fully transparent; we are done
			return TRUE;
		}
		
		// Only if the fill color is NOT fully opaque, draw it with
		// the (much) slower FreeImage_DrawLine function and return.
		// Since we do not have the FreeImage_DrawLine function in this
		// release, just assume to have an unicolor background and fill
		// all with an 'alpha-blended' color.
		if (color->rgbReserved < 255) {
							
			// If we will draw on an unicolor background, it's
			// faster to draw opaque with an alpha blended color.
			// So, first get the color from the first pixel in the
			// image (bottom-left pixel).
			RGBQUAD bgcolor;
			if (bpp == 8) {
				bgcolor = FreeImage_GetPalette(dib)[*src_bits];
			} else {	
				bgcolor.rgbBlue = src_bits[FI_RGBA_BLUE];
				bgcolor.rgbGreen = src_bits[FI_RGBA_GREEN];
				bgcolor.rgbRed = src_bits[FI_RGBA_RED];
				bgcolor.rgbReserved = 0xFF;
			}
			RGBQUAD blend;
			GetAlphaBlendedColor(&bgcolor, color_intl, &blend);
			color_intl = &blend;
		}
	}
	
	int index = (bpp <= 8) ? GetPaletteIndex(dib, color_intl, options, &color_type) : 0;
	if (index == -1) {
		// No palette index found for a palletized
		// image. This should never happen...
		return FALSE;
	}
	
	// first, build the first scanline (line 0)
	switch (bpp) {
		case 1: {
			unsigned bytes = (width / 8);
			memset(dst_bits, ((index == 1) ? 0xFF : 0x00), bytes);
			//int n = width % 8;
			int n = width & 7;
			if (n) {
				if (index == 1) {
					// set n leftmost bits
					dst_bits[bytes] |= (0xFF << (8 - n));
				} else {
					// clear n leftmost bits
					dst_bits[bytes] &= (0xFF >> n);
				}
			}
			break;
		}
		case 4: {
			unsigned bytes = (width / 2);
			memset(dst_bits, (index | (index << 4)), bytes);
			//if (bytes % 2) {
			if (bytes & 1) {
				dst_bits[bytes] &= 0x0F;
				dst_bits[bytes] |= (index << 4);
			}
			break;
		}
		case 8: {
			memset(dst_bits, index, FreeImage_GetLine(dib));
			break;
		}
		case 16: {
			WORD wcolor = RGBQUAD_TO_WORD(dib, color_intl);
			for (unsigned x = 0; x < width; x++) {
				((WORD *)dst_bits)[x] = wcolor;
			}
			break;
		}
		case 24: {
			RGBTRIPLE rgbt = *((RGBTRIPLE *)color_intl);
			for (unsigned x = 0; x < width; x++) {
				((RGBTRIPLE *)dst_bits)[x] = rgbt;
			}
			break;
		}
		case 32: {
			RGBQUAD rgbq;
			rgbq.rgbBlue = ((RGBTRIPLE *)color_intl)->rgbtBlue;
			rgbq.rgbGreen = ((RGBTRIPLE *)color_intl)->rgbtGreen;
			rgbq.rgbRed = ((RGBTRIPLE *)color_intl)->rgbtRed;
			rgbq.rgbReserved = 0xFF;
			for (unsigned x = 0; x < width; x++) {
				((RGBQUAD *)dst_bits)[x] = rgbq;
			}
			break;
		}
		default:
			return FALSE;
	}

	// Then, copy the first scanline into all following scanlines.
	// 'src_bits' is a pointer to the first scanline and is already
	// set up correctly.
	if (src_bits) {
		unsigned pitch = FreeImage_GetPitch(dib);
		unsigned bytes = FreeImage_GetLine(dib);
		dst_bits = src_bits + pitch;
		for (unsigned y = 1; y < height; y++) {
			memcpy(dst_bits, src_bits, bytes);
			dst_bits += pitch;
		}
	}
	return TRUE;
}
/**
   Tone mapping operator
   @param dib Input / Output RGBF image
   @param Y Input luminance image version of dib
   @param f Overall intensity in range [-8:8] : default to 0
   @param m Contrast in range [0.3:1) : default to 0
   @param a Adaptation in range [0:1] : default to 1
   @param c Color correction in range [0:1] : default to 0
   @return Returns TRUE if successful, returns FALSE otherwise
   @see LuminanceFromY
*/
static BOOL
ToneMappingReinhard05(FIBITMAP *dib, FIBITMAP *Y, float f, float m, float a, float c) {
    float Cav[3];       // channel average
    float Lav = 0;      // average luminance
    float Llav = 0;     // log average luminance
    float minLum = 1;   // min luminance
    float maxLum = 1;   // max luminance

    float L;        // pixel luminance
    float I_g, I_l; // global and local light adaptation
    float I_a;      // interpolated pixel light adaptation
    float k;        // key (low-key means overall dark image, high-key means overall light image)

    // check input parameters

    if((FreeImage_GetImageType(dib) != FIT_RGBF) || (FreeImage_GetImageType(Y) != FIT_FLOAT)) {
        return FALSE;
    }

    if(f < -8) f = -8; if(f > 8) f = 8;
    if(m < 0)  m = 0;  if(m > 1) m = 1;
    if(a < 0)  a = 0;  if(a > 1) a = 1;
    if(c < 0)  c = 0;  if(c > 1) c = 1;

    const unsigned width  = FreeImage_GetWidth(dib);
    const unsigned height = FreeImage_GetHeight(dib);

    const unsigned dib_pitch  = FreeImage_GetPitch(dib);
    const unsigned y_pitch    = FreeImage_GetPitch(Y);

    int i;
    unsigned x, y;
    BYTE *bits = NULL, *Ybits = NULL;

    // get statistics about the data (but only if its really needed)

    f = exp(-f);
    if((m == 0) || (a != 1) && (c != 1)) {
        // avoid these calculations if its not needed after ...
        LuminanceFromY(Y, &maxLum, &minLum, &Lav, &Llav);
        k = (log(maxLum) - Llav) / (log(maxLum) - log(minLum));
        if(k < 0) {
            // pow(k, 1.4F) is undefined ...
            // there's an ambiguity about the calculation of Llav between Reinhard papers and the various implementations  ...
            // try another world adaptation luminance formula using instead 'worldLum = log(Llav)'
            k = (log(maxLum) - log(Llav)) / (log(maxLum) - log(minLum));
            if(k < 0) m = 0.3F;
        }
    }
    m = (m > 0) ? m : (float)(0.3 + 0.7 * pow(k, 1.4F));

    float max_color = -1e6F;
    float min_color = +1e6F;

    // tone map image

    bits  = (BYTE*)FreeImage_GetBits(dib);
    Ybits = (BYTE*)FreeImage_GetBits(Y);

    if((a == 1) && (c == 0)) {
        // when using default values, use a fastest code

        for(y = 0; y < height; y++) {
            float *Y     = (float*)Ybits;
            float *color = (float*)bits;

            for(x = 0; x < width; x++) {
                I_a = Y[x]; // luminance(x, y)
                for (i = 0; i < 3; i++) {
                    *color /= ( *color + pow(f * I_a, m) );

                    max_color = (*color > max_color) ? *color : max_color;
                    min_color = (*color < min_color) ? *color : min_color;

                    color++;
                }
            }
            // next line
            bits  += dib_pitch;
            Ybits += y_pitch;
        }
    } else {
        // complete algorithm

        // channel averages

        Cav[0] = Cav[1] = Cav[2] = 0;
        if((a != 1) && (c != 0)) {
            // channel averages are not needed when (a == 1) or (c == 0)
            bits = (BYTE*)FreeImage_GetBits(dib);
            for(y = 0; y < height; y++) {
                float *color = (float*)bits;
                for(x = 0; x < width; x++) {
                    for(i = 0; i < 3; i++) {
                        Cav[i] += *color;
                        color++;
                    }
                }
                // next line
                bits += dib_pitch;
            }
            const float image_size = (float)width * height;
            for(i = 0; i < 3; i++) {
                Cav[i] /= image_size;
            }
        }

        // perform tone mapping

        bits = (BYTE*)FreeImage_GetBits(dib);
        for(y = 0; y < height; y++) {
            const float *Y     = (float*)Ybits;
            float *color = (float*)bits;

            for(x = 0; x < width; x++) {
                L = Y[x];   // luminance(x, y)
                for (i = 0; i < 3; i++) {
                    I_l = c * *color + (1-c) * L;
                    I_g = c * Cav[i] + (1-c) * Lav;
                    I_a = a * I_l + (1-a) * I_g;
                    *color /= ( *color + pow(f * I_a, m) );

                    max_color = (*color > max_color) ? *color : max_color;
                    min_color = (*color < min_color) ? *color : min_color;

                    color++;
                }
            }
            // next line
            bits  += dib_pitch;
            Ybits += y_pitch;
        }
    }

    // normalize intensities

    if(max_color != min_color) {
        bits = (BYTE*)FreeImage_GetBits(dib);
        const float range = max_color - min_color;
        for(y = 0; y < height; y++) {
            float *color = (float*)bits;
            for(x = 0; x < width; x++) {
                for(i = 0; i < 3; i++) {
                    *color = (*color - min_color) / range;
                    color++;
                }
            }
            // next line
            bits += dib_pitch;
        }
    }

    return TRUE;
}
Exemple #3
0
bool StFreeImage::loadExtra(const StString& theFilePath,
                            ImageType       theImageType,
                            uint8_t*        theDataPtr,
                            int             theDataSize,
                            bool            theIsOnlyRGB) {
    (void )theIsOnlyRGB;
    if(!StFreeImage::init()) {
        setState("FreeImage library is not initialized");
        return false;
    }

    // reset current data
    StImage::nullify();
    setState();
    close();

    FREE_IMAGE_FORMAT aFIF = convertToFIF(theImageType);
    if(theDataPtr != NULL && theDataSize != 0 && aFIF != FIF_UNKNOWN) {
        FIMEMORY* aFIMemory = FreeImage_OpenMemory(theDataPtr, theDataSize);
        if(aFIMemory == NULL) {
            setState("FreeImage library, internal error");
            return false;
        }
        myDIB = FreeImage_LoadFromMemory(aFIF, aFIMemory, 0);
        FreeImage_CloseMemory(aFIMemory);
    } else {
        // check the file signature and deduce its format
    #if defined(_WIN32)
        StStringUtfWide aFilePathWide = theFilePath.toUtfWide();
        aFIF = FreeImage_GetFileType(aFilePathWide.toCString(), 0);
    #else
        aFIF = FreeImage_GetFileType(theFilePath.toCString(), 0);
    #endif
        if(aFIF == FIF_UNKNOWN) {
            // no signature? try to guess the file format from the file extension
        #if defined(_WIN32)
            aFIF = FreeImage_GetFIFFromFilename(aFilePathWide.toCString());
        #else
            aFIF = FreeImage_GetFIFFromFilename(theFilePath.toCString());
        #endif
        }
        if((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading(aFIF)) {
            setState("FreeImage library does not support image format");
            return false;
        }

        int loadFlags = 0;
        if(aFIF == FIF_GIF) {
            // GIF_PLAYBACK - 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
            loadFlags = 2;
        } else if(aFIF == FIF_ICO) {
            // ICO_MAKEALPHA - convert to 32bpp and create an alpha channel from the AND-mask when loading
            loadFlags = 1;
        }
    #if defined(_WIN32)
        myDIB = FreeImage_Load(aFIF, aFilePathWide.toCString(), loadFlags);
    #else
        myDIB = FreeImage_Load(aFIF, theFilePath.toCString(),   loadFlags);
    #endif
    }
    if(myDIB == NULL) {
        setState("FreeImage library, loading file failed");
        return false;
    }

    StImagePlane::ImgFormat stImgFormat = convertFromFreeFormat(FreeImage_GetImageType(myDIB),
                                                                FreeImage_GetColorType(myDIB),
                                                                FreeImage_GetBPP(myDIB));

    if(stImgFormat == StImagePlane::ImgUNKNOWN) {
        setState(StString("StFreeImage, image format ")
                 + FreeImage_GetImageType(myDIB) + ", " + FreeImage_GetColorType(myDIB)
                 + " doesn't supported by application");
        close();
        return false;
    }

    setColorModelPacked(stImgFormat);
    changePlane(0).initWrapper(stImgFormat, FreeImage_GetBits(myDIB),
                               FreeImage_GetWidth(myDIB),
                               FreeImage_GetHeight(myDIB),
                               FreeImage_GetPitch(myDIB));
    // FreeImage data always bottom-up...
    changePlane(0).setTopDown(false);

    // set debug information
    StString aDummy, aFileName;
    StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName);
    setState(StString("FreeImage library, loaded image '") + aFileName + "' " + getDescription());

    // we should not close the file because we create a wrapper over FreeImage native object
    return true;
}
Exemple #4
0
bool convert(const std::string &filename) {
	
	std::string file    = removePath(filename);
	std::string outFile = getPrefix(filename, '.') + ".cfrt";
	
	/* Retrieve file format */
	FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(filename.c_str(), 0);
	if (fif == FIF_UNKNOWN) fif = FreeImage_GetFIFFromFilename(filename.c_str());
	if (fif == FIF_UNKNOWN) {
		std::cout << "Unknown file format " << file << std::endl;
		return false;
	}
	
	/* Load image */
	FIBITMAP *dib = nullptr;
	if (FreeImage_FIFSupportsReading(fif)) dib = FreeImage_Load(fif, filename.c_str());
	if (!dib) {
		std::cout << "Failed to load " << file << std::endl;
		return false;
	}
	
	/* Convert to standard format if necessary */
	if (FreeImage_GetImageType(dib) != FIT_BITMAP) {
		FIBITMAP *tmp = dib;
		dib = FreeImage_ConvertToStandardType(dib);
		FreeImage_Unload(tmp);
		if (!dib) {
			std::cout << "Failed to convert " << file << " to standard type." << std::endl;
			return false;
		}
	}
	
	/* Convert bpp if needed */
	unsigned int bpp = FreeImage_GetBPP(dib);
	if (bpp <= 8) {
		FIBITMAP *tmp = dib;
		dib = FreeImage_ConvertToGreyscale(dib);
		FreeImage_Unload(tmp);
		bpp = 8;
		if (!dib || FreeImage_GetBPP(dib) != 8) bpp = 0;
	} else if (bpp > 32) {
		FIBITMAP *tmp = dib;
		dib = FreeImage_ConvertTo32Bits(dib);
		FreeImage_Unload(tmp);
		bpp = 32;
		if (!dib || FreeImage_GetBPP(dib) != 32) bpp = 0;
	}
	
	/* Get image information */
	unsigned int width  = FreeImage_GetWidth(dib);
	unsigned int height = FreeImage_GetHeight(dib);
	unsigned int bytes    = 1;
	unsigned int channels = 0;
	switch (bpp) {
		case 8:  channels = 1; break;
		case 24: channels = 3; break;
		case 32: channels = 4; break;
		default: bpp = 0;
	}
	
	/* Check if image is valid */
	if (!dib || bpp == 0 || width == 0 || height == 0 || !FreeImage_HasPixels(dib)) {
		if (dib) FreeImage_Unload(dib);
		std::cout << "Invalid image " << file << std::endl;
		return false;
	}
	
	std::cout << file << " Loaded. Converting.\n";
	
	/* Create CFR texture */
	CFR::Texture texture(
		width, height, 1,
		channels, bytes
	);
	
	/* Set texture pixels */
	for (unsigned int y = 0; y < height; y++) {
		BYTE* bits = FreeImage_GetScanLine(dib, height - y - 1);
		for (unsigned int x = 0; x < width; x++) {
			CFR::Pixel8 pixel(0, 0, 0, 0);
			BYTE *p = bits + (channels * x);
			if (channels >= 1) pixel.r = p[FI_RGBA_RED];
			if (channels >= 2) pixel.g = p[FI_RGBA_GREEN];
			if (channels >= 3) pixel.b = p[FI_RGBA_BLUE];
			if (channels >= 4) pixel.a = p[FI_RGBA_ALPHA];
			texture.setPixel8(pixel, x, y, 0);
		}
	}
	
	/* Unload image */
	FreeImage_Unload(dib);
	
	/* Save texture */
	try {
		texture.saveToFile(outFile);
	} catch (CFR::Exception &fail) {
		std::cout << "Failed to save " << removePath(outFile) << ": " << fail.what() << std::endl;
	}
	
	return true;
}
Exemple #5
0
/**
Encode a FIBITMAP to a WebP image
@param hmem Memory output stream, containing on return the encoded image
@param dib The FIBITMAP to encode
@param flags FreeImage save flags
@return Returns TRUE if successfull, returns FALSE otherwise
*/
static BOOL
EncodeImage(FIMEMORY *hmem, FIBITMAP *dib, int flags) {
	WebPPicture picture;	// Input buffer
	WebPConfig config;		// Coding parameters

	BOOL bIsFlipped = FALSE;

	try {
		const unsigned width = FreeImage_GetWidth(dib);
		const unsigned height = FreeImage_GetHeight(dib);
		const unsigned bpp = FreeImage_GetBPP(dib);
		const unsigned pitch = FreeImage_GetPitch(dib);

		// check image type
		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);

		if( !((image_type == FIT_BITMAP) && ((bpp == 24) || (bpp == 32))) )  {
			throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
		}

		// check format limits
		if(MAX(width, height) > WEBP_MAX_DIMENSION) {
			FreeImage_OutputMessageProc(s_format_id, "Unsupported image size: width x height = %d x %d", width, height);
			return FALSE;
		}

		// Initialize output I/O
		if(WebPPictureInit(&picture) == 1) {
			picture.writer = WebP_MemoryWriter;
			picture.custom_ptr = hmem;
			picture.width = (int)width;
			picture.height = (int)height;
		} else {
			throw "Couldn't initialize WebPPicture";
		}

		// --- Set encoding parameters ---

		// Initialize encoding parameters to default values
		WebPConfigInit(&config);

		// quality/speed trade-off (0=fast, 6=slower-better)
		config.method = 6;

		if((flags & WEBP_LOSSLESS) == WEBP_LOSSLESS) {
			// lossless encoding
			config.lossless = 1;
			picture.use_argb = 1;
		} else if((flags & 0x7F) > 0) {
			// lossy encoding
			config.lossless = 0;
			// quality is between 1 (smallest file) and 100 (biggest) - default to 75
			config.quality = (float)(flags & 0x7F);
			if(config.quality > 100) {
				config.quality = 100;
			}
		}

		// validate encoding parameters
		if(WebPValidateConfig(&config) == 0) {
			throw "Failed to initialize encoder";
		}

		// --- Perform encoding ---
		
		// Invert dib scanlines
		bIsFlipped = FreeImage_FlipVertical(dib);


		// convert dib buffer to output stream

		const BYTE *bits = FreeImage_GetBits(dib);

#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
		switch(bpp) {
			case 24:
				WebPPictureImportBGR(&picture, bits, pitch);
				break;
			case 32:
				WebPPictureImportBGRA(&picture, bits, pitch);
				break;
		}
#else
		switch(bpp) {
			case 24:
				WebPPictureImportRGB(&picture, bits, pitch);
				break;
			case 32:
				WebPPictureImportRGBA(&picture, bits, pitch);
				break;
		}

#endif // FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR

		if(!WebPEncode(&config, &picture)) {
			throw "Failed to encode image";
		}

		WebPPictureFree(&picture);

		if(bIsFlipped) {
			// invert dib scanlines
			FreeImage_FlipVertical(dib);
		}

		return TRUE;

	} catch (const char* text) {

		WebPPictureFree(&picture);

		if(bIsFlipped) {
			// invert dib scanlines
			FreeImage_FlipVertical(dib);
		}

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

	return FALSE;
}
Exemple #6
0
FREE_IMAGE_COLOR_TYPE DLL_CALLCONV
FreeImage_GetColorType(FIBITMAP *dib) {
	RGBQUAD *rgb;

	const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);

	// special bitmap type
	if(image_type != FIT_BITMAP) {
		switch(image_type) {
			case FIT_RGB16:
			case FIT_RGBF:
				return FIC_RGB;
			case FIT_RGBA16:
			case FIT_RGBAF:
				return FIC_RGBALPHA;
		}

		return FIC_MINISBLACK;
	}

	// standard image type
	switch (FreeImage_GetBPP(dib)) {
		case 1:
		{
			rgb = FreeImage_GetPalette(dib);

			if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) {
				rgb++;

				if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255))
					return FIC_MINISBLACK;				
			}

			if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) {
				rgb++;

				if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0))
					return FIC_MINISWHITE;				
			}

			return FIC_PALETTE;
		}

		case 4:
		case 8:	// Check if the DIB has a color or a greyscale palette
		{
			int ncolors = FreeImage_GetColorsUsed(dib);
		    int minisblack = 1;
			rgb = FreeImage_GetPalette(dib);

			for (int i = 0; i < ncolors; i++) {
				if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue))
					return FIC_PALETTE;

				// The DIB has a color palette if the greyscale isn't a linear ramp
				// Take care of reversed grey images
				if (rgb->rgbRed != i) {
					if ((ncolors-i-1) != rgb->rgbRed)
						return FIC_PALETTE;
				    else
						minisblack = 0;
				}

				rgb++;
			}

			return minisblack ? FIC_MINISBLACK : FIC_MINISWHITE;
		}

		case 16:
		case 24:
			return FIC_RGB;

		case 32:
		{
			if (FreeImage_GetICCProfile(dib)->flags & FIICC_COLOR_IS_CMYK)
				return FIC_CMYK;

			for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
				rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y);

				for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++)
					if (rgb[x].rgbReserved != 0xFF)
						return FIC_RGBALPHA;			
			}

			return FIC_RGB;
		}
				
		default :
			return FIC_MINISBLACK;
	}
}
Exemple #7
0
FIBITMAP * DLL_CALLCONV
FreeImage_Clone(FIBITMAP *dib) {
	if(!dib) return NULL;

	FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib);
	unsigned width       = FreeImage_GetWidth(dib);
	unsigned height      = FreeImage_GetHeight(dib);
	unsigned bpp         = FreeImage_GetBPP(dib);
	
	// check for pixel availability ...
	BOOL header_only = FreeImage_HasPixels(dib) ? FALSE : TRUE;
	// check whether this image has masks defined ...
	BOOL need_masks  = (bpp == 16 && type == FIT_BITMAP) ? TRUE : FALSE;

	// allocate a new dib
	FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, type, width, height, bpp,
			FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib));

	if (new_dib) {
		// save ICC profile links
		FIICCPROFILE *src_iccProfile = FreeImage_GetICCProfile(dib);
		FIICCPROFILE *dst_iccProfile = FreeImage_GetICCProfile(new_dib);

		// save metadata links
		METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
		METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata;

		// calculate the size of a FreeImage image
		// align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary
		// palette is aligned on a 16 bytes boundary
		// pixels are aligned on a 16 bytes boundary

		size_t dib_size = FreeImage_GetImageSizeHeader(header_only, width, height, bpp, need_masks);

		// copy the bitmap + internal pointers (remember to restore new_dib internal pointers later)
		memcpy(new_dib->data, dib->data, dib_size);

		// reset ICC profile link for new_dib
		memset(dst_iccProfile, 0, sizeof(FIICCPROFILE));

		// restore metadata link for new_dib
		((FREEIMAGEHEADER *)new_dib->data)->metadata = dst_metadata;

		// reset thumbnail link for new_dib
		((FREEIMAGEHEADER *)new_dib->data)->thumbnail = NULL;

		// copy possible ICC profile
		FreeImage_CreateICCProfile(new_dib, src_iccProfile->data, src_iccProfile->size);
		dst_iccProfile->flags = src_iccProfile->flags;

		// copy metadata models
		for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) {
			int model = (*i).first;
			TAGMAP *src_tagmap = (*i).second;

			if(src_tagmap) {
				// create a metadata model
				TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP();

				if(dst_tagmap) {
					// fill the model
					for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) {
						std::string dst_key = (*j).first;
						FITAG *dst_tag = FreeImage_CloneTag( (*j).second );

						// assign key and tag value
						(*dst_tagmap)[dst_key] = dst_tag;
					}

					// assign model and tagmap
					(*dst_metadata)[model] = dst_tagmap;
				}
			}
		}

		// copy the thumbnail
		FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib));

		return new_dib;
	}

	return NULL;
}
Exemple #8
0
/**
Write a FIBITMAP to a JNG stream
@param format_id ID of the caller
@param io Stream i/o functions
@param dib Image to be saved
@param handle Stream handle
@param flags Saving flags
@return Returns TRUE if successful, returns FALSE otherwise
*/
BOOL 
mng_WriteJNG(int format_id, FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int flags) {
	DWORD jng_width = 0;
	DWORD jng_height = 0;
	BYTE jng_color_type = 0;
	BYTE jng_image_sample_depth = 8;
	BYTE jng_image_compression_method = 8;	//  8: ISO-10918-1 Huffman-coded baseline JPEG.
	BYTE jng_image_interlace_method = 0;

	BYTE jng_alpha_sample_depth = 0;
	BYTE jng_alpha_compression_method = 0;
	BYTE jng_alpha_filter_method = 0;
	BYTE jng_alpha_interlace_method = 0;

	BYTE buffer[16];

	FIMEMORY *hJngMemory = NULL;
	FIMEMORY *hJpegMemory = NULL;
	FIMEMORY *hPngMemory = NULL;

	FIBITMAP *dib_rgb = NULL;
	FIBITMAP *dib_alpha = NULL;

	if(!dib || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
		return FALSE;
	}

	unsigned bpp = FreeImage_GetBPP(dib);

	switch(bpp) {
		case 8:
			if(FreeImage_GetColorType(dib) == FIC_MINISBLACK) {
				dib_rgb = dib;
				jng_color_type = MNG_COLORTYPE_JPEGGRAY;
			} else {
				// JPEG plugin will convert other types (FIC_MINISWHITE, FIC_PALETTE) to 24-bit on the fly
				//dib_rgb = FreeImage_ConvertTo24Bits(dib);
				dib_rgb = dib;
				jng_color_type = MNG_COLORTYPE_JPEGCOLOR;

			}
			break;
		case 24:
			dib_rgb = dib;
			jng_color_type = MNG_COLORTYPE_JPEGCOLOR;
			break;
		case 32:
			dib_rgb = FreeImage_ConvertTo24Bits(dib);
			jng_color_type = MNG_COLORTYPE_JPEGCOLORA;
			jng_alpha_sample_depth = 8;
			break;
		default:
			return FALSE;
	}

	jng_width = (DWORD)FreeImage_GetWidth(dib);
	jng_height = (DWORD)FreeImage_GetHeight(dib);

	try {
		hJngMemory = FreeImage_OpenMemory();

		// --- write JNG file signature ---
		FreeImage_WriteMemory(g_jng_signature, 1, 8, hJngMemory);

		// --- write a JHDR chunk ---
		SwapLong(&jng_width);
		SwapLong(&jng_height);
		memcpy(&buffer[0], &jng_width, 4);
		memcpy(&buffer[4], &jng_height, 4);
		SwapLong(&jng_width);
		SwapLong(&jng_height);
		buffer[8] = jng_color_type;
		buffer[9] = jng_image_sample_depth;
		buffer[10] = jng_image_compression_method;
		buffer[11] = jng_image_interlace_method;
		buffer[12] = jng_alpha_sample_depth;
		buffer[13] = jng_alpha_compression_method;
		buffer[14] = jng_alpha_filter_method;
		buffer[15] = jng_alpha_interlace_method;
		mng_WriteChunk(mng_JHDR, &buffer[0], 16, hJngMemory);

		// --- write a sequence of JDAT chunks ---
		hJpegMemory = FreeImage_OpenMemory();
		flags |= JPEG_BASELINE;
		if(!FreeImage_SaveToMemory(FIF_JPEG, dib_rgb, hJpegMemory, flags)) {
			throw (const char*)NULL;
		}
		if(dib_rgb != dib) {
			FreeImage_Unload(dib_rgb);
			dib_rgb = NULL;
		}
		{
			BYTE *jpeg_data = NULL;
			DWORD size_in_bytes = 0;
			
			// get a pointer to the stream buffer
			FreeImage_AcquireMemory(hJpegMemory, &jpeg_data, &size_in_bytes);
			// write chunks
			for(DWORD k = 0; k < size_in_bytes;) {
				DWORD bytes_left = size_in_bytes - k;
				DWORD chunk_size = MIN(JPEG_CHUNK_SIZE, bytes_left);
				mng_WriteChunk(mng_JDAT, &jpeg_data[k], chunk_size, hJngMemory);
				k += chunk_size;
			}
		}
		FreeImage_CloseMemory(hJpegMemory);
		hJpegMemory = NULL;

		// --- write alpha layer as a sequence of IDAT chunk ---
		if((bpp == 32) && (jng_color_type == MNG_COLORTYPE_JPEGCOLORA)) {
			dib_alpha = FreeImage_GetChannel(dib, FICC_ALPHA);

			hPngMemory = FreeImage_OpenMemory();
			if(!FreeImage_SaveToMemory(FIF_PNG, dib_alpha, hPngMemory, PNG_DEFAULT)) {
				throw (const char*)NULL;
			}
			FreeImage_Unload(dib_alpha);
			dib_alpha = NULL;
			// get the IDAT chunk
			{		
				BOOL bResult = FALSE;
				DWORD start_pos = 0;
				DWORD next_pos = 0;
				long offset = 8;
				
				do {
					// find the next IDAT chunk from 'offset' position
					bResult = mng_FindChunk(hPngMemory, mng_IDAT, offset, &start_pos, &next_pos);
					if(!bResult) break;
					
					BYTE *png_data = NULL;
					DWORD size_in_bytes = 0;
					
					// get a pointer to the stream buffer
					FreeImage_AcquireMemory(hPngMemory, &png_data, &size_in_bytes);
					// write the IDAT chunk
					mng_WriteChunk(mng_IDAT, &png_data[start_pos+8], next_pos - start_pos - 12, hJngMemory);

					offset = next_pos;

				} while(bResult);
			}

			FreeImage_CloseMemory(hPngMemory);
			hPngMemory = NULL;
		}

		// --- write a IEND chunk ---
		mng_WriteChunk(mng_IEND, NULL, 0, hJngMemory);

		// write the JNG on output stream
		{
			BYTE *jng_data = NULL;
			DWORD size_in_bytes = 0;
			FreeImage_AcquireMemory(hJngMemory, &jng_data, &size_in_bytes);
			io->write_proc(jng_data, 1, size_in_bytes, handle);			
		}

		FreeImage_CloseMemory(hJngMemory);
		FreeImage_CloseMemory(hJpegMemory);
		FreeImage_CloseMemory(hPngMemory);

		return TRUE;

	} catch(const char *text) {
		FreeImage_CloseMemory(hJngMemory);
		FreeImage_CloseMemory(hJpegMemory);
		FreeImage_CloseMemory(hPngMemory);
		if(dib_rgb && (dib_rgb != dib)) {
			FreeImage_Unload(dib_rgb);
		}
		FreeImage_Unload(dib_alpha);
		if(text) {
			FreeImage_OutputMessageProc(format_id, text);
		}
		return FALSE;
	}
}
Exemple #9
0
/**
Load a FIBITMAP from a MNG or a JNG stream
@param format_id ID of the caller
@param io Stream i/o functions
@param handle Stream handle
@param Offset Start of the first chunk
@param flags Loading flags
@return Returns a dib if successful, returns NULL otherwise
*/
FIBITMAP* 
mng_ReadChunks(int format_id, FreeImageIO *io, fi_handle handle, long Offset, int flags = 0) {
	DWORD mLength = 0;
	BYTE mChunkName[5];
	BYTE *mChunk = NULL;
	DWORD crc_file;
	long LastOffset;
	long mOrigPos;
	BYTE *PLTE_file_chunk = NULL;	// whole PLTE chunk (lentgh, name, array, crc)
	DWORD PLTE_file_size = 0;		// size of PLTE chunk

	BOOL m_HasGlobalPalette = FALSE; // may turn to TRUE in PLTE chunk
	unsigned m_TotalBytesOfChunks = 0;
	FIBITMAP *dib = NULL;
	FIBITMAP *dib_alpha = NULL;

	FIMEMORY *hJpegMemory = NULL;
	FIMEMORY *hPngMemory = NULL;
	FIMEMORY *hIDATMemory = NULL;

	// ---
	DWORD jng_width = 0;
	DWORD jng_height = 0;
	BYTE jng_color_type = 0;
	BYTE jng_image_sample_depth = 0;
	BYTE jng_image_compression_method = 0;

	BYTE jng_alpha_sample_depth = 0;
	BYTE jng_alpha_compression_method = 0;
	BYTE jng_alpha_filter_method = 0;
	BYTE jng_alpha_interlace_method = 0;

	DWORD mng_frame_width = 0;
	DWORD mng_frame_height = 0;
	DWORD mng_ticks_per_second = 0;
	DWORD mng_nominal_layer_count = 0;
	DWORD mng_nominal_frame_count = 0;
	DWORD mng_nominal_play_time = 0;
	DWORD mng_simplicity_profile = 0;


	DWORD res_x = 2835;	// 72 dpi
	DWORD res_y = 2835;	// 72 dpi
	RGBQUAD rgbBkColor = {0, 0, 0, 0};
	WORD bk_red, bk_green, bk_blue;
	BOOL hasBkColor = FALSE;
	BOOL mHasIDAT = FALSE;

	tEXtMAP key_value_pair;

	// ---

	BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
	
	// get the file size
	const long mLOF = mng_LOF(io, handle);
	// go to the first chunk
	io->seek_proc(handle, Offset, SEEK_SET);

	try {
		BOOL mEnd = FALSE;

		while(mEnd == FALSE) {
			// start of the chunk
			LastOffset = io->tell_proc(handle);
			// read length
			mLength = 0;			
			io->read_proc(&mLength, 1, sizeof(mLength), handle);
			mng_SwapLong(&mLength);
			// read name			
			io->read_proc(&mChunkName[0], 1, 4, handle);
			mChunkName[4] = '\0';

			if(mLength > 0) {
				mChunk = (BYTE*)realloc(mChunk, mLength);
				if(!mChunk) {
					FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: out of memory", mChunkName);
					throw (const char*)NULL;
				}				
				Offset = io->tell_proc(handle);
				if(Offset + (long)mLength > mLOF) {
					FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: unexpected end of file", mChunkName);
					throw (const char*)NULL;
				}
				// read chunk
				io->read_proc(mChunk, 1, mLength, handle);
			}
			// read crc
			io->read_proc(&crc_file, 1, sizeof(crc_file), handle);
			mng_SwapLong(&crc_file);
			// check crc
			DWORD crc_check = FreeImage_ZLibCRC32(0, &mChunkName[0], 4);
			crc_check = FreeImage_ZLibCRC32(crc_check, mChunk, mLength);
			if(crc_check != crc_file) {
				FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: bad CRC", mChunkName);
				throw (const char*)NULL;
			}		

			switch( mng_GetChunckType(mChunkName) ) {
				case MHDR:
					// The MHDR chunk is always first in all MNG datastreams except for those 
					// that consist of a single PNG or JNG datastream with a PNG or JNG signature. 
					if(mLength == 28) {
						memcpy(&mng_frame_width, &mChunk[0], 4);
						memcpy(&mng_frame_height, &mChunk[4], 4);
						memcpy(&mng_ticks_per_second, &mChunk[8], 4);
						memcpy(&mng_nominal_layer_count, &mChunk[12], 4);
						memcpy(&mng_nominal_frame_count, &mChunk[16], 4);
						memcpy(&mng_nominal_play_time, &mChunk[20], 4);
						memcpy(&mng_simplicity_profile, &mChunk[24], 4);

						mng_SwapLong(&mng_frame_width);
						mng_SwapLong(&mng_frame_height);
						mng_SwapLong(&mng_ticks_per_second);
						mng_SwapLong(&mng_nominal_layer_count);
						mng_SwapLong(&mng_nominal_frame_count);
						mng_SwapLong(&mng_nominal_play_time);
						mng_SwapLong(&mng_simplicity_profile);

					} else {
						FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: size is %d instead of 28", mChunkName, mLength);
					}
					break;

				case MEND:
					mEnd = TRUE;
					break;

				case LOOP:
				case ENDL:
					break;
				case DEFI:
					break;
				case SAVE:
				case SEEK:
				case TERM:
					break;
				case BACK:
					break;

					// Global "PLTE" and "tRNS" (if any).  PNG "PLTE" will be of 0 byte, as it uses global data.
				case PLTE:	// Global
					m_HasGlobalPalette = TRUE;
					PLTE_file_size = mLength + 12; // (lentgh, name, array, crc) = (4, 4, mLength, 4)
					PLTE_file_chunk = (BYTE*)realloc(PLTE_file_chunk, PLTE_file_size);
					if(!PLTE_file_chunk) {
						FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: out of memory", mChunkName);
						throw (const char*)NULL;
					} else {
						mOrigPos = io->tell_proc(handle);
						// seek to the start of the chunk
						io->seek_proc(handle, LastOffset, SEEK_SET);
						// load the whole chunk
						io->read_proc(PLTE_file_chunk, 1, PLTE_file_size, handle);
						// go to the start of the next chunk
						io->seek_proc(handle, mOrigPos, SEEK_SET);
					}
					break;

				case tRNS:	// Global
					break;
					
				case IHDR:
					Offset = LastOffset;
					// parse the PNG file and get its file size
					if(mng_CountPNGChunks(io, handle, Offset, &m_TotalBytesOfChunks) == FALSE) {
						// reach an unexpected end of file
						mEnd = TRUE;
						FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: unexpected end of PNG file", mChunkName);
						break;
					}
					
					// wrap the { IHDR, ..., IEND } chunks as a PNG stream
					if(hPngMemory == NULL) {
						hPngMemory = FreeImage_OpenMemory();
					}

					mOrigPos = io->tell_proc(handle);

					// write PNG file signature
					FreeImage_SeekMemory(hPngMemory, 0, SEEK_SET);
					FreeImage_WriteMemory(g_png_signature, 1, 8, hPngMemory);

					mChunk = (BYTE*)realloc(mChunk, m_TotalBytesOfChunks);
					if(!mChunk) {
						FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: out of memory", mChunkName);
						throw (const char*)NULL;
					}
					
					// on calling CountPNGChunks earlier, we were in Offset pos,
					// go back there
					io->seek_proc(handle, Offset, SEEK_SET);
					io->read_proc(mChunk, 1, m_TotalBytesOfChunks, handle);
					// Put back to original pos
					io->seek_proc(handle, mOrigPos, SEEK_SET);
					// write the PNG chunks
					FreeImage_WriteMemory(mChunk, 1, m_TotalBytesOfChunks, hPngMemory);

					// plug in global PLTE if local PLTE exists
					if(m_HasGlobalPalette) {
						// ensure we remove some local chunks, so that global
						// "PLTE" can be inserted right before "IDAT".
						mng_RemoveChunk(hPngMemory, mng_PLTE);
						mng_RemoveChunk(hPngMemory, mng_tRNS);
						mng_RemoveChunk(hPngMemory, mng_bKGD);
						// insert global "PLTE" chunk in its entirety before "IDAT"
						mng_InsertChunk(hPngMemory, mng_IDAT, PLTE_file_chunk, PLTE_file_size);
					}

					if(dib) FreeImage_Unload(dib);
					dib = mng_LoadFromMemoryHandle(hPngMemory, flags);

					// stop after the first image
					mEnd = TRUE;
					break;

				case JHDR:
					if(mLength == 16) {
						memcpy(&jng_width, &mChunk[0], 4);
						memcpy(&jng_height, &mChunk[4], 4);
						mng_SwapLong(&jng_width);
						mng_SwapLong(&jng_height);

						jng_color_type = mChunk[8];
						jng_image_sample_depth = mChunk[9];
						jng_image_compression_method = mChunk[10];
						BYTE jng_image_interlace_method = mChunk[11];

						jng_alpha_sample_depth = mChunk[12];
						jng_alpha_compression_method = mChunk[13];
						jng_alpha_filter_method = mChunk[14];
						jng_alpha_interlace_method = mChunk[15];
					} else {
						FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: invalid chunk length", mChunkName);
						throw (const char*)NULL;
					}
					break;

				case JDAT:
					if(hJpegMemory == NULL) {
						hJpegMemory = FreeImage_OpenMemory();
					}
					// as there may be several JDAT chunks, concatenate them
					FreeImage_WriteMemory(mChunk, 1, mLength, hJpegMemory);
					break;

				case IDAT:
					if(!header_only && (jng_alpha_compression_method == 0)) {
						// PNG grayscale IDAT format
						if(hIDATMemory == NULL) {
							hIDATMemory = FreeImage_OpenMemory();
							mHasIDAT = TRUE;
						}
						// as there may be several IDAT chunks, concatenate them
						FreeImage_WriteMemory(mChunk, 1, mLength, hIDATMemory);
					}
					break;

				case IEND:
					if(!hJpegMemory) {
						mEnd = TRUE;
						break;
					}
					// load the JPEG
					if(dib) FreeImage_Unload(dib);
					dib = mng_LoadFromMemoryHandle(hJpegMemory, flags);

					// load the PNG alpha layer
					if(mHasIDAT) {
						BYTE *data = NULL;
						DWORD size_in_bytes = 0;

						// get a pointer to the IDAT buffer
						FreeImage_AcquireMemory(hIDATMemory, &data, &size_in_bytes);
						if(data && size_in_bytes) {
							// wrap the IDAT chunk as a PNG stream
							if(hPngMemory == NULL) {
								hPngMemory = FreeImage_OpenMemory();
							}
							mng_WritePNGStream(jng_width, jng_height, jng_alpha_sample_depth, data, size_in_bytes, hPngMemory);
							// load the PNG
							if(dib_alpha) FreeImage_Unload(dib_alpha);
							dib_alpha = mng_LoadFromMemoryHandle(hPngMemory, flags);
						}
					}
					// stop the parsing
					mEnd = TRUE;
					break;

				case JDAA:
					break;

				case gAMA:
					break;

				case pHYs:
					// unit is pixels per meter
					memcpy(&res_x, &mChunk[0], 4);
					mng_SwapLong(&res_x);
					memcpy(&res_y, &mChunk[4], 4);
					mng_SwapLong(&res_y);
					break;

				case bKGD:
					memcpy(&bk_red, &mChunk[0], 2);
					mng_SwapShort(&bk_red);
					rgbBkColor.rgbRed = (BYTE)bk_red;
					memcpy(&bk_green, &mChunk[2], 2);
					mng_SwapShort(&bk_green);
					rgbBkColor.rgbGreen = (BYTE)bk_green;
					memcpy(&bk_blue, &mChunk[4], 2);
					mng_SwapShort(&bk_blue);
					rgbBkColor.rgbBlue = (BYTE)bk_blue;
					hasBkColor = TRUE;
					break;
				
				case tEXt:
					mng_SetMetadata_tEXt(key_value_pair, mChunk, mLength);
					break;

				case UNKNOWN_CHUNCK:
				default:
					break;


			} // switch( GetChunckType )
		} // while(!mEnd)

		FreeImage_CloseMemory(hJpegMemory);
		FreeImage_CloseMemory(hPngMemory);
		FreeImage_CloseMemory(hIDATMemory);
		free(mChunk);
		free(PLTE_file_chunk);

		// convert to 32-bit if a transparent layer is available
		if(!header_only && dib_alpha) {
			FIBITMAP *dst = FreeImage_ConvertTo32Bits(dib);
			if((FreeImage_GetBPP(dib_alpha) == 8) && (FreeImage_GetImageType(dib_alpha) == FIT_BITMAP)) {
				FreeImage_SetChannel(dst, dib_alpha, FICC_ALPHA);
			} else {
				FIBITMAP *dst_alpha = FreeImage_ConvertTo8Bits(dib_alpha);
				FreeImage_SetChannel(dst, dst_alpha, FICC_ALPHA);
				FreeImage_Unload(dst_alpha);
			}			
			FreeImage_Unload(dib);
			dib = dst;
		}
		FreeImage_Unload(dib_alpha);

		if(dib) {
			// set metadata
			FreeImage_SetDotsPerMeterX(dib, res_x);
			FreeImage_SetDotsPerMeterY(dib, res_y);
			if(hasBkColor) {
				FreeImage_SetBackgroundColor(dib, &rgbBkColor);
			}
			if(key_value_pair.size()) {
				for(tEXtMAP::iterator j = key_value_pair.begin(); j != key_value_pair.end(); j++) {
					std::string key = (*j).first;
					std::string value = (*j).second;
					mng_SetKeyValue(FIMD_COMMENTS, dib, key.c_str(), value.c_str());
				}
			}
		}
			
		return dib;

	} catch(const char *text) {
		FreeImage_CloseMemory(hJpegMemory);
		FreeImage_CloseMemory(hPngMemory);
		FreeImage_CloseMemory(hIDATMemory);
		free(mChunk);
		free(PLTE_file_chunk);
		FreeImage_Unload(dib);
		FreeImage_Unload(dib_alpha);
		if(text) {
			FreeImage_OutputMessageProc(format_id, text);
		}
		return NULL;
	}
}
Exemple #10
0
int ReadImageFile( const char *filename, uchar **imageData,
                   int *imageWidth, int *imageHeight, int *numComponents,
				   int flags )
{
// Determine image format.
    FREE_IMAGE_FORMAT fif = FreeImage_GetFileType( filename, 0 );
    if( fif == FIF_UNKNOWN ) fif = FreeImage_GetFIFFromFilename( filename );
    if( fif == FIF_UNKNOWN )
    {
        printf( "Error: Cannot determine image format of %s.\n", filename );
        return 0;
    }

// Read image data from file.
    FIBITMAP *dib = NULL;
    if( FreeImage_FIFSupportsReading( fif ) )
        dib = FreeImage_Load( fif, filename, flags );

    if( !dib )
    {
        printf( "Error: Cannot read image file %s.\n", filename );
        return 0;
    }

// Check image type.
    FREE_IMAGE_TYPE fit = FreeImage_GetImageType( dib );
    if ( fit != FIT_BITMAP )
    {
        FreeImage_Unload( dib );
        printf( "Error: Only 8-bits-per-component standard bitmap is supported.\n" );
        return 0;
    }

// Check bits per pixel.
    int bits_per_pixel = FreeImage_GetBPP( dib );
    if ( bits_per_pixel != 8 && bits_per_pixel != 16 && bits_per_pixel != 24 && bits_per_pixel != 32 )
    {
        FreeImage_Unload( dib );
        printf( "Error: Only 8, 16, 24, 32 bits per pixel are supported.\n" );
        return 0;
    }

    int _numComponents = bits_per_pixel / 8;
    int _imageWidth = FreeImage_GetWidth( dib );
    int _imageHeight = FreeImage_GetHeight( dib );
    uchar *_imageData = (uchar *) malloc( _imageWidth * _imageHeight * _numComponents );
    if ( _imageData == NULL )
    {
        FreeImage_Unload( dib );
        printf( "Error: Not enough memory.\n" );
        return 0;
    }

// Copy image in FIBITMAP to user image data.
    int imageDataCount = 0;

    if ( _numComponents == 1 )
    {
        for( int y = 0; y < _imageHeight; y++ )
        {
            BYTE *dibData = FreeImage_GetScanLine( dib, y );

            for( int x = 0; x < _imageWidth; x++) 
            {
                _imageData[imageDataCount++] = dibData[x];
            }
        }
    }
    else if ( _numComponents == 2 )
    {
        for( int y = 0; y < _imageHeight; y++ )
        {
            BYTE *dibData = FreeImage_GetScanLine( dib, y );

            for( int x = 0; x < _imageWidth; x++) 
            {
                _imageData[imageDataCount++] = dibData[0];
                _imageData[imageDataCount++] = dibData[1];
                dibData += _numComponents;
            }
        }
    }
    else if ( _numComponents == 3 )
    {
        for( int y = 0; y < _imageHeight; y++ )
        {
            BYTE *dibData = FreeImage_GetScanLine( dib, y );

            for( int x = 0; x < _imageWidth; x++) 
            {
                _imageData[imageDataCount++] = dibData[FI_RGBA_RED];
                _imageData[imageDataCount++] = dibData[FI_RGBA_GREEN];
                _imageData[imageDataCount++] = dibData[FI_RGBA_BLUE];
                dibData += _numComponents;
            }
        }
    }
    else if ( _numComponents == 4 )
    {
        for( int y = 0; y < _imageHeight; y++ )
        {
            BYTE *dibData = FreeImage_GetScanLine( dib, y );

            for( int x = 0; x < _imageWidth; x++) 
            {
                _imageData[imageDataCount++] = dibData[FI_RGBA_RED];
                _imageData[imageDataCount++] = dibData[FI_RGBA_GREEN];
                _imageData[imageDataCount++] = dibData[FI_RGBA_BLUE];
                _imageData[imageDataCount++] = dibData[FI_RGBA_ALPHA];
                dibData += _numComponents;
            }
        }
    }

    FreeImage_Unload( dib );

    (*numComponents) = _numComponents;
    (*imageWidth) = _imageWidth;
    (*imageHeight) = _imageHeight;
    (*imageData) = _imageData;
    return 1; 
}
Exemple #11
0
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
	const char *channel_name[4] = { "R", "G", "B", "A" };
	BOOL bIsFlipped = FALSE;
	half *halfData = NULL;

	if(!dib || !handle) return FALSE;

	try {
		// check for EXR_LC compression and verify that the format is RGB
		if((flags & EXR_LC) == EXR_LC) {
			FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
			if(((image_type != FIT_RGBF) && (image_type != FIT_RGBAF)) || ((flags & EXR_FLOAT) == EXR_FLOAT)) {
				THROW (Iex::IoExc, "EXR_LC compression is only available with RGB[A]F images");
			}
			if((FreeImage_GetWidth(dib) % 2) || (FreeImage_GetHeight(dib) % 2)) {
				THROW (Iex::IoExc, "EXR_LC compression only works when the width and height are a multiple of 2");
			}
		}

		// wrap the FreeImage IO stream
		C_OStream ostream(io, handle);

		// compression
		Imf::Compression compress;
		if((flags & EXR_NONE) == EXR_NONE) {
			// no compression
			compress = Imf::NO_COMPRESSION;
		} else if((flags & EXR_ZIP) == EXR_ZIP) {
			// zlib compression, in blocks of 16 scan lines
			compress = Imf::ZIP_COMPRESSION;
		} else if((flags & EXR_PIZ) == EXR_PIZ) {
			// piz-based wavelet compression
			compress = Imf::PIZ_COMPRESSION;
		} else if((flags & EXR_PXR24) == EXR_PXR24) {
			// lossy 24-bit float compression
			compress = Imf::PXR24_COMPRESSION;
		} else if((flags & EXR_B44) == EXR_B44) {
			// lossy 44% float compression
			compress = Imf::B44_COMPRESSION;
		} else {
			// default value
			compress = Imf::PIZ_COMPRESSION;
		}

		// create the header
		int width  = FreeImage_GetWidth(dib);
		int height = FreeImage_GetHeight(dib);
		int dx = 0, dy = 0;

		Imath::Box2i dataWindow (Imath::V2i (0, 0), Imath::V2i (width - 1, height - 1));
		Imath::Box2i displayWindow (Imath::V2i (-dx, -dy), Imath::V2i (width - dx - 1, height - dy - 1));

		Imf::Header header = Imf::Header(displayWindow, dataWindow, 1, 
			Imath::V2f(0,0), 1, 
			Imf::INCREASING_Y, compress);        		

		// handle thumbnail
		SetPreviewImage(dib, header);
		
		// check for EXR_LC compression
		if((flags & EXR_LC) == EXR_LC) {
			return SaveAsEXR_LC(ostream, dib, header, width, height);
		}

		// output pixel type
		Imf::PixelType pixelType;
		if((flags & EXR_FLOAT) == EXR_FLOAT) {
			pixelType = Imf::FLOAT;	// save as float data type
		} else {
			// default value
			pixelType = Imf::HALF;	// save as half data type
		}

		// check the data type and number of channels
		int components = 0;
		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
		switch(image_type) {
			case FIT_FLOAT:
				components = 1;
				// insert luminance channel
				header.channels().insert ("Y", Imf::Channel(pixelType));
				break;
			case FIT_RGBF:
				components = 3;
				for(int c = 0; c < components; c++) {
					// insert R, G and B channels
					header.channels().insert (channel_name[c], Imf::Channel(pixelType));
				}
				break;
			case FIT_RGBAF:
				components = 4;
				for(int c = 0; c < components; c++) {
					// insert R, G, B and A channels
					header.channels().insert (channel_name[c], Imf::Channel(pixelType));
				}
				break;
			default:
				THROW (Iex::ArgExc, "Cannot save: invalid data type.\nConvert the image to float before saving as OpenEXR.");
		}

		// build a frame buffer (i.e. what we have on input)
		Imf::FrameBuffer frameBuffer;

		BYTE *bits = NULL;	// pointer to our pixel buffer
		size_t bytespp = 0;	// size of our pixel in bytes
		size_t bytespc = 0;	// size of our pixel component in bytes
		unsigned pitch = 0;	// size of our yStride in bytes


		if(pixelType == Imf::HALF) {
			// convert from float to half
			halfData = new(std::nothrow) half[width * height * components];
			if(!halfData) {
				THROW (Iex::NullExc, FI_MSG_ERROR_MEMORY);
			}

			for(int y = 0; y < height; y++) {
				float *src_bits = (float*)FreeImage_GetScanLine(dib, height - 1 - y);
				half *dst_bits = halfData + y * width * components;
				for(int x = 0; x < width; x++) {
					for(int c = 0; c < components; c++) {
						dst_bits[c] = src_bits[c];
					}
					src_bits += components;
					dst_bits += components;
				}
			}
			bits = (BYTE*)halfData;
			bytespc = sizeof(half);
			bytespp = sizeof(half) * components;
			pitch = sizeof(half) * width * components;
		} else if(pixelType == Imf::FLOAT) {
			// invert dib scanlines
			bIsFlipped = FreeImage_FlipVertical(dib);
		
			bits = FreeImage_GetBits(dib);
			bytespc = sizeof(float);
			bytespp = sizeof(float) * components;
			pitch = FreeImage_GetPitch(dib);
		}

		if(image_type == FIT_FLOAT) {
			frameBuffer.insert ("Y",	// name
				Imf::Slice (pixelType,	// type
				(char*)(bits),			// base
				bytespp,				// xStride
				pitch));				// yStride
		} else if((image_type == FIT_RGBF) || (image_type == FIT_RGBAF)) {			
			for(int c = 0; c < components; c++) {
				char *channel_base = (char*)(bits) + c*bytespc;
				frameBuffer.insert (channel_name[c],// name
					Imf::Slice (pixelType,			// type
					channel_base,					// base
					bytespp,	// xStride
					pitch));	// yStride
			}
		}

		// write the data
		Imf::OutputFile file (ostream, header);
		file.setFrameBuffer (frameBuffer);
		file.writePixels (height);

		if(halfData != NULL) {
			delete[] halfData;
		}
		if(bIsFlipped) {
			// invert dib scanlines
			FreeImage_FlipVertical(dib);
		}

		return TRUE;

	} catch(Iex::BaseExc & e) {
		if(halfData != NULL) {
			delete[] halfData;
		}
		if(bIsFlipped) {
			// invert dib scanlines
			FreeImage_FlipVertical(dib);
		}

		FreeImage_OutputMessageProc(s_format_id, e.what());

		return FALSE;
	}	
}
static inline void 
SET_FREEIMAGE_MARKER(BITMAPINFOHEADER *bmih, FIBITMAP *dib) {
	// Windows constants goes from 0L to 5L
	// Add 0xFF to avoid conflicts
	bmih->biCompression = 0xFF + FreeImage_GetImageType(dib);
}
Exemple #13
0
/**
Convert a FIBITMAP to a OpenJPEG image
@param format_id Plugin ID
@param dib FreeImage image
@param parameters Compression parameters
@return Returns the converted image if successful, returns NULL otherwise
*/
opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters) {
	int prec, numcomps, x, y, index;
	OPJ_COLOR_SPACE color_space;
	opj_image_cmptparm_t cmptparm[4];	// maximum of 4 components 
	opj_image_t *image = NULL;			// image to encode

	try {
		int w = FreeImage_GetWidth(dib);
		int h = FreeImage_GetHeight(dib);

		// get image characteristics
		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);

		if(image_type == FIT_BITMAP) {
			// standard image ...
			prec = 8;
			switch(FreeImage_GetColorType(dib)) {
				case FIC_MINISBLACK:
					numcomps = 1;
					color_space = CLRSPC_GRAY;
					break;
				case FIC_RGB:
					if(FreeImage_GetBPP(dib) == 32) {
						// 32-bit image with a fully opaque layer
						numcomps = 4;
						color_space = CLRSPC_SRGB;
					} else {
						// 24-bit image
						numcomps = 3;
						color_space = CLRSPC_SRGB;
					}
					break;
				case FIC_RGBALPHA:
					numcomps = 4;
					color_space = CLRSPC_SRGB;
					break;
				default:
					return NULL;
			}
		} else {
			// HDR image ...
			prec = 16;
			switch(image_type) {
				case FIT_UINT16:
					numcomps = 1;
					color_space = CLRSPC_GRAY;
					break;
				case FIT_RGB16:
					numcomps = 3;
					color_space = CLRSPC_SRGB;
					break;
				case FIT_RGBA16:
					numcomps = 4;
					color_space = CLRSPC_SRGB;
					break;
				default:
					return NULL;
			}
		}

		// initialize image components 
		memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t));
		for(int i = 0; i < numcomps; i++) {
			cmptparm[i].dx = parameters->subsampling_dx;
			cmptparm[i].dy = parameters->subsampling_dy;
			cmptparm[i].w = w;
			cmptparm[i].h = h;
			cmptparm[i].prec = prec;
			cmptparm[i].bpp = prec;
			cmptparm[i].sgnd = 0;
		}
		// create the image 
		image = opj_image_create(numcomps, &cmptparm[0], color_space);
		if(!image) {
			throw FI_MSG_ERROR_DIB_MEMORY;
		}

		// set image offset and reference grid 
		image->x0 = parameters->image_offset_x0;
		image->y0 = parameters->image_offset_y0;
		image->x1 = parameters->image_offset_x0 + (w - 1) *	parameters->subsampling_dx + 1;
		image->y1 = parameters->image_offset_y0 + (h - 1) *	parameters->subsampling_dy + 1;

		// set image data 
		if(prec == 8) {
			switch(numcomps) {
				case 1:
					index = 0;
					for(y = 0; y < h; y++) {
						BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
						for(x = 0; x < w; x++) {
							image->comps[0].data[index] = bits[x];
							index++;
						}
					}
					break;
				case 3:
					index = 0;
					for(y = 0; y < h; y++) {
						BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
						for(x = 0; x < w; x++) {
							image->comps[0].data[index] = bits[FI_RGBA_RED];
							image->comps[1].data[index] = bits[FI_RGBA_GREEN];
							image->comps[2].data[index] = bits[FI_RGBA_BLUE];
							bits += 3;
							index++;
						}
					}
					break;
				case 4:
					index = 0;
					for(y = 0; y < h; y++) {
						BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
						for(x = 0; x < w; x++) {
							image->comps[0].data[index] = bits[FI_RGBA_RED];
							image->comps[1].data[index] = bits[FI_RGBA_GREEN];
							image->comps[2].data[index] = bits[FI_RGBA_BLUE];
							image->comps[3].data[index] = bits[FI_RGBA_ALPHA];
							bits += 4;
							index++;
						}
					}
					break;
			}
		}
		else if(prec == 16) {
			switch(numcomps) {
				case 1:
					index = 0;
					for(y = 0; y < h; y++) {
						WORD *bits = (WORD*)FreeImage_GetScanLine(dib, h - 1 - y);
						for(x = 0; x < w; x++) {
							image->comps[0].data[index] = bits[x];
							index++;
						}
					}
					break;
				case 3:
					index = 0;
					for(y = 0; y < h; y++) {
						FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, h - 1 - y);
						for(x = 0; x < w; x++) {
							image->comps[0].data[index] = bits[x].red;
							image->comps[1].data[index] = bits[x].green;
							image->comps[2].data[index] = bits[x].blue;
							index++;
						}
					}
					break;
				case 4:
					index = 0;
					for(y = 0; y < h; y++) {
						FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, h - 1 - y);
						for(x = 0; x < w; x++) {
							image->comps[0].data[index] = bits[x].red;
							image->comps[1].data[index] = bits[x].green;
							image->comps[2].data[index] = bits[x].blue;
							image->comps[3].data[index] = bits[x].alpha;
							index++;
						}
					}
					break;
			}
		}

		return image;

	} catch (const char *text) {
		if(image) opj_image_destroy(image);
		FreeImage_OutputMessageProc(format_id, text);
		return NULL;
	}
}
//!!!be sure to release memory before return null
ResHandler* WIPResourceManager::alloc(const char* filename, WIPResourceType type)
{
    ResHandler* res = new ResHandler;
    switch (type)
    {
    case TEXT:
    {

    }
    break;
    case TEXTURE:
    {
        TextureData *data = new TextureData;
        //初始化FreeImage
        FreeImage_Initialise(TRUE);

        FIBITMAP* bmpConverted = NULL;
        FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
        fif = FreeImage_GetFileType(filename);
        if (fif == FIF_UNKNOWN)
            fif = FreeImage_GetFIFFromFilename(filename);
        if ((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif))
        {

            FIBITMAP *dib = FreeImage_Load(fif, filename);

            if (!dib)
            {
                printf("[fatal error]: \"%s\" load error!\n", filename);
                delete data;
                delete_handler(res);
                return NULL;
            }

            // we are top left, FIBITMAP is bottom left
            FreeImage_FlipVertical(dib);
            //get infomation
            FREE_IMAGE_TYPE imgType = FreeImage_GetImageType(dib);
            FREE_IMAGE_COLOR_TYPE colorType = FreeImage_GetColorType(dib);
            unsigned int bpp = FreeImage_GetBPP(dib);

            data->bpp = bpp;
            data->color_type = colorType;
            data->image_type = imgType;
            data->channel = 4;

            int x, y;
            RGBQUAD m_rgb;

            //获取图片长宽
            int width = (int)FreeImage_GetWidth(dib);
            int height = (int)FreeImage_GetHeight(dib);

            unsigned char* imgBuf = new unsigned char[width*height * 4];



            bool is_tr = FreeImage_IsTransparent(dib);

            bool is_little = FreeImage_IsLittleEndian();
            //获取图片数据
            //按RGBA格式保存到数组中
            for (y = 0; y<height; y++)
            {
                for (x = 0; x<width; x++)
                {
                    //获取像素值
                    FreeImage_GetPixelColor(dib, x, y, &m_rgb);

                    if (is_little)
                    {
                        imgBuf[y*width * 4 + x * 4 + 0] = m_rgb.rgbRed;
                        imgBuf[y*width * 4 + x * 4 + 1] = m_rgb.rgbGreen;
                        imgBuf[y*width * 4 + x * 4 + 2] = m_rgb.rgbBlue;
                        //判断是否透明图片
                        //如果是就取alpha值保存
                        if (is_tr)
                            imgBuf[y*width * 4 + x * 4 + 3] = m_rgb.rgbReserved;
                        else
                            imgBuf[y*width * 4 + x * 4 + 3] = 255;
                    }
                    else
                    {
                        //大端警告!
                        //Big Endian Warnning!
                        printf("Note:This is a Big endian!\n");
                    }
                }
            }


            data->width = width;
            data->height = height;
            data->size = height*width * 4;


            FreeImage_Unload(dib);

            res->file_name = filename;
            res->extra = data;
            res->nref = 1;
            res->ptr = imgBuf;
            res->size = width*height * 4;
            res->type = TEXTURE;

            _map[filename] = res;

            return res;
        }
    }
    break;

    case SOUND:
    {
    }
    default:
        return res;
        break;
    }
    delete_handler(res);
    return NULL;
}
FIBITMAP * DLL_CALLCONV
FreeImage_ConvertToUINT16(FIBITMAP *dib) {
	FIBITMAP *src = NULL;
	FIBITMAP *dst = NULL;

	if(!FreeImage_HasPixels(dib)) return NULL;

	const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);

	// check for allowed conversions 
	switch(src_type) {
		case FIT_BITMAP:
		{
			// convert to greyscale if needed
			if((FreeImage_GetBPP(dib) == 8) && (FreeImage_GetColorType(dib) == FIC_MINISBLACK)) {
				src = dib;
			} else {
				src = FreeImage_ConvertToGreyscale(dib);
				if(!src) return NULL;
			}
			break;
		}
		case FIT_UINT16:
			// UINT16 type : clone the src
			return FreeImage_Clone(dib);
			break;
		case FIT_RGB16:
			// allow conversion from 48-bit RGB
			src = dib;
			break;
		case FIT_RGBA16:
			// allow conversion from 64-bit RGBA (ignore the alpha channel)
			src = dib;
			break;
		default:
			return NULL;
	}

	// allocate dst image

	const unsigned width = FreeImage_GetWidth(src);
	const unsigned height = FreeImage_GetHeight(src);

	dst = FreeImage_AllocateT(FIT_UINT16, width, height);
	if(!dst) return NULL;

	// copy metadata from src to dst
	FreeImage_CloneMetadata(dst, src);

	// convert from src type to UINT16

	switch(src_type) {
		case FIT_BITMAP:
		{
			for(unsigned y = 0; y < height; y++) {
				const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y);
				WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					dst_bits[x] = src_bits[x] << 8;
				}
			}
		}
		break;

		case FIT_RGB16:
		{
			for(unsigned y = 0; y < height; y++) {
				const FIRGB16 *src_bits = (FIRGB16*)FreeImage_GetScanLine(src, y);
				WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					// convert to grey
					dst_bits[x] = (WORD)LUMA_REC709(src_bits[x].red, src_bits[x].green, src_bits[x].blue);
				}
			}
		}
		break;

		case FIT_RGBA16:
		{
			for(unsigned y = 0; y < height; y++) {
				const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y);
				WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					// convert to grey
					dst_bits[x] = (WORD)LUMA_REC709(src_bits[x].red, src_bits[x].green, src_bits[x].blue);
				}
			}
		}
		break;

		default:
			break;
	}

	if(src != dib) {
		FreeImage_Unload(src);
	}

	return dst;
}
Exemple #16
0
/** @brief Perfoms an histogram transformation on a 8, 24 or 32-bit image 
according to the values of a lookup table (LUT).

The transformation is done as follows.<br>
Image 8-bit : if the image has a color palette, the LUT is applied to this palette, 
otherwise, it is applied to the grey values.<br>
Image 24-bit & 32-bit : if channel == FICC_RGB, the same LUT is applied to each color
plane (R,G, and B). Otherwise, the LUT is applied to the specified channel only.
@param src Input image to be processed.
@param LUT Lookup table. <b>The size of 'LUT' is assumed to be 256.</b>
@param channel The color channel to be processed (only used with 24 & 32-bit DIB).
@return Returns TRUE if successful, FALSE otherwise.
@see FREE_IMAGE_COLOR_CHANNEL
*/
BOOL DLL_CALLCONV 
FreeImage_AdjustCurve(FIBITMAP *src, BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel) {
	unsigned x, y;
	BYTE *bits = NULL;

	if(!FreeImage_HasPixels(src) || !LUT || (FreeImage_GetImageType(src) != FIT_BITMAP))
		return FALSE;

	int bpp = FreeImage_GetBPP(src);
	if((bpp != 8) && (bpp != 24) && (bpp != 32))
		return FALSE;

	// apply the LUT
	switch(bpp) {

		case 8 :
		{
			// if the dib has a colormap, apply the LUT to it
			// else, apply the LUT to pixel values

			if(FreeImage_GetColorType(src) == FIC_PALETTE) {
				RGBQUAD *rgb = FreeImage_GetPalette(src);
				for (unsigned pal = 0; pal < FreeImage_GetColorsUsed(src); pal++) {
					rgb->rgbRed   = LUT[rgb->rgbRed];
					rgb->rgbGreen = LUT[rgb->rgbGreen];
					rgb->rgbBlue  = LUT[rgb->rgbBlue];
					rgb++;
				}
			}
			else {
				for(y = 0; y < FreeImage_GetHeight(src); y++) {
					bits =  FreeImage_GetScanLine(src, y);
					for(x = 0; x < FreeImage_GetWidth(src); x++) {
						bits[x] = LUT[ bits[x] ];
					}
				}
			}

			break;
		}

		case 24 :
		case 32 :
		{
			int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);

			switch(channel) {
				case FICC_RGB :
					for(y = 0; y < FreeImage_GetHeight(src); y++) {
						bits =  FreeImage_GetScanLine(src, y);
						for(x = 0; x < FreeImage_GetWidth(src); x++) {
							bits[FI_RGBA_BLUE]	= LUT[ bits[FI_RGBA_BLUE] ];	// B
							bits[FI_RGBA_GREEN] = LUT[ bits[FI_RGBA_GREEN] ];	// G
							bits[FI_RGBA_RED]	= LUT[ bits[FI_RGBA_RED] ];		// R
							
							bits += bytespp;
						}
					}
					break;

				case FICC_BLUE :
					for(y = 0; y < FreeImage_GetHeight(src); y++) {
						bits =  FreeImage_GetScanLine(src, y);
						for(x = 0; x < FreeImage_GetWidth(src); x++) {
							bits[FI_RGBA_BLUE] = LUT[ bits[FI_RGBA_BLUE] ];		// B
							
							bits += bytespp;
						}
					}
					break;

				case FICC_GREEN :
					for(y = 0; y < FreeImage_GetHeight(src); y++) {
						bits =  FreeImage_GetScanLine(src, y);
						for(x = 0; x < FreeImage_GetWidth(src); x++) {
							bits[FI_RGBA_GREEN] = LUT[ bits[FI_RGBA_GREEN] ];	// G
							
							bits += bytespp;
						}
					}
					break;

				case FICC_RED :
					for(y = 0; y < FreeImage_GetHeight(src); y++) {
						bits =  FreeImage_GetScanLine(src, y);
						for(x = 0; x < FreeImage_GetWidth(src); x++) {
							bits[FI_RGBA_RED] = LUT[ bits[FI_RGBA_RED] ];		// R
							
							bits += bytespp;
						}
					}
					break;
					
				case FICC_ALPHA :
					if(32 == bpp) {
						for(y = 0; y < FreeImage_GetHeight(src); y++) {
							bits =  FreeImage_GetScanLine(src, y);
							for(x = 0; x < FreeImage_GetWidth(src); x++) {
								bits[FI_RGBA_ALPHA] = LUT[ bits[FI_RGBA_ALPHA] ];	// A
								
								bits += bytespp;
							}
						}
					}
					break;

				default:
					break;
			}
			break;
		}
	}

	return TRUE;
}
Exemple #17
0
FIBITMAP * DLL_CALLCONV
FreeImage_Clone(FIBITMAP *dib) {
	if(!dib) return NULL;

	unsigned width  = FreeImage_GetWidth(dib);
	unsigned height = FreeImage_GetHeight(dib);
	unsigned bpp    = FreeImage_GetBPP(dib);
	
	// allocate a new dib
	FIBITMAP *new_dib = FreeImage_AllocateT(FreeImage_GetImageType(dib), width, height, bpp, 
			FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib));

	if (new_dib) {
		// save ICC profile links
		FIICCPROFILE *src_iccProfile = FreeImage_GetICCProfile(dib);
		FIICCPROFILE *dst_iccProfile = FreeImage_GetICCProfile(new_dib);

		// save metadata links
		METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
		METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata;

		// calculate the size of a FreeImage image
		// align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary
		// palette is aligned on a 16 bytes boundary
		// pixels are aligned on a 16 bytes boundary

		unsigned dib_size = FreeImage_GetImageSize(width, height, bpp); 

		// copy the bitmap + internal pointers (remember to restore new_dib internal pointers later)
		memcpy(new_dib->data, dib->data, dib_size);

		// reset ICC profile link for new_dib
		memset(dst_iccProfile, 0, sizeof(FIICCPROFILE));

		// restore metadata link for new_dib
		((FREEIMAGEHEADER *)new_dib->data)->metadata = dst_metadata;

		// copy possible ICC profile
		FreeImage_CreateICCProfile(new_dib, src_iccProfile->data, src_iccProfile->size);
		dst_iccProfile->flags = src_iccProfile->flags;

		// copy metadata models
		for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) {
			int model = (*i).first;
			TAGMAP *src_tagmap = (*i).second;

			if(src_tagmap) {
				// create a metadata model
				TAGMAP *dst_tagmap = new TAGMAP();

				// fill the model
				for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) {
					std::string dst_key = (*j).first;
					FITAG *dst_tag = FreeImage_CloneTag( (*j).second );

					// assign key and tag value
					(*dst_tagmap)[dst_key] = dst_tag;
				}

				// assign model and tagmap
				(*dst_metadata)[model] = dst_tagmap;
			}
		}

		return new_dib;
	}

	return NULL;
}
Exemple #18
0
/** @brief Inverts each pixel data.

@param src Input image to be processed.
@return Returns TRUE if successful, FALSE otherwise.
*/
BOOL DLL_CALLCONV 
FreeImage_Invert(FIBITMAP *src) {

	if (!FreeImage_HasPixels(src)) return FALSE;
	
	unsigned i, x, y, k;
	
	const unsigned width = FreeImage_GetWidth(src);
	const unsigned height = FreeImage_GetHeight(src);
	const unsigned bpp = FreeImage_GetBPP(src);

	FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);

	if(image_type == FIT_BITMAP) {
		switch(bpp) {
			case 1 :
			case 4 :
			case 8 :
			{
				// if the dib has a colormap, just invert it
				// else, keep the linear grayscale

				if (FreeImage_GetColorType(src) == FIC_PALETTE) {
					RGBQUAD *pal = FreeImage_GetPalette(src);

					for(i = 0; i < FreeImage_GetColorsUsed(src); i++) {
						pal[i].rgbRed	= 255 - pal[i].rgbRed;
						pal[i].rgbGreen = 255 - pal[i].rgbGreen;
						pal[i].rgbBlue	= 255 - pal[i].rgbBlue;
					}
				} else {
					for(y = 0; y < height; y++) {
						BYTE *bits = FreeImage_GetScanLine(src, y);

						for (x = 0; x < FreeImage_GetLine(src); x++) {
							bits[x] = ~bits[x];
						}
					}
				}

				break;
			}		

			case 24 :
			case 32 :
			{
				// Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit)
				const unsigned bytespp = FreeImage_GetLine(src) / width;

				for(y = 0; y < height; y++) {
					BYTE *bits = FreeImage_GetScanLine(src, y);
					for(x = 0; x < width; x++) {
						for(k = 0; k < bytespp; k++) {
							bits[k] = ~bits[k];
						}
						bits += bytespp;
					}
				}

				break;
			}
			default:
				return FALSE;
		}
	}
	else if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
		// Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
		const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD);

		for(y = 0; y < height; y++) {
			WORD *bits = (WORD*)FreeImage_GetScanLine(src, y);
			for(x = 0; x < width; x++) {
				for(k = 0; k < wordspp; k++) {
					bits[k] = ~bits[k];
				}
				bits += wordspp;
			}
		}
	}
	else {
		// anything else ... 
		return FALSE;
	}
		
	return TRUE;
}
Exemple #19
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;
} 
Exemple #20
0
/** @brief Applies color mapping for one or several colors on a 1-, 4- or 8-bit
 palletized or a 16-, 24- or 32-bit high color image.

 This function maps up to <i>count</i> colors specified in <i>srccolors</i> to
 these specified in <i>dstcolors</i>. Thereby, color <i>srccolors[N]</i>,
 if found in the image, will be replaced by color <i>dstcolors[N]</i>. If
 parameter <i>swap</i> is TRUE, additionally all colors specified in
 <i>dstcolors</i> are also mapped to these specified in <i>srccolors</i>. For
 high color images, the actual image data will be modified whereas, for
 palletized images only the palette will be changed.<br>

 The function returns the number of pixels changed or zero, if no pixels were
 changed. 

 Both arrays <i>srccolors</i> and <i>dstcolors</i> are assumed not to hold less
 than <i>count</i> colors.<br>

 For 16-bit images, all colors specified are transparently converted to their 
 proper 16-bit representation (either in RGB555 or RGB565 format, which is
 determined by the image's red- green- and blue-mask).<br>

 <b>Note, that this behaviour is different from what FreeImage_ApplyPaletteIndexMapping()
 does, which modifies the actual image data on palletized images.</b>

 @param dib Input/output image to be processed.
 @param srccolors Array of colors to be used as the mapping source.
 @param dstcolors Array of colors to be used as the mapping destination.
 @param count The number of colors to be mapped. This is the size of both
 <i>srccolors</i> and <i>dstcolors</i>.  
 @param ignore_alpha If TRUE, 32-bit images and colors are treated as 24-bit.
 @param swap If TRUE, source and destination colors are swapped, that is,
 each destination color is also mapped to the corresponding source color.  
 @return Returns the total number of pixels changed. 
 */
unsigned DLL_CALLCONV
FreeImage_ApplyColorMapping(FIBITMAP *dib, RGBQUAD *srccolors, RGBQUAD *dstcolors, unsigned count, BOOL ignore_alpha, BOOL swap) {
	unsigned result = 0;

	if (!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
		return 0;
	}

	// validate parameters
	if ((!srccolors) || (!dstcolors)|| (count < 1)) {
		return 0;
	}

	int bpp = FreeImage_GetBPP(dib);
	switch (bpp) {
		case 1:
		case 4:
		case 8: {
			unsigned size = FreeImage_GetColorsUsed(dib);
			RGBQUAD *pal = FreeImage_GetPalette(dib);
			RGBQUAD *a, *b;
			for (unsigned x = 0; x < size; x++) {
				for (unsigned j = 0; j < count; j++) {
					a = srccolors;
					b = dstcolors;
					for (int i = (swap ? 0 : 1); i < 2; i++) {
						if ((pal[x].rgbBlue == a[j].rgbBlue)&&(pal[x].rgbGreen == a[j].rgbGreen) &&(pal[x].rgbRed== a[j].rgbRed)) {
							pal[x].rgbBlue = b[j].rgbBlue;
							pal[x].rgbGreen = b[j].rgbGreen;
							pal[x].rgbRed = b[j].rgbRed;
							result++;
							j = count;
							break;
						}
						a = dstcolors;
						b = srccolors;
					}
				}
			}
			return result;
		}
		case 16: {
			WORD *src16 = (WORD *)malloc(sizeof(WORD) * count);
			if (NULL == src16) {
				return 0;
			}

			WORD *dst16 = (WORD *)malloc(sizeof(WORD) * count);
			if (NULL == dst16) {
				free(src16);
				return 0;
			}

			for (unsigned j = 0; j < count; j++) {
				src16[j] = RGBQUAD_TO_WORD(dib, (srccolors + j));
				dst16[j] = RGBQUAD_TO_WORD(dib, (dstcolors + j));
			}

			unsigned height = FreeImage_GetHeight(dib);
			unsigned width = FreeImage_GetWidth(dib);
			WORD *a, *b;
			for (unsigned y = 0; y < height; y++) {
				WORD *bits = (WORD *)FreeImage_GetScanLine(dib, y);
				for (unsigned x = 0; x < width; x++, bits++) {
					for (unsigned j = 0; j < count; j++) {
						a = src16;
						b = dst16;
						for (int i = (swap ? 0 : 1); i < 2; i++) {
							if (*bits == a[j]) {
								*bits = b[j];
								result++;
								j = count;
								break;
							}
							a = dst16;
							b = src16;
						}
					}
				}
			}
			free(src16);
			free(dst16);
			return result;
		}
		case 24: {
			unsigned height = FreeImage_GetHeight(dib);
			unsigned width = FreeImage_GetWidth(dib);
			RGBQUAD *a, *b;
			for (unsigned y = 0; y < height; y++) {
				BYTE *bits = FreeImage_GetScanLine(dib, y);
				for (unsigned x = 0; x < width; x++, bits += 3) {
					for (unsigned j = 0; j < count; j++) {
						a = srccolors;
						b = dstcolors;
						for (int i = (swap ? 0 : 1); i < 2; i++) {
							if ((bits[FI_RGBA_BLUE] == a[j].rgbBlue) && (bits[FI_RGBA_GREEN] == a[j].rgbGreen) &&(bits[FI_RGBA_RED] == a[j].rgbRed)) {
								bits[FI_RGBA_BLUE] = b[j].rgbBlue;
								bits[FI_RGBA_GREEN] = b[j].rgbGreen;
								bits[FI_RGBA_RED] = b[j].rgbRed;
								result++;
								j = count;
								break;
							}
							a = dstcolors;
							b = srccolors;
						}
					}
				}
			}
			return result;
		}
		case 32: {
			unsigned height = FreeImage_GetHeight(dib);
			unsigned width = FreeImage_GetWidth(dib);
			RGBQUAD *a, *b;
			for (unsigned y = 0; y < height; y++) {
				BYTE *bits = FreeImage_GetScanLine(dib, y);
				for (unsigned x = 0; x < width; x++, bits += 4) {
					for (unsigned j = 0; j < count; j++) {
						a = srccolors;
						b = dstcolors;
						for (int i = (swap ? 0 : 1); i < 2; i++) {
							if ((bits[FI_RGBA_BLUE] == a[j].rgbBlue) &&(bits[FI_RGBA_GREEN] == a[j].rgbGreen) &&(bits[FI_RGBA_RED] == a[j].rgbRed)
								&&((ignore_alpha) || (bits[FI_RGBA_ALPHA] == a[j].rgbReserved))) {
								bits[FI_RGBA_BLUE] = b[j].rgbBlue;
								bits[FI_RGBA_GREEN] = b[j].rgbGreen;
								bits[FI_RGBA_RED] = b[j].rgbRed;
								if (!ignore_alpha) {
									bits[FI_RGBA_ALPHA] = b[j].rgbReserved;
								}
								result++;
								j = count;
								break;
							}
							a = dstcolors;
							b = srccolors;
						}
					}
				}
			}
			return result;
		}
		default: {
			return 0;
		}
	}
}
Exemple #21
0
FREE_IMAGE_COLOR_TYPE DLL_CALLCONV
FreeImage_GetColorType(FIBITMAP *dib) {
	RGBQUAD *rgb;

	const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);

	// special bitmap type
	if(image_type != FIT_BITMAP) {
		switch(image_type) {
			case FIT_UINT16:
			{
				// 16-bit greyscale TIF can be either FIC_MINISBLACK (the most common case) or FIC_MINISWHITE
				// you can check this using EXIF_MAIN metadata
				FITAG *photometricTag = NULL;
				if(FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "PhotometricInterpretation", &photometricTag)) {
					const short *value = (short*)FreeImage_GetTagValue(photometricTag);
					// PHOTOMETRIC_MINISWHITE = 0 => min value is white
					// PHOTOMETRIC_MINISBLACK = 1 => min value is black
					return (*value == 0) ? FIC_MINISWHITE : FIC_MINISBLACK;
				}
				return FIC_MINISBLACK;
			}
			break;
			case FIT_RGB16:
			case FIT_RGBF:
				return FIC_RGB;
			case FIT_RGBA16:
			case FIT_RGBAF:
				return FIC_RGBALPHA;
		}

		return FIC_MINISBLACK;
	}

	// standard image type
	switch (FreeImage_GetBPP(dib)) {
		case 1:
		{
			rgb = FreeImage_GetPalette(dib);

			if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) {
				rgb++;

				if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255))
					return FIC_MINISBLACK;				
			}

			if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) {
				rgb++;

				if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0))
					return FIC_MINISWHITE;				
			}

			return FIC_PALETTE;
		}

		case 4:
		case 8:	// Check if the DIB has a color or a greyscale palette
		{
			int ncolors = FreeImage_GetColorsUsed(dib);
		    int minisblack = 1;
			rgb = FreeImage_GetPalette(dib);

			for (int i = 0; i < ncolors; i++) {
				if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue))
					return FIC_PALETTE;

				// The DIB has a color palette if the greyscale isn't a linear ramp
				// Take care of reversed grey images
				if (rgb->rgbRed != i) {
					if ((ncolors-i-1) != rgb->rgbRed)
						return FIC_PALETTE;
				    else
						minisblack = 0;
				}

				rgb++;
			}

			return minisblack ? FIC_MINISBLACK : FIC_MINISWHITE;
		}

		case 16:
		case 24:
			return FIC_RGB;

		case 32:
		{
			if (FreeImage_GetICCProfile(dib)->flags & FIICC_COLOR_IS_CMYK)
				return FIC_CMYK;

			if( FreeImage_HasPixels(dib) ) {
				// check for fully opaque alpha layer
				for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
					rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y);

					for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++)
						if (rgb[x].rgbReserved != 0xFF)
							return FIC_RGBALPHA;			
				}
				return FIC_RGB;
			}

			return FIC_RGBALPHA;
		}
				
		default :
			return FIC_MINISBLACK;
	}
}
Exemple #22
0
/** @brief Applies palette index mapping for one or several indices on a 1-, 4- 
 or 8-bit palletized image.

 This function maps up to <i>count</i> palette indices specified in
 <i>srcindices</i> to these specified in <i>dstindices</i>. Thereby, index 
 <i>srcindices[N]</i>, if present in the image, will be replaced by index
 <i>dstindices[N]</i>. If parameter <i>swap</i> is TRUE, additionally all indices
 specified in <i>dstindices</i> are also mapped to these specified in 
 <i>srcindices</i>.<br>

 The function returns the number of pixels changed or zero, if no pixels were
 changed. 

 Both arrays <i>srcindices</i> and <i>dstindices</i> are assumed not to hold less
 than <i>count</i> indices.<br>

 <b>Note, that this behaviour is different from what FreeImage_ApplyColorMapping()
 does, which modifies the actual image data on palletized images.</b>

 @param dib Input/output image to be processed.
 @param srcindices Array of palette indices to be used as the mapping source.
 @param dstindices Array of palette indices to be used as the mapping destination.
 @param count The number of palette indices to be mapped. This is the size of both
 <i>srcindices</i> and <i>dstindices</i>.  
 @param swap If TRUE, source and destination palette indices are swapped, that is,
 each destination index is also mapped to the corresponding source index.  
 @return Returns the total number of pixels changed. 
 */
unsigned DLL_CALLCONV
FreeImage_ApplyPaletteIndexMapping(FIBITMAP *dib, BYTE *srcindices,	BYTE *dstindices, unsigned count, BOOL swap) {
	unsigned result = 0;

	if (!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
		return 0;
	}

	// validate parameters
	if ((!srcindices) || (!dstindices)|| (count < 1)) {
		return 0;
	}

	unsigned height = FreeImage_GetHeight(dib);
	unsigned width = FreeImage_GetLine(dib);
	BYTE *a, *b;

	int bpp = FreeImage_GetBPP(dib);
	switch (bpp) {
		case 1: {

			return result;
		}
		case 4: {
			int skip_last = (FreeImage_GetWidth(dib) & 0x01);
			unsigned max_x = width - 1;
			for (unsigned y = 0; y < height; y++) {
				BYTE *bits = FreeImage_GetScanLine(dib, y);
				for (unsigned x = 0; x < width; x++) {
					int start = ((skip_last) && (x == max_x)) ? 1 : 0;
					for (int cn = start; cn < 2; cn++) {
						for (unsigned j = 0; j < count; j++) {
							a = srcindices;
							b = dstindices;
							for (int i = ((swap) ? 0 : 1); i < 2; i++) {
								if (GET_NIBBLE(cn, bits[x]) == (a[j] & 0x0F)) {
									SET_NIBBLE(cn, bits[x], b[j]);
									result++;
									j = count;
									break;
								}
								a = dstindices;
								b = srcindices;
							}
						}
					}
				}
			}
			return result;
		}
		case 8: {
			for (unsigned y = 0; y < height; y++) {
				BYTE *bits = FreeImage_GetScanLine(dib, y);
				for (unsigned x = 0; x < width; x++) {
					for (unsigned j = 0; j < count; j++) {
						a = srcindices;
						b = dstindices;
						for (int i = ((swap) ? 0 : 1); i < 2; i++) {
							if (bits[x] == a[j]) {
								bits[x] = b[j];
								result++;
								j = count;
								break;
							}
							a = dstindices;
							b = srcindices;
						}
					}
				}
			}
			return result;
		}
		default: {
			return 0;
		}
	}
}
Exemple #23
0
Texture* loadTexture(const std::string& filename, bool useCompression) {
    std::string _loggerCat = "loadTexture";

#if defined( GHOUL_USE_DEVIL )
    ilInit();
    iluInit();
    
    //ilOriginFunc(IL_ORIGIN_LOWER_LEFT);
    //ilEnable(IL_ORIGIN_SET);

    ILboolean loadSuccess = ilLoadImage(filename.c_str());
    if (!loadSuccess) {
        ILenum error = ilGetError();
        LERROR("Error while loading image '" << filename << "': " <<
                    iluErrorString(error));
        return nullptr;
    }
    ILint imageFormat = ilGetInteger(IL_IMAGE_FORMAT);
    ILint imageType = ilGetInteger(IL_IMAGE_TYPE);
    ILint imageByte = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
    ILint width = ilGetInteger(IL_IMAGE_WIDTH);
    ILint height = ilGetInteger(IL_IMAGE_HEIGHT);
    ILint depth = ilGetInteger(IL_IMAGE_DEPTH);

    // Copy data from common data store to own address space
    ILubyte* data = new ILubyte[width * height * imageByte];
    ilCopyPixels(0, 0, 0, width, height, 1, imageFormat, IL_UNSIGNED_BYTE, data);

    glm::size3_t size(width, height, depth);

    Texture::Format format;
    switch (imageFormat) {
        case IL_RGB:
            format = Texture::Format::RGB;
            break;
        case IL_RGBA:
            format = Texture::Format::RGBA;
            break;
        case IL_BGR:
            format = Texture::Format::BGR;
            break;
        case IL_BGRA:
            format = Texture::Format::BGRA;
            break;
        default:
            LERROR("Could not read image file '" << filename << "' of format: '" <<
                        imageFormat << "'");
            return nullptr;
    }

    
    GLenum type;
    switch (imageType) {
        case IL_UNSIGNED_BYTE:
            type = GL_UNSIGNED_BYTE;
            break;
        case IL_BYTE:
            type = GL_BYTE;
            break;
        case IL_UNSIGNED_SHORT:
            type = GL_UNSIGNED_SHORT;
            break;
        case IL_SHORT:
            type = GL_SHORT;
            break;
        case IL_UNSIGNED_INT:
            type = GL_UNSIGNED_INT;
            break;
        case IL_INT:
            type = GL_INT;
            break;
        case IL_FLOAT:
            type = GL_FLOAT;
            break;
        default:
            LERROR("Could not read image file '" << filename <<
                        "' of data type: '" << imageType << "'");
            return nullptr;
    }

#elif defined( GHOUL_USE_FREEIMAGE)

	//image format
	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
	//pointer to the image, once loaded
	FIBITMAP *dib(0);
	//pointer to the image data
	BYTE* bits(0);
	//image width and height
	unsigned int width(0), height(0);
	//OpenGL's image ID to map to
	GLuint gl_texID;

	//check the file signature and deduce its format
	fif = FreeImage_GetFileType(filename.c_str(), 0);
	//if still unknown, try to guess the file format from the file extension
	if (fif == FIF_UNKNOWN)
		fif = FreeImage_GetFIFFromFilename(filename.c_str());
	//if still unkown, return failure
	if (fif == FIF_UNKNOWN)
		return nullptr;

	//check that the plugin has reading capabilities and load the file
	if (FreeImage_FIFSupportsReading(fif))
		dib = FreeImage_Load(fif, filename.c_str());
	//if the image failed to load, return failure
	if (!dib)
		return nullptr;

	//retrieve the image data
	bits = FreeImage_GetBits(dib);
	//get the image width and height
	width = FreeImage_GetWidth(dib);
	height = FreeImage_GetHeight(dib);

	glm::size3_t size(width, height, 1);
	//if this somehow one of these failed (they shouldn't), return failure
	if ((bits == 0) || (width == 0) || (height == 0))
		return nullptr;


	FREE_IMAGE_TYPE			imageType = FreeImage_GetImageType(dib);
	FREE_IMAGE_COLOR_TYPE	colorType = FreeImage_GetColorType(dib);
	BITMAPINFOHEADER*		infoheader = FreeImage_GetInfoHeader(dib);
	/*
	FIT_UNKNOWN = 0,	// unknown type
		FIT_BITMAP = 1,	// standard image			: 1-, 4-, 8-, 16-, 24-, 32-bit
		FIT_UINT16 = 2,	// array of unsigned short	: unsigned 16-bit
		FIT_INT16 = 3,	// array of short			: signed 16-bit
		FIT_UINT32 = 4,	// array of unsigned long	: unsigned 32-bit
		FIT_INT32 = 5,	// array of long			: signed 32-bit
		FIT_FLOAT = 6,	// array of float			: 32-bit IEEE floating point
		FIT_DOUBLE = 7,	// array of double			: 64-bit IEEE floating point
		FIT_COMPLEX = 8,	// array of FICOMPLEX		: 2 x 64-bit IEEE floating point
		FIT_RGB16 = 9,	// 48-bit RGB image			: 3 x 16-bit
		FIT_RGBA16 = 10,	// 64-bit RGBA image		: 4 x 16-bit
		FIT_RGBF = 11,	// 96-bit RGB float image	: 3 x 32-bit IEEE floating point
		FIT_RGBAF = 12	// 128-bit RGBA float image	: 4 x 32-bit IEEE floating point

		FI_ENUM(FREE_IMAGE_COLOR_TYPE) {
		FIC_MINISWHITE = 0,		// min value is white
		FIC_MINISBLACK = 1,		// min value is black
		FIC_RGB        = 2,		// RGB color model
		FIC_PALETTE    = 3,		// color map indexed
		FIC_RGBALPHA   = 4,		// RGB color model with alpha channel
		FIC_CMYK       = 5		// CMYK color model
		};

		*/

	if (imageType != FIT_BITMAP) {
		LERROR("Could not read image file '" << filename <<
			"' of data type: '" << imageType << "'");
		return nullptr;
	}
	GLenum type = GL_UNSIGNED_BYTE;
	Texture::Format format;
	switch (colorType) {
	case FIC_RGB:
		format = Texture::Format::RGB;
		break;
	case FIC_RGBALPHA:
		format = Texture::Format::RGBA;
		break;
	default:
		LERROR("Could not read image file '" << filename <<
			"' of color type: '" << colorType << "'");
		return nullptr;

	}
	int imageByte = FreeImage_GetBPP(dib);
	unsigned int pitch = FreeImage_GetPitch(dib);
	BYTE* data = new BYTE[width * height * imageByte/8];

	FreeImage_ConvertToRawBits(data, dib, pitch, imageByte, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, TRUE);
	FreeImage_Unload(dib);


	// Swap red and blue channels, cannot use GL_BGR in OpenGL core profile
	for (size_t i = 0; i < width * height; ++i) {
		size_t index = i * imageByte / 8;
		std::swap(data[index], data[index + 2]);
	}

#endif

    Texture* result;
    if (useCompression) {
        switch (format) {
            case Texture::Format::RGB:
                result = new Texture(data, size, format,
                                     GL_COMPRESSED_RGB_S3TC_DXT1_EXT, type);
                break;
            case Texture::Format::RGBA:
                result = new Texture(data, size, format,
                                     GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, type);
                break;
            default:
                LERROR("Could not assign compressed format for: '" <<
                    GLint(format) << "'. Using no compression instead");
                result = new Texture(data, size, format, static_cast<int>(format), type);
                break;
        }
    }
    else
        result = new Texture(data, size, format, static_cast<int>(format), type);

	return result;

}
Exemple #24
0
FIBITMAP * DLL_CALLCONV
FreeImage_ConvertToRGB16(FIBITMAP *dib) {
	FIBITMAP *src = NULL;
	FIBITMAP *dst = NULL;

	if(!FreeImage_HasPixels(dib)) return NULL;

	const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);

	// check for allowed conversions 
	switch(src_type) {
		case FIT_BITMAP:
		{
			// convert to 24-bit if needed
			if((FreeImage_GetBPP(dib) == 24) || (FreeImage_GetBPP(dib) == 32)) {
				src = dib;
			} else {
				src = FreeImage_ConvertTo24Bits(dib);
				if(!src) return NULL;
			}
			break;
		}
		case FIT_UINT16:
			// allow conversion from unsigned 16-bit
			src = dib;
			break;
		case FIT_RGB16:
			// RGB16 type : clone the src
			return FreeImage_Clone(dib);
			break;
		case FIT_RGBA16:
			// allow conversion from 64-bit RGBA (ignore the alpha channel)
			src = dib;
			break;
		default:
			return NULL;
	}

	// allocate dst image

	const unsigned width = FreeImage_GetWidth(src);
	const unsigned height = FreeImage_GetHeight(src);

	dst = FreeImage_AllocateT(FIT_RGB16, width, height);
	if(!dst) {
		if(src != dib) {
			FreeImage_Unload(src);
		}
		return NULL;
	}

	// copy metadata from src to dst
	FreeImage_CloneMetadata(dst, src);

	// convert from src type to RGB16

	switch(src_type) {
		case FIT_BITMAP:
		{
			// Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
			const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);

			for(unsigned y = 0; y < height; y++) {
				const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y);
				FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					dst_bits[x].red   = src_bits[FI_RGBA_RED] << 8;
					dst_bits[x].green = src_bits[FI_RGBA_GREEN] << 8;
					dst_bits[x].blue  = src_bits[FI_RGBA_BLUE] << 8;
					src_bits += bytespp;
				}
			}
		}
		break;

		case FIT_UINT16:
		{
			for(unsigned y = 0; y < height; y++) {
				const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y);
				FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					// convert by copying greyscale channel to each R, G, B channels
					dst_bits[x].red   = src_bits[x];
					dst_bits[x].green = src_bits[x];
					dst_bits[x].blue  = src_bits[x];
				}
			}
		}
		break;

		case FIT_RGBA16:
		{
			for(unsigned y = 0; y < height; y++) {
				const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y);
				FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					// convert and skip alpha channel
					dst_bits[x].red   = src_bits[x].red;
					dst_bits[x].green = src_bits[x].green;
					dst_bits[x].blue  = src_bits[x].blue;
				}
			}
		}
		break;

		default:
			break;
	}

	if(src != dib) {
		FreeImage_Unload(src);
	}

	return dst;
}
    //---------------------------------------------------------------------
    Codec::DecodeResult FreeImageCodec::decode(DataStreamPtr& input) const
    {
		// Buffer stream into memory (TODO: override IO functions instead?)
		MemoryDataStream memStream(input, true);

		FIMEMORY* fiMem = 
			FreeImage_OpenMemory(memStream.getPtr(), static_cast<DWORD>(memStream.size()));

		FIBITMAP* fiBitmap = FreeImage_LoadFromMemory(
			(FREE_IMAGE_FORMAT)mFreeImageType, fiMem);
		if (!fiBitmap)
		{
			OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
				"Error decoding image", 
				"FreeImageCodec::decode");
		}


		ImageData* imgData = new ImageData();
		MemoryDataStreamPtr output;

		imgData->depth = 1; // only 2D formats handled by this codec
		imgData->width = FreeImage_GetWidth(fiBitmap);
		imgData->height = FreeImage_GetHeight(fiBitmap);
        imgData->num_mipmaps = 0; // no mipmaps in non-DDS 
        imgData->flags = 0;

		// Must derive format first, this may perform conversions
		
		FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(fiBitmap);
		FREE_IMAGE_COLOR_TYPE colourType = FreeImage_GetColorType(fiBitmap);
		unsigned bpp = FreeImage_GetBPP(fiBitmap);

		switch(imageType)
		{
		case FIT_UNKNOWN:
		case FIT_COMPLEX:
		case FIT_UINT32:
		case FIT_INT32:
		case FIT_DOUBLE:
        default:
			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
				"Unknown or unsupported image format", 
				"FreeImageCodec::decode");
				
			break;
		case FIT_BITMAP:
			// Standard image type
			// Perform any colour conversions for greyscale
			if (colourType == FIC_MINISWHITE || colourType == FIC_MINISBLACK)
			{
				FIBITMAP* newBitmap = FreeImage_ConvertToGreyscale(fiBitmap);
				// free old bitmap and replace
				FreeImage_Unload(fiBitmap);
				fiBitmap = newBitmap;
				// get new formats
				bpp = FreeImage_GetBPP(fiBitmap);
				colourType = FreeImage_GetColorType(fiBitmap);
			}
			// Perform any colour conversions for RGB
			else if (bpp < 8 || colourType == FIC_PALETTE || colourType == FIC_CMYK)
			{
				FIBITMAP* newBitmap = FreeImage_ConvertTo24Bits(fiBitmap);
				// free old bitmap and replace
				FreeImage_Unload(fiBitmap);
				fiBitmap = newBitmap;
				// get new formats
				bpp = FreeImage_GetBPP(fiBitmap);
				colourType = FreeImage_GetColorType(fiBitmap);
			}

			// by this stage, 8-bit is greyscale, 16/24/32 bit are RGB[A]
			switch(bpp)
			{
			case 8:
				imgData->format = PF_L8;
				break;
			case 16:
				// Determine 555 or 565 from green mask
				// cannot be 16-bit greyscale since that's FIT_UINT16
				if(FreeImage_GetGreenMask(fiBitmap) == FI16_565_GREEN_MASK)
				{
					imgData->format = PF_R5G6B5;
				}
				else
				{
					// FreeImage doesn't support 4444 format so must be 1555
					imgData->format = PF_A1R5G5B5;
				}
				break;
			case 24:
				// FreeImage differs per platform
				//     PF_BYTE_BGR[A] for little endian (== PF_ARGB native)
				//     PF_BYTE_RGB[A] for big endian (== PF_RGBA native)
#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
				imgData->format = PF_BYTE_RGB;
#else
				imgData->format = PF_BYTE_BGR;
#endif
				break;
			case 32:
#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
				imgData->format = PF_BYTE_RGBA;
#else
				imgData->format = PF_BYTE_BGRA;
#endif
				break;
				
				
			};
			break;
		case FIT_UINT16:
		case FIT_INT16:
			// 16-bit greyscale
			imgData->format = PF_L16;
			break;
		case FIT_FLOAT:
			// Single-component floating point data
			imgData->format = PF_FLOAT32_R;
			break;
		case FIT_RGB16:
			imgData->format = PF_SHORT_RGB;
			break;
		case FIT_RGBA16:
			imgData->format = PF_SHORT_RGBA;
			break;
		case FIT_RGBF:
			imgData->format = PF_FLOAT32_RGB;
			break;
		case FIT_RGBAF:
			imgData->format = PF_FLOAT32_RGBA;
			break;
			
			
		};

		unsigned char* srcData = FreeImage_GetBits(fiBitmap);
		unsigned srcPitch = FreeImage_GetPitch(fiBitmap);

		// Final data - invert image and trim pitch at the same time
		size_t dstPitch = imgData->width * PixelUtil::getNumElemBytes(imgData->format);
		imgData->size = dstPitch * imgData->height;
        // Bind output buffer
        output.bind(new MemoryDataStream(imgData->size));

		uchar* pSrc;
		uchar* pDst = output->getPtr();
		for (size_t y = 0; y < imgData->height; ++y)
		{
			pSrc = srcData + (imgData->height - y - 1) * srcPitch;
			memcpy(pDst, pSrc, dstPitch);
			pDst += dstPitch;
		}

		
		FreeImage_Unload(fiBitmap);
		FreeImage_CloseMemory(fiMem);


        DecodeResult ret;
        ret.first = output;
        ret.second = CodecDataPtr(imgData);
		return ret;

    }
FIBITMAP * DLL_CALLCONV
FreeImage_ConvertToRGBF(FIBITMAP *dib) {
	FIBITMAP *src = NULL;
	FIBITMAP *dst = NULL;

	if(!FreeImage_HasPixels(dib)) return NULL;

	const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);

	// check for allowed conversions 
	switch(src_type) {
		case FIT_BITMAP:
		{
			// allow conversion from 24- and 32-bit
			const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
			if((color_type != FIC_RGB) && (color_type != FIC_RGBALPHA)) {
				src = FreeImage_ConvertTo24Bits(dib);
				if(!src) return NULL;
			} else {
				src = dib;
			}
			break;
		}
		case FIT_UINT16:
			// allow conversion from 16-bit
			src = dib;
			break;
		case FIT_RGB16:
			// allow conversion from 48-bit RGB
			src = dib;
			break;
		case FIT_RGBA16:
			// allow conversion from 64-bit RGBA (ignore the alpha channel)
			src = dib;
			break;
		case FIT_FLOAT:
			// allow conversion from 32-bit float
			src = dib;
			break;
		case FIT_RGBAF:
			// allow conversion from 128-bit RGBAF
			src = dib;
			break;
		case FIT_RGBF:
			// RGBF type : clone the src
			return FreeImage_Clone(dib);
			break;
		default:
			return NULL;
	}

	// allocate dst image

	const unsigned width = FreeImage_GetWidth(src);
	const unsigned height = FreeImage_GetHeight(src);

	dst = FreeImage_AllocateT(FIT_RGBF, width, height);
	if(!dst) return NULL;

	// copy metadata from src to dst
	FreeImage_CloneMetadata(dst, src);

	// convert from src type to RGBF

	const unsigned src_pitch = FreeImage_GetPitch(src);
	const unsigned dst_pitch = FreeImage_GetPitch(dst);

	switch(src_type) {
		case FIT_BITMAP:
		{
			// calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit)
			const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);

			const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
			BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);

			for(unsigned y = 0; y < height; y++) {
				const BYTE   *src_pixel = (BYTE*)src_bits;
				FIRGBF *dst_pixel = (FIRGBF*)dst_bits;
				for(unsigned x = 0; x < width; x++) {
					// convert and scale to the range [0..1]
					dst_pixel->red   = (float)(src_pixel[FI_RGBA_RED])   / 255.0F;
					dst_pixel->green = (float)(src_pixel[FI_RGBA_GREEN]) / 255.0F;
					dst_pixel->blue  = (float)(src_pixel[FI_RGBA_BLUE])  / 255.0F;

					src_pixel += bytespp;
					dst_pixel ++;
				}
				src_bits += src_pitch;
				dst_bits += dst_pitch;
			}
		}
		break;

		case FIT_UINT16:
		{
			const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
			BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);

			for(unsigned y = 0; y < height; y++) {
				const WORD *src_pixel = (WORD*)src_bits;
				FIRGBF *dst_pixel = (FIRGBF*)dst_bits;

				for(unsigned x = 0; x < width; x++) {
					// convert and scale to the range [0..1]
					const float dst_value = (float)src_pixel[x] / 65535.0F;
					dst_pixel[x].red   = dst_value;
					dst_pixel[x].green = dst_value;
					dst_pixel[x].blue  = dst_value;
				}
				src_bits += src_pitch;
				dst_bits += dst_pitch;
			}
		}
		break;

		case FIT_RGB16:
		{
			const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
			BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);

			for(unsigned y = 0; y < height; y++) {
				const FIRGB16 *src_pixel = (FIRGB16*) src_bits;
				FIRGBF  *dst_pixel = (FIRGBF*)  dst_bits;

				for(unsigned x = 0; x < width; x++) {
					// convert and scale to the range [0..1]
					dst_pixel[x].red   = (float)(src_pixel[x].red)   / 65535.0F;
					dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F;
					dst_pixel[x].blue  = (float)(src_pixel[x].blue)  / 65535.0F;
				}
				src_bits += src_pitch;
				dst_bits += dst_pitch;
			}
		}
		break;

		case FIT_RGBA16:
		{
			const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
			BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);

			for(unsigned y = 0; y < height; y++) {
				const FIRGBA16 *src_pixel = (FIRGBA16*) src_bits;
				FIRGBF  *dst_pixel = (FIRGBF*)  dst_bits;

				for(unsigned x = 0; x < width; x++) {
					// convert and scale to the range [0..1]
					dst_pixel[x].red   = (float)(src_pixel[x].red)   / 65535.0F;
					dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F;
					dst_pixel[x].blue  = (float)(src_pixel[x].blue)  / 65535.0F;
				}
				src_bits += src_pitch;
				dst_bits += dst_pitch;
			}
		}
		break;

		case FIT_FLOAT:
		{
			const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
			BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);

			for(unsigned y = 0; y < height; y++) {
				const float *src_pixel = (float*) src_bits;
				FIRGBF  *dst_pixel = (FIRGBF*)  dst_bits;

				for(unsigned x = 0; x < width; x++) {
					// convert by copying greyscale channel to each R, G, B channels
					dst_pixel[x].red   = src_pixel[x];
					dst_pixel[x].green = src_pixel[x];
					dst_pixel[x].blue  = src_pixel[x];
				}
				src_bits += src_pitch;
				dst_bits += dst_pitch;
			}
		}
		break;

		case FIT_RGBAF:
		{
			const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
			BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);

			for(unsigned y = 0; y < height; y++) {
				const FIRGBAF *src_pixel = (FIRGBAF*) src_bits;
				FIRGBF  *dst_pixel = (FIRGBF*)  dst_bits;

				for(unsigned x = 0; x < width; x++) {
					// convert and skip alpha channel
					dst_pixel[x].red   = src_pixel[x].red;
					dst_pixel[x].green = src_pixel[x].green;
					dst_pixel[x].blue  = src_pixel[x].blue;
				}
				src_bits += src_pitch;
				dst_bits += dst_pitch;
			}
		}
		break;
	}

	if(src != dib) {
		FreeImage_Unload(src);
	}

	return dst;
}
Exemple #27
0
bool M_loadImage(const char * filename, void * data, void * arg)
{
	if(! filename)
		return false;
		
	if(! data)
		return false;

	// freeimage io
	FreeImageIO io;
	io.read_proc  = (FI_ReadProc)readProc;
	io.write_proc = (FI_WriteProc)writeProc;
	io.tell_proc  = (FI_TellProc)tellProc;
	io.seek_proc  = (FI_SeekProc)seekProc;
	
	
	// read file buffer
	MFile * fp = M_fopen(filename, "rb");
	if(! fp)
	{
		printf("Error : can't read file %s\n", filename);
		return false;
	}
	
	
	// read freeimage
	FREE_IMAGE_FORMAT format = FreeImage_GetFileTypeFromHandle(&io, (fi_handle)fp, 0);
	if(format == FIF_UNKNOWN)
	{
		printf("Error : unknow format %s\n", filename);
		M_fclose(fp);
		return false;
	}
	
	FIBITMAP * dib = FreeImage_LoadFromHandle(format, &io, (fi_handle)fp);
	if(! dib)
	{
		printf("Error : unknow dib %s\n", filename);
		M_fclose(fp);
		return false;
	}
	
	BYTE * bits = FreeImage_GetBits(dib);
	unsigned int width = FreeImage_GetWidth(dib);
	unsigned int height = FreeImage_GetHeight(dib);
	unsigned int bpp = FreeImage_GetBPP(dib);
	FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
	
	if((bits == 0) || (width == 0) || (height == 0))
	{
		FreeImage_Unload(dib);
		M_fclose(fp);
		return false;
	}
	
	// flip
	FreeImage_FlipVertical(dib);
	
	// create image
	MImage * image = (MImage *)data;
	
	switch(image_type)
	{
	case FIT_BITMAP:
		switch(bpp)
		{
		case 8:
			image->create(M_UBYTE, width, height, 1);
			for(unsigned int y=0; y<height; y++)
			{
				unsigned char * dest = (unsigned char *)image->getData() + width*y;
				bits = FreeImage_GetScanLine(dib, y);
				memcpy(dest, bits, width*sizeof(char));
			}
			break;

		case 24:
			SwapRedBlue32(dib);
			image->create(M_UBYTE, width, height, 3);
			for(unsigned int y=0; y<height; y++)
			{
				unsigned char * dest = (unsigned char *)image->getData() + width*y*3;
				bits = FreeImage_GetScanLine(dib, y);
				memcpy(dest, bits, width*3*sizeof(char));
			}
			break;
	
		case 32:
			SwapRedBlue32(dib);
			image->create(M_UBYTE, width, height, 4);
			for(unsigned int y=0; y<height; y++)
			{
				unsigned char * dest = (unsigned char *)image->getData() + width*y*4;
				bits = FreeImage_GetScanLine(dib, y);
				memcpy(dest, bits, width*4*sizeof(char));
			}
			break;
			
		default:
			break;
		}
		break;
		
	case FIT_RGB16:
		image->create(M_USHORT, width, height, 3);
		for(unsigned int y=0; y<height; y++)
		{
			unsigned short * dest = (unsigned short *)image->getData() + width*y*3;
			bits = FreeImage_GetScanLine(dib, y);
			memcpy(dest, bits, width*3*sizeof(short));
		}
		break;
	
	case FIT_RGBA16:
		image->create(M_USHORT, width, height, 4);
		for(unsigned int y=0; y<height; y++)
		{
			unsigned short * dest = (unsigned short *)image->getData() + width*y*4;
			bits = FreeImage_GetScanLine(dib, y);
			memcpy(dest, bits, width*4*sizeof(short));
		}
		break;

	case FIT_FLOAT:
		image->create(M_FLOAT, width, height, 1);
		for(unsigned int y=0; y<height; y++)
		{
			float * dest = (float *)image->getData() + width*y;
			bits = FreeImage_GetScanLine(dib, y);
			memcpy(dest, bits, width*sizeof(float));
		}
		break;
		
	case FIT_RGBF:
		image->create(M_FLOAT, width, height, 3);
		for(unsigned int y=0; y<height; y++)
		{
			float * dest = (float *)image->getData() + width*y*3;
			bits = FreeImage_GetScanLine(dib, y);
			memcpy(dest, bits, width*3*sizeof(float));
		}
		break;
		
	case FIT_RGBAF:
		image->create(M_FLOAT, width, height, 4);
		for(unsigned int y=0; y<height; y++)
		{
			float * dest = (float *)image->getData() + width*y*4;
			bits = FreeImage_GetScanLine(dib, y);
			memcpy(dest, bits, width*4*sizeof(float));
		}
		break;
		
	default:
		break;
	}
	
	
	// clean
	FreeImage_Unload(dib);
	M_fclose(fp);
	return true;
}
FIABITMAP *DLL_CALLCONV
FIA_SetBorder (FIBITMAP * src, int xborder, int yborder, BorderType type, double constant)
{
    FIABITMAP *dst = NULL;

    if (!src)
    {
        return NULL;
    }
    FREE_IMAGE_TYPE src_type = FreeImage_GetImageType (src);

    switch (src_type)
    {
        case FIT_BITMAP:
        {                       // standard image: 1-, 4-, 8-, 16-, 24-, 32-bit
            if (FreeImage_GetBPP (src) == 8)
            {
                dst = borderUCharImage.SetBorder (src, xborder, yborder, type,
                                                  (unsigned char) constant);
                break;
            }
        }
        case FIT_UINT16:
        {                       // array of unsigned short: unsigned 16-bit
            dst = borderUShortImage.SetBorder (src, xborder, yborder, type,
                                               (unsigned short) constant);
            break;
        }
        case FIT_INT16:
        {                       // array of short: signed 16-bit
            dst = borderShortImage.SetBorder (src, xborder, yborder, type, (short) constant);
            break;
        }
        case FIT_UINT32:
        {                       // array of unsigned long: unsigned 32-bit
            dst = borderULongImage.SetBorder (src, xborder, yborder, type,
                                              (unsigned long) constant);
            break;
        }
        case FIT_INT32:
        {                       // array of long: signed 32-bit
            dst = borderLongImage.SetBorder (src, xborder, yborder, type, (long) constant);
            break;
        }
        case FIT_FLOAT:
        {                       // array of float: 32-bit
            dst = borderFloatImage.SetBorder (src, xborder, yborder, type, (float) constant);
            break;
        }
        case FIT_DOUBLE:
        {                       // array of double: 64-bit
            dst = borderDoubleImage.SetBorder (src, xborder, yborder, type, constant);
            break;
        }
        default:
        {
            break;
        }
    }

    if (NULL == dst)
    {
        FreeImage_OutputMessageProc (FIF_UNKNOWN,
                                     "FREE_IMAGE_TYPE: Unable to set border for type %d.", type);
    }

    return dst;
}
Exemple #29
0
bool StFreeImage::save(const StString& theFilePath,
                       ImageType       theImageType,
                       StFormat ) {
    if(!StFreeImage::init()) {
        setState("FreeImage library is not initialized");
        return false;
    }

    FREE_IMAGE_FORMAT aFIF = convertToFIF(theImageType);
    if(aFIF == FIF_UNKNOWN) {
        setState("FreeImage library, not supported image file format");
        return false;
    }

    StImage stSaveImage;
    if(getColorModel() != ImgColor_RGB && getColorModel() != ImgColor_RGBA && getColorModel() != ImgColor_GRAY) {
        // convert from YUV and so on
        if(!stSaveImage.initRGB(*this)) {
            setState("StFreeImage, only RGB image could be saved");
            return false;
        }
    } else {
        stSaveImage.initWrapper(*this);
    }
    const StImagePlane& stImgPlane = stSaveImage.getPlane();

    FREE_IMAGE_TYPE aSaveFormatFI = FIT_UNKNOWN;
    if(!convertToFreeFormat(stImgPlane.getFormat(), aSaveFormatFI)) {
        setState("StFreeImage, image format currently not supported");
        return false;
    }

    // allocate FreeImage native structure
    FIBITMAP* aSaveDIB = FreeImage_AllocateT(aSaveFormatFI, (int )stImgPlane.getSizeX(), (int )stImgPlane.getSizeY(),
                                             (unsigned )stImgPlane.getSizePixelBytes() * 8, 0, 0, 0);
    if(aSaveDIB == NULL) {
        setState("FreeImage library, internal error");
        FreeImage_Unload(aSaveDIB);
        return false;
    }
    // wrapper the created data
    StImagePlane stImgPlaneSave;
    StImagePlane::ImgFormat stImgFormatSave = convertFromFreeFormat(FreeImage_GetImageType(aSaveDIB),
                                                                    FreeImage_GetColorType(aSaveDIB),
                                                                    FreeImage_GetBPP(aSaveDIB));
    stImgPlaneSave.initWrapper(stImgFormatSave, FreeImage_GetBits(aSaveDIB),
                               FreeImage_GetWidth(aSaveDIB), FreeImage_GetHeight(aSaveDIB),
                               FreeImage_GetPitch(aSaveDIB));
    // FreeImage data should be bottom-up...
    stImgPlaneSave.setTopDown(false);

    // copy from local structure to the FreeImage structure
    size_t aRowInc = (( stImgPlaneSave.isTopDown() &&  stImgPlane.isTopDown()) ||
                      (!stImgPlaneSave.isTopDown() && !stImgPlane.isTopDown())) ? 1 : size_t(-1);
    size_t aRowTo = (aRowInc == 1) ? 0 : (stImgPlane.getSizeY() - 1);
    for(size_t aRowFrom = 0; aRowFrom < stImgPlane.getSizeY(); ++aRowFrom, aRowTo += aRowInc) {
        for(size_t aCol = 0; aCol < stImgPlane.getSizeX(); ++aCol) {
            stMemCpy(stImgPlaneSave.changeData(aRowTo, aCol), stImgPlane.getData(aRowFrom, aCol), stImgPlane.getSizePixelBytes());
        }
    }

    // now save the image file!
#if defined(_WIN32)
    if(!FreeImage_Save(aFIF, aSaveDIB, theFilePath.toUtfWide().toCString(), 0)) {
#else
    if(!FreeImage_Save(aFIF, aSaveDIB, theFilePath.toCString(), 0)) {
#endif
        setState("FreeImage library, image save failed");
        FreeImage_Unload(aSaveDIB);
        return false;
    }

    // free resources
    FreeImage_Unload(aSaveDIB);

    // set debug information
    StString aDummy, aFileName;
    StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName);
    setState(StString("FreeImage library, saved image '") + aFileName + "' " + getDescription());

    return true;
}
Exemple #30
0
/**
Scan input dib format and return the equivalent PKPixelFormatGUID format for saving
@param dib Image to be saved
@param guid_format (returned value) GUID format
@param bHasAlpha (returned value) TRUE if an alpha layer is present
@return Returns TRUE if successful, returns FALSE otherwise
*/
static ERR
GetOutputPixelFormat(FIBITMAP *dib, PKPixelFormatGUID *guid_format, BOOL *bHasAlpha) {
	const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
	const unsigned bpp = FreeImage_GetBPP(dib);
	const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);

	*guid_format = GUID_PKPixelFormatDontCare;
	*bHasAlpha = FALSE;

	switch(image_type) {
		case FIT_BITMAP:	// standard image	: 1-, 4-, 8-, 16-, 24-, 32-bit
			switch(bpp) {
				case 1:
					// assume FIC_MINISBLACK
					if(color_type == FIC_MINISBLACK) {
						*guid_format = GUID_PKPixelFormatBlackWhite;
					}
					break;
				case 8:
					// assume FIC_MINISBLACK
					if(color_type == FIC_MINISBLACK) {
						*guid_format = GUID_PKPixelFormat8bppGray;
					}
					break;
				case 16:
					if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
						*guid_format = GUID_PKPixelFormat16bppRGB565;
					} else {
						// includes case where all the masks are 0
						*guid_format = GUID_PKPixelFormat16bppRGB555;
					}
					break;
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
				case 24:
					*guid_format = GUID_PKPixelFormat24bppBGR;
					break;
				case 32:
					*guid_format = GUID_PKPixelFormat32bppBGRA;
					*bHasAlpha = TRUE;
					break;
#elif FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
				case 24:
					*guid_format = GUID_PKPixelFormat24bppRGB;
					break;
				case 32:
					*guid_format = GUID_PKPixelFormat32bppRGBA;
					*bHasAlpha = TRUE;
					break;
#endif
				case 4:
				default:
					// not supported
					break;
			}
			break;
		case FIT_UINT16:	// array of unsigned short	: unsigned 16-bit
			*guid_format = GUID_PKPixelFormat16bppGray;
			break;
		case FIT_FLOAT:		// array of float			: 32-bit IEEE floating point
			*guid_format = GUID_PKPixelFormat32bppGrayFloat;
			break;
		case FIT_RGB16:		// 48-bit RGB image			: 3 x 16-bit
			*guid_format = GUID_PKPixelFormat48bppRGB;
			break;
		case FIT_RGBA16:	// 64-bit RGBA image		: 4 x 16-bit
			*guid_format = GUID_PKPixelFormat64bppRGBA;
			*bHasAlpha = TRUE;
			break;
		case FIT_RGBF:		// 96-bit RGB float image	: 3 x 32-bit IEEE floating point
			*guid_format = GUID_PKPixelFormat96bppRGBFloat;
			break;
		case FIT_RGBAF:		// 128-bit RGBA float image	: 4 x 32-bit IEEE floating point
			*guid_format = GUID_PKPixelFormat128bppRGBAFloat;
			*bHasAlpha = TRUE;
			break;

		case FIT_INT16:		// array of short			: signed 16-bit
		case FIT_UINT32:	// array of unsigned long	: unsigned 32-bit
		case FIT_INT32:		// array of long			: signed 32-bit
		case FIT_DOUBLE:	// array of double			: 64-bit IEEE floating point
		case FIT_COMPLEX:	// array of FICOMPLEX		: 2 x 64-bit IEEE floating point

		default:
			// unsupported format
			break;
	}

	return (*guid_format != GUID_PKPixelFormatDontCare) ? WMP_errSuccess : WMP_errUnsupportedFormat;
}