Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/FreeImage/PluginICO.cpp  view on Meta::CPAN

static BOOL DLL_CALLCONV
SupportsNoPixels() {
	return TRUE;
}

// ----------------------------------------------------------

static void * DLL_CALLCONV
Open(FreeImageIO *io, fi_handle handle, BOOL read) {
	// Allocate memory for the header structure
	ICONHEADER *lpIH = (ICONHEADER*)malloc(sizeof(ICONHEADER));
	if(lpIH == NULL) {
		return NULL;
	}

	if (read) {
		// Read in the header
		io->read_proc(lpIH, 1, sizeof(ICONHEADER), handle);
#ifdef FREEIMAGE_BIGENDIAN
		SwapIconHeader(lpIH);
#endif

		if(!(lpIH->idReserved == 0) || !(lpIH->idType == 1)) {
			// Not an ICO file
			free(lpIH);
			return NULL;
		}
	}
	else {
		// Fill the header
		lpIH->idReserved = 0;
		lpIH->idType = 1;
		lpIH->idCount = 0;
	}

	return lpIH;
}

static void DLL_CALLCONV
Close(FreeImageIO *io, fi_handle handle, void *data) {
	// free the header structure
	ICONHEADER *lpIH = (ICONHEADER*)data;
	free(lpIH);
}

// ----------------------------------------------------------

static int DLL_CALLCONV
PageCount(FreeImageIO *io, fi_handle handle, void *data) {
	ICONHEADER *lpIH = (ICONHEADER*)data;

	if(lpIH) {
		return lpIH->idCount;
	}
	return 1;
}

// ----------------------------------------------------------

static FIBITMAP*
LoadStandardIcon(FreeImageIO *io, fi_handle handle, int flags, BOOL header_only) {
	FIBITMAP *dib = NULL;

	// load the BITMAPINFOHEADER
	BITMAPINFOHEADER bmih;
	io->read_proc(&bmih, sizeof(BITMAPINFOHEADER), 1, handle);
#ifdef FREEIMAGE_BIGENDIAN
	SwapInfoHeader(&bmih);
#endif

	// allocate the bitmap
	int width  = bmih.biWidth;
	int height = bmih.biHeight / 2; // height == xor + and mask
	unsigned bit_count = bmih.biBitCount;
	unsigned line   = CalculateLine(width, bit_count);
	unsigned pitch  = CalculatePitch(line);

	// allocate memory for one icon

	dib = FreeImage_AllocateHeader(header_only, width, height, bit_count);

	if (dib == NULL) {
		return NULL;
	}

	if( bmih.biBitCount <= 8 ) {
		// read the palette data
		io->read_proc(FreeImage_GetPalette(dib), CalculateUsedPaletteEntries(bit_count) * sizeof(RGBQUAD), 1, handle);
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
		RGBQUAD *pal = FreeImage_GetPalette(dib);
		for(unsigned i = 0; i < CalculateUsedPaletteEntries(bit_count); i++) {
			INPLACESWAP(pal[i].rgbRed, pal[i].rgbBlue);
		}
#endif
	}
	
	if(header_only) {
		// header only mode
		return dib;
	}

	// read the icon
	io->read_proc(FreeImage_GetBits(dib), height * pitch, 1, handle);

#ifdef FREEIMAGE_BIGENDIAN
	if (bit_count == 16) {
		for(int y = 0; y < height; y++) {
			WORD *pixel = (WORD *)FreeImage_GetScanLine(dib, y);
			for(int x = 0; x < width; x++) {
				SwapShort(pixel);
				pixel++;
			}
		}
	}
#endif
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
	if (bit_count == 24 || bit_count == 32) {
		for(int y = 0; y < height; y++) {
			BYTE *pixel = FreeImage_GetScanLine(dib, y);
			for(int x = 0; x < width; x++) {
				INPLACESWAP(pixel[0], pixel[2]);
				pixel += (bit_count>>3);
			}
		}
	}
#endif
	// bitmap has been loaded successfully!

	// convert to 32bpp and generate an alpha channel
	// apply the AND mask only if the image is not 32 bpp
	if(((flags & ICO_MAKEALPHA) == ICO_MAKEALPHA) && (bit_count < 32)) {
		FIBITMAP *dib32 = FreeImage_ConvertTo32Bits(dib);
		FreeImage_Unload(dib);

		if (dib32 == NULL) {
			return NULL;
		}

		int width_and	= WidthBytes(width);
		BYTE *line_and	= (BYTE *)malloc(width_and);

		if( line_and == NULL ) {
			FreeImage_Unload(dib32);
			return NULL;
		}

		//loop through each line of the AND-mask generating the alpha channel, invert XOR-mask
		for(int y = 0; y < height; y++) {
			RGBQUAD *quad = (RGBQUAD *)FreeImage_GetScanLine(dib32, y);
			io->read_proc(line_and, width_and, 1, handle);
			for(int x = 0; x < width; x++) {
				quad->rgbReserved = (line_and[x>>3] & (0x80 >> (x & 0x07))) != 0 ? 0 : 0xFF;
				if( quad->rgbReserved == 0 ) {
					quad->rgbBlue ^= 0xFF;
					quad->rgbGreen ^= 0xFF;
					quad->rgbRed ^= 0xFF;
				}
				quad++;
			}
		}
		free(line_and);

		return dib32;
	}

	return dib;
}

static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	if (page == -1) {
		page = 0;
	}

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

	if (handle != NULL) {
		FIBITMAP *dib = NULL;

		// get the icon header
		ICONHEADER *icon_header = (ICONHEADER*)data;

		if (icon_header) {
			// load the icon descriptions
			ICONDIRENTRY *icon_list = (ICONDIRENTRY*)malloc(icon_header->idCount * sizeof(ICONDIRENTRY));
			if(icon_list == NULL) {
				return NULL;
			}
			io->seek_proc(handle, sizeof(ICONHEADER), SEEK_SET);
			io->read_proc(icon_list, icon_header->idCount * sizeof(ICONDIRENTRY), 1, handle);
#ifdef FREEIMAGE_BIGENDIAN
			SwapIconDirEntries(icon_list, icon_header->idCount);
#endif

			// load the requested icon
			if (page < icon_header->idCount) {
				// seek to the start of the bitmap data for the icon
				io->seek_proc(handle, icon_list[page].dwImageOffset, SEEK_SET);

				if( IsPNG(io, handle) ) {
					// Vista icon support
					// see http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
					dib = FreeImage_LoadFromHandle(FIF_PNG, io, handle, header_only ? FIF_LOAD_NOPIXELS : PNG_DEFAULT);
				}
				else {
					// standard icon support
					// see http://msdn.microsoft.com/en-us/library/ms997538.aspx
					// see http://blogs.msdn.com/b/oldnewthing/archive/2010/10/18/10077133.aspx
					dib = LoadStandardIcon(io, handle, flags, header_only);
				}

				free(icon_list);

				return dib;

			} else {
				free(icon_list);
				FreeImage_OutputMessageProc(s_format_id, "Page doesn't exist");
			}
		} else {
			FreeImage_OutputMessageProc(s_format_id, "File is not an ICO file");
		}
	}

	return NULL;
}

// ----------------------------------------------------------

static BOOL 
SaveStandardIcon(FreeImageIO *io, FIBITMAP *dib, fi_handle handle) {
	BITMAPINFOHEADER *bmih = NULL;

	// write the BITMAPINFOHEADER
	bmih = FreeImage_GetInfoHeader(dib);
	bmih->biHeight *= 2;	// height == xor + and mask
#ifdef FREEIMAGE_BIGENDIAN
	SwapInfoHeader(bmih);
#endif
	io->write_proc(bmih, sizeof(BITMAPINFOHEADER), 1, handle);
#ifdef FREEIMAGE_BIGENDIAN
	SwapInfoHeader(bmih);
#endif
	bmih->biHeight /= 2;

	// write the palette data
	if (FreeImage_GetPalette(dib) != NULL) {
		RGBQUAD *pal = FreeImage_GetPalette(dib);
		FILE_BGRA bgra;
		for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++) {
			bgra.b = pal[i].rgbBlue;
			bgra.g = pal[i].rgbGreen;
			bgra.r = pal[i].rgbRed;
			bgra.a = pal[i].rgbReserved;
			io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle);
		}
	}

	// write the bits
	int width			= bmih->biWidth;
	int height			= bmih->biHeight;
	unsigned bit_count	= bmih->biBitCount;
	unsigned line		= CalculateLine(width, bit_count);
	unsigned pitch		= CalculatePitch(line);
	int size_xor		= height * pitch;
	int size_and		= height * WidthBytes(width);

	// XOR mask
#ifdef FREEIMAGE_BIGENDIAN

src/Source/FreeImage/PluginICO.cpp  view on Meta::CPAN

							if(trns[index] != 0xFF) {
								// set any transparent color to full transparency
								and_bits[x >> 3] |= (0x80 >> (x & 0x7)); 
							}
						}
						and_bits += width_and;
					}
				}
				break;

				case 4:
				{
					for(int y = 0; y < height; y++) {
						BYTE *bits = (BYTE*)FreeImage_GetScanLine(dib, y);
						for(int x = 0; x < width; x++) {
							// get pixel at (x, y)
							BYTE shift = (BYTE)((1 - x % 2) << 2);
							BYTE index = (bits[x >> 1] & (0x0F << shift)) >> shift;
							if(trns[index] != 0xFF) {
								// set any transparent color to full transparency
								and_bits[x >> 3] |= (0x80 >> (x & 0x7)); 
							}
						}
						and_bits += width_and;
					}
				}
				break;

				case 8:
				{
					for(int y = 0; y < height; y++) {
						BYTE *bits = (BYTE*)FreeImage_GetScanLine(dib, y);
						for(int x = 0; x < width; x++) {
							// get pixel at (x, y)
							BYTE index = bits[x];
							if(trns[index] != 0xFF) {
								// set any transparent color to full transparency
								and_bits[x >> 3] |= (0x80 >> (x & 0x7)); 
							}
						}
						and_bits += width_and;
					}
				}
				break;

			}
		}
	}
	else {
		// empty AND mask
		memset(and_mask, 0, size_and);
	}

	io->write_proc(and_mask, size_and, 1, handle);
	free(and_mask);

	return TRUE;
}

static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
	ICONHEADER *icon_header = NULL;
	std::vector<FIBITMAP*> vPages;
	int k;

	if(!dib || !handle || !data) {
		return FALSE;
	}

	// check format limits
	unsigned w = FreeImage_GetWidth(dib);
	unsigned h = FreeImage_GetHeight(dib);
	if((w < 16) || (w > 256) || (h < 16) || (h > 256) || (w != h)) {
		FreeImage_OutputMessageProc(s_format_id, "Unsupported icon size: width x height = %d x %d", w, h);
		return FALSE;
	}

	if (page == -1) {
		page = 0;
	}
	
	// get the icon header
	icon_header = (ICONHEADER*)data;

	try {
		FIBITMAP *icon_dib = NULL;

		// load all icons
		for(k = 0; k < icon_header->idCount; k++) {
			icon_dib = Load(io, handle, k, flags, data);
			if(!icon_dib) {
				throw FI_MSG_ERROR_DIB_MEMORY;
			}
			vPages.push_back(icon_dib);
		}

		// add the page
		icon_dib = FreeImage_Clone(dib);
		vPages.push_back(icon_dib);
		icon_header->idCount++;

		// write the header
		io->seek_proc(handle, 0, SEEK_SET);
#ifdef FREEIMAGE_BIGENDIAN
		SwapIconHeader(icon_header);
#endif
		io->write_proc(icon_header, sizeof(ICONHEADER), 1, handle);
#ifdef FREEIMAGE_BIGENDIAN
		SwapIconHeader(icon_header);
#endif

		// write all icons
		// ...
		
		// save the icon descriptions

		ICONDIRENTRY *icon_list = (ICONDIRENTRY *)malloc(icon_header->idCount * sizeof(ICONDIRENTRY));
		if(!icon_list) {
			throw FI_MSG_ERROR_MEMORY;
		}
		memset(icon_list, 0, icon_header->idCount * sizeof(ICONDIRENTRY));

		for(k = 0; k < icon_header->idCount; k++) {
			icon_dib = (FIBITMAP*)vPages[k];

			// convert internal format to ICONDIRENTRY
			// take into account Vista icons whose size is 256x256
			const BITMAPINFOHEADER *bmih = FreeImage_GetInfoHeader(icon_dib);
			icon_list[k].bWidth			= (bmih->biWidth > 255)  ? 0 : (BYTE)bmih->biWidth;
			icon_list[k].bHeight		= (bmih->biHeight > 255) ? 0 : (BYTE)bmih->biHeight;
			icon_list[k].bReserved		= 0;
			icon_list[k].wPlanes		= bmih->biPlanes;
			icon_list[k].wBitCount		= bmih->biBitCount;
			if( (icon_list[k].wPlanes * icon_list[k].wBitCount) >= 8 ) {
				icon_list[k].bColorCount = 0;
			} else {
				icon_list[k].bColorCount = (BYTE)(1 << (icon_list[k].wPlanes * icon_list[k].wBitCount));
			}
			// initial guess (correct only for standard icons)
			icon_list[k].dwBytesInRes	= CalculateImageSize(icon_dib);
			icon_list[k].dwImageOffset = CalculateImageOffset(vPages, k);
		}

		// make a room for icon dir entries, until later update
		const long directory_start = io->tell_proc(handle);
		io->write_proc(icon_list, sizeof(ICONDIRENTRY) * icon_header->idCount, 1, handle);

		// write the image bits for each image
		
		DWORD dwImageOffset = (DWORD)io->tell_proc(handle);



( run in 0.420 second using v1.01-cache-2.11-cpan-524268b4103 )