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 )