![]() |
Unuk 1.0
|
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 }