PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/RayMarcher/BMP/EasyBMP.cpp

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