summaryrefslogtreecommitdiff
path: root/osframework/source/ImageLib/ImageLib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'osframework/source/ImageLib/ImageLib.cpp')
-rw-r--r--osframework/source/ImageLib/ImageLib.cpp1660
1 files changed, 1660 insertions, 0 deletions
diff --git a/osframework/source/ImageLib/ImageLib.cpp b/osframework/source/ImageLib/ImageLib.cpp
new file mode 100644
index 0000000..b8179c6
--- /dev/null
+++ b/osframework/source/ImageLib/ImageLib.cpp
@@ -0,0 +1,1660 @@
+#define XMD_H
+
+#include <windows.h>
+#include "ImageLib.h"
+#include "png\png.h"
+#include <math.h>
+#include <tchar.h>
+#include "..\PakLib\PakInterface.h"
+
+extern "C"
+{
+#include "jpeg\jpeglib.h"
+#include "jpeg\jerror.h"
+}
+
+//#include "jpeg2000/jasper.h"
+
+using namespace ImageLib;
+
+Image::Image()
+{
+ mWidth = 0;
+ mHeight = 0;
+ mBits = NULL;
+}
+
+Image::~Image()
+{
+ delete mBits;
+}
+
+int Image::GetWidth()
+{
+ return mWidth;
+}
+
+int Image::GetHeight()
+{
+ return mHeight;
+}
+
+unsigned long* Image::GetBits()
+{
+ return mBits;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// PNG Pak Support
+
+static void png_pak_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_size_t check;
+
+ /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ * instead of an int, which is what fread() actually returns.
+ */
+ check = (png_size_t)p_fread(data, (png_size_t)1, length,
+ (PFILE*)png_ptr->io_ptr);
+
+ if (check != length)
+ {
+ png_error(png_ptr, "Read Error");
+ }
+}
+
+Image* GetPNGImage(const std::string& theFileName)
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+ unsigned int sig_read = 0;
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type;
+ PFILE *fp;
+
+ if ((fp = p_fopen(theFileName.c_str(), "rb")) == NULL)
+ return NULL;
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL);
+ png_set_read_fn(png_ptr, (png_voidp)fp, png_pak_read_data);
+
+ if (png_ptr == NULL)
+ {
+ p_fclose(fp);
+ return NULL;
+ }
+
+ /* Allocate/initialize the memory for image information. REQUIRED. */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ p_fclose(fp);
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ return NULL;
+ }
+
+ /* Set error handling if you are using the setjmp/longjmp method (this is
+ * the normal method of doing things with libpng). REQUIRED unless you
+ * set up your own error handlers in the png_create_read_struct() earlier.
+ */
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ /* Free all of the memory associated with the png_ptr and info_ptr */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ p_fclose(fp);
+ /* If we get here, we had a problem reading the file */
+ return NULL;
+ }
+
+ //png_init_io(png_ptr, fp);
+
+ //png_ptr->io_ptr = (png_voidp)fp;
+
+ png_read_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+ &interlace_type, NULL, NULL);
+
+ /* Add filler (or alpha) byte (before/after each RGB triplet) */
+ png_set_expand(png_ptr);
+ png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+ //png_set_gray_1_2_4_to_8(png_ptr);
+ png_set_palette_to_rgb(png_ptr);
+ png_set_gray_to_rgb(png_ptr);
+ png_set_bgr(png_ptr);
+
+// int aNumBytes = png_get_rowbytes(png_ptr, info_ptr) * height / 4;
+ unsigned long* aBits = new unsigned long[width*height];
+ unsigned long* anAddr = aBits;
+ for (int i = 0; i < height; i++)
+ {
+ png_read_rows(png_ptr, (png_bytepp) &anAddr, NULL, 1);
+ anAddr += width;
+ }
+
+ /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
+ png_read_end(png_ptr, info_ptr);
+
+ /* clean up after the read, and free any memory allocated - REQUIRED */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+ /* close the file */
+ p_fclose(fp);
+
+ Image* anImage = new Image();
+ anImage->mWidth = width;
+ anImage->mHeight = height;
+ anImage->mBits = aBits;
+
+ return anImage;
+}
+
+Image* GetTGAImage(const std::string& theFileName)
+{
+ PFILE* aTGAFile = p_fopen(theFileName.c_str(), "rb");
+ if (aTGAFile == NULL)
+ return NULL;
+
+ BYTE aHeaderIDLen;
+ p_fread(&aHeaderIDLen, sizeof(BYTE), 1, aTGAFile);
+
+ BYTE aColorMapType;
+ p_fread(&aColorMapType, sizeof(BYTE), 1, aTGAFile);
+
+ BYTE anImageType;
+ p_fread(&anImageType, sizeof(BYTE), 1, aTGAFile);
+
+ WORD aFirstEntryIdx;
+ p_fread(&aFirstEntryIdx, sizeof(WORD), 1, aTGAFile);
+
+ WORD aColorMapLen;
+ p_fread(&aColorMapLen, sizeof(WORD), 1, aTGAFile);
+
+ BYTE aColorMapEntrySize;
+ p_fread(&aColorMapEntrySize, sizeof(BYTE), 1, aTGAFile);
+
+ WORD anXOrigin;
+ p_fread(&anXOrigin, sizeof(WORD), 1, aTGAFile);
+
+ WORD aYOrigin;
+ p_fread(&aYOrigin, sizeof(WORD), 1, aTGAFile);
+
+ WORD anImageWidth;
+ p_fread(&anImageWidth, sizeof(WORD), 1, aTGAFile);
+
+ WORD anImageHeight;
+ p_fread(&anImageHeight, sizeof(WORD), 1, aTGAFile);
+
+ BYTE aBitCount = 32;
+ p_fread(&aBitCount, sizeof(BYTE), 1, aTGAFile);
+
+ BYTE anImageDescriptor = 8 | (1<<5);
+ p_fread(&anImageDescriptor, sizeof(BYTE), 1, aTGAFile);
+
+ if ((aBitCount != 32) ||
+ (anImageDescriptor != (8 | (1<<5))))
+ {
+ p_fclose(aTGAFile);
+ return NULL;
+ }
+
+ Image* anImage = new Image();
+
+ anImage->mWidth = anImageWidth;
+ anImage->mHeight = anImageHeight;
+ anImage->mBits = new unsigned long[anImageWidth*anImageHeight];
+
+ p_fread(anImage->mBits, 4, anImage->mWidth*anImage->mHeight, aTGAFile);
+
+ p_fclose(aTGAFile);
+
+ return anImage;
+}
+
+int ReadBlobBlock(PFILE* fp, char* data)
+{
+ unsigned char aCount = 0;
+ p_fread(&aCount, sizeof(char), 1, fp);
+ p_fread(data, sizeof(char), aCount, fp);
+ return aCount;
+}
+
+Image* GetGIFImage(const std::string& theFileName)
+{
+ #define BitSet(byte,bit) (((byte) & (bit)) == (bit))
+ #define LSBFirstOrder(x,y) (((y) << 8) | (x))
+
+ int
+ opacity,
+ status;
+
+ register int i;
+
+ register unsigned char *p;
+
+ unsigned char
+ background,
+ c,
+ flag,
+ *global_colormap,
+ header[1664],
+ magick[12];
+
+ unsigned int
+ delay,
+ dispose,
+ global_colors,
+ image_count,
+ iterations;
+
+ /*
+ Open image file.
+ */
+
+ PFILE *fp;
+
+ if ((fp = p_fopen(theFileName.c_str(), "rb")) == NULL)
+ return NULL;
+ /*
+ Determine if this is a GIF file.
+ */
+ status=p_fread(magick, sizeof(char), 6, fp);
+
+ if (((strncmp((char *) magick,"GIF87",5) != 0) &&
+ (strncmp((char *) magick,"GIF89",5) != 0)))
+ return NULL;
+
+ global_colors=0;
+ global_colormap=(unsigned char *) NULL;
+
+ short pw;
+ short ph;
+
+ p_fread(&pw, sizeof(short), 1, fp);
+ p_fread(&ph, sizeof(short), 1, fp);
+ p_fread(&flag, sizeof(char), 1, fp);
+ p_fread(&background, sizeof(char), 1, fp);
+ p_fread(&c, sizeof(char), 1, fp);
+
+ if (BitSet(flag,0x80))
+ {
+ /*
+ opacity global colormap.
+ */
+ global_colors=1 << ((flag & 0x07)+1);
+ global_colormap=new unsigned char[3*global_colors];
+ if (global_colormap == (unsigned char *) NULL)
+ return NULL;
+
+ p_fread(global_colormap, sizeof(char), 3*global_colors, fp);
+ }
+
+ delay=0;
+ dispose=0;
+ iterations=1;
+ opacity=(-1);
+ image_count=0;
+
+ for ( ; ; )
+ {
+ if (p_fread(&c, sizeof(char), 1, fp) == 0)
+ break;
+
+ if (c == ';')
+ break; /* terminator */
+ if (c == '!')
+ {
+ /*
+ GIF Extension block.
+ */
+ p_fread(&c, sizeof(char), 1, fp);
+
+ switch (c)
+ {
+ case 0xf9:
+ {
+ /*
+ Read Graphics Control extension.
+ */
+ while (ReadBlobBlock(fp,(char *) header) > 0);
+
+ dispose=header[0] >> 2;
+ delay=(header[2] << 8) | header[1];
+ if ((header[0] & 0x01) == 1)
+ opacity=header[3];
+ break;
+ }
+ case 0xfe:
+ {
+ char *comments;
+ int length;
+
+ /*
+ Read Comment extension.
+ */
+ comments=(char *) NULL;
+ for ( ; ; )
+ {
+ length=ReadBlobBlock(fp,(char *) header);
+ if (length <= 0)
+ break;
+ if (comments == NULL)
+ {
+ comments= new char[length+1];
+ if (comments != (char *) NULL)
+ *comments='\0';
+ }
+
+ header[length]='\0';
+ strcat(comments,(char *) header);
+ }
+ if (comments == (char *) NULL)
+ break;
+
+ delete comments;
+ break;
+ }
+ case 0xff:
+ {
+ int
+ loop;
+
+ /*
+ Read Netscape Loop extension.
+ */
+ loop=false;
+ if (ReadBlobBlock(fp,(char *) header) > 0)
+ loop=!strncmp((char *) header,"NETSCAPE2.0",11);
+ while (ReadBlobBlock(fp,(char *) header) > 0)
+ if (loop)
+ iterations=(header[2] << 8) | header[1];
+ break;
+ }
+ default:
+ {
+ while (ReadBlobBlock(fp,(char *) header) > 0);
+ break;
+ }
+ }
+ }
+
+ if (c != ',')
+ continue;
+
+ if (image_count != 0)
+ {
+ /*
+ Allocate next image structure.
+ */
+
+ /*AllocateNextImage(image_info,image);
+ if (image->next == (Image *) NULL)
+ {
+ DestroyImages(image);
+ return((Image *) NULL);
+ }
+ image=image->next;
+ MagickMonitor(LoadImagesText,TellBlob(image),image->filesize);*/
+ }
+ image_count++;
+
+ short pagex;
+ short pagey;
+ short width;
+ short height;
+ int colors;
+ bool interlaced;
+
+ p_fread(&pagex, sizeof(short), 1, fp);
+ p_fread(&pagey, sizeof(short), 1, fp);
+ p_fread(&width, sizeof(short), 1, fp);
+ p_fread(&height, sizeof(short), 1, fp);
+ p_fread(&flag, sizeof(char), 1, fp);
+
+ colors=!BitSet(flag,0x80) ? global_colors : 1 << ((flag & 0x07)+1);
+ unsigned long* colortable = new unsigned long[colors];
+
+ interlaced = BitSet(flag,0x40);
+
+ delay=0;
+ dispose=0;
+ iterations=1;
+ /*if (image_info->ping)
+ {
+ f (opacity >= 0)
+ /image->matte=true;
+
+ CloseBlob(image);
+ return(image);
+ }*/
+ if ((width == 0) || (height == 0))
+ return NULL;
+ /*
+ Inititialize colormap.
+ */
+ /*if (!AllocateImageColormap(image,image->colors))
+ ThrowReaderException(ResourceLimitWarning,"Memory allocation failed",
+ image);*/
+ if (!BitSet(flag,0x80))
+ {
+ /*
+ Use global colormap.
+ */
+ p=global_colormap;
+ for (i=0; i < (int) colors; i++)
+ {
+ int r = *p++;
+ int g = *p++;
+ int b = *p++;
+
+ colortable[i] = 0xFF000000 | (r << 16) | (g << 8) | (b);
+ }
+
+ //image->background_color=
+ //image->colormap[Min(background,image->colors-1)];
+ }
+ else
+ {
+ unsigned char
+ *colormap;
+
+ /*
+ Read local colormap.
+ */
+ colormap=new unsigned char[3*colors];
+
+ int pos = p_ftell(fp);
+ p_fread(colormap, sizeof(char), 3*colors, fp);
+
+ p=colormap;
+ for (i=0; i < (int) colors; i++)
+ {
+ int r = *p++;
+ int g = *p++;
+ int b = *p++;
+
+ colortable[i] = 0xFF000000 | (r << 16) | (g << 8) | (b);
+ }
+ delete colormap;
+ }
+
+ /*if (opacity >= (int) colors)
+ {
+ for (i=colors; i < (opacity+1); i++)
+ {
+ image->colormap[i].red=0;
+ image->colormap[i].green=0;
+ image->colormap[i].blue=0;
+ }
+ image->colors=opacity+1;
+ }*/
+ /*
+ Decode image.
+ */
+ //status=DecodeImage(image,opacity,exception);
+
+ //if (global_colormap != (unsigned char *) NULL)
+ // LiberateMemory((void **) &global_colormap);
+ if (global_colormap != NULL)
+ {
+ delete [] global_colormap;
+ global_colormap = NULL;
+ }
+
+ //while (image->previous != (Image *) NULL)
+ // image=image->previous;
+
+ #define MaxStackSize 4096
+ #define NullCode (-1)
+
+ int
+ available,
+ bits,
+ code,
+ clear,
+ code_mask,
+ code_size,
+ count,
+ end_of_information,
+ in_code,
+ offset,
+ old_code,
+ pass,
+ y;
+
+ register int
+ x;
+
+ register unsigned int
+ datum;
+
+ short
+ *prefix;
+
+ unsigned char
+ data_size,
+ first,
+ *packet,
+ *pixel_stack,
+ *suffix,
+ *top_stack;
+
+ /*
+ Allocate decoder tables.
+ */
+
+ packet=new unsigned char[256];
+ prefix=new short[MaxStackSize];
+ suffix=new unsigned char [MaxStackSize];
+ pixel_stack= new unsigned char[MaxStackSize+1];
+
+ /*
+ Initialize GIF data stream decoder.
+ */
+ p_fread(&data_size, sizeof(char), 1, fp);
+ clear=1 << data_size;
+ end_of_information=clear+1;
+ available=clear+2;
+ old_code=NullCode;
+ code_size=data_size+1;
+ code_mask=(1 << code_size)-1;
+ for (code=0; code < clear; code++)
+ {
+ prefix[code]=0;
+ suffix[code]=(unsigned char) code;
+ }
+ /*
+ Decode GIF pixel stream.
+ */
+ datum=0;
+ bits=0;
+ c=0;
+ count=0;
+ first=0;
+ offset=0;
+ pass=0;
+ top_stack=pixel_stack;
+
+ unsigned long* aBits = new unsigned long[width*height];
+
+ register unsigned char *c = NULL;
+
+ for (y=0; y < (int) height; y++)
+ {
+ //q=SetImagePixels(image,0,offset,width,1);
+ //if (q == (PixelPacket *) NULL)
+ //break;
+ //indexes=GetIndexes(image);
+
+ unsigned long* q = aBits + offset*width;
+
+
+
+ for (x=0; x < (int) width; )
+ {
+ if (top_stack == pixel_stack)
+ {
+ if (bits < code_size)
+ {
+ /*
+ Load bytes until there is enough bits for a code.
+ */
+ if (count == 0)
+ {
+ /*
+ Read a new data block.
+ */
+ int pos = p_ftell(fp);
+
+ count=ReadBlobBlock(fp,(char *) packet);
+ if (count <= 0)
+ break;
+ c=packet;
+ }
+ datum+=(*c) << bits;
+ bits+=8;
+ c++;
+ count--;
+ continue;
+ }
+ /*
+ Get the next code.
+ */
+ code=datum & code_mask;
+ datum>>=code_size;
+ bits-=code_size;
+ /*
+ Interpret the code
+ */
+ if ((code > available) || (code == end_of_information))
+ break;
+ if (code == clear)
+ {
+ /*
+ Reset decoder.
+ */
+ code_size=data_size+1;
+ code_mask=(1 << code_size)-1;
+ available=clear+2;
+ old_code=NullCode;
+ continue;
+ }
+ if (old_code == NullCode)
+ {
+ *top_stack++=suffix[code];
+ old_code=code;
+ first=(unsigned char) code;
+ continue;
+ }
+ in_code=code;
+ if (code >= available)
+ {
+ *top_stack++=first;
+ code=old_code;
+ }
+ while (code >= clear)
+ {
+ *top_stack++=suffix[code];
+ code=prefix[code];
+ }
+ first=suffix[code];
+ /*
+ Add a new string to the string table,
+ */
+ if (available >= MaxStackSize)
+ break;
+ *top_stack++=first;
+ prefix[available]=old_code;
+ suffix[available]=first;
+ available++;
+ if (((available & code_mask) == 0) && (available < MaxStackSize))
+ {
+ code_size++;
+ code_mask+=available;
+ }
+ old_code=in_code;
+ }
+ /*
+ Pop a pixel off the pixel stack.
+ */
+ top_stack--;
+
+ int index=(*top_stack);
+
+ *q=colortable[index];
+
+ if (index == opacity)
+ *q = 0;
+
+ x++;
+ q++;
+ }
+
+ if (!interlaced)
+ offset++;
+ else
+ {
+ switch (pass)
+ {
+ case 0:
+ default:
+ {
+ offset+=8;
+ if (offset >= height)
+ {
+ pass++;
+ offset=4;
+ }
+ break;
+ }
+ case 1:
+ {
+ offset+=8;
+ if (offset >= height)
+ {
+ pass++;
+ offset=2;
+ }
+ break;
+ }
+ case 2:
+ {
+ offset+=4;
+ if (offset >= height)
+ {
+ pass++;
+ offset=1;
+ }
+ break;
+ }
+ case 3:
+ {
+ offset+=2;
+ break;
+ }
+ }
+ }
+
+ if (x < width)
+ break;
+
+ /*if (image->previous == (Image *) NULL)
+ if (QuantumTick(y,image->rows))
+ MagickMonitor(LoadImageText,y,image->rows);*/
+ }
+ delete pixel_stack;
+ delete suffix;
+ delete prefix;
+ delete packet;
+
+ delete colortable;
+
+ //if (y < image->rows)
+ //failed = true;
+
+ Image* anImage = new Image();
+
+ anImage->mWidth = width;
+ anImage->mHeight = height;
+ anImage->mBits = aBits;
+
+ //TODO: Change for animation crap
+ p_fclose(fp);
+ return anImage;
+ }
+
+ p_fclose(fp);
+
+ return NULL;
+}
+
+typedef struct my_error_mgr * my_error_ptr;
+
+struct my_error_mgr
+{
+ struct jpeg_error_mgr pub; /* "public" fields */
+
+ jmp_buf setjmp_buffer; /* for return to caller */
+};
+
+METHODDEF(void)
+my_error_exit (j_common_ptr cinfo)
+{
+ /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
+ my_error_ptr myerr = (my_error_ptr) cinfo->err;
+
+ /* Always display the message. */
+ /* We could postpone this until after returning, if we chose. */
+ (*cinfo->err->output_message) (cinfo);
+
+ /* Return control to the setjmp point */
+ longjmp(myerr->setjmp_buffer, 1);
+
+}
+
+bool ImageLib::WriteJPEGImage(const std::string& theFileName, Image* theImage)
+{
+ FILE *fp;
+
+ if ((fp = fopen(theFileName.c_str(), "wb")) == NULL)
+ return false;
+
+ struct jpeg_compress_struct cinfo;
+ struct my_error_mgr jerr;
+
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = my_error_exit;
+
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_compress(&cinfo);
+ fclose(fp);
+ return false;
+ }
+
+ jpeg_create_compress(&cinfo);
+
+ cinfo.image_width = theImage->mWidth;
+ cinfo.image_height = theImage->mHeight;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+ cinfo.optimize_coding = 1;
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, 80, TRUE);
+
+ jpeg_stdio_dest(&cinfo, fp);
+
+ jpeg_start_compress(&cinfo, true);
+
+ int row_stride = theImage->GetWidth() * 3;
+
+ unsigned char* aTempBuffer = new unsigned char[row_stride];
+
+ unsigned long* aSrcPtr = theImage->mBits;
+
+ for (int aRow = 0; aRow < theImage->mHeight; aRow++)
+ {
+ unsigned char* aDest = aTempBuffer;
+
+ for (int aCol = 0; aCol < theImage->mWidth; aCol++)
+ {
+ unsigned long src = *(aSrcPtr++);
+
+ *aDest++ = (src >> 16) & 0xFF;
+ *aDest++ = (src >> 8) & 0xFF;
+ *aDest++ = (src ) & 0xFF;
+ }
+
+ jpeg_write_scanlines(&cinfo, &aTempBuffer, 1);
+ }
+
+ delete [] aTempBuffer;
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ fclose(fp);
+
+ return true;
+}
+
+bool ImageLib::WritePNGImage(const std::string& theFileName, Image* theImage)
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ FILE *fp;
+
+ if ((fp = fopen(theFileName.c_str(), "wb")) == NULL)
+ return false;
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL);
+
+ if (png_ptr == NULL)
+ {
+ fclose(fp);
+ return false;
+ }
+
+ // Allocate/initialize the memory for image information. REQUIRED.
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ return false;
+ }
+
+ // Set error handling if you are using the setjmp/longjmp method (this is
+ // the normal method of doing things with libpng). REQUIRED unless you
+ // set up your own error handlers in the png_create_write_struct() earlier.
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ // Free all of the memory associated with the png_ptr and info_ptr
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ // If we get here, we had a problem writeing the file
+ return NULL;
+ }
+
+ png_init_io(png_ptr, fp);
+
+ png_color_8 sig_bit;
+ sig_bit.red = 8;
+ sig_bit.green = 8;
+ sig_bit.blue = 8;
+ /* if the image has an alpha channel then */
+ sig_bit.alpha = 8;
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+ png_set_bgr(png_ptr);
+
+ png_set_IHDR(png_ptr, info_ptr, theImage->mWidth, theImage->mHeight, 8, PNG_COLOR_TYPE_RGB_ALPHA,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ // Add filler (or alpha) byte (before/after each RGB triplet)
+ //png_set_expand(png_ptr);
+ //png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+ //png_set_gray_1_2_4_to_8(png_ptr);
+ //png_set_palette_to_rgb(png_ptr);
+ //png_set_gray_to_rgb(png_ptr);
+
+ png_write_info(png_ptr, info_ptr);
+
+ for (int i = 0; i < theImage->mHeight; i++)
+ {
+ png_bytep aRowPtr = (png_bytep) (theImage->mBits + i*theImage->mWidth);
+ png_write_rows(png_ptr, &aRowPtr, 1);
+ }
+
+ // write rest of file, and get additional chunks in info_ptr - REQUIRED
+ png_write_end(png_ptr, info_ptr);
+
+ // clean up after the write, and free any memory allocated - REQUIRED
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ // close the file
+ fclose(fp);
+
+ return true;
+}
+
+bool ImageLib::WriteTGAImage(const std::string& theFileName, Image* theImage)
+{
+ FILE* aTGAFile = fopen(theFileName.c_str(), "wb");
+ if (aTGAFile == NULL)
+ return false;
+
+ BYTE aHeaderIDLen = 0;
+ fwrite(&aHeaderIDLen, sizeof(BYTE), 1, aTGAFile);
+
+ BYTE aColorMapType = 0;
+ fwrite(&aColorMapType, sizeof(BYTE), 1, aTGAFile);
+
+ BYTE anImageType = 2;
+ fwrite(&anImageType, sizeof(BYTE), 1, aTGAFile);
+
+ WORD aFirstEntryIdx = 0;
+ fwrite(&aFirstEntryIdx, sizeof(WORD), 1, aTGAFile);
+
+ WORD aColorMapLen = 0;
+ fwrite(&aColorMapLen, sizeof(WORD), 1, aTGAFile);
+
+ BYTE aColorMapEntrySize = 0;
+ fwrite(&aColorMapEntrySize, sizeof(BYTE), 1, aTGAFile);
+
+ WORD anXOrigin = 0;
+ fwrite(&anXOrigin, sizeof(WORD), 1, aTGAFile);
+
+ WORD aYOrigin = 0;
+ fwrite(&aYOrigin, sizeof(WORD), 1, aTGAFile);
+
+ WORD anImageWidth = theImage->mWidth;
+ fwrite(&anImageWidth, sizeof(WORD), 1, aTGAFile);
+
+ WORD anImageHeight = theImage->mHeight;
+ fwrite(&anImageHeight, sizeof(WORD), 1, aTGAFile);
+
+ BYTE aBitCount = 32;
+ fwrite(&aBitCount, sizeof(BYTE), 1, aTGAFile);
+
+ BYTE anImageDescriptor = 8 | (1<<5);
+ fwrite(&anImageDescriptor, sizeof(BYTE), 1, aTGAFile);
+
+ fwrite(theImage->mBits, 4, theImage->mWidth*theImage->mHeight, aTGAFile);
+
+ fclose(aTGAFile);
+
+ return true;
+}
+
+bool ImageLib::WriteBMPImage(const std::string& theFileName, Image* theImage)
+{
+ FILE* aFile = fopen(theFileName.c_str(), "wb");
+ if (aFile == NULL)
+ return false;
+
+ BITMAPFILEHEADER aFileHeader;
+ BITMAPINFOHEADER aHeader;
+
+ memset(&aFileHeader,0,sizeof(aFileHeader));
+ memset(&aHeader,0,sizeof(aHeader));
+
+ int aNumBytes = theImage->mWidth*theImage->mHeight*4;
+
+ aFileHeader.bfType = ('M'<<8) | 'B';
+ aFileHeader.bfSize = sizeof(aFileHeader) + sizeof(aHeader) + aNumBytes;
+ aFileHeader.bfOffBits = sizeof(aHeader);
+
+ aHeader.biSize = sizeof(aHeader);
+ aHeader.biWidth = theImage->mWidth;
+ aHeader.biHeight = theImage->mHeight;
+ aHeader.biPlanes = 1;
+ aHeader.biBitCount = 32;
+ aHeader.biCompression = BI_RGB;
+
+ fwrite(&aFileHeader,sizeof(aFileHeader),1,aFile);
+ fwrite(&aHeader,sizeof(aHeader),1,aFile);
+ DWORD *aRow = theImage->mBits + (theImage->mHeight-1)*theImage->mWidth;
+ int aRowSize = theImage->mWidth*4;
+ for (int i=0; i<theImage->mHeight; i++, aRow-=theImage->mWidth)
+ fwrite(aRow,4,theImage->mWidth,aFile);
+
+ fclose(aFile);
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// JPEG Pak Reader
+
+typedef struct {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ PFILE * infile; /* source stream */
+ JOCTET * buffer; /* start of buffer */
+ boolean start_of_file; /* have we gotten any data yet? */
+} pak_source_mgr;
+
+typedef pak_source_mgr * pak_src_ptr;
+
+#define INPUT_BUF_SIZE 4096
+
+METHODDEF(void) init_source (j_decompress_ptr cinfo)
+{
+ pak_src_ptr src = (pak_src_ptr) cinfo->src;
+ src->start_of_file = TRUE;
+}
+
+METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo)
+{
+ pak_src_ptr src = (pak_src_ptr) cinfo->src;
+ size_t nbytes;
+
+ nbytes = p_fread(src->buffer, 1, INPUT_BUF_SIZE, src->infile);
+ //((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
+
+ if (nbytes <= 0) {
+ if (src->start_of_file) /* Treat empty input file as fatal error */
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ nbytes = 2;
+ }
+
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+ src->start_of_file = FALSE;
+
+ return TRUE;
+}
+
+METHODDEF(void) skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ pak_src_ptr src = (pak_src_ptr) cinfo->src;
+
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->pub.bytes_in_buffer) {
+ num_bytes -= (long) src->pub.bytes_in_buffer;
+ (void) fill_input_buffer(cinfo);
+ }
+ src->pub.next_input_byte += (size_t) num_bytes;
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+METHODDEF(void) term_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+void jpeg_pak_src (j_decompress_ptr cinfo, PFILE* infile)
+{
+ pak_src_ptr src;
+
+ /* The source object and input buffer are made permanent so that a series
+ * of JPEG images can be read from the same file by calling jpeg_stdio_src
+ * only before the first one. (If we discarded the buffer at the end of
+ * one image, we'd likely lose the start of the next one.)
+ * This makes it unsafe to use this manager and a different source
+ * manager serially with the same JPEG object. Caveat programmer.
+ */
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ sizeof(pak_source_mgr));
+ src = (pak_src_ptr) cinfo->src;
+ src->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ INPUT_BUF_SIZE * sizeof(JOCTET));
+ }
+
+ src = (pak_src_ptr) cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->pub.term_source = term_source;
+ src->infile = infile;
+ src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+ src->pub.next_input_byte = NULL; /* until buffer loaded */
+}
+
+
+Image* GetJPEGImage(const std::string& theFileName)
+{
+ PFILE *fp;
+
+ if ((fp = p_fopen(theFileName.c_str(), "rb")) == NULL)
+ return NULL;
+
+ struct jpeg_decompress_struct cinfo;
+ struct my_error_mgr jerr;
+
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = my_error_exit;
+
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_decompress(&cinfo);
+ p_fclose(fp);
+ return 0;
+ }
+
+ jpeg_create_decompress(&cinfo);
+ jpeg_pak_src(&cinfo, fp);
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_start_decompress(&cinfo);
+ int row_stride = cinfo.output_width * cinfo.output_components;
+
+ unsigned char** buffer = (*cinfo.mem->alloc_sarray)
+ ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
+
+ unsigned long* aBits = new unsigned long[cinfo.output_width*cinfo.output_height];
+ unsigned long* q = aBits;
+
+ if (cinfo.output_components==1)
+ {
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ jpeg_read_scanlines(&cinfo, buffer, 1);
+
+ unsigned char* p = *buffer;
+ for (int i = 0; i < cinfo.output_width; i++)
+ {
+ int r = *p++;
+ *q++ = 0xFF000000 | (r << 16) | (r << 8) | (r);
+ }
+ }
+ }
+ else
+ {
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ jpeg_read_scanlines(&cinfo, buffer, 1);
+
+ unsigned char* p = *buffer;
+ for (int i = 0; i < cinfo.output_width; i++)
+ {
+ int r = *p++;
+ int g = *p++;
+ int b = *p++;
+
+ *q++ = 0xFF000000 | (r << 16) | (g << 8) | (b);
+ }
+ }
+ }
+
+ Image* anImage = new Image();
+ anImage->mWidth = cinfo.output_width;
+ anImage->mHeight = cinfo.output_height;
+ anImage->mBits = aBits;
+
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+
+ p_fclose(fp);
+
+ return anImage;
+}
+
+#if 0
+Image* GetJPEG2000Image(const std::string& theFileName)
+{
+ DWORD aTick = GetTickCount();
+
+ static bool inited = false;
+ if (!inited)
+ {
+ inited = true;
+ jas_init();
+ }
+
+ jas_stream_t* aStream = jas_stream_fopen(theFileName.c_str(),"rb");
+ if (!aStream)
+ return NULL;
+
+ // Read Image Header
+ int aFormat = jas_image_getfmt(aStream);
+ if (aFormat < 0)
+ {
+ jas_stream_close(aStream);
+ return NULL;
+ }
+
+ jas_image_t* aJasImage = jas_image_decode(aStream,aFormat,NULL);
+ if (!aJasImage)
+ {
+ jas_stream_close(aStream);
+ return NULL;
+ }
+
+ DWORD aDecodeTime = GetTickCount() - aTick;
+
+ int aNumComponents = jas_image_numcmpts(aJasImage);
+ if (aNumComponents<1 || aNumComponents>4)
+ {
+ jas_stream_close(aStream);
+ jas_image_destroy(aJasImage);
+ return NULL;
+ }
+
+ int i;
+ int aMaxWidth = 0;
+ int aMaxHeight = 0;
+ for (i=0; i<aNumComponents; i++)
+ {
+ int hstep = jas_image_cmpthstep(aJasImage,i);
+ int numHSteps = jas_image_cmptwidth(aJasImage,i);
+
+ int vstep = jas_image_cmptvstep(aJasImage,i);
+ int numVSteps = jas_image_cmptheight(aJasImage,i);
+
+ int aWidth = jas_image_cmpttlx(aJasImage,i) + hstep*numHSteps;
+ int aHeight = jas_image_cmpttly(aJasImage,i) + vstep*numVSteps;
+
+ if (aWidth > aMaxWidth)
+ aMaxWidth = aWidth;
+
+ if (aHeight > aMaxHeight)
+ aMaxHeight = aHeight;
+ }
+
+ // Read Image Data
+ Image *anImage = new Image;
+ anImage->mWidth = aMaxWidth;
+ anImage->mHeight = aMaxHeight;
+ anImage->mBits = new unsigned long[aMaxWidth * aMaxHeight];
+ memset(anImage->mBits,0,aMaxWidth * aMaxHeight*4);
+
+ int aColorModel = jas_image_clrspc(aJasImage);
+
+ for (i=0; i<aNumComponents; i++)
+ {
+ int hstep = jas_image_cmpthstep(aJasImage,i);
+ int vstep = jas_image_cmptvstep(aJasImage,i);
+ int numHSteps = jas_image_cmptwidth(aJasImage,i);
+ int numVSteps = jas_image_cmptheight(aJasImage,i);
+ int xorig = jas_image_cmpttlx(aJasImage,i);
+ int yorig = jas_image_cmpttly(aJasImage,i);
+ bool sign = jas_image_cmptsgnd(aJasImage,i)?true:false;
+
+ jas_matrix_t* aMatrix = jas_matrix_create(1,numHSteps);
+ if (!aMatrix)
+ {
+ delete anImage;
+ jas_image_destroy(aJasImage);
+ jas_stream_close(aStream);
+
+ return NULL;
+ }
+
+ int aShift = 8 - jas_image_cmptprec(aJasImage,i);
+ if (aShift<0)
+ {
+ delete anImage;
+ jas_matrix_destroy(aMatrix);
+ jas_image_destroy(aJasImage);
+ jas_stream_close(aStream);
+
+ return NULL;
+ }
+
+ unsigned long* destRow = anImage->mBits + yorig*numVSteps*anImage->GetWidth() + xorig*numHSteps;
+
+ // color model
+ int aComponentType = jas_image_cmpttype(aJasImage,i);
+ int aColorType = JAS_IMAGE_CT_COLOR(aComponentType);
+
+ switch (aColorType)
+ {
+ case JAS_IMAGE_CT_RGB_R: aShift += 16; break;
+ case JAS_IMAGE_CT_RGB_G: aShift += 8; break;
+ case JAS_IMAGE_CT_RGB_B: break;
+ default: aShift += 24; break;
+ }
+
+ for (int y=0; y<numVSteps; y++)
+ {
+ if (jas_image_readcmpt(aJasImage,i,0,y,numHSteps,1,aMatrix) )
+ {
+ delete anImage;
+ jas_matrix_destroy(aMatrix);
+ jas_image_destroy(aJasImage);
+ jas_stream_close(aStream);
+
+ return NULL;
+ }
+
+ unsigned long* dest = destRow;
+ for (int x=0; x<numHSteps; x++)
+ {
+ int aVal = jas_matrix_getv(aMatrix,x);
+ if (sign)
+ aVal = (unsigned char)(aVal + 128);
+
+ aVal <<= aShift;
+
+ unsigned long *destRowWriter = dest;
+ for (int j=0; j<vstep; j++)
+ {
+ unsigned long *destWriter = destRowWriter;
+ for (int k=0; k<hstep; k++)
+ *destWriter++ |= aVal;
+
+ destRowWriter += anImage->GetWidth();
+ }
+
+ dest += hstep;
+ }
+ destRow += vstep*anImage->GetWidth();
+ }
+
+ // release decoding matrix
+ jas_matrix_destroy(aMatrix);
+ }
+
+ DWORD aReadTime = GetTickCount() - aTick;
+ char aBuf[512];
+ sprintf(aBuf,"%d %d\n",aDecodeTime,aReadTime);
+ OutputDebugString(aBuf);
+
+
+ if (aNumComponents < 4) // add 255 alpha
+ {
+ int aSize = anImage->GetWidth()*anImage->GetHeight();
+ unsigned long *dest = anImage->mBits;
+ for (i=0; i<aSize; i++)
+ *dest++ |= 0xff000000;
+ }
+
+ jas_image_destroy(aJasImage);
+ jas_stream_close(aStream);
+
+ return anImage;
+}
+#else
+
+#include "j2k-codec\j2k-codec.h"
+
+HMODULE gJ2KCodec = NULL;
+std::string gJ2KCodecKey = "Your registration here";
+
+void ImageLib::InitJPEG2000()
+{
+ gJ2KCodec = ::LoadLibrary(_T("j2k-codec.dll"));
+}
+
+void ImageLib::CloseJPEG2000()
+{
+ if (gJ2KCodec != NULL)
+ {
+ ::FreeLibrary(gJ2KCodec);
+ gJ2KCodec = NULL;
+ }
+}
+
+void ImageLib::SetJ2KCodecKey(const std::string& theKey)
+{
+ gJ2KCodecKey = theKey;
+}
+
+int __stdcall Pak_seek(void *data_source, int offset)
+{
+ return p_fseek((PFILE*) data_source, offset, SEEK_SET);
+}
+
+int __stdcall Pak_read(void *ptr, int size, void *data_source)
+{
+ return p_fread(ptr, 1, size, (PFILE*) data_source);
+}
+
+void __stdcall Pak_close(void *data_source)
+{
+}
+
+Image* GetJPEG2000Image(const std::string& theFileName)
+{
+ if (gJ2KCodec != NULL)
+ {
+ PFILE* aFP = p_fopen(theFileName.c_str(), "rb");
+ if (aFP == NULL)
+ return NULL;
+
+ static int (__stdcall *fJ2K_getVersion)() = NULL;
+ static void (__stdcall *fJ2K_Unlock)(const char*) = NULL;
+ static void* (__stdcall *fJ2K_OpenCustom)(void*, J2K_Callbacks*) = NULL;
+ static void* (__stdcall *fJ2K_OpenFile)(const char*) = NULL;
+ static void (__stdcall *fJ2K_Close)(void*) = NULL;
+ static int (__stdcall *fJ2K_GetInfo)(void*, int*, int*, int*) = NULL;
+ static int (__stdcall *fJ2K_GetResolutionDimensions)(void*, int, int*, int*) = NULL;
+ static int (__stdcall *fJ2K_Decode)(void*, unsigned char**, int*, char*, int*) = NULL;
+ static int (__stdcall *fJ2K_getLastError)() = NULL;
+ static const char* (__stdcall *fJ2K_getErrorStr)(int) = NULL;
+ static bool loadFuncs = true;
+
+ if (loadFuncs)
+ {
+ loadFuncs = false;
+ *((void**)&fJ2K_getVersion) = (void*)::GetProcAddress(gJ2KCodec, "_J2K_getVersion@0");
+ *((void**)&fJ2K_Unlock) = (void*)::GetProcAddress(gJ2KCodec, "_J2K_Unlock@4");
+ *((void**)&fJ2K_OpenCustom) = (void*)::GetProcAddress(gJ2KCodec, "_J2K_OpenCustom@8");
+ *((void**)&fJ2K_OpenFile) = (void*)::GetProcAddress(gJ2KCodec, "_J2K_OpenFile@4");
+ *((void**)&fJ2K_Close) = (void*)::GetProcAddress(gJ2KCodec, "_J2K_Close@4");
+ *((void**)&fJ2K_GetInfo) = (void*)::GetProcAddress(gJ2KCodec, "_J2K_GetInfo@16");
+ *((void**)&fJ2K_GetResolutionDimensions) = (void*)::GetProcAddress(gJ2KCodec, "_J2K_GetResolutionDimensions@16");
+ *((void**)&fJ2K_Decode) = (void*)::GetProcAddress(gJ2KCodec, "_J2K_Decode@20");
+ *((void**)&fJ2K_getLastError) = (void*)::GetProcAddress(gJ2KCodec, "_J2K_getLastError@0");
+ *((void**)&fJ2K_getErrorStr) = (void*)::GetProcAddress(gJ2KCodec, "_J2K_getErrorStr@4");
+
+ // j2k guys didn't use declare the export names. yay! now we have to update these mangled names any time the DLL changes.
+
+ if (!(fJ2K_getVersion != NULL &&
+ fJ2K_Unlock != NULL &&
+ fJ2K_OpenCustom != NULL &&
+ fJ2K_OpenFile != NULL &&
+ fJ2K_Close != NULL &&
+ fJ2K_GetInfo != NULL &&
+ fJ2K_GetResolutionDimensions != NULL &&
+ fJ2K_Decode != NULL &&
+ fJ2K_getLastError != NULL &&
+ fJ2K_getErrorStr != NULL))
+ {
+ CloseJPEG2000();
+ return NULL;
+ }
+
+ int aJ2kVer = (*fJ2K_getVersion)();
+ if (aJ2kVer < 0x120000)
+ {
+ CloseJPEG2000();
+ return NULL;
+ }
+
+ (*fJ2K_Unlock)(gJ2KCodecKey.c_str());
+ }
+
+ J2K_Callbacks aCallbacks;
+ aCallbacks.read = Pak_read;
+ aCallbacks.seek = Pak_seek;
+ aCallbacks.close = Pak_close;
+
+ //theFileName.c_str()
+ void* aJ2KImage = (*fJ2K_OpenCustom)(aFP, &aCallbacks);
+ if (aJ2KImage == NULL)
+ {
+ int anErrNum = (*fJ2K_getLastError)();
+ std::string anErrorMessage = (*fJ2K_getErrorStr)(anErrNum);
+ return NULL;
+ }
+
+ int aWidth, aHeight, aComponents;
+ if ((*fJ2K_GetInfo)(aJ2KImage, &aWidth, &aHeight, &aComponents) != J2KERR_SUCCESS)
+ {
+ (*fJ2K_Close)(aJ2KImage);
+ return NULL;
+ }
+
+ (*fJ2K_GetResolutionDimensions)(aJ2KImage, 0, &aWidth, &aHeight);
+
+ unsigned long* aBuffer = new unsigned long[aWidth*aHeight];
+ if (aBuffer == NULL)
+ {
+ (*fJ2K_Close)(aJ2KImage);
+ return NULL;
+ }
+
+ char anOptsBuffer[32];
+ strcpy(anOptsBuffer, "bpp=4,rl=0");
+
+ int aSize = aWidth*aHeight*4;
+ int aPitch = aWidth*4;
+ if ((*fJ2K_Decode)(aJ2KImage, (unsigned char**)&aBuffer, &aSize, anOptsBuffer, &aPitch) != J2KERR_SUCCESS)
+ {
+ (*fJ2K_Close)(aJ2KImage);
+ delete[] aBuffer;
+ return NULL;
+ }
+ (*fJ2K_Close)(aJ2KImage);
+
+ ImageLib::Image* anImage = new ImageLib::Image;
+ anImage->mBits = aBuffer;
+ anImage->mWidth = aWidth;
+ anImage->mHeight = aHeight;
+ if (gIgnoreJPEG2000Alpha)
+ {
+ DWORD *aPtr = anImage->mBits;
+ DWORD *anEnd = aPtr+anImage->mWidth*anImage->mHeight;
+ for (; aPtr!=anEnd; ++aPtr)
+ *aPtr |= 0xFF000000;
+ }
+
+ p_fclose(aFP);
+
+ return anImage;
+ }
+ return NULL;
+}
+
+#endif
+
+
+int ImageLib::gAlphaComposeColor = 0xFFFFFF;
+bool ImageLib::gAutoLoadAlpha = true;
+bool ImageLib::gIgnoreJPEG2000Alpha = true;
+
+Image* ImageLib::GetImage(const std::string& theFilename, bool lookForAlphaImage)
+{
+ if (!gAutoLoadAlpha)
+ lookForAlphaImage = false;
+
+ int aLastDotPos = theFilename.rfind('.');
+ int aLastSlashPos = max((int)theFilename.rfind('\\'), (int)theFilename.rfind('/'));
+
+ std::string anExt;
+ std::string aFilename;
+
+ if (aLastDotPos > aLastSlashPos)
+ {
+ anExt = theFilename.substr(aLastDotPos, theFilename.length() - aLastDotPos);
+ aFilename = theFilename.substr(0, aLastDotPos);
+ }
+ else
+ aFilename = theFilename;
+
+ Image* anImage = NULL;
+
+ if ((anImage == NULL) && ((stricmp(anExt.c_str(), ".tga") == 0) || (anExt.length() == 0)))
+ anImage = GetTGAImage(aFilename + ".tga");
+
+ if ((anImage == NULL) && ((stricmp(anExt.c_str(), ".jpg") == 0) || (anExt.length() == 0)))
+ anImage = GetJPEGImage(aFilename + ".jpg");
+
+ if ((anImage == NULL) && ((stricmp(anExt.c_str(), ".png") == 0) || (anExt.length() == 0)))
+ anImage = GetPNGImage(aFilename + ".png");
+
+ if ((anImage == NULL) && ((stricmp(anExt.c_str(), ".gif") == 0) || (anExt.length() == 0)))
+ anImage = GetGIFImage(aFilename + ".gif");
+
+ if (anImage == NULL && (stricmp(anExt.c_str(), ".j2k") == 0 || anExt.length() == 0))
+ anImage = GetJPEG2000Image(aFilename + ".j2k");
+ if (anImage == NULL && (stricmp(anExt.c_str(), ".jp2") == 0 || anExt.length() == 0))
+ anImage = GetJPEG2000Image(aFilename + ".jp2");
+
+
+ // Check for alpha images
+ Image* anAlphaImage = NULL;
+ if(lookForAlphaImage)
+ {
+ // Check _ImageName
+ anAlphaImage = GetImage(theFilename.substr(0, aLastSlashPos+1) + "_" +
+ theFilename.substr(aLastSlashPos+1, theFilename.length() - aLastSlashPos - 1), false);
+
+ // Check ImageName_
+ if(anAlphaImage==NULL)
+ anAlphaImage = GetImage(theFilename + "_", false);
+ }
+
+
+
+ // Compose alpha channel with image
+ if (anAlphaImage != NULL)
+ {
+ if (anImage != NULL)
+ {
+ if ((anImage->mWidth == anAlphaImage->mWidth) &&
+ (anImage->mHeight == anAlphaImage->mHeight))
+ {
+ unsigned long* aBits1 = anImage->mBits;
+ unsigned long* aBits2 = anAlphaImage->mBits;
+ int aSize = anImage->mWidth*anImage->mHeight;
+
+ for (int i = 0; i < aSize; i++)
+ {
+ *aBits1 = (*aBits1 & 0x00FFFFFF) | ((*aBits2 & 0xFF) << 24);
+ ++aBits1;
+ ++aBits2;
+ }
+ }
+
+ delete anAlphaImage;
+ }
+ else if (gAlphaComposeColor==0xFFFFFF)
+ {
+ anImage = anAlphaImage;
+
+ unsigned long* aBits1 = anImage->mBits;
+
+ int aSize = anImage->mWidth*anImage->mHeight;
+ for (int i = 0; i < aSize; i++)
+ {
+ *aBits1 = (0x00FFFFFF) | ((*aBits1 & 0xFF) << 24);
+ ++aBits1;
+ }
+ }
+ else
+ {
+ const int aColor = gAlphaComposeColor;
+ anImage = anAlphaImage;
+
+ unsigned long* aBits1 = anImage->mBits;
+
+ int aSize = anImage->mWidth*anImage->mHeight;
+ for (int i = 0; i < aSize; i++)
+ {
+ *aBits1 = aColor | ((*aBits1 & 0xFF) << 24);
+ ++aBits1;
+ }
+ }
+ }
+
+ return anImage;
+}