summaryrefslogtreecommitdiff
path: root/DevIL/src-IL/src/il_icon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'DevIL/src-IL/src/il_icon.cpp')
-rw-r--r--DevIL/src-IL/src/il_icon.cpp674
1 files changed, 674 insertions, 0 deletions
diff --git a/DevIL/src-IL/src/il_icon.cpp b/DevIL/src-IL/src/il_icon.cpp
new file mode 100644
index 00000000..fd9475dc
--- /dev/null
+++ b/DevIL/src-IL/src/il_icon.cpp
@@ -0,0 +1,674 @@
+//-----------------------------------------------------------------------------
+//
+// ImageLib Sources
+// Copyright (C) 2001-2009 by Denton Woods
+// Last modified: 03/07/2009
+//
+// Filename: src-IL/src/il_icon.c
+//
+// Description: Reads from a Windows icon (.ico) file.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "il_internal.h"
+#ifndef IL_NO_ICO
+#include "il_icon.h"
+#ifndef IL_NO_PNG
+ #include <png.h>
+#endif
+
+//! Reads an icon file.
+ILboolean ilLoadIcon(ILconst_string FileName)
+{
+ ILHANDLE IconFile;
+ ILboolean bIcon = IL_FALSE;
+
+ IconFile = iopenr(FileName);
+ if (IconFile == NULL) {
+ ilSetError(IL_COULD_NOT_OPEN_FILE);
+ return bIcon;
+ }
+
+ bIcon = ilLoadIconF(IconFile);
+ icloser(IconFile);
+
+ return bIcon;
+}
+
+
+//! Reads an already-opened icon file.
+ILboolean ilLoadIconF(ILHANDLE File)
+{
+ ILuint FirstPos;
+ ILboolean bRet;
+
+ iSetInputFile(File);
+ FirstPos = itell();
+ bRet = iLoadIconInternal();
+ iseek(FirstPos, IL_SEEK_SET);
+
+ return bRet;
+}
+
+
+//! Reads from a memory "lump" that contains an icon.
+ILboolean ilLoadIconL(const void *Lump, ILuint Size)
+{
+ iSetInputLump(Lump, Size);
+ return iLoadIconInternal();
+}
+
+
+// Internal function used to load the icon.
+ILboolean iLoadIconInternal()
+{
+ ICODIR IconDir;
+ ICODIRENTRY *DirEntries = NULL;
+ ICOIMAGE *IconImages = NULL;
+ ILimage *Image = NULL;
+ ILint i;
+ ILuint Size, PadSize, ANDPadSize, j, k, l, m, x, w, CurAndByte, AndBytes;
+ ILboolean BaseCreated = IL_FALSE;
+ ILubyte PNGTest[3];
+
+ if (iCurImage == NULL) {
+ ilSetError(IL_ILLEGAL_OPERATION);
+ return IL_FALSE;
+ }
+
+ IconDir.Reserved = GetLittleShort();
+ IconDir.Type = GetLittleShort();
+ IconDir.Count = GetLittleShort();
+
+ if (ieof())
+ goto file_read_error;
+
+ DirEntries = (ICODIRENTRY*)ialloc(sizeof(ICODIRENTRY) * IconDir.Count);
+ IconImages = (ICOIMAGE*)ialloc(sizeof(ICOIMAGE) * IconDir.Count);
+ if (DirEntries == NULL || IconImages == NULL) {
+ ifree(DirEntries);
+ ifree(IconImages);
+ return IL_FALSE;
+ }
+
+ // Make it easier for file_read_error.
+ for (i = 0; i < IconDir.Count; i++)
+ imemclear(&IconImages[i], sizeof(ICOIMAGE));
+
+ for (i = 0; i < IconDir.Count; ++i) {
+ DirEntries[i].Width = (ILubyte)igetc();
+ DirEntries[i].Height = (ILubyte)igetc();
+ DirEntries[i].NumColours = (ILubyte)igetc();
+ DirEntries[i].Reserved = (ILubyte)igetc();
+ DirEntries[i].Planes = GetLittleShort();
+ DirEntries[i].Bpp = GetLittleShort();
+ DirEntries[i].SizeOfData = GetLittleUInt();
+ DirEntries[i].Offset = GetLittleUInt();
+
+ if (ieof())
+ goto file_read_error;
+ }
+
+ for (i = 0; i < IconDir.Count; i++) {
+ iseek(DirEntries[i].Offset, IL_SEEK_SET);
+
+ // 08-22-2008: Adding test for compressed PNG data
+ igetc(); // Skip the first character...seems to vary.
+ iread(PNGTest, 3, 1);
+ if (!strnicmp((char*)PNGTest, "PNG", 3)) // Characters 'P', 'N', 'G' for PNG header
+ {
+#ifdef IL_NO_PNG
+ ilSetError(IL_FORMAT_NOT_SUPPORTED); // Cannot handle these without libpng.
+ goto file_read_error;
+#else
+ iseek(DirEntries[i].Offset, IL_SEEK_SET);
+ if (!iLoadIconPNG(&IconImages[i]))
+ goto file_read_error;
+#endif
+ }
+ else
+ {
+ // Need to go back the 4 bytes that were just read.
+ iseek(DirEntries[i].Offset, IL_SEEK_SET);
+
+ IconImages[i].Head.Size = GetLittleInt();
+ IconImages[i].Head.Width = GetLittleInt();
+ IconImages[i].Head.Height = GetLittleInt();
+ IconImages[i].Head.Planes = GetLittleShort();
+ IconImages[i].Head.BitCount = GetLittleShort();
+ IconImages[i].Head.Compression = GetLittleInt();
+ IconImages[i].Head.SizeImage = GetLittleInt();
+ IconImages[i].Head.XPixPerMeter = GetLittleInt();
+ IconImages[i].Head.YPixPerMeter = GetLittleInt();
+ IconImages[i].Head.ColourUsed = GetLittleInt();
+ IconImages[i].Head.ColourImportant = GetLittleInt();
+
+ if (ieof())
+ goto file_read_error;
+
+ if (IconImages[i].Head.BitCount < 8) {
+ if (IconImages[i].Head.ColourUsed == 0) {
+ switch (IconImages[i].Head.BitCount)
+ {
+ case 1:
+ IconImages[i].Head.ColourUsed = 2;
+ break;
+ case 4:
+ IconImages[i].Head.ColourUsed = 16;
+ break;
+ }
+ }
+ IconImages[i].Pal = (ILubyte*)ialloc(IconImages[i].Head.ColourUsed * 4);
+ if (IconImages[i].Pal == NULL)
+ goto file_read_error; // @TODO: Rename the label.
+ if (iread(IconImages[i].Pal, IconImages[i].Head.ColourUsed * 4, 1) != 1)
+ goto file_read_error;
+ }
+ else if (IconImages[i].Head.BitCount == 8) {
+ IconImages[i].Pal = (ILubyte*)ialloc(256 * 4);
+ if (IconImages[i].Pal == NULL)
+ goto file_read_error;
+ if (iread(IconImages[i].Pal, 1, 256 * 4) != 256*4)
+ goto file_read_error;
+ }
+ else {
+ IconImages[i].Pal = NULL;
+ }
+
+ PadSize = (4 - ((IconImages[i].Head.Width*IconImages[i].Head.BitCount + 7) / 8) % 4) % 4; // Has to be DWORD-aligned.
+ ANDPadSize = (4 - ((IconImages[i].Head.Width + 7) / 8) % 4) % 4; // AND is 1 bit/pixel
+ Size = ((IconImages[i].Head.Width*IconImages[i].Head.BitCount + 7) / 8 + PadSize)
+ * (IconImages[i].Head.Height / 2);
+
+
+ IconImages[i].Data = (ILubyte*)ialloc(Size);
+ if (IconImages[i].Data == NULL)
+ goto file_read_error;
+ if (iread(IconImages[i].Data, 1, Size) != Size)
+ goto file_read_error;
+
+ Size = (((IconImages[i].Head.Width + 7) /8) + ANDPadSize) * (IconImages[i].Head.Height / 2);
+ IconImages[i].AND = (ILubyte*)ialloc(Size);
+ if (IconImages[i].AND == NULL)
+ goto file_read_error;
+ if (iread(IconImages[i].AND, 1, Size) != Size)
+ goto file_read_error;
+ }
+ }
+
+
+ for (i = 0; i < IconDir.Count; i++) {
+ if (IconImages[i].Head.BitCount != 1 && IconImages[i].Head.BitCount != 4 &&
+ IconImages[i].Head.BitCount != 8 && IconImages[i].Head.BitCount != 24 &&
+
+ IconImages[i].Head.BitCount != 32)
+ continue;
+
+ if (!BaseCreated) {
+ if (IconImages[i].Head.Size == 0) // PNG compressed icon
+ ilTexImage(IconImages[i].Head.Width, IconImages[i].Head.Height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
+ else
+ ilTexImage(IconImages[i].Head.Width, IconImages[i].Head.Height / 2, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
+ iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
+ Image = iCurImage;
+ BaseCreated = IL_TRUE;
+ }
+ else {
+ if (IconImages[i].Head.Size == 0) // PNG compressed icon
+ Image->Next = ilNewImage(IconImages[i].Head.Width, IconImages[i].Head.Height, 1, 4, 1);
+ else
+ Image->Next = ilNewImage(IconImages[i].Head.Width, IconImages[i].Head.Height / 2, 1, 4, 1);
+ Image = Image->Next;
+ Image->Format = IL_BGRA;
+ }
+ Image->Type = IL_UNSIGNED_BYTE;
+
+ j = 0; k = 0; l = 128; CurAndByte = 0; x = 0;
+
+ w = IconImages[i].Head.Width;
+ PadSize = (4 - ((w*IconImages[i].Head.BitCount + 7) / 8) % 4) % 4; // Has to be DWORD-aligned.
+
+ ANDPadSize = (4 - ((w + 7) / 8) % 4) % 4; // AND is 1 bit/pixel
+ AndBytes = (w + 7) / 8;
+
+ if (IconImages[i].Head.BitCount == 1) {
+ for (; j < Image->SizeOfData; k++) {
+ for (m = 128; m && x < w; m >>= 1) {
+ Image->Data[j] = IconImages[i].Pal[!!(IconImages[i].Data[k] & m) * 4];
+ Image->Data[j+1] = IconImages[i].Pal[!!(IconImages[i].Data[k] & m) * 4 + 1];
+ Image->Data[j+2] = IconImages[i].Pal[!!(IconImages[i].Data[k] & m) * 4 + 2];
+ Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
+ j += 4;
+ l >>= 1;
+
+ ++x;
+ }
+ if (l == 0 || x == w) {
+ l = 128;
+ CurAndByte++;
+ if (x == w) {
+ CurAndByte += ANDPadSize;
+ k += PadSize;
+ x = 0;
+ }
+
+ }
+ }
+ }
+ else if (IconImages[i].Head.BitCount == 4) {
+ for (; j < Image->SizeOfData; j += 8, k++) {
+ Image->Data[j] = IconImages[i].Pal[((IconImages[i].Data[k] & 0xF0) >> 4) * 4];
+ Image->Data[j+1] = IconImages[i].Pal[((IconImages[i].Data[k] & 0xF0) >> 4) * 4 + 1];
+ Image->Data[j+2] = IconImages[i].Pal[((IconImages[i].Data[k] & 0xF0) >> 4) * 4 + 2];
+ Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
+ l >>= 1;
+
+ ++x;
+
+ if(x < w) {
+ Image->Data[j+4] = IconImages[i].Pal[(IconImages[i].Data[k] & 0x0F) * 4];
+ Image->Data[j+5] = IconImages[i].Pal[(IconImages[i].Data[k] & 0x0F) * 4 + 1];
+ Image->Data[j+6] = IconImages[i].Pal[(IconImages[i].Data[k] & 0x0F) * 4 + 2];
+ Image->Data[j+7] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
+ l >>= 1;
+
+ ++x;
+
+ }
+
+ else
+
+ j -= 4;
+
+
+ if (l == 0 || x == w) {
+ l = 128;
+ CurAndByte++;
+ if (x == w) {
+ CurAndByte += ANDPadSize;
+
+ k += PadSize;
+ x = 0;
+ }
+ }
+ }
+ }
+ else if (IconImages[i].Head.BitCount == 8) {
+ for (; j < Image->SizeOfData; j += 4, k++) {
+ Image->Data[j] = IconImages[i].Pal[IconImages[i].Data[k] * 4];
+ Image->Data[j+1] = IconImages[i].Pal[IconImages[i].Data[k] * 4 + 1];
+ Image->Data[j+2] = IconImages[i].Pal[IconImages[i].Data[k] * 4 + 2];
+ if (IconImages[i].AND == NULL) // PNG Palette
+ {
+ Image->Data[j+3] = IconImages[i].Pal[IconImages[i].Data[k] * 4 + 3];
+ }
+ else
+ {
+ Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
+ }
+ l >>= 1;
+
+ ++x;
+ if (l == 0 || x == w) {
+ l = 128;
+ CurAndByte++;
+ if (x == w) {
+ CurAndByte += ANDPadSize;
+
+ k += PadSize;
+ x = 0;
+ }
+ }
+ }
+ }
+ else if (IconImages[i].Head.BitCount == 24) {
+ for (; j < Image->SizeOfData; j += 4, k += 3) {
+ Image->Data[j] = IconImages[i].Data[k];
+ Image->Data[j+1] = IconImages[i].Data[k+1];
+ Image->Data[j+2] = IconImages[i].Data[k+2];
+ Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
+ l >>= 1;
+
+ ++x;
+ if (l == 0 || x == w) {
+ l = 128;
+ CurAndByte++;
+ if (x == w) {
+ CurAndByte += ANDPadSize;
+
+ k += PadSize;
+ x = 0;
+ }
+ }
+ }
+ }
+
+ else if (IconImages[i].Head.BitCount == 32) {
+ for (; j < Image->SizeOfData; j += 4, k += 4) {
+ Image->Data[j] = IconImages[i].Data[k];
+ Image->Data[j+1] = IconImages[i].Data[k+1];
+ Image->Data[j+2] = IconImages[i].Data[k+2];
+
+ //If the icon has 4 channels, use 4th channel for alpha...
+ //(for Windows XP style icons with true alpha channel
+ Image->Data[j+3] = IconImages[i].Data[k+3];
+ }
+ }
+ }
+
+
+ for (i = 0; i < IconDir.Count; i++) {
+ ifree(IconImages[i].Pal);
+ ifree(IconImages[i].Data);
+ ifree(IconImages[i].AND);
+ }
+ ifree(IconImages);
+ ifree(DirEntries);
+
+ return ilFixImage();
+
+file_read_error:
+ if (IconImages) {
+ for (i = 0; i < IconDir.Count; i++) {
+ if (IconImages[i].Pal)
+ ifree(IconImages[i].Pal);
+ if (IconImages[i].Data)
+ ifree(IconImages[i].Data);
+ if (IconImages[i].AND)
+ ifree(IconImages[i].AND);
+ }
+ ifree(IconImages);
+ }
+ if (DirEntries)
+ ifree(DirEntries);
+ return IL_FALSE;
+}
+
+
+#ifndef IL_NO_PNG
+// 08-22-2008: Copying a lot of this over from il_png.c for the moment.
+// @TODO: Make .ico and .png use the same functions.
+png_structp ico_png_ptr = NULL;
+png_infop ico_info_ptr = NULL;
+ILint ico_color_type;
+
+#define GAMMA_CORRECTION 1.0 // Doesn't seem to be doing anything...
+
+ILint ico_readpng_init();
+ILboolean ico_readpng_get_image(ICOIMAGE *Icon, ILdouble display_exponent);
+void ico_readpng_cleanup();
+#endif
+
+ILboolean iLoadIconPNG(ICOIMAGE *Icon)
+{
+#ifndef IL_NO_PNG
+ ILint init;
+ init = ico_readpng_init();
+ if (init)
+ return IL_FALSE;
+ if (!ico_readpng_get_image(Icon, GAMMA_CORRECTION))
+ return IL_FALSE;
+
+ ico_readpng_cleanup();
+ Icon->Head.Size = 0; // Easiest way to tell that this is a PNG.
+ // In the normal routine, it will not be 0.
+
+ return IL_TRUE;
+#else
+ Icon;
+ return IL_FALSE;
+#endif
+}
+
+#ifndef IL_NO_PNG
+static void ico_png_read(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ (void)png_ptr;
+ iread(data, 1, (ILuint)length);
+ return;
+}
+
+
+static void ico_png_error_func(png_structp png_ptr, png_const_charp message)
+{
+ message;
+ ilSetError(IL_LIB_PNG_ERROR);
+
+ /*
+ changed 20040224
+ From the libpng docs:
+ "Errors handled through png_error() are fatal, meaning that png_error()
+ should never return to its caller. Currently, this is handled via
+ setjmp() and longjmp()"
+ */
+ //return;
+ longjmp(png_jmpbuf(png_ptr), 1);
+}
+
+static void ico_png_warn_func(png_structp png_ptr, png_const_charp message)
+{
+ png_ptr; message;
+ return;
+}
+
+
+ILint ico_readpng_init()
+{
+ ico_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, ico_png_error_func, ico_png_warn_func);
+ if (!ico_png_ptr)
+ return 4; /* out of memory */
+
+ ico_info_ptr = png_create_info_struct(ico_png_ptr);
+ if (!ico_info_ptr) {
+ png_destroy_read_struct(&ico_png_ptr, NULL, NULL);
+ return 4; /* out of memory */
+ }
+
+
+ /* we could create a second info struct here (end_info), but it's only
+ * useful if we want to keep pre- and post-IDAT chunk info separated
+ * (mainly for PNG-aware image editors and converters) */
+
+
+ /* setjmp() must be called in every function that calls a PNG-reading
+ * libpng function */
+
+ if (setjmp(png_jmpbuf(ico_png_ptr))) {
+ png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
+ return 2;
+ }
+
+
+ png_set_read_fn(ico_png_ptr, NULL, ico_png_read);
+ png_set_error_fn(ico_png_ptr, NULL, ico_png_error_func, ico_png_warn_func);
+
+// png_set_sig_bytes(ico_png_ptr, 8); /* we already read the 8 signature bytes */
+
+ png_read_info(ico_png_ptr, ico_info_ptr); /* read all PNG info up to image data */
+
+ /* alternatively, could make separate calls to png_get_image_width(),
+ * etc., but want bit_depth and ico_color_type for later [don't care about
+ * compression_type and filter_type => NULLs] */
+
+ /* OK, that's all we need for now; return happy */
+
+ return 0;
+}
+
+
+ILboolean ico_readpng_get_image(ICOIMAGE *Icon, ILdouble display_exponent)
+{
+ png_bytepp row_pointers = NULL;
+ png_uint_32 width, height; // Changed the type to fix AMD64 bit problems, thanks to Eric Werness
+ ILdouble screen_gamma = 1.0;
+ ILuint i, channels;
+ ILenum format;
+ png_colorp palette;
+ ILint num_palette, j, bit_depth;
+#if _WIN32 || DJGPP
+ ILdouble image_gamma;
+#endif
+
+ display_exponent;
+
+ /* setjmp() must be called in every function that calls a PNG-reading
+ * libpng function */
+
+ if (setjmp(png_jmpbuf(ico_png_ptr))) {
+ png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
+ return IL_FALSE;
+ }
+
+ png_get_IHDR(ico_png_ptr, ico_info_ptr, (png_uint_32*)&width, (png_uint_32*)&height,
+ &bit_depth, &ico_color_type, NULL, NULL, NULL);
+
+ // Expand low-bit-depth grayscale images to 8 bits
+ if (ico_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
+ png_set_expand_gray_1_2_4_to_8(ico_png_ptr);
+ }
+
+ // Expand RGB images with transparency to full alpha channels
+ // so the data will be available as RGBA quartets.
+ // But don't expand paletted images, since we want alpha palettes!
+ if (png_get_valid(ico_png_ptr, ico_info_ptr, PNG_INFO_tRNS) && !(png_get_valid(ico_png_ptr, ico_info_ptr, PNG_INFO_PLTE)))
+ png_set_tRNS_to_alpha(ico_png_ptr);
+
+ //refresh information (added 20040224)
+ png_get_IHDR(ico_png_ptr, ico_info_ptr, (png_uint_32*)&width, (png_uint_32*)&height,
+ &bit_depth, &ico_color_type, NULL, NULL, NULL);
+
+ if (bit_depth < 8) { // Expanded earlier for grayscale, now take care of palette and rgb
+ bit_depth = 8;
+ png_set_packing(ico_png_ptr);
+ }
+
+ // Perform gamma correction.
+ // @TODO: Determine if we should call png_set_gamma if image_gamma is 1.0.
+#if _WIN32 || DJGPP
+ screen_gamma = 2.2;
+ if (png_get_gAMA(ico_png_ptr, ico_info_ptr, &image_gamma))
+ png_set_gamma(ico_png_ptr, screen_gamma, image_gamma);
+#else
+ screen_gamma = screen_gamma;
+#endif
+
+ //fix endianess
+#ifdef __LITTLE_ENDIAN__
+ if (bit_depth == 16)
+ png_set_swap(ico_png_ptr);
+#endif
+
+
+ png_read_update_info(ico_png_ptr, ico_info_ptr);
+ channels = (ILint)png_get_channels(ico_png_ptr, ico_info_ptr);
+ // added 20040224: update ico_color_type so that it has the correct value
+ // in iLoadPngInternal (globals rule...)
+ ico_color_type = png_get_color_type(ico_png_ptr, ico_info_ptr);
+
+ // Determine internal format
+ switch (ico_color_type)
+ {
+ case PNG_COLOR_TYPE_PALETTE:
+ Icon->Head.BitCount = 8;
+ format = IL_COLOUR_INDEX;
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ Icon->Head.BitCount = 24;
+ format = IL_RGB;
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ Icon->Head.BitCount = 32;
+ format = IL_RGBA;
+ break;
+ default:
+ ilSetError(IL_ILLEGAL_FILE_VALUE);
+ png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
+ return IL_FALSE;
+ }
+
+ if (ico_color_type & PNG_COLOR_MASK_COLOR)
+ png_set_bgr(ico_png_ptr);
+
+ Icon->Head.Width = width;
+ Icon->Head.Height = height;
+ Icon->Data = ialloc(width * height * Icon->Head.BitCount / 8);
+ if (Icon->Data == NULL)
+ {
+ png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
+ return IL_FALSE;
+ }
+
+ // Copy Palette
+ if (format == IL_COLOUR_INDEX)
+ {
+ int chans;
+ png_bytep trans = NULL;
+ int num_trans = -1;
+ if (!png_get_PLTE(ico_png_ptr, ico_info_ptr, &palette, &num_palette)) {
+ ilSetError(IL_ILLEGAL_FILE_VALUE);
+ png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
+ return IL_FALSE;
+ }
+
+ chans = 4;
+
+ if (png_get_valid(ico_png_ptr, ico_info_ptr, PNG_INFO_tRNS)) {
+ png_get_tRNS(ico_png_ptr, ico_info_ptr, &trans, &num_trans, NULL);
+ }
+
+// @TODO: We may need to keep track of the size of the palette.
+ Icon->Pal = (ILubyte*)ialloc(num_palette * chans);
+
+ for (j = 0; j < num_palette; ++j) {
+ Icon->Pal[chans*j + 0] = palette[j].blue;
+ Icon->Pal[chans*j + 1] = palette[j].green;
+ Icon->Pal[chans*j + 2] = palette[j].red;
+ if (trans != NULL) {
+ if (j < num_trans)
+ Icon->Pal[chans*j + 3] = trans[j];
+ else
+ Icon->Pal[chans*j + 3] = 255;
+ }
+ }
+
+ Icon->AND = NULL; // Transparency information is obtained from libpng.
+ }
+
+ //allocate row pointers
+ if ((row_pointers = (png_bytepp)ialloc(height * sizeof(png_bytep))) == NULL) {
+ png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
+ return IL_FALSE;
+ }
+
+
+ // Set the individual row_pointers to point at the correct offsets
+ // Needs to be flipped
+ for (i = 0; i < height; i++)
+ row_pointers[height - i - 1] = Icon->Data + i * width * Icon->Head.BitCount / 8;
+ //row_pointers[i] = Icon->Data + i * width * Icon->Head.BitCount / 8;
+
+
+ // Now we can go ahead and just read the whole image
+ png_read_image(ico_png_ptr, row_pointers);
+
+ /* and we're done! (png_read_end() can be omitted if no processing of
+ * post-IDAT text/time/etc. is desired) */
+ //png_read_end(ico_png_ptr, NULL);
+ ifree(row_pointers);
+
+ return IL_TRUE;
+}
+
+
+void ico_readpng_cleanup()
+{
+ if (ico_png_ptr && ico_info_ptr) {
+ png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
+ ico_png_ptr = NULL;
+ ico_info_ptr = NULL;
+ }
+}
+#endif//IL_NO_PNG
+
+#endif//IL_NO_ICO