PageRenderTime 22ms CodeModel.GetById 107ms app.highlight 874ms RepoModel.GetById 102ms app.codeStats 1ms

/IO/EasyBmp/EasyBMP.cpp

https://bitbucket.org/cosmin189/ray_tracing
C++ | 1905 lines | 1567 code | 250 blank | 88 comment | 352 complexity | e70481f121b44f9d439566e96d4b53ef MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*************************************************
   2*                                                *
   3*  EasyBMP Cross-Platform Windows Bitmap Library * 
   4*                                                *
   5*  Author: Paul Macklin                          *
   6*   email: macklin01@users.sourceforge.net       *
   7* support: http://easybmp.sourceforge.net        *
   8*                                                *
   9*          file: EasyBMP.cpp                     * 
  10*    date added: 03-31-2006                      *
  11* date modified: 12-01-2006                      *
  12*       version: 1.06                            *
  13*                                                *
  14*   License: BSD (revised/modified)              *
  15* Copyright: 2005-6 by the EasyBMP Project       * 
  16*                                                *
  17* description: Actual source file                *
  18*                                                *
  19*************************************************/
  20
  21#include "EasyBMP.h"

  22
  23/* These functions are defined in EasyBMP.h */
  24
  25bool EasyBMPwarnings = true;
  26
  27void SetEasyBMPwarningsOff( void )
  28{ EasyBMPwarnings = false; }
  29void SetEasyBMPwarningsOn( void )
  30{ EasyBMPwarnings = true; }
  31bool GetEasyBMPwarningState( void )
  32{ return EasyBMPwarnings; }
  33
  34/* These functions are defined in EasyBMP_DataStructures.h */
  35
  36int IntPow( int base, int exponent )
  37{
  38 int i;
  39 int output = 1;
  40 for( i=0 ; i < exponent ; i++ )
  41 { output *= base; }
  42 return output;
  43}
  44
  45BMFH::BMFH()
  46{
  47 bfType = 19778;
  48 bfReserved1 = 0;
  49 bfReserved2 = 0;
  50}
  51
  52void BMFH::SwitchEndianess( void )
  53{
  54 bfType = FlipWORD( bfType );
  55 bfSize = FlipDWORD( bfSize );
  56 bfReserved1 = FlipWORD( bfReserved1 );
  57 bfReserved2 = FlipWORD( bfReserved2 );
  58 bfOffBits = FlipDWORD( bfOffBits );
  59 return;
  60}
  61
  62BMIH::BMIH()
  63{
  64 biPlanes = 1;
  65 biCompression = 0;
  66 biXPelsPerMeter = DefaultXPelsPerMeter;  
  67 biYPelsPerMeter = DefaultYPelsPerMeter;
  68 biClrUsed = 0;
  69 biClrImportant = 0;
  70}
  71
  72void BMIH::SwitchEndianess( void )
  73{
  74 biSize = FlipDWORD( biSize );
  75 biWidth = FlipDWORD( biWidth );
  76 biHeight = FlipDWORD( biHeight );
  77 biPlanes = FlipWORD( biPlanes );
  78 biBitCount = FlipWORD( biBitCount );
  79 biCompression = FlipDWORD( biCompression );
  80 biSizeImage = FlipDWORD( biSizeImage );
  81 biXPelsPerMeter = FlipDWORD( biXPelsPerMeter );
  82 biYPelsPerMeter = FlipDWORD( biYPelsPerMeter );
  83 biClrUsed = FlipDWORD( biClrUsed );
  84 biClrImportant = FlipDWORD( biClrImportant );
  85 return;
  86}
  87
  88void BMIH::display( void )
  89{
  90 using namespace std;
  91 cout << "biSize: " << (int) biSize << endl
  92      << "biWidth: " << (int) biWidth << endl
  93      << "biHeight: " << (int) biHeight << endl
  94      << "biPlanes: " << (int) biPlanes << endl
  95      << "biBitCount: " << (int) biBitCount << endl
  96      << "biCompression: " << (int) biCompression << endl
  97      << "biSizeImage: " << (int) biSizeImage << endl
  98      << "biXPelsPerMeter: " << (int) biXPelsPerMeter << endl
  99      << "biYPelsPerMeter: " << (int) biYPelsPerMeter << endl
 100      << "biClrUsed: " << (int) biClrUsed << endl
 101      << "biClrImportant: " << (int) biClrImportant << endl << endl;
 102}
 103
 104void BMFH::display( void )
 105{
 106 using namespace std;
 107 cout << "bfType: " << (int) bfType << endl
 108      << "bfSize: " << (int) bfSize << endl
 109      << "bfReserved1: " << (int) bfReserved1 << endl
 110      << "bfReserved2: " << (int) bfReserved2 << endl
 111      << "bfOffBits: " << (int) bfOffBits << endl << endl;
 112}
 113
 114/* These functions are defined in EasyBMP_BMP.h */
 115
 116RGBApixel BMP::GetPixel( int i, int j ) const
 117{
 118 using namespace std;
 119 bool Warn = false;
 120 if( i >= Width )
 121 { i = Width-1; Warn = true; }
 122 if( i < 0 )
 123 { i = 0; Warn = true; }
 124 if( j >= Height )
 125 { j = Height-1; Warn = true; }
 126 if( j < 0 )
 127 { j = 0; Warn = true; }
 128 if( Warn && EasyBMPwarnings )
 129 {
 130  cout << "EasyBMP Warning: Attempted to access non-existent pixel;" << endl
 131       << "                 Truncating request to fit in the range [0,"
 132       << Width-1 << "] x [0," << Height-1 << "]." << endl;
 133 }	
 134 return Pixels[i][j];
 135}
 136
 137bool BMP::SetPixel( int i, int j, RGBApixel NewPixel )
 138{
 139 Pixels[i][j] = NewPixel;
 140 return true;
 141}
 142
 143
 144bool BMP::SetColor( int ColorNumber , RGBApixel NewColor )
 145{
 146 using namespace std;
 147 if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
 148 {
 149  if( EasyBMPwarnings )
 150  {
 151   cout << "EasyBMP Warning: Attempted to change color table for a BMP object" << endl
 152        << "                 that lacks a color table. Ignoring request." << endl;
 153  }
 154  return false;
 155 }
 156 if( !Colors )
 157 {
 158  if( EasyBMPwarnings )
 159  {
 160   cout << "EasyBMP Warning: Attempted to set a color, but the color table" << endl
 161        << "                 is not defined. Ignoring request." << endl; 
 162  }
 163  return false; 
 164 }
 165 if( ColorNumber >= TellNumberOfColors() )
 166 {
 167  if( EasyBMPwarnings )
 168  {
 169   cout << "EasyBMP Warning: Requested color number " 
 170        << ColorNumber << " is outside the allowed" << endl
 171        << "                 range [0," << TellNumberOfColors()-1 
 172	    << "]. Ignoring request to set this color." << endl;
 173  }
 174  return false;
 175 }
 176 Colors[ColorNumber] = NewColor;
 177 return true;
 178}
 179
 180// RGBApixel BMP::GetColor( int ColorNumber ) const
 181RGBApixel BMP::GetColor( int ColorNumber )
 182{ 
 183 RGBApixel Output;
 184 Output.Red   = 255;
 185 Output.Green = 255;
 186 Output.Blue  = 255;
 187 Output.Alpha = 0;
 188 
 189 using namespace std;
 190 if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
 191 {
 192  if( EasyBMPwarnings )
 193  {
 194   cout << "EasyBMP Warning: Attempted to access color table for a BMP object" << endl
 195        << "                 that lacks a color table. Ignoring request." << endl;
 196  }
 197  return Output;
 198 }
 199 if( !Colors )
 200 {
 201  if( EasyBMPwarnings )
 202  {
 203   cout << "EasyBMP Warning: Requested a color, but the color table" << endl
 204        << "                 is not defined. Ignoring request." << endl;
 205  }
 206  return Output; 
 207 }
 208 if( ColorNumber >= TellNumberOfColors() )
 209 {
 210  if( EasyBMPwarnings )
 211  {
 212   cout << "EasyBMP Warning: Requested color number " 
 213        << ColorNumber << " is outside the allowed" << endl
 214        << "                 range [0," << TellNumberOfColors()-1 
 215	    << "]. Ignoring request to get this color." << endl;
 216  }
 217  return Output;
 218 }
 219 Output = Colors[ColorNumber];
 220 return Output;
 221}
 222
 223BMP::BMP()
 224{
 225 Width = 1;
 226 Height = 1;
 227 BitDepth = 24;
 228 Pixels = new RGBApixel* [Width];
 229 Pixels[0] = new RGBApixel [Height];
 230 Colors = NULL;
 231 
 232 XPelsPerMeter = 0;
 233 YPelsPerMeter = 0;
 234 
 235 MetaData1 = NULL;
 236 SizeOfMetaData1 = 0;
 237 MetaData2 = NULL;
 238 SizeOfMetaData2 = 0;
 239}
 240
 241// BMP::BMP( const BMP& Input )
 242BMP::BMP( BMP& Input )
 243{
 244 // first, make the image empty.
 245
 246 Width = 1;
 247 Height = 1;
 248 BitDepth = 24;
 249 Pixels = new RGBApixel* [Width];
 250 Pixels[0] = new RGBApixel [Height];
 251 Colors = NULL; 
 252 XPelsPerMeter = 0;
 253 YPelsPerMeter = 0;
 254 
 255 MetaData1 = NULL;
 256 SizeOfMetaData1 = 0;
 257 MetaData2 = NULL;
 258 SizeOfMetaData2 = 0;
 259
 260 // now, set the correct bit depth
 261 
 262 SetBitDepth( Input.TellBitDepth() );
 263 
 264 // set the correct pixel size 
 265 
 266 SetSize( Input.TellWidth() , Input.TellHeight() );
 267
 268 // set the DPI information from Input
 269 
 270 SetDPI( Input.TellHorizontalDPI() , Input.TellVerticalDPI() );
 271 
 272 // if there is a color table, get all the colors
 273
 274 if( BitDepth == 1 || BitDepth == 4 ||  
 275     BitDepth == 8 )
 276 {
 277  for( int k=0 ; k < TellNumberOfColors() ; k++ )
 278  {
 279   SetColor( k, Input.GetColor( k )); 
 280  }
 281 }
 282 
 283 // get all the pixels 
 284 
 285 for( int j=0; j < Height ; j++ )
 286 {
 287  for( int i=0; i < Width ; i++ )
 288  {
 289   Pixels[i][j] = *Input(i,j);
 290//   Pixels[i][j] = Input.GetPixel(i,j); // *Input(i,j);
 291  }
 292 }
 293}
 294
 295BMP::~BMP()
 296{
 297 int i;
 298 for(i=0;i<Width;i++)
 299 { delete [] Pixels[i]; }
 300 delete [] Pixels;
 301 if( Colors )
 302 { delete [] Colors; }
 303 
 304 if( MetaData1 )
 305 { delete [] MetaData1; }
 306 if( MetaData2 )
 307 { delete [] MetaData2; }
 308} 
 309
 310RGBApixel* BMP::operator()(int i, int j)
 311{
 312 using namespace std;
 313 bool Warn = false;
 314 if( i >= Width )
 315 { i = Width-1; Warn = true; }
 316 if( i < 0 )
 317 { i = 0; Warn = true; }
 318 if( j >= Height )
 319 { j = Height-1; Warn = true; }
 320 if( j < 0 )
 321 { j = 0; Warn = true; }
 322 if( Warn && EasyBMPwarnings )
 323 {
 324  cout << "EasyBMP Warning: Attempted to access non-existent pixel;" << endl
 325       << "                 Truncating request to fit in the range [0,"
 326       << Width-1 << "] x [0," << Height-1 << "]." << endl;
 327 }	
 328 return &(Pixels[i][j]);
 329}
 330
 331// int BMP::TellBitDepth( void ) const
 332int BMP::TellBitDepth( void )
 333{ return BitDepth; }
 334
 335// int BMP::TellHeight( void ) const
 336int BMP::TellHeight( void )
 337{ return Height; }
 338
 339// int BMP::TellWidth( void ) const
 340int BMP::TellWidth( void )
 341{ return Width; }
 342
 343// int BMP::TellNumberOfColors( void ) const
 344int BMP::TellNumberOfColors( void )
 345{
 346 int output = IntPow( 2, BitDepth );
 347 if( BitDepth == 32 )
 348 { output = IntPow( 2, 24 ); }
 349 return output;
 350}
 351
 352bool BMP::SetBitDepth( int NewDepth )
 353{
 354 using namespace std;
 355 if( NewDepth != 1 && NewDepth != 4 && 
 356     NewDepth != 8 && NewDepth != 16 && 
 357     NewDepth != 24 && NewDepth != 32 )
 358 {
 359  if( EasyBMPwarnings )
 360  {
 361   cout << "EasyBMP Warning: User attempted to set unsupported bit depth " 
 362        << NewDepth << "." << endl
 363        << "                 Bit depth remains unchanged at " 
 364	    << BitDepth << "." << endl;
 365  }
 366  return false;
 367 }
 368 
 369 BitDepth = NewDepth;
 370 if( Colors )
 371 { delete [] Colors; }
 372 int NumberOfColors = IntPow( 2, BitDepth );
 373 if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
 374 { Colors = new RGBApixel [NumberOfColors]; }
 375 else
 376 { Colors = NULL; } 
 377 if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
 378 { CreateStandardColorTable(); }
 379 
 380 return true;
 381}
 382
 383bool BMP::SetSize(int NewWidth , int NewHeight )
 384{
 385 using namespace std;
 386 if( NewWidth <= 0 || NewHeight <= 0 )
 387 {
 388  if( EasyBMPwarnings )
 389  {
 390   cout << "EasyBMP Warning: User attempted to set a non-positive width or height." << endl
 391        << "                 Size remains unchanged at " 
 392        << Width << " x " << Height << "." << endl;
 393  }
 394  return false;
 395 }
 396
 397 int i,j; 
 398
 399 for(i=0;i<Width;i++)
 400 { delete [] Pixels[i]; }
 401 delete [] Pixels;
 402
 403 Width = NewWidth;
 404 Height = NewHeight;
 405 Pixels = new RGBApixel* [ Width ]; 
 406 
 407 for(i=0; i<Width; i++)
 408 { Pixels[i] = new RGBApixel [ Height ]; }
 409 
 410 for( i=0 ; i < Width ; i++)
 411 {
 412  for( j=0 ; j < Height ; j++ )
 413  {
 414   Pixels[i][j].Red = 255; 
 415   Pixels[i][j].Green = 255; 
 416   Pixels[i][j].Blue = 255; 
 417   Pixels[i][j].Alpha = 0;    
 418  }
 419 }
 420
 421 return true; 
 422}
 423
 424bool BMP::WriteToFile( const char* FileName )
 425{
 426 using namespace std;
 427 if( !EasyBMPcheckDataSize() )
 428 {
 429  if( EasyBMPwarnings )
 430  {
 431   cout << "EasyBMP Error: Data types are wrong size!" << endl
 432        << "               You may need to mess with EasyBMP_DataTypes.h" << endl
 433	    << "               to fix these errors, and then recompile." << endl
 434	    << "               All 32-bit and 64-bit machines should be" << endl
 435	    << "               supported, however." << endl << endl;
 436  }
 437  return false; 
 438 }
 439 
 440 FILE* fp = fopen( FileName, "wb" );
 441 if( fp == NULL )
 442 {
 443  if( EasyBMPwarnings )
 444  {
 445   cout << "EasyBMP Error: Cannot open file " 
 446        << FileName << " for output." << endl;
 447  }
 448  fclose( fp );
 449  return false;
 450 }
 451  
 452 // some preliminaries
 453 
 454 double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
 455 double dBytesPerRow = dBytesPerPixel * (Width+0.0);
 456 dBytesPerRow = ceil(dBytesPerRow);
 457  
 458 int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
 459 if( BytePaddingPerRow == 4 )
 460 { BytePaddingPerRow = 0; } 
 461 
 462 double dActualBytesPerRow = dBytesPerRow + BytePaddingPerRow;
 463 
 464 double dTotalPixelBytes = Height * dActualBytesPerRow;
 465 
 466 double dPaletteSize = 0;
 467 if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
 468 { dPaletteSize = IntPow(2,BitDepth)*4.0; }
 469
 470 // leave some room for 16-bit masks 
 471 if( BitDepth == 16 )
 472 { dPaletteSize = 3*4; }
 473 
 474 double dTotalFileSize = 14 + 40 + dPaletteSize + dTotalPixelBytes;
 475 
 476 // write the file header 
 477 
 478 BMFH bmfh;
 479 bmfh.bfSize = (ebmpDWORD) dTotalFileSize; 
 480 bmfh.bfReserved1 = 0; 
 481 bmfh.bfReserved2 = 0; 
 482 bmfh.bfOffBits = (ebmpDWORD) (14+40+dPaletteSize);  
 483 
 484 if( IsBigEndian() )
 485 { bmfh.SwitchEndianess(); }
 486 
 487 fwrite( (char*) &(bmfh.bfType) , sizeof(ebmpWORD) , 1 , fp );
 488 fwrite( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1 , fp );
 489 fwrite( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1 , fp );
 490 fwrite( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1 , fp );
 491 fwrite( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp );
 492 
 493 // write the info header 
 494 
 495 BMIH bmih;
 496 bmih.biSize = 40;
 497 bmih.biWidth = Width;
 498 bmih.biHeight = Height;
 499 bmih.biPlanes = 1;
 500 bmih.biBitCount = BitDepth;
 501 bmih.biCompression = 0;
 502 bmih.biSizeImage = (ebmpDWORD) dTotalPixelBytes;
 503 if( XPelsPerMeter )
 504 { bmih.biXPelsPerMeter = XPelsPerMeter; }
 505 else
 506 { bmih.biXPelsPerMeter = DefaultXPelsPerMeter; }
 507 if( YPelsPerMeter )
 508 { bmih.biYPelsPerMeter = YPelsPerMeter; }
 509 else
 510 { bmih.biYPelsPerMeter = DefaultYPelsPerMeter; }
 511
 512 bmih.biClrUsed = 0;
 513 bmih.biClrImportant = 0;
 514
 515 // indicates that we'll be using bit fields for 16-bit files
 516 if( BitDepth == 16 )
 517 { bmih.biCompression = 3; }
 518 
 519 if( IsBigEndian() )
 520 { bmih.SwitchEndianess(); }
 521 
 522 fwrite( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp );
 523 fwrite( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp );
 524 fwrite( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp );
 525 fwrite( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1 , fp );
 526 fwrite( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1 , fp );
 527 fwrite( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp );
 528 fwrite( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp );
 529 fwrite( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp );
 530 fwrite( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp ); 
 531 fwrite( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
 532 fwrite( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
 533 
 534 // write the palette 
 535 if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
 536 {
 537  int NumberOfColors = IntPow(2,BitDepth);
 538  
 539  // if there is no palette, create one 
 540  if( !Colors )
 541  {
 542   if( !Colors )
 543   { Colors = new RGBApixel [NumberOfColors]; }
 544   CreateStandardColorTable(); 
 545  }
 546   
 547  int n;
 548  for( n=0 ; n < NumberOfColors ; n++ )
 549  { fwrite( (char*) &(Colors[n]) , 4 , 1 , fp ); }
 550 }
 551 
 552 // write the pixels 
 553 int i,j;
 554 if( BitDepth != 16 )
 555 {  
 556  ebmpBYTE* Buffer;
 557  int BufferSize = (int) ( (Width*BitDepth)/8.0 );
 558  while( 8*BufferSize < Width*BitDepth )
 559  { BufferSize++; }
 560  while( BufferSize % 4 )
 561  { BufferSize++; }
 562  
 563  Buffer = new ebmpBYTE [BufferSize];
 564  for( j=0 ; j < BufferSize; j++ )
 565  { Buffer[j] = 0; }
 566    
 567  j=Height-1;
 568  
 569  while( j > -1 )
 570  {
 571   bool Success = false;
 572   if( BitDepth == 32 )
 573   { Success = Write32bitRow( Buffer, BufferSize, j ); }
 574   if( BitDepth == 24 )
 575   { Success = Write24bitRow( Buffer, BufferSize, j ); }
 576   if( BitDepth == 8  )
 577   { Success = Write8bitRow( Buffer, BufferSize, j ); }
 578   if( BitDepth == 4  )
 579   { Success = Write4bitRow( Buffer, BufferSize, j ); }
 580   if( BitDepth == 1  )
 581   { Success = Write1bitRow( Buffer, BufferSize, j ); }
 582   if( Success )
 583   {
 584    int BytesWritten = (int) fwrite( (char*) Buffer, 1, BufferSize, fp );
 585    if( BytesWritten != BufferSize )
 586    { Success = false; }
 587   }
 588   if( !Success )
 589   {
 590    if( EasyBMPwarnings )
 591    {
 592     cout << "EasyBMP Error: Could not write proper amount of data." << endl;
 593	}
 594    j = -1; 
 595   }
 596   j--; 
 597  }
 598  
 599  delete [] Buffer;
 600 }
 601 
 602 if( BitDepth == 16 )
 603 {
 604  // write the bit masks
 605
 606  ebmpWORD BlueMask = 31;    // bits 12-16
 607  ebmpWORD GreenMask = 2016; // bits 6-11
 608  ebmpWORD RedMask = 63488;  // bits 1-5
 609  ebmpWORD ZeroWORD;
 610  
 611  if( IsBigEndian() )
 612  { RedMask = FlipWORD( RedMask ); }
 613  fwrite( (char*) &RedMask , 2 , 1 , fp );
 614  fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
 615
 616  if( IsBigEndian() )
 617  { GreenMask = FlipWORD( GreenMask ); }
 618  fwrite( (char*) &GreenMask , 2 , 1 , fp );
 619  fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
 620
 621  if( IsBigEndian() )
 622  { BlueMask = FlipWORD( BlueMask ); }
 623  fwrite( (char*) &BlueMask , 2 , 1 , fp );
 624  fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
 625
 626  int DataBytes = Width*2;
 627  int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;
 628  
 629  // write the actual pixels
 630  
 631  for( j=Height-1 ; j >= 0 ; j-- )
 632  {
 633   // write all row pixel data
 634   i=0;
 635   int WriteNumber = 0;
 636   while( WriteNumber < DataBytes )
 637   {
 638    ebmpWORD TempWORD;
 639	
 640	ebmpWORD RedWORD = (ebmpWORD) ((Pixels[i][j]).Red / 8);
 641	ebmpWORD GreenWORD = (ebmpWORD) ((Pixels[i][j]).Green / 4);
 642	ebmpWORD BlueWORD = (ebmpWORD) ((Pixels[i][j]).Blue / 8);
 643	
 644    TempWORD = (RedWORD<<11) + (GreenWORD<<5) + BlueWORD;
 645	if( IsBigEndian() )
 646	{ TempWORD = FlipWORD( TempWORD ); }
 647	
 648    fwrite( (char*) &TempWORD , 2, 1, fp);
 649    WriteNumber += 2;
 650	i++;
 651   }
 652   // write any necessary row padding
 653   WriteNumber = 0;
 654   while( WriteNumber < PaddingBytes )
 655   {
 656    ebmpBYTE TempBYTE;
 657    fwrite( (char*) &TempBYTE , 1, 1, fp);
 658    WriteNumber++;
 659   }
 660  }
 661  
 662 }
 663
 664 fclose(fp);
 665 return true;
 666}
 667
 668bool BMP::ReadFromFile( const char* FileName )
 669{ 
 670 using namespace std;
 671 if( !EasyBMPcheckDataSize() )
 672 {
 673  if( EasyBMPwarnings )
 674  {
 675   cout << "EasyBMP Error: Data types are wrong size!" << endl
 676        << "               You may need to mess with EasyBMP_DataTypes.h" << endl
 677	    << "               to fix these errors, and then recompile." << endl
 678	    << "               All 32-bit and 64-bit machines should be" << endl
 679	    << "               supported, however." << endl << endl;
 680  }
 681  return false; 
 682 }
 683
 684 FILE* fp = fopen( FileName, "rb" );
 685 if( fp == NULL )
 686 {
 687  if( EasyBMPwarnings )
 688  {
 689   cout << "EasyBMP Error: Cannot open file " 
 690        << FileName << " for input." << endl;
 691  }
 692  SetBitDepth(1);
 693  SetSize(1,1);
 694  return false;
 695 }
 696 
 697 // read the file header 
 698 
 699 BMFH bmfh;
 700 bool NotCorrupted = true;
 701 
 702 NotCorrupted &= SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD), 1, fp);
 703 
 704 bool IsBitmap = false;
 705 
 706 if( IsBigEndian() && bmfh.bfType == 16973 )
 707 { IsBitmap = true; }
 708 if( !IsBigEndian() && bmfh.bfType == 19778 )
 709 { IsBitmap = true; }
 710 
 711 if( !IsBitmap ) 
 712 {
 713  if( EasyBMPwarnings )
 714  {
 715   cout << "EasyBMP Error: " << FileName 
 716        << " is not a Windows BMP file!" << endl; 
 717  }
 718  fclose( fp ); 
 719  return false;
 720 }
 721
 722 NotCorrupted &= SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1, fp); 
 723 NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1, fp);
 724 NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1, fp);
 725 NotCorrupted &= SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp);
 726 
 727 if( IsBigEndian() ) 
 728 { bmfh.SwitchEndianess(); }
 729  
 730 // read the info header
 731
 732 BMIH bmih; 
 733 
 734 NotCorrupted &= SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp);
 735 NotCorrupted &= SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp); 
 736 NotCorrupted &= SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp);
 737 NotCorrupted &= SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1, fp); 
 738 NotCorrupted &= SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1, fp);
 739
 740 NotCorrupted &= SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp);
 741 NotCorrupted &= SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp);
 742 NotCorrupted &= SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
 743 NotCorrupted &= SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
 744 NotCorrupted &= SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
 745 NotCorrupted &= SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
 746 
 747 if( IsBigEndian() ) 
 748 { bmih.SwitchEndianess(); }
 749
 750 // a safety catch: if any of the header information didn't read properly, abort
 751 // future idea: check to see if at least most is self-consistent
 752  
 753 if( !NotCorrupted )
 754 {
 755  if( EasyBMPwarnings )
 756  {
 757   cout << "EasyBMP Error: " << FileName 
 758        << " is obviously corrupted." << endl;
 759  }
 760  SetSize(1,1);
 761  SetBitDepth(1);
 762  fclose(fp);
 763  return false;
 764 } 
 765 
 766 XPelsPerMeter = bmih.biXPelsPerMeter;
 767 YPelsPerMeter = bmih.biYPelsPerMeter;
 768 
 769 // if bmih.biCompression 1 or 2, then the file is RLE compressed
 770 
 771 if( bmih.biCompression == 1 || bmih.biCompression == 2 )
 772 {
 773  if( EasyBMPwarnings )
 774  {
 775   cout << "EasyBMP Error: " << FileName << " is (RLE) compressed." << endl
 776        << "               EasyBMP does not support compression." << endl;
 777  }
 778  SetSize(1,1);
 779  SetBitDepth(1);
 780  fclose(fp);
 781  return false; 
 782 }
 783 
 784 // if bmih.biCompression > 3, then something strange is going on 
 785 // it's probably an OS2 bitmap file.
 786 
 787 if( bmih.biCompression > 3 )
 788 {
 789  if( EasyBMPwarnings )
 790  {
 791   cout << "EasyBMP Error: " << FileName << " is in an unsupported format." 
 792        << endl
 793        << "               (bmih.biCompression = " 
 794	    << bmih.biCompression << ")" << endl
 795	    << "               The file is probably an old OS2 bitmap or corrupted." 
 796	    << endl;
 797  }		
 798  SetSize(1,1);
 799  SetBitDepth(1);
 800  fclose(fp);
 801  return false; 
 802 }
 803 
 804 if( bmih.biCompression == 3 && bmih.biBitCount != 16 )
 805 {
 806  if( EasyBMPwarnings )
 807  {
 808   cout << "EasyBMP Error: " << FileName 
 809        << " uses bit fields and is not a" << endl
 810        << "               16-bit file. This is not supported." << endl;
 811  }
 812  SetSize(1,1);
 813  SetBitDepth(1);
 814  fclose(fp);
 815  return false; 
 816 }
 817
 818 // set the bit depth
 819 
 820 int TempBitDepth = (int) bmih.biBitCount;
 821 if(    TempBitDepth != 1  && TempBitDepth != 4 
 822     && TempBitDepth != 8  && TempBitDepth != 16
 823     && TempBitDepth != 24 && TempBitDepth != 32 )
 824 {
 825  if( EasyBMPwarnings )
 826  {
 827   cout << "EasyBMP Error: " << FileName << " has unrecognized bit depth." << endl;
 828  }
 829  SetSize(1,1);
 830  SetBitDepth(1);
 831  fclose(fp);
 832  return false;
 833 }
 834 SetBitDepth( (int) bmih.biBitCount ); 
 835 
 836 // set the size
 837
 838 if( (int) bmih.biWidth <= 0 || (int) bmih.biHeight <= 0 ) 
 839 {
 840  if( EasyBMPwarnings )
 841  {
 842   cout << "EasyBMP Error: " << FileName 
 843        << " has a non-positive width or height." << endl;
 844  }
 845  SetSize(1,1);
 846  SetBitDepth(1);
 847  fclose(fp);
 848  return false;
 849 } 
 850 SetSize( (int) bmih.biWidth , (int) bmih.biHeight );
 851  
 852 // some preliminaries
 853 
 854 double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
 855 double dBytesPerRow = dBytesPerPixel * (Width+0.0);
 856 dBytesPerRow = ceil(dBytesPerRow);
 857  
 858 int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
 859 if( BytePaddingPerRow == 4 )
 860 { BytePaddingPerRow = 0; }  
 861 
 862 // if < 16 bits, read the palette
 863 
 864 if( BitDepth < 16 )
 865 {
 866  // determine the number of colors specified in the 
 867  // color table
 868  
 869  int NumberOfColorsToRead = ((int) bmfh.bfOffBits - 54 )/4;  
 870  if( NumberOfColorsToRead > IntPow(2,BitDepth) )
 871  { NumberOfColorsToRead = IntPow(2,BitDepth); }
 872 
 873  if( NumberOfColorsToRead < TellNumberOfColors() )
 874  {
 875   if( EasyBMPwarnings )
 876   {
 877    cout << "EasyBMP Warning: file " << FileName << " has an underspecified" << endl
 878         << "                 color table. The table will be padded with extra" << endl
 879	 	 << "                 white (255,255,255,0) entries." << endl;
 880   }
 881  }
 882 
 883  int n;
 884  for( n=0; n < NumberOfColorsToRead ; n++ )
 885  {
 886   SafeFread( (char*) &(Colors[n]) , 4 , 1 , fp);     
 887  }
 888  for( n=NumberOfColorsToRead ; n < TellNumberOfColors() ; n++ )
 889  {
 890   RGBApixel WHITE; 
 891   WHITE.Red = 255;
 892   WHITE.Green = 255;
 893   WHITE.Blue = 255;
 894   WHITE.Alpha = 0;
 895   SetColor( n , WHITE );
 896  }
 897  
 898  
 899 }
 900 
 901 // skip blank data if bfOffBits so indicates
 902 
 903 int BytesToSkip = bmfh.bfOffBits - 54;;
 904 if( BitDepth < 16 )
 905 { BytesToSkip -= 4*IntPow(2,BitDepth); }
 906 if( BitDepth == 16 && bmih.biCompression == 3 )
 907 { BytesToSkip -= 3*4; }
 908 if( BytesToSkip < 0 )
 909 { BytesToSkip = 0; }
 910 if( BytesToSkip > 0 && BitDepth != 16 )
 911 {
 912  if( EasyBMPwarnings )
 913  {
 914   cout << "EasyBMP Warning: Extra meta data detected in file " << FileName << endl
 915        << "                 Data will be skipped." << endl;
 916  }
 917  ebmpBYTE* TempSkipBYTE;
 918  TempSkipBYTE = new ebmpBYTE [BytesToSkip];
 919  SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);   
 920  delete [] TempSkipBYTE;
 921 } 
 922  
 923 // This code reads 1, 4, 8, 24, and 32-bpp files 
 924 // with a more-efficient buffered technique.
 925
 926 int i,j;
 927 if( BitDepth != 16 )
 928 {
 929  int BufferSize = (int) ( (Width*BitDepth) / 8.0 );
 930  while( 8*BufferSize < Width*BitDepth )
 931  { BufferSize++; }
 932  while( BufferSize % 4 )
 933  { BufferSize++; }
 934  ebmpBYTE* Buffer;
 935  Buffer = new ebmpBYTE [BufferSize];
 936  j= Height-1;
 937  while( j > -1 )
 938  {
 939   int BytesRead = (int) fread( (char*) Buffer, 1, BufferSize, fp );
 940   if( BytesRead < BufferSize )
 941   {
 942    j = -1; 
 943    if( EasyBMPwarnings )
 944    {
 945     cout << "EasyBMP Error: Could not read proper amount of data." << endl;
 946	}
 947   }
 948   else
 949   {
 950    bool Success = false;
 951    if( BitDepth == 1  )
 952	{ Success = Read1bitRow(  Buffer, BufferSize, j ); }
 953    if( BitDepth == 4  )
 954	{ Success = Read4bitRow(  Buffer, BufferSize, j ); }
 955    if( BitDepth == 8  )
 956	{ Success = Read8bitRow(  Buffer, BufferSize, j ); }
 957    if( BitDepth == 24 )
 958	{ Success = Read24bitRow( Buffer, BufferSize, j ); }
 959	if( BitDepth == 32 )
 960	{ Success = Read32bitRow( Buffer, BufferSize, j ); }
 961    if( !Success )
 962    {
 963     if( EasyBMPwarnings )
 964     {
 965      cout << "EasyBMP Error: Could not read enough pixel data!" << endl;
 966	 }
 967	 j = -1;
 968    }
 969   }   
 970   j--;
 971  }
 972  delete [] Buffer; 
 973 }
 974
 975 if( BitDepth == 16 )
 976 {
 977  int DataBytes = Width*2;
 978  int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;
 979
 980  // set the default mask
 981  
 982  ebmpWORD BlueMask = 31; // bits 12-16
 983  ebmpWORD GreenMask = 992; // bits 7-11
 984  ebmpWORD RedMask = 31744; // bits 2-6
 985
 986  // read the bit fields, if necessary, to 
 987  // override the default 5-5-5 mask
 988  
 989  if( bmih.biCompression != 0 )
 990  {
 991   // read the three bit masks
 992
 993   ebmpWORD TempMaskWORD;
 994   ebmpWORD ZeroWORD;
 995  
 996   SafeFread( (char*) &RedMask , 2 , 1 , fp );
 997   if( IsBigEndian() )
 998   { RedMask = FlipWORD(RedMask); }
 999   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
1000  
1001   SafeFread( (char*) &GreenMask , 2 , 1 , fp );
1002   if( IsBigEndian() )
1003   { GreenMask = FlipWORD(GreenMask); }
1004   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
1005
1006   SafeFread( (char*) &BlueMask , 2 , 1 , fp );
1007   if( IsBigEndian() )
1008   { BlueMask = FlipWORD(BlueMask); }
1009   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
1010  }
1011  
1012  // read and skip any meta data
1013
1014  if( BytesToSkip > 0 )
1015  {
1016   if( EasyBMPwarnings )
1017   {
1018    cout << "EasyBMP Warning: Extra meta data detected in file " 
1019         << FileName << endl
1020         << "                 Data will be skipped." << endl;
1021   }
1022   ebmpBYTE* TempSkipBYTE;
1023   TempSkipBYTE = new ebmpBYTE [BytesToSkip];
1024   SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);
1025   delete [] TempSkipBYTE;   
1026  } 
1027  
1028  // determine the red, green and blue shifts
1029  
1030  int GreenShift = 0; 
1031  ebmpWORD TempShiftWORD = GreenMask;
1032  while( TempShiftWORD > 31 )
1033  { TempShiftWORD = TempShiftWORD>>1; GreenShift++; }  
1034  int BlueShift = 0;
1035  TempShiftWORD = BlueMask;
1036  while( TempShiftWORD > 31 )
1037  { TempShiftWORD = TempShiftWORD>>1; BlueShift++; }  
1038  int RedShift = 0;  
1039  TempShiftWORD = RedMask;
1040  while( TempShiftWORD > 31 )
1041  { TempShiftWORD = TempShiftWORD>>1; RedShift++; }  
1042  
1043  // read the actual pixels
1044  
1045  for( j=Height-1 ; j >= 0 ; j-- )
1046  {
1047   i=0;
1048   int ReadNumber = 0;
1049   while( ReadNumber < DataBytes )
1050   {
1051	ebmpWORD TempWORD;
1052	SafeFread( (char*) &TempWORD , 2 , 1 , fp );
1053	if( IsBigEndian() )
1054	{ TempWORD = FlipWORD(TempWORD); }
1055    ReadNumber += 2;
1056  
1057    ebmpWORD Red = RedMask & TempWORD;
1058    ebmpWORD Green = GreenMask & TempWORD;
1059    ebmpWORD Blue = BlueMask & TempWORD;
1060				
1061	ebmpBYTE BlueBYTE = (ebmpBYTE) 8*(Blue>>BlueShift);
1062    ebmpBYTE GreenBYTE = (ebmpBYTE) 8*(Green>>GreenShift);
1063    ebmpBYTE RedBYTE = (ebmpBYTE) 8*(Red>>RedShift);
1064		
1065	(Pixels[i][j]).Red = RedBYTE;
1066	(Pixels[i][j]).Green = GreenBYTE;
1067	(Pixels[i][j]).Blue = BlueBYTE;
1068	
1069	i++;
1070   }
1071   ReadNumber = 0;
1072   while( ReadNumber < PaddingBytes )
1073   {
1074    ebmpBYTE TempBYTE;
1075    SafeFread( (char*) &TempBYTE , 1, 1, fp);
1076    ReadNumber++;
1077   }
1078  }
1079
1080 }
1081 
1082 fclose(fp);
1083 return true;
1084}
1085
1086bool BMP::CreateStandardColorTable( void )
1087{
1088 using namespace std;
1089 if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
1090 {
1091  if( EasyBMPwarnings )
1092  {
1093   cout << "EasyBMP Warning: Attempted to create color table at a bit" << endl
1094        << "                 depth that does not require a color table." << endl
1095    	<< "                 Ignoring request." << endl;
1096  }
1097  return false;
1098 }
1099
1100 if( BitDepth == 1 )
1101 {
1102  int i;
1103  for( i=0 ; i < 2 ; i++ )
1104  {
1105   Colors[i].Red = i*255;
1106   Colors[i].Green = i*255;
1107   Colors[i].Blue = i*255;
1108   Colors[i].Alpha = 0;
1109  } 
1110  return true;
1111 } 
1112
1113 if( BitDepth == 4 )
1114 {
1115  int i = 0;
1116  int j,k,ell;
1117  
1118  // simplify the code for the first 8 colors
1119  for( ell=0 ; ell < 2 ; ell++ )
1120  {
1121   for( k=0 ; k < 2 ; k++ )
1122   {
1123    for( j=0 ; j < 2 ; j++ )
1124    {
1125     Colors[i].Red = j*128; 
1126	 Colors[i].Green = k*128;
1127 	 Colors[i].Blue = ell*128;
1128   	 i++;
1129    }
1130   }
1131  }
1132 
1133  // simplify the code for the last 8 colors
1134  for( ell=0 ; ell < 2 ; ell++ )
1135  {
1136   for( k=0 ; k < 2 ; k++ )
1137   {
1138    for( j=0 ; j < 2 ; j++ )
1139    {
1140     Colors[i].Red = j*255;
1141     Colors[i].Green = k*255; 
1142     Colors[i].Blue = ell*255;
1143	 i++;
1144    }
1145   }
1146  }
1147 
1148  // overwrite the duplicate color
1149  i=8; 
1150  Colors[i].Red = 192;
1151  Colors[i].Green = 192;
1152  Colors[i].Blue = 192;
1153   
1154  for( i=0 ; i < 16 ; i++ )
1155  { Colors[i].Alpha = 0; }
1156  return true;
1157 }
1158
1159 if( BitDepth == 8 )
1160 {
1161  int i=0;
1162  int j,k,ell;
1163    
1164  // do an easy loop, which works for all but colors 
1165  // 0 to 9 and 246 to 255
1166  for( ell=0 ; ell < 4 ; ell++ ) 
1167  {
1168   for( k=0 ; k < 8 ; k++ )
1169   {
1170    for( j=0; j < 8 ; j++ )
1171    {
1172     Colors[i].Red = j*32; 
1173     Colors[i].Green = k*32;
1174     Colors[i].Blue = ell*64;
1175     Colors[i].Alpha = 0;
1176     i++;
1177    }
1178   }
1179  } 
1180   
1181  // now redo the first 8 colors  
1182  i=0;
1183  for( ell=0 ; ell < 2 ; ell++ ) 
1184  {
1185   for( k=0 ; k < 2 ; k++ )
1186   {
1187    for( j=0; j < 2 ; j++ )
1188    {
1189     Colors[i].Red = j*128;
1190     Colors[i].Green = k*128;
1191     Colors[i].Blue = ell*128;
1192     i++;
1193    }
1194   }
1195  } 
1196 
1197  // overwrite colors 7, 8, 9
1198  i=7;
1199  Colors[i].Red = 192;
1200  Colors[i].Green = 192;
1201  Colors[i].Blue = 192;
1202  i++; // 8
1203  Colors[i].Red = 192;
1204  Colors[i].Green = 220;
1205  Colors[i].Blue = 192;
1206  i++; // 9
1207  Colors[i].Red = 166;
1208  Colors[i].Green = 202;
1209  Colors[i].Blue = 240;
1210   
1211  // overwrite colors 246 to 255 
1212  i=246;
1213  Colors[i].Red = 255;
1214  Colors[i].Green = 251;
1215  Colors[i].Blue = 240;
1216  i++; // 247
1217  Colors[i].Red = 160;
1218  Colors[i].Green = 160;
1219  Colors[i].Blue = 164;
1220  i++; // 248
1221  Colors[i].Red = 128;
1222  Colors[i].Green = 128;
1223  Colors[i].Blue = 128;
1224  i++; // 249
1225  Colors[i].Red = 255;
1226  Colors[i].Green = 0;
1227  Colors[i].Blue = 0;
1228  i++; // 250
1229  Colors[i].Red = 0;
1230  Colors[i].Green = 255;
1231  Colors[i].Blue = 0;
1232  i++; // 251
1233  Colors[i].Red = 255;
1234  Colors[i].Green = 255;
1235  Colors[i].Blue = 0;
1236  i++; // 252
1237  Colors[i].Red = 0;
1238  Colors[i].Green = 0;
1239  Colors[i].Blue = 255;
1240  i++; // 253
1241  Colors[i].Red = 255;
1242  Colors[i].Green = 0;
1243  Colors[i].Blue = 255;
1244  i++; // 254
1245  Colors[i].Red = 0;
1246  Colors[i].Green = 255;
1247  Colors[i].Blue = 255;
1248  i++; // 255
1249  Colors[i].Red = 255;
1250  Colors[i].Green = 255;
1251  Colors[i].Blue = 255;
1252  
1253  return true;
1254 }
1255 return true;
1256}
1257
1258bool SafeFread( char* buffer, int size, int number, FILE* fp )
1259{
1260 using namespace std;
1261 int ItemsRead;
1262 if( feof(fp) )
1263 { return false; }
1264 ItemsRead = (int) fread( buffer , size , number , fp );
1265 if( ItemsRead < number )
1266 { return false; }
1267 return true;
1268}
1269
1270void BMP::SetDPI( int HorizontalDPI, int VerticalDPI )
1271{
1272 XPelsPerMeter = (int) ( HorizontalDPI * 39.37007874015748 );
1273 YPelsPerMeter = (int) (   VerticalDPI * 39.37007874015748 );
1274}
1275
1276// int BMP::TellVerticalDPI( void ) const
1277int BMP::TellVerticalDPI( void )
1278{
1279 if( !YPelsPerMeter )
1280 { YPelsPerMeter = DefaultYPelsPerMeter; }
1281 return (int) ( YPelsPerMeter / (double) 39.37007874015748 ); 
1282}
1283
1284// int BMP::TellHorizontalDPI( void ) const
1285int BMP::TellHorizontalDPI( void )
1286{
1287 if( !XPelsPerMeter )
1288 { XPelsPerMeter = DefaultXPelsPerMeter; }
1289 return (int) ( XPelsPerMeter / (double) 39.37007874015748 );
1290}
1291
1292/* These functions are defined in EasyBMP_VariousBMPutilities.h */
1293
1294BMFH GetBMFH( const char* szFileNameIn )
1295{
1296 using namespace std;
1297 BMFH bmfh;
1298
1299 FILE* fp;
1300 fp = fopen( szFileNameIn,"rb");
1301 
1302 if( !fp  )
1303 {
1304  if( EasyBMPwarnings )
1305  {
1306   cout << "EasyBMP Error: Cannot initialize from file " 
1307        << szFileNameIn << "." << endl
1308        << "               File cannot be opened or does not exist." 
1309	    << endl;
1310  }
1311  bmfh.bfType = 0;
1312  return bmfh;
1313 } 
1314 
1315 SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD) , 1 , fp );
1316 SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1 , fp ); 
1317 SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1 , fp ); 
1318 SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1 , fp ); 
1319 SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp ); 
1320 
1321 fclose( fp );
1322 
1323 if( IsBigEndian() )
1324 { bmfh.SwitchEndianess(); }
1325
1326 return bmfh;
1327}
1328
1329BMIH GetBMIH( const char* szFileNameIn )
1330{
1331 using namespace std;
1332 BMFH bmfh;
1333 BMIH bmih;
1334
1335 FILE* fp;
1336 fp = fopen( szFileNameIn,"rb");
1337
1338 if( !fp  )
1339 {
1340  if( EasyBMPwarnings )
1341  {
1342   cout << "EasyBMP Error: Cannot initialize from file " 
1343        << szFileNameIn << "." << endl
1344        << "               File cannot be opened or does not exist." 
1345	    << endl;
1346  }
1347  return bmih;
1348 } 
1349 
1350 // read the bmfh, i.e., first 14 bytes (just to get it out of the way);
1351 
1352 ebmpBYTE TempBYTE;
1353 int i;
1354 for( i = 14 ; i > 0 ; i-- )
1355 { SafeFread( (char*) &TempBYTE , sizeof(ebmpBYTE) , 1, fp ); }
1356
1357 // read the bmih 
1358
1359 SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp );
1360 SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp ); 
1361 SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp ); 
1362 SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1 , fp ); 
1363 
1364 SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1 , fp );
1365 SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp ); 
1366 SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp ); 
1367 SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp ); 
1368 
1369 SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp ); 
1370 SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp ); 
1371 SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp ); 
1372 
1373 fclose( fp );
1374 
1375 if( IsBigEndian() )
1376 { bmih.SwitchEndianess(); }
1377
1378 return bmih;
1379}
1380
1381void DisplayBitmapInfo( const char* szFileNameIn )
1382{
1383 using namespace std;
1384 FILE* fp;
1385 fp = fopen( szFileNameIn,"rb");
1386 
1387 if( !fp  )
1388 {
1389  if( EasyBMPwarnings )
1390  {
1391   cout << "EasyBMP Error: Cannot initialize from file " 
1392        << szFileNameIn << "." << endl
1393        << "               File cannot be opened or does not exist." 
1394	    << endl;
1395  }
1396  return;
1397 } 
1398 fclose( fp );
1399
1400 // don't duplicate work! Just use the functions from above!
1401 
1402 BMFH bmfh = GetBMFH(szFileNameIn);
1403 BMIH bmih = GetBMIH(szFileNameIn);
1404
1405 cout << "File information for file " << szFileNameIn 
1406      << ":" << endl << endl;
1407
1408 cout << "BITMAPFILEHEADER:" << endl
1409      << "bfType: " << bmfh.bfType << endl
1410      << "bfSize: " << bmfh.bfSize << endl
1411      << "bfReserved1: " << bmfh.bfReserved1 << endl
1412      << "bfReserved2: " << bmfh.bfReserved2 << endl    
1413      << "bfOffBits: " << bmfh.bfOffBits << endl << endl;
1414
1415 cout << "BITMAPINFOHEADER:" << endl
1416      << "biSize: " << bmih.biSize << endl
1417      << "biWidth: " << bmih.biWidth << endl
1418      << "biHeight: " << bmih.biHeight << endl
1419      << "biPlanes: " << bmih.biPlanes << endl
1420      << "biBitCount: " << bmih.biBitCount << endl
1421      << "biCompression: " << bmih.biCompression << endl
1422      << "biSizeImage: " << bmih.biSizeImage << endl
1423      << "biXPelsPerMeter: " << bmih.biXPelsPerMeter << endl
1424      << "biYPelsPerMeter: " << bmih.biYPelsPerMeter << endl
1425      << "biClrUsed: " << bmih.biClrUsed << endl
1426      << "biClrImportant: " << bmih.biClrImportant << endl << endl;  
1427 return;
1428}
1429
1430int GetBitmapColorDepth( const char* szFileNameIn )
1431{
1432 BMIH bmih = GetBMIH( szFileNameIn );
1433 return (int) bmih.biBitCount;
1434}
1435
1436void PixelToPixelCopy( BMP& From, int FromX, int FromY,  
1437                       BMP& To, int ToX, int ToY)
1438{
1439 *To(ToX,ToY) = *From(FromX,FromY);
1440 return;
1441}
1442
1443void PixelToPixelCopyTransparent( BMP& From, int FromX, int FromY,  
1444                                  BMP& To, int ToX, int ToY,
1445                                  RGBApixel& Transparent )
1446{
1447 if( From(FromX,FromY)->Red != Transparent.Red ||
1448     From(FromX,FromY)->Green != Transparent.Green ||
1449     From(FromX,FromY)->Blue != Transparent.Blue )	 
1450 { *To(ToX,ToY) = *From(FromX,FromY); }
1451 return;
1452}
1453
1454void RangedPixelToPixelCopy( BMP& From, int FromL , int FromR, int FromB, int FromT, 
1455                             BMP& To, int ToX, int ToY )
1456{
1457 // make sure the conventions are followed
1458 if( FromB < FromT )
1459 { int Temp = FromT; FromT = FromB; FromB = Temp; }
1460
1461 // make sure that the copied regions exist in both bitmaps
1462 if( FromR >= From.TellWidth() )
1463 { FromR = From.TellWidth()-1; }
1464 if( FromL < 0 ){ FromL = 0; }
1465
1466 if( FromB >= From.TellHeight() )
1467 { FromB = From.TellHeight()-1; }
1468 if( FromT < 0 ){ FromT = 0; }
1469 
1470 if( ToX+(FromR-FromL) >= To.TellWidth() )
1471 { FromR = To.TellWidth()-1+FromL-ToX; }
1472 if( ToY+(FromB-FromT) >= To.TellHeight() )
1473 { FromB = To.TellHeight()-1+FromT-ToY; } 
1474 
1475 int i,j;
1476 for( j=FromT ; j <= FromB ; j++ )
1477 { 
1478  for( i=FromL ; i <= FromR ; i++ )
1479  {
1480   PixelToPixelCopy( From, i,j,  
1481                     To, ToX+(i-FromL), ToY+(j-FromT) );
1482  }
1483 }
1484
1485 return;
1486}
1487
1488void RangedPixelToPixelCopyTransparent( 
1489     BMP& From, int FromL , int FromR, int FromB, int FromT, 
1490     BMP& To, int ToX, int ToY ,
1491     RGBApixel& Transparent )
1492{
1493 // make sure the conventions are followed
1494 if( FromB < FromT )
1495 { int Temp = FromT; FromT = FromB; FromB = Temp; }
1496
1497 // make sure that the copied regions exist in both bitmaps
1498 if( FromR >= From.TellWidth() )
1499 { FromR = From.TellWidth()-1; }
1500 if( FromL < 0 ){ FromL = 0; }
1501
1502 if( FromB >= From.TellHeight() )
1503 { FromB = From.TellHeight()-1; }
1504 if( FromT < 0 ){ FromT = 0; }
1505 
1506 if( ToX+(FromR-FromL) >= To.TellWidth() )
1507 { FromR = To.TellWidth()-1+FromL-ToX; }
1508 if( ToY+(FromB-FromT) >= To.TellHeight() )
1509 { FromB = To.TellHeight()-1+FromT-ToY; } 
1510 
1511 int i,j;
1512 for( j=FromT ; j <= FromB ; j++ )
1513 { 
1514  for( i=FromL ; i <= FromR ; i++ )
1515  {
1516   PixelToPixelCopyTransparent( From, i,j,  
1517                     To, ToX+(i-FromL), ToY+(j-FromT) , 
1518                     Transparent);
1519  }
1520 }
1521
1522 return;
1523}
1524
1525bool CreateGrayscaleColorTable( BMP& InputImage )
1526{
1527 using namespace std;
1528 int BitDepth = InputImage.TellBitDepth();
1529 if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
1530 {
1531  if( EasyBMPwarnings )
1532  {
1533   cout << "EasyBMP Warning: Attempted to create color table at a bit" << endl
1534        << "                 depth that does not require a color table." << endl
1535   	    << "                 Ignoring request." << endl;
1536  }
1537  return false;
1538 }
1539 int i;
1540 int NumberOfColors = InputImage.TellNumberOfColors();
1541 
1542 ebmpBYTE StepSize;
1543 if( BitDepth != 1 )
1544 { StepSize = 255/(NumberOfColors-1); }
1545 else
1546 { StepSize = 255; }
1547  
1548 for( i=0 ; i < NumberOfColors ; i++ )
1549 {
1550  ebmpBYTE TempBYTE = i*StepSize;
1551  RGBApixel TempColor;
1552  TempColor.Red = TempBYTE;
1553  TempColor.Green = TempBYTE;
1554  TempColor.Blue = TempBYTE;
1555  TempColor.Alpha = 0;
1556  InputImage.SetColor( i , TempColor );  
1557 }
1558 return true;
1559}
1560
1561bool BMP::Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1562{ 
1563 int i;
1564 if( Width*4 > BufferSize )
1565 { return false; }
1566 for( i=0 ; i < Width ; i++ )
1567 { memcpy( (char*) &(Pixels[i][Row]), (char*) Buffer+4*i, 4 ); }
1568 return true;
1569}
1570
1571bool BMP::Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1572{ 
1573 int i;
1574 if( Width*3 > BufferSize )
1575 { return false; }
1576 for( i=0 ; i < Width ; i++ )
1577 { memcpy( (char*) &(Pixels[i][Row]), Buffer+3*i, 3 ); }
1578 return true;
1579}
1580
1581bool BMP::Read8bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
1582{
1583 int i;
1584 if( Width > BufferSize )
1585 { return false; }
1586 for( i=0 ; i < Width ; i++ )
1587 {
1588  int Index = Buffer[i];
1589  *( this->operator()(i,Row) )= GetColor(Index); 
1590 }
1591 return true;
1592}
1593
1594bool BMP::Read4bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
1595{
1596 int Shifts[2] = {4  ,0 };
1597 int Masks[2]  = {240,15};
1598 
1599 int i=0;
1600 int j;
1601 int k=0;
1602 if( Width > 2*BufferSize )
1603 { return false; }
1604 while( i < Width )
1605 {
1606  j=0;
1607  while( j < 2 && i < Width )
1608  {
1609   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
1610   *( this->operator()(i,Row) )= GetColor(Index); 
1611   i++; j++;   
1612  }
1613  k++;
1614 }
1615 return true;
1616}
1617bool BMP::Read1bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
1618{
1619 int Shifts[8] = {7  ,6 ,5 ,4 ,3,2,1,0};
1620 int Masks[8]  = {128,64,32,16,8,4,2,1};
1621 
1622 int i=0;
1623 int j;
1624 int k=0;
1625 
1626 if( Width > 8*BufferSize )
1627 { return false; }
1628 while( i < Width )
1629 {
1630  j=0;
1631  while( j < 8 && i < Width )
1632  {
1633   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
1634   *( this->operator()(i,Row) )= GetColor(Index); 
1635   i++; j++;   
1636  }
1637  k++;
1638 }
1639 return true;
1640}
1641
1642bool BMP::Write32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1643{ 
1644 int i;
1645 if( Width*4 > BufferSize )
1646 { return false; }
1647 for( i=0 ; i < Width ; i++ )
1648 { memcpy( (char*) Buffer+4*i, (char*) &(Pixels[i][Row]), 4 ); }
1649 return true;
1650}
1651
1652bool BMP::Write24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1653{ 
1654 int i;
1655 if( Width*3 > BufferSize )
1656 { return false; }
1657 for( i=0 ; i < Width ; i++ )
1658 { memcpy( (char*) Buffer+3*i,  (char*) &(Pixels[i][Row]), 3 ); }
1659 return true;
1660}
1661
1662bool BMP::Write8bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
1663{
1664 int i;
1665 if( Width > BufferSize )
1666 { return false; }
1667 for( i=0 ; i < Width ; i++ )
1668 { Buffer[i] = FindClosestColor( Pixels[i][Row] ); }
1669 return true;
1670}
1671
1672bool BMP::Write4bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
1673{ 
1674 int PositionWeights[2]  = {16,1};
1675 
1676 int i=0;
1677 int j;
1678 int k=0;
1679 if( Width > 2*BufferSize )
1680 { return false; }
1681 while( i < Width )
1682 {
1683  j=0;
1684  int Index = 0;
1685  while( j < 2 && i < Width )
1686  {
1687   Index += ( PositionWeights[j]* (int) FindClosestColor( Pixels[i][Row] ) ); 
1688   i++; j++;   
1689  }
1690  Buffer[k] = (ebmpBYTE) Index;
1691  k++;
1692 }
1693 return true;
1694}
1695
1696bool BMP::Write1bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
1697{ 
1698 int PositionWeights[8]  = {128,64,32,16,8,4,2,1};
1699 
1700 int i=0;
1701 int j;
1702 int k=0;
1703 if( Width > 8*BufferSize )
1704 { return false; }
1705 while( i < Width )
1706 {
1707  j=0;
1708  int Index = 0;
1709  while( j < 8 && i < Width )
1710  {
1711   Index += ( PositionWeights[j]* (int) FindClosestColor( Pixels[i][Row] ) ); 
1712   i++; j++;   
1713  }
1714  Buffer[k] = (ebmpBYTE) Index;
1715  k++;
1716 }
1717 return true;
1718}
1719
1720ebmpBYTE BMP::FindClosestColor( RGBApixel& input )
1721{
1722 using namespace std;
1723 
1724 int i=0;
1725 int NumberOfColors = TellNumberOfColors();
1726 ebmpBYTE BestI = 0;
1727 int BestMatch = 999999;
1728  
1729 while( i < NumberOfColors )
1730 {
1731  RGBApixel Attempt = GetColor( i );
1732  int TempMatch = IntSquare( (int) Attempt.Red - (int) input.Red )
1733                + IntSquare( (int) Attempt.Green - (int) input.Green )
1734                + IntSquare( (int) Attempt.Blue - (int) input.Blue );
1735  if( TempMatch < BestMatch )
1736  { BestI = (ebmpBYTE) i; BestMatch = TempMatch; }
1737  if( BestMatch < 1 )
1738  { i = NumberOfColors; }
1739  i++;
1740 }
1741 return BestI;
1742}
1743
1744bool EasyBMPcheckDataSize( void )
1745{
1746 using namespace std;
1747 bool ReturnValue = true;
1748 if( sizeof( ebmpBYTE ) != 1 )
1749 {
1750  if( EasyBMPwarnings )
1751  {
1752   cout << "EasyBMP Error: ebmpBYTE has the wrong size (" 
1753        << sizeof( ebmpBYTE ) << " bytes)," << endl
1754	    << "               Compared to the expected 1 byte value" << endl;
1755  }
1756  ReturnValue = false;
1757 }
1758 if( sizeof( ebmpWORD ) != 2 )
1759 {
1760  if( EasyBMPwarnings )
1761  {
1762   cout << "EasyBMP Error: ebmpWORD has the wrong size (" 
1763        << sizeof( ebmpWORD ) << " bytes)," << endl
1764	    << "               Compared to the expected 2 byte value" << endl;
1765  }
1766  ReturnValue = false;
1767 }
1768 if( sizeof( ebmpDWORD ) != 4 )
1769 {
1770  if( EasyBMPwarnings )
1771  {
1772   cout << "EasyBMP Error: ebmpDWORD has the wrong size (" 
1773        << sizeof( ebmpDWORD ) << " bytes)," << endl
1774	    << "               Compared to the expected 4 byte value" << endl;
1775  }
1776  ReturnValue = false;
1777 }
1778 return ReturnValue;
1779}
1780
1781bool Rescale( BMP& InputImage , char mode, int NewDimension )
1782{
1783 using namespace std;
1784 int CapMode = toupper( mode );
1785
1786 BMP OldImage( InputImage );
1787 
1788 if( CapMode != 'P' &&
1789     CapMode != 'W' &&
1790     CapMode != 'H' && 
1791     CapMode != 'F' )
1792 {
1793  if( EasyBMPwarnings )
1794  {
1795   char ErrorMessage [1024];
1796   sprintf( ErrorMessage, "EasyBMP Error: Unknown rescale mode %c requested\n" , mode );
1797   cout << ErrorMessage; 
1798  }
1799  return false;
1800 }
1801
1802 int NewWidth  =0;
1803 int NewHeight =0;
1804 
1805 int OldWidth = OldImage.TellWidth();
1806 int OldHeight= OldImage.TellHeight();
1807 
1808 if( CapMode == 'P' )
1809 {
1810  NewWidth = (int) floor( OldWidth * NewDimension / 100.0 );
1811  NewHeight = (int) floor( OldHeight * NewDimension / 100.0 );
1812 }
1813 if( CapMode == 'F' )
1814 {
1815  if( OldWidth > OldHeight )
1816  { CapMode = 'W'; }
1817  else
1818  { CapMode = 'H'; }
1819 }
1820
1821 if( CapMode == 'W' )
1822 {
1823  double percent = (double) NewDimension / (double) OldWidth;
1824  NewWidth = NewDimension;
1825  NewHeight = (int) floor( OldHeight * percent );
1826 }
1827 if( CapMode == 'H' )
1828 {
1829  double percent = (double) NewDimension / (double) OldHeight;
1830  NewHeight = NewDimension;
1831  NewWidth = (int) floor( OldWidth * percent );
1832 }
1833 
1834 if( NewWidth < 1 )
1835 { NewWidth = 1; }
1836 if( NewHeight < 1 )
1837 { NewHeight = 1; }
1838 
1839 InputImage.SetSize( NewWidth, NewHeight );
1840 InputImage.SetBitDepth( 24 );
1841
1842 int I,J;
1843 double ThetaI,ThetaJ;
1844 
1845 for( int j=0; j < NewHeight-1 ; j++ )
1846 {
1847  ThetaJ = (double)(j*(OldHeight-1.0))
1848          /(double)(NewHeight-1.0);
1849  J	= (int) floor( ThetaJ );
1850  ThetaJ -= J;  
1851  
1852  for( int i=0; i < NewWidth-1 ; i++ )
1853  {
1854   ThetaI = (double)(i*(OldWidth-1.0))
1855           /(double)(NewWidth-1.0);
1856   I = (int) floor( ThetaI );
1857   ThetaI -= I;  
1858   
1859   InputImage(i,j)->Red = (ebmpBYTE) 
1860                          ( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*(OldImage(I,J)->Red)
1861                           +(ThetaI-ThetaI*ThetaJ)*(OldImage(I+1,J)->Red)   
1862                           +(ThetaJ-ThetaI*ThetaJ)*(OldImage(I,J+1)->Red)   
1863                           +(ThetaI*ThetaJ)*(OldImage(I+1,J+1)->Red) );
1864   InputImage(i,j)->Green = (ebmpBYTE) 
1865                          ( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*OldImage(I,J)->Green
1866                           +(ThetaI-ThetaI*ThetaJ)*OldImage(I+1,J)->Green   
1867                           +(ThetaJ-ThetaI*ThetaJ)*OldImage(I,J+1)->Green   
1868                           +(ThetaI*ThetaJ)*OldImage(I+1,J+1)->Green );  
1869   InputImage(i,j)->Blue = (ebmpBYTE) 
1870                          ( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*OldImage(I,J)->Blue
1871                           +(ThetaI-ThetaI*ThetaJ)*OldImage(I+1,J)->Blue   
1872                           +(ThetaJ-ThetaI*ThetaJ)*OldImage(I,J+1)->Blue   
1873                           +(ThetaI*ThetaJ)*OldImage(I+1,J+1)->Blue ); 
1874  }
1875   InputImage(NewWidth-1,j)->Red = (ebmpBYTE) 
1876                            ( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Red)
1877                          + ThetaJ*(OldImage(OldWidth-1,J+1)->Red) ); 
1878   InputImage(NewWidth-1,j)->Green = (ebmpBYTE) 
1879                            ( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Green)
1880                          + ThetaJ*(OldImage(OldWidth-1,J+1)->Green) ); 
1881   InputImage(NewWidth-1,j)->Blue = (ebmpBYTE) 
1882                            ( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Blue)
1883                          + ThetaJ*(OldImage(OldWidth-1,J+1)->Blue) ); 
1884 } 
1885
1886 for( int i=0 ; i < NewWidth-1 ; i++ )
1887 {
1888  ThetaI = (double)(i*(OldWidth-1.0))
1889          /(double)(NewWidth-1.0);
1890  I = (int) floor( ThetaI );
1891  ThetaI -= I;  
1892  InputImage(i,NewHeight-1)->Red = (ebmpBYTE) 
1893                            ( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Red)
1894                          + ThetaI*(OldImage(I,OldHeight-1)->Red) ); 
1895  InputImage(i,NewHeight-1)->Green = (ebmpBYTE) 
1896                            ( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Green)
1897                          + ThetaI*(OldImage(I,OldHeight-1)->Green) ); 
1898  InputImage(i,NewHeight-1)->Blue = (ebmpBYTE) 
1899                            ( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Blue)
1900                          + ThetaI*(OldImage(I,OldHeight-1)->Blue) ); 
1901 }
1902 
1903 *InputImage(NewWidth-1,NewHeight-1) = *OldImage(OldWidth-1,OldHeight-1);
1904 return tru

Large files files are truncated, but you can click here to view the full file