Main Page   Modules   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

DIBitmap.cpp

Go to the documentation of this file.
00001 // DIBitmap.cpp: implementation of the DIBitmap class.
00004 
00005 
00006 #include "stdafx.h"
00007 #include "DIBitmap.h"
00008 
00010 // Construction/Destruction
00012 
00016 DIBitmap::DIBitmap()
00017 {
00018     assignedMemory = NULL;
00019     bmInfoHeader = NULL;
00020     RGBQuads = NULL;
00021     imageBytes = NULL;
00022 }
00023 
00027 DIBitmap::DIBitmap(const DIBitmap &copy)
00028 {
00029     assignedMemory = NULL;
00030     bmInfoHeader = NULL;
00031     RGBQuads = NULL;
00032     imageBytes = NULL;
00033 
00034     set(copy);
00035 }
00036 
00040 DIBitmap::~DIBitmap()
00041 {
00042     clear();
00043 }
00044 
00046 // Member functions
00048 
00056 bool DIBitmap::loadFile(PCTSTR fName)
00057 {
00058     BITMAPFILEHEADER filehdr;
00059     BITMAPINFOHEADER infohdr;
00060     DWORD infoHeaderSize, noBytesRead = 0;
00061 
00062     HANDLE hFile = INVALID_HANDLE_VALUE;
00063     void* ptr = NULL;
00064     BOOL isOk = true; 
00065     bool status = false;
00066 
00067     // This SEH ensures that handles are released but doesn't catch exceptions
00068     __try {
00069         if( fName == NULL )
00070             __leave;
00071 
00072         hFile = CreateFile(fName, 
00073             GENERIC_READ, FILE_SHARE_READ, NULL, 
00074             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
00075         
00076         isOk = ReadFile(hFile, &filehdr, sizeof(BITMAPFILEHEADER), &noBytesRead, NULL);
00077         if( !isOk || (noBytesRead == 0) )
00078             __leave;
00079 
00080         if( 0x4d42 != filehdr.bfType )
00081             __leave;
00082 
00083         isOk = ReadFile(hFile, &infoHeaderSize, sizeof(DWORD), &noBytesRead, NULL);
00084         if( !isOk || (noBytesRead == 0) )
00085             __leave;
00086     
00087         infohdr.biSize = sizeof(BITMAPINFOHEADER);
00088 
00089         switch(infoHeaderSize){
00090 #if WINVER >= 0x0500
00091         case sizeof(BITMAPV5HEADER):
00092             ptr = new BITMAPV5HEADER;
00093     
00094             isOk = ReadFile(hFile, (BYTE*)ptr + sizeof(DWORD), 
00095                 sizeof(BITMAPV5HEADER) - sizeof(DWORD), &noBytesRead, NULL);
00096             if( !isOk || (noBytesRead == 0) )
00097                 __leave;
00098 
00099             infohdr.biBitCount = ((PBITMAPV5HEADER)ptr)->bV5BitCount;
00100             infohdr.biClrImportant = ((PBITMAPV5HEADER)ptr)->bV5ClrImportant;
00101             infohdr.biClrUsed = ((PBITMAPV5HEADER)ptr)->bV5ClrUsed;
00102             infohdr.biCompression = ((PBITMAPV5HEADER)ptr)->bV5Compression;
00103             infohdr.biHeight = ((PBITMAPV5HEADER)ptr)->bV5Height;
00104             infohdr.biPlanes = ((PBITMAPV5HEADER)ptr)->bV5Planes;
00105             infohdr.biSizeImage = ((PBITMAPV5HEADER)ptr)->bV5SizeImage;
00106             infohdr.biWidth = ((PBITMAPV5HEADER)ptr)->bV5Width;
00107             infohdr.biXPelsPerMeter = ((PBITMAPV5HEADER)ptr)->bV5XPelsPerMeter;
00108             infohdr.biYPelsPerMeter = ((PBITMAPV5HEADER)ptr)->bV5YPelsPerMeter;
00109             break;
00110 #endif
00111 #if ((WINVER >= 0x0400) && (_WIN32_WINNT >= 0x0400))
00112         case sizeof(BITMAPV4HEADER):
00113             ptr = new BITMAPV4HEADER;
00114             
00115             isOk = ReadFile(hFile, (BYTE*)ptr + sizeof(DWORD), 
00116                 sizeof(BITMAPV4HEADER) - sizeof(DWORD), &noBytesRead, NULL);
00117             if( !isOk || (noBytesRead == 0) )
00118                 __leave;
00119             
00120             infohdr.biBitCount = ((PBITMAPV4HEADER)ptr)->bV4BitCount;
00121             infohdr.biClrImportant = ((PBITMAPV4HEADER)ptr)->bV4ClrImportant;
00122             infohdr.biClrUsed = ((PBITMAPV4HEADER)ptr)->bV4ClrUsed;
00123             infohdr.biCompression = ((PBITMAPV4HEADER)ptr)->bV4V4Compression;
00124             infohdr.biHeight = ((PBITMAPV4HEADER)ptr)->bV4Height;
00125             infohdr.biPlanes = ((PBITMAPV4HEADER)ptr)->bV4Planes;
00126             infohdr.biSizeImage = ((PBITMAPV4HEADER)ptr)->bV4SizeImage;
00127             infohdr.biWidth = ((PBITMAPV4HEADER)ptr)->bV4Width;
00128             infohdr.biXPelsPerMeter = ((PBITMAPV4HEADER)ptr)->bV4XPelsPerMeter;
00129             infohdr.biYPelsPerMeter = ((PBITMAPV4HEADER)ptr)->bV4YPelsPerMeter;
00130             break;
00131 #endif
00132         case sizeof(BITMAPINFOHEADER):
00133             isOk = ReadFile(hFile, (BYTE*)(&infohdr) + sizeof(DWORD), 
00134                 sizeof(BITMAPINFOHEADER) - sizeof(DWORD), &noBytesRead, NULL);
00135             if( !isOk || (noBytesRead == 0) )
00136                 __leave;
00137             break;
00138         default:
00139             __leave;
00140         }
00141         
00142         if(!imageMemAlloc(&infohdr))
00143             __leave;
00144 
00145         if(bmInfoHeader->biClrUsed != 0){
00146             isOk = ReadFile(hFile, RGBQuads, 
00147                 sizeof(RGBQUAD) * bmInfoHeader->biClrUsed, &noBytesRead, NULL);
00148             if( !isOk || (noBytesRead == 0) )
00149                 __leave;
00150         }
00151 
00152         isOk = ReadFile(hFile, imageBytes, bmInfoHeader->biSizeImage, 
00153             &noBytesRead, NULL);
00154         if( !isOk )
00155                 __leave;
00156 
00157         status = true;
00158     }
00159     __finally {
00160         if(hFile != INVALID_HANDLE_VALUE)
00161             CloseHandle(hFile);
00162         if(ptr != NULL)
00163             delete ptr;
00164     }
00165 
00166     return status;
00167 }
00168 
00184 bool DIBitmap::saveFile(PCTSTR fName, const DWORD disposition) const
00185 {   
00186     BITMAPFILEHEADER filehdr;
00187     DWORD noBytesWritten, offBits, sizeLessFileHdr;
00188     
00189     HANDLE hFile = INVALID_HANDLE_VALUE;
00190     bool status = false;
00191     BOOL isOk = true;
00192 
00193     // SEH ensures that handles are released but doesn't catch exceptions
00194     __try {
00195         if( fName == NULL || assignedMemory == NULL)
00196             __leave;
00197 
00198         if( !(disposition == CREATE_NEW || disposition == CREATE_ALWAYS 
00199             || disposition == TRUNCATE_EXISTING) )
00200             __leave;
00201 
00202         hFile = CreateFile(fName, 
00203             GENERIC_WRITE, 0,NULL, 
00204             disposition, FILE_ATTRIBUTE_NORMAL, NULL);
00205             
00206         if(hFile == INVALID_HANDLE_VALUE)
00207             __leave;
00208         
00209         offBits = sizeof(BITMAPINFOHEADER) + (bmInfoHeader->biClrUsed * sizeof(RGBQUAD));
00210         sizeLessFileHdr = offBits + bmInfoHeader->biSizeImage;
00211 
00212         filehdr.bfType = (WORD) 0x4d42;        
00213         filehdr.bfSize = (DWORD) (sizeLessFileHdr + sizeof(BITMAPFILEHEADER));
00214         filehdr.bfReserved1 = 0;
00215         filehdr.bfReserved2 = 0;
00216         filehdr.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER) + offBits);
00217 
00218         isOk = WriteFile(hFile, &filehdr, sizeof(BITMAPFILEHEADER), &noBytesWritten, NULL);
00219         if( !isOk || (noBytesWritten != sizeof(BITMAPFILEHEADER)) ){
00220             isOk = false;
00221             __leave;
00222         }
00223 
00224         isOk = WriteFile(hFile, bmInfoHeader, sizeLessFileHdr, &noBytesWritten, NULL);
00225         if( !isOk || (noBytesWritten != sizeLessFileHdr) ){
00226             isOk = false;
00227             __leave;
00228         }
00229 
00230         status = true;
00231     }
00232     __finally {
00233         if(hFile != INVALID_HANDLE_VALUE)
00234             CloseHandle(hFile);
00235 
00236         // If file can not be written correctly then delete it
00237         // Only needs to happens if a new file/truncated file 
00238         // has been correctly created
00239         if(!isOk)
00240             DeleteFile(fName);
00241     }
00242 
00243     return status;
00244 }
00245 
00254 bool DIBitmap::imageMemAlloc(const PBITMAPINFOHEADER infoHeader)
00255 {
00256     if(infoHeader == bmInfoHeader || infoHeader == NULL)
00257         return false;
00258 
00259     if(!isCompatibleBitmap(infoHeader))
00260         return false;
00261 
00262     // Calculate the image size (if it's not given).
00263     DWORD sizeImage;
00264     if( 0 == infoHeader->biSizeImage ){
00265         // The image size hasn't been supplied the following calculates how large 
00266         // an image with the given width, height and bitcount is.
00267         
00268         // ((((width * bitcount) + 31) bitwiseAND -31) SHIFTLEFT 3) * absolute(height)
00269         sizeImage =
00270             (((( infoHeader->biWidth * infoHeader->biBitCount ) + 31) & ~31) >> 3) 
00271                 * abs(infoHeader->biHeight);
00272     } else {
00273         sizeImage = infoHeader->biSizeImage;
00274     }
00275 
00276     // Calculate the number of colours used (if not specified)
00277     DWORD clrUsed;
00278     if( 0 == infoHeader->biClrUsed ) {
00279         if(infoHeader->biCompression == BI_BITFIELDS) {
00280             clrUsed = 3;
00281         } else {
00282             switch(infoHeader->biBitCount){
00283             case 32:
00284             case 24:
00285             case 16:
00286                 clrUsed = 0;
00287                 break;
00288             case 8:
00289             case 4:
00290             case 1:
00291                 // shifts 1 right by the bitcount
00292                 // ie 1 << 8 = 256
00293                 //    1 << 4 = 32
00294                 //    1 << 1 = 2
00295                 clrUsed = 1 << infoHeader->biBitCount;
00296                 break;
00297             default:
00298                 // This should never happen since isCompatibleBitmap() passed the header
00299                 clrUsed = 0;
00300                 break;
00301             }
00302         }
00303     }
00304     else
00305         clrUsed = infoHeader->biClrUsed;
00306 
00307     int paletteBytes = sizeof(RGBQUAD) * clrUsed;
00308     int totalBytes = sizeof(BITMAPINFOHEADER) + paletteBytes + sizeImage;
00309 
00310     // If the current allocated memory is different from the required allocation.
00311     // There are times when reallocation occurs unnecessarily, there is little point
00312     // mudding this check to catch these though.
00313     if( bmInfoHeader == NULL 
00314         || bmInfoHeader->biSize != sizeImage 
00315         || bmInfoHeader->biClrUsed != clrUsed){
00316 
00317         imageMemDealloc();
00318 
00319         // The new opperator could be replaced with a windows stack function
00320         // providing that imageMemDealloc is also adjusted
00321         assignedMemory = new BYTE[totalBytes];
00322         if(assignedMemory == NULL)
00323             return false;
00324     }
00325     
00326     // A windows function which does what the name suggests
00327     // The purpose is to ensure that padding is zeroed (as it is not normally set 
00328     // anywhere else).
00329     ZeroMemory(assignedMemory, totalBytes);
00330     
00331     bmInfoHeader = (BITMAPINFOHEADER*)assignedMemory;
00332     if(paletteBytes != 0)
00333         RGBQuads = (RGBQUAD*)(assignedMemory + sizeof(BITMAPINFOHEADER));
00334     else
00335         RGBQuads = NULL;
00336     imageBytes = assignedMemory + paletteBytes + sizeof(BITMAPINFOHEADER);
00337     
00338     // Windows copy function
00339     CopyMemory(bmInfoHeader, (BYTE*)infoHeader, sizeof(BITMAPINFOHEADER));
00340 
00341     bmInfoHeader->biSizeImage = sizeImage;
00342     bmInfoHeader->biClrUsed = clrUsed;
00343 
00344     return true;
00345 }
00346 
00347 
00355 DIBitmap::imageMemDealloc()
00356 {
00357     if(assignedMemory != NULL){
00358         delete [] assignedMemory;
00359         assignedMemory = NULL;
00360         bmInfoHeader = NULL;
00361         RGBQuads = NULL;
00362         imageBytes = NULL; 
00363     }
00364 }
00365 
00373 bool DIBitmap::set(const PBITMAPINFO dib)
00374 {
00375     bool rtrn= false;
00376 
00377     if( dib == NULL )
00378         return false;
00379     if( (PBITMAPINFOHEADER)dib == bmInfoHeader )
00380         return true;
00381 
00382     __try {
00383         if( !imageMemAlloc((PBITMAPINFOHEADER)dib) )
00384             __leave;
00385         
00386         int size = (sizeof(RGBQUAD) * bmInfoHeader->biClrUsed) + bmInfoHeader->biSizeImage;
00387         CopyMemory( (BYTE*) bmInfoHeader + sizeof(BITMAPINFOHEADER), 
00388             (BYTE*) dib + sizeof(BITMAPINFOHEADER), size );
00389         rtrn = true;
00390     }
00391     __except( (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) 
00392             ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
00393         clear();
00394     }
00395 
00396     return rtrn;
00397 }
00398 
00399 
00412 bool DIBitmap::createCompatible(const int width, const int height, const int bits)
00413 {
00414     // sanity checks are performed with a call to isCompatibleBitmap from imageMemAlloc
00415     
00416     BITMAPINFOHEADER tempHdr;
00417 
00418     tempHdr.biSize = sizeof(BITMAPINFOHEADER); 
00419     tempHdr.biWidth = width; 
00420     tempHdr.biHeight = height; 
00421     tempHdr.biPlanes = 1; 
00422     tempHdr.biBitCount = bits; 
00423     tempHdr.biCompression = BI_RGB; 
00424     tempHdr.biSizeImage = 0; 
00425     tempHdr.biXPelsPerMeter = 0; 
00426     tempHdr.biYPelsPerMeter = 0; 
00427     tempHdr.biClrUsed = 0; 
00428     tempHdr.biClrImportant = 0; 
00429 
00430     return imageMemAlloc(&tempHdr);
00431 }
00432 
00433 
00439 const DIBitmap &DIBitmap::operator=(const DIBitmap& right)
00440 {
00441     // Check for self assignement
00442     if(&right != this) {
00443         clear();
00444         if( right.getPBITMAPINFOHEADER() != NULL ){
00445             set(right);
00446         }
00447     }
00448 
00449     return *this;
00450 }
00451 
00460 bool DIBitmap::isCompatibleBitmap(const PBITMAPINFOHEADER ptrHeader)
00461 {
00462     if(ptrHeader == NULL)
00463         return false;
00464     
00465     if(ptrHeader->biSize != sizeof(BITMAPINFOHEADER))
00466         return false;
00467     if(ptrHeader->biWidth < 1)
00468         return false;
00469     if(ptrHeader->biPlanes != 1)
00470         return false;
00471     if(ptrHeader->biSizeImage < 0)
00472         return false;
00473     if(ptrHeader->biXPelsPerMeter < 0)
00474         return false;
00475     if(ptrHeader->biYPelsPerMeter < 0)
00476         return false;
00477     if(ptrHeader->biClrUsed < 0  || ptrHeader->biClrUsed > 256)
00478         return false;
00479     if(ptrHeader->biClrImportant < 0 || ptrHeader->biClrImportant > 256)
00480         return false;
00481 
00482     switch(ptrHeader->biCompression){
00483     case BI_RLE8:
00484         if(ptrHeader->biHeight < 1)
00485             return false;
00486         if(ptrHeader->biBitCount == 8)
00487             return true;
00488         else
00489             return false;
00490     case BI_RLE4:
00491         if(ptrHeader->biHeight < 1)
00492             return false;
00493         if(ptrHeader->biBitCount == 4)
00494             return true;
00495         else
00496             return false;
00497     case BI_BITFIELDS:
00498         if(ptrHeader->biHeight == 0)
00499             return false;
00500         if(ptrHeader->biBitCount == 24 || ptrHeader->biBitCount == 32)
00501             return true;
00502         else
00503             return false;
00504     case BI_RGB:
00505         if(ptrHeader->biHeight == 0)
00506             return false;
00507         switch(ptrHeader->biBitCount){
00508         case 32:
00509         case 24:
00510         case 16:
00511         case 8:
00512         case 4:
00513         case 1:
00514             return true;
00515         default:
00516             return false;
00517         }
00518     default:
00519         return false;
00520     }
00521     // function has already returned by this point
00522 }

Generated on Mon Mar 25 06:29:59 2002 for Window Dressing by doxygen1.2.13.1 written by Dimitri van Heesch, © 1997-2001