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