Unuk 1.0
src/libUnuk/ImageLoader.cpp
Go to the documentation of this file.
00001 #include <cstdio>
00002 #include <cstring>
00003 #include <errno.h>
00004 #include "ImageLoader.h"
00005 #include "Debug.h"
00006 #define BITMAP_TYPE 19778
00007 
00008 // Initialize an empty image.
00009 ImageLoader::ImageLoader(void) {
00010   Reset();
00011 }
00012 
00013 // Initializes an image with an image from the disk.
00014 ImageLoader::ImageLoader(const char *filename) {
00015   Reset();
00016   LoadBMP(filename);
00017 }
00018 
00019 ImageLoader::~ImageLoader(void) {
00020   if(colors != NULL) {
00021     delete [] colors;
00022   }
00023 
00024   if(pixelData != NULL) {
00025     delete [] pixelData;
00026   }
00027 }
00028 
00029 bool ImageLoader::LoadBMP(const char* filename) {
00030   FILE *in      = NULL;
00031   bool result   = false;
00032 
00033   // Open the file for reading in binary mode.
00034   in = fopen(filename, "rb");
00035   if(in == NULL) {
00036     perror("Error");
00037     Debug::logger->message("\nError Number: %d", errno);
00038     return false;
00039   }
00040 
00041   fread(&bmfh, sizeof(BITMAPFILEHEADER), 1, in);
00042 
00043   // Check if this is even the right type of file.
00044   if(bmfh.bfType != BITMAP_TYPE) {
00045     perror("Error");
00046     Debug::logger->message("\nError Number: %d", errno);
00047     return false;
00048   }
00049 
00050   fread(&bmih, sizeof(BITMAPINFOHEADER), 1, in);
00051   width  = bmih.biWidth;
00052   height = bmih.biHeight;
00053   bpp    = bmih.biBitCount;
00054 
00055   // TODO: Get this running on 24-bit images too, right now it will seg fault if it is 24-bit.
00056   // Set the number of colors.
00057   LONG numColors = 1 << bmih.biBitCount;
00058 
00059   // The bitmap is not yet loaded.
00060   loaded = false;
00061   // Make sure memory is not lost.
00062   if(colors != NULL) {
00063     delete [] colors;
00064   }
00065 
00066   if(pixelData != NULL) {
00067     delete [] pixelData;
00068   }
00069 
00070   // Load the palette for 8 bits per pixel.
00071   if(bmih.biBitCount < 24) {
00072     colors = new RGBQUAD[numColors];
00073     fread(colors, sizeof(RGBQUAD), numColors, in);
00074   }
00075 
00076   DWORD size = bmfh.bfSize - bmfh.bfOffBits;
00077 
00078   BYTE *tempPixelData = NULL;
00079   tempPixelData = new BYTE[size];
00080 
00081   if(tempPixelData == NULL) {
00082     Debug::logger->message("\nError: Out of memory. Cannot find space to load image into memory.");
00083     fclose(in);
00084     return false;
00085   }
00086   
00087   fread(tempPixelData, sizeof(BYTE), size, in);
00088 
00089   result = FixPadding(tempPixelData, size);
00090   loaded = result;
00091 
00092   delete [] tempPixelData;
00093   fclose(in);
00094 
00095   return result;
00096 }
00097 
00098 bool ImageLoader::FixPadding(BYTE const * const tempPixelData, DWORD size) {
00099   // byteWidth is the width of the actual image in bytes. padWidth is
00100   // the width of the image plus the extrapadding.
00101   LONG byteWidth, padWidth;
00102 
00103   // Set both to the width of the image.
00104   byteWidth = padWidth = (LONG)((float)width * (float)bpp / 8.0);
00105 
00106   // Add any extra space to bring each line to a DWORD boundary.
00107   short padding = padWidth % 4 != 0;
00108   padWidth += padding;
00109 
00110   DWORD diff;
00111   int offset;
00112  
00113   height = bmih.biHeight;
00114   // Set the diff to the actual image size (without any padding).
00115   diff = height * byteWidth;
00116   // allocate memory for the image.
00117   pixelData = new BYTE[diff];
00118   
00119   if(pixelData == NULL) {
00120     return false;
00121   }
00122 
00123   // ===================================================================
00124   // Bitmap is inverted, so the paddind needs to be removed and the
00125   // image reversed. Here you can start from the back of the file or
00126   // the front, after the header. The only problem is that some programs
00127   // will pad not only the data, but also the file size to be divisiaible
00128   // by 4 bytes.
00129   // ===================================================================
00130   if(height > 0) {
00131     offset = padWidth - byteWidth;
00132     for(unsigned int i = 0; i < size - 2; i += 4) {
00133       if((i + 1) % padWidth == 0) {
00134         i += offset;
00135       }
00136       // Now we need to swap the data for it to have the right order.
00137       *(pixelData + i)          = *(tempPixelData + i + 2); // R
00138       *(pixelData + i + 1)      = *(tempPixelData + i + 1); // G
00139       *(pixelData + i + 2)      = *(tempPixelData + i);     // B
00140       *(pixelData + i + 3)      = *(tempPixelData + i + 3); // A
00141     }
00142   } else {
00143     // The image is not reserved. Only the padding needs to be removed.
00144     height = height * -1;
00145     offset = 0;
00146     while(offset < height) {
00147       memcpy((pixelData + (offset * byteWidth)), (tempPixelData + (offset * padWidth)), byteWidth);
00148       offset++;
00149     }
00150   }
00151   return true;
00152 }
00153 
00154 void ImageLoader::Reset(void) {
00155   width     = 0;
00156   height    = 0;
00157   pixelData = NULL;
00158   colors    = NULL;
00159   loaded    = false;
00160 }
00161 
00162 // Get the alpha channel as an array of bytes.
00163 // The size of the array will return -1 on failure.
00164 BYTE *ImageLoader::GetAlpha() const {
00165   LONG arraySize = width * height;
00166   BYTE *array = new BYTE[arraySize];
00167   
00168   if(array == NULL) {
00169     delete [] array;
00170     return NULL;
00171   }
00172 
00173   for(long i = 0; i < arraySize; i++) {
00174     // Jump to the alpha and extract it everytime.
00175     array[i] = pixelData[i * 4 + 3];
00176   }
00177   return array;
00178 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines