PageRenderTime 12ms CodeModel.GetById 71ms app.highlight 303ms RepoModel.GetById 19ms app.codeStats 1ms

/examples/pyeasybmp_dev/easybmp/EasyBMP.cpp

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

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