PageRenderTime 91ms CodeModel.GetById 39ms RepoModel.GetById 0ms app.codeStats 0ms

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