00001
00004
00005
00006 #include "stdafx.h"
00007 #include "DIBitmap.h"
00008
00010
00012
00016 DIBitmap::DIBitmap()
00017 {
00018 assignedMemory = NULL;
00019 bmInfoHeader = NULL;
00020 RGBQuads = NULL;
00021 imageBytes = NULL;
00022 }
00023
00027 DIBitmap::DIBitmap(const DIBitmap ©)
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
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
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
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
00237
00238
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
00263 DWORD sizeImage;
00264 if( 0 == infoHeader->biSizeImage ){
00265
00266
00267
00268
00269 sizeImage =
00270 (((( infoHeader->biWidth * infoHeader->biBitCount ) + 31) & ~31) >> 3)
00271 * abs(infoHeader->biHeight);
00272 } else {
00273 sizeImage = infoHeader->biSizeImage;
00274 }
00275
00276
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
00292
00293
00294
00295 clrUsed = 1 << infoHeader->biBitCount;
00296 break;
00297 default:
00298
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
00311
00312
00313 if( bmInfoHeader == NULL
00314 || bmInfoHeader->biSize != sizeImage
00315 || bmInfoHeader->biClrUsed != clrUsed){
00316
00317 imageMemDealloc();
00318
00319
00320
00321 assignedMemory = new BYTE[totalBytes];
00322 if(assignedMemory == NULL)
00323 return false;
00324 }
00325
00326
00327
00328
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
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
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
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
00522 }