You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

799 lines
20 KiB

  1. #include "qdbmp.h"
  2. #include <stdlib.h>
  3. #include <string.h>
  4. /* Bitmap header */
  5. typedef struct _BMP_Header
  6. {
  7. USHORT Magic; /* Magic identifier: "BM" */
  8. UINT FileSize; /* Size of the BMP file in bytes */
  9. USHORT Reserved1; /* Reserved */
  10. USHORT Reserved2; /* Reserved */
  11. UINT DataOffset; /* Offset of image data relative to the file's start */
  12. UINT HeaderSize; /* Size of the header in bytes */
  13. UINT Width; /* Bitmap's width */
  14. UINT Height; /* Bitmap's height */
  15. USHORT Planes; /* Number of color planes in the bitmap */
  16. USHORT BitsPerPixel; /* Number of bits per pixel */
  17. UINT CompressionType; /* Compression type */
  18. UINT ImageDataSize; /* Size of uncompressed image's data */
  19. UINT HPixelsPerMeter; /* Horizontal resolution (pixels per meter) */
  20. UINT VPixelsPerMeter; /* Vertical resolution (pixels per meter) */
  21. UINT ColorsUsed; /* Number of color indexes in the color table that are actually used by the bitmap */
  22. UINT ColorsRequired; /* Number of color indexes that are required for displaying the bitmap */
  23. } BMP_Header;
  24. /* Private data structure */
  25. struct _BMP
  26. {
  27. BMP_Header Header;
  28. UCHAR* Palette;
  29. UCHAR* Data;
  30. };
  31. /* Holds the last error code */
  32. static BMP_STATUS BMP_LAST_ERROR_CODE = 0;
  33. /* Error description strings */
  34. static const char* BMP_ERROR_STRING[] =
  35. {
  36. "",
  37. "General error",
  38. "Could not allocate enough memory to complete the operation",
  39. "File input/output error",
  40. "File not found",
  41. "File is not a supported BMP variant (must be uncompressed 8, 24 or 32 BPP)",
  42. "File is not a valid BMP image",
  43. "An argument is invalid or out of range",
  44. "The requested action is not compatible with the BMP's type"
  45. };
  46. /* Size of the palette data for 8 BPP bitmaps */
  47. #define BMP_PALETTE_SIZE ( 256 * 4 )
  48. /*********************************** Forward declarations **********************************/
  49. int ReadHeader ( BMP* bmp, FILE* f );
  50. int WriteHeader ( BMP* bmp, FILE* f );
  51. int ReadUINT ( UINT* x, FILE* f );
  52. int ReadUSHORT ( USHORT *x, FILE* f );
  53. int WriteUINT ( UINT x, FILE* f );
  54. int WriteUSHORT ( USHORT x, FILE* f );
  55. /*********************************** Public methods **********************************/
  56. /**************************************************************
  57. Creates a blank BMP image with the specified dimensions
  58. and bit depth.
  59. **************************************************************/
  60. BMP* BMP_Create( UINT width, UINT height, USHORT depth )
  61. {
  62. BMP* bmp;
  63. int bytes_per_pixel = depth >> 3;
  64. UINT bytes_per_row;
  65. if ( height <= 0 || width <= 0 )
  66. {
  67. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  68. return NULL;
  69. }
  70. if ( depth != 8 && depth != 24 && depth != 32 )
  71. {
  72. BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
  73. return NULL;
  74. }
  75. /* Allocate the bitmap data structure */
  76. bmp = calloc( 1, sizeof( BMP ) );
  77. if ( bmp == NULL )
  78. {
  79. BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
  80. return NULL;
  81. }
  82. /* Set header' default values */
  83. bmp->Header.Magic = 0x4D42;
  84. bmp->Header.Reserved1 = 0;
  85. bmp->Header.Reserved2 = 0;
  86. bmp->Header.HeaderSize = 40;
  87. bmp->Header.Planes = 1;
  88. bmp->Header.CompressionType = 0;
  89. bmp->Header.HPixelsPerMeter = 0;
  90. bmp->Header.VPixelsPerMeter = 0;
  91. bmp->Header.ColorsUsed = 0;
  92. bmp->Header.ColorsRequired = 0;
  93. /* Calculate the number of bytes used to store a single image row. This is always
  94. rounded up to the next multiple of 4. */
  95. bytes_per_row = width * bytes_per_pixel;
  96. bytes_per_row += ( bytes_per_row % 4 ? 4 - bytes_per_row % 4 : 0 );
  97. /* Set header's image specific values */
  98. bmp->Header.Width = width;
  99. bmp->Header.Height = height;
  100. bmp->Header.BitsPerPixel = depth;
  101. bmp->Header.ImageDataSize = bytes_per_row * height;
  102. bmp->Header.FileSize = bmp->Header.ImageDataSize + 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
  103. bmp->Header.DataOffset = 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
  104. /* Allocate palette */
  105. if ( bmp->Header.BitsPerPixel == 8 )
  106. {
  107. bmp->Palette = (UCHAR*) calloc( BMP_PALETTE_SIZE, sizeof( UCHAR ) );
  108. if ( bmp->Palette == NULL )
  109. {
  110. BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
  111. free( bmp );
  112. return NULL;
  113. }
  114. }
  115. else
  116. {
  117. bmp->Palette = NULL;
  118. }
  119. /* Allocate pixels */
  120. bmp->Data = (UCHAR*) calloc( bmp->Header.ImageDataSize, sizeof( UCHAR ) );
  121. if ( bmp->Data == NULL )
  122. {
  123. BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
  124. free( bmp->Palette );
  125. free( bmp );
  126. return NULL;
  127. }
  128. BMP_LAST_ERROR_CODE = BMP_OK;
  129. return bmp;
  130. }
  131. /**************************************************************
  132. Frees all the memory used by the specified BMP image.
  133. **************************************************************/
  134. void BMP_Free( BMP* bmp )
  135. {
  136. if ( bmp == NULL )
  137. {
  138. return;
  139. }
  140. if ( bmp->Palette != NULL )
  141. {
  142. free( bmp->Palette );
  143. }
  144. if ( bmp->Data != NULL )
  145. {
  146. free( bmp->Data );
  147. }
  148. free( bmp );
  149. BMP_LAST_ERROR_CODE = BMP_OK;
  150. }
  151. /**************************************************************
  152. Reads the specified BMP image file.
  153. **************************************************************/
  154. BMP* BMP_ReadFile( const char* filename )
  155. {
  156. BMP* bmp;
  157. FILE* f;
  158. if ( filename == NULL )
  159. {
  160. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  161. return NULL;
  162. }
  163. /* Allocate */
  164. bmp = calloc( 1, sizeof( BMP ) );
  165. if ( bmp == NULL )
  166. {
  167. BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
  168. return NULL;
  169. }
  170. /* Open file */
  171. f = fopen( filename, "rb" );
  172. if ( f == NULL )
  173. {
  174. BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
  175. free( bmp );
  176. return NULL;
  177. }
  178. /* Read header */
  179. if ( ReadHeader( bmp, f ) != BMP_OK || bmp->Header.Magic != 0x4D42 )
  180. {
  181. BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
  182. fclose( f );
  183. free( bmp );
  184. return NULL;
  185. }
  186. /* Verify that the bitmap variant is supported */
  187. if ( ( bmp->Header.BitsPerPixel != 32 && bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 8 )
  188. || bmp->Header.CompressionType != 0 || bmp->Header.HeaderSize != 40 )
  189. {
  190. BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
  191. fclose( f );
  192. free( bmp );
  193. return NULL;
  194. }
  195. /* Allocate and read palette */
  196. if ( bmp->Header.BitsPerPixel == 8 )
  197. {
  198. bmp->Palette = (UCHAR*) malloc( BMP_PALETTE_SIZE * sizeof( UCHAR ) );
  199. if ( bmp->Palette == NULL )
  200. {
  201. BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
  202. fclose( f );
  203. free( bmp );
  204. return NULL;
  205. }
  206. if ( fread( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
  207. {
  208. BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
  209. fclose( f );
  210. free( bmp->Palette );
  211. free( bmp );
  212. return NULL;
  213. }
  214. }
  215. else /* Not an indexed image */
  216. {
  217. bmp->Palette = NULL;
  218. }
  219. /* Allocate memory for image data */
  220. bmp->Data = (UCHAR*) malloc( bmp->Header.ImageDataSize );
  221. if ( bmp->Data == NULL )
  222. {
  223. BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
  224. fclose( f );
  225. free( bmp->Palette );
  226. free( bmp );
  227. return NULL;
  228. }
  229. /* Read image data */
  230. if ( fread( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
  231. {
  232. BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
  233. fclose( f );
  234. free( bmp->Data );
  235. free( bmp->Palette );
  236. free( bmp );
  237. return NULL;
  238. }
  239. fclose( f );
  240. BMP_LAST_ERROR_CODE = BMP_OK;
  241. return bmp;
  242. }
  243. /**************************************************************
  244. Writes the BMP image to the specified file.
  245. **************************************************************/
  246. void BMP_WriteFile( BMP* bmp, const char* filename )
  247. {
  248. FILE* f;
  249. if ( filename == NULL )
  250. {
  251. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  252. return;
  253. }
  254. /* Open file */
  255. f = fopen( filename, "wb" );
  256. if ( f == NULL )
  257. {
  258. BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
  259. return;
  260. }
  261. /* Write header */
  262. if ( WriteHeader( bmp, f ) != BMP_OK )
  263. {
  264. BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
  265. fclose( f );
  266. return;
  267. }
  268. /* Write palette */
  269. if ( bmp->Palette )
  270. {
  271. if ( fwrite( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
  272. {
  273. BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
  274. fclose( f );
  275. return;
  276. }
  277. }
  278. /* Write data */
  279. if ( fwrite( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
  280. {
  281. BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
  282. fclose( f );
  283. return;
  284. }
  285. BMP_LAST_ERROR_CODE = BMP_OK;
  286. fclose( f );
  287. }
  288. /**************************************************************
  289. Returns the image's width.
  290. **************************************************************/
  291. UINT BMP_GetWidth( BMP* bmp )
  292. {
  293. if ( bmp == NULL )
  294. {
  295. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  296. return -1;
  297. }
  298. BMP_LAST_ERROR_CODE = BMP_OK;
  299. return ( bmp->Header.Width );
  300. }
  301. /**************************************************************
  302. Returns the image's height.
  303. **************************************************************/
  304. UINT BMP_GetHeight( BMP* bmp )
  305. {
  306. if ( bmp == NULL )
  307. {
  308. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  309. return -1;
  310. }
  311. BMP_LAST_ERROR_CODE = BMP_OK;
  312. return ( bmp->Header.Height );
  313. }
  314. /**************************************************************
  315. Returns the image's color depth (bits per pixel).
  316. **************************************************************/
  317. USHORT BMP_GetDepth( BMP* bmp )
  318. {
  319. if ( bmp == NULL )
  320. {
  321. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  322. return -1;
  323. }
  324. BMP_LAST_ERROR_CODE = BMP_OK;
  325. return ( bmp->Header.BitsPerPixel );
  326. }
  327. /**************************************************************
  328. Populates the arguments with the specified pixel's RGB
  329. values.
  330. **************************************************************/
  331. void BMP_GetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b )
  332. {
  333. UCHAR* pixel;
  334. UINT bytes_per_row;
  335. UCHAR bytes_per_pixel;
  336. if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
  337. {
  338. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  339. }
  340. else
  341. {
  342. BMP_LAST_ERROR_CODE = BMP_OK;
  343. bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
  344. /* Row's size is rounded up to the next multiple of 4 bytes */
  345. bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
  346. /* Calculate the location of the relevant pixel (rows are flipped) */
  347. pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
  348. /* In indexed color mode the pixel's value is an index within the palette */
  349. if ( bmp->Header.BitsPerPixel == 8 )
  350. {
  351. pixel = bmp->Palette + *pixel * 4;
  352. }
  353. /* Note: colors are stored in BGR order */
  354. if ( r ) *r = *( pixel + 2 );
  355. if ( g ) *g = *( pixel + 1 );
  356. if ( b ) *b = *( pixel + 0 );
  357. }
  358. }
  359. /**************************************************************
  360. Sets the specified pixel's RGB values.
  361. **************************************************************/
  362. void BMP_SetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b )
  363. {
  364. UCHAR* pixel;
  365. UINT bytes_per_row;
  366. UCHAR bytes_per_pixel;
  367. if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
  368. {
  369. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  370. }
  371. else if ( bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 32 )
  372. {
  373. BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
  374. }
  375. else
  376. {
  377. BMP_LAST_ERROR_CODE = BMP_OK;
  378. bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
  379. /* Row's size is rounded up to the next multiple of 4 bytes */
  380. bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
  381. /* Calculate the location of the relevant pixel (rows are flipped) */
  382. pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
  383. /* Note: colors are stored in BGR order */
  384. *( pixel + 2 ) = r;
  385. *( pixel + 1 ) = g;
  386. *( pixel + 0 ) = b;
  387. }
  388. }
  389. /**************************************************************
  390. Gets the specified pixel's color index.
  391. **************************************************************/
  392. void BMP_GetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR* val )
  393. {
  394. UCHAR* pixel;
  395. UINT bytes_per_row;
  396. if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
  397. {
  398. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  399. }
  400. else if ( bmp->Header.BitsPerPixel != 8 )
  401. {
  402. BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
  403. }
  404. else
  405. {
  406. BMP_LAST_ERROR_CODE = BMP_OK;
  407. /* Row's size is rounded up to the next multiple of 4 bytes */
  408. bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
  409. /* Calculate the location of the relevant pixel */
  410. pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
  411. if ( val ) *val = *pixel;
  412. }
  413. }
  414. /**************************************************************
  415. Sets the specified pixel's color index.
  416. **************************************************************/
  417. void BMP_SetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR val )
  418. {
  419. UCHAR* pixel;
  420. UINT bytes_per_row;
  421. if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
  422. {
  423. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  424. }
  425. else if ( bmp->Header.BitsPerPixel != 8 )
  426. {
  427. BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
  428. }
  429. else
  430. {
  431. BMP_LAST_ERROR_CODE = BMP_OK;
  432. /* Row's size is rounded up to the next multiple of 4 bytes */
  433. bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
  434. /* Calculate the location of the relevant pixel */
  435. pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
  436. *pixel = val;
  437. }
  438. }
  439. /**************************************************************
  440. Gets the color value for the specified palette index.
  441. **************************************************************/
  442. void BMP_GetPaletteColor( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b )
  443. {
  444. if ( bmp == NULL )
  445. {
  446. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  447. }
  448. else if ( bmp->Header.BitsPerPixel != 8 )
  449. {
  450. BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
  451. }
  452. else
  453. {
  454. if ( r ) *r = *( bmp->Palette + index * 4 + 2 );
  455. if ( g ) *g = *( bmp->Palette + index * 4 + 1 );
  456. if ( b ) *b = *( bmp->Palette + index * 4 + 0 );
  457. BMP_LAST_ERROR_CODE = BMP_OK;
  458. }
  459. }
  460. /**************************************************************
  461. Sets the color value for the specified palette index.
  462. **************************************************************/
  463. void BMP_SetPaletteColor( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b )
  464. {
  465. if ( bmp == NULL )
  466. {
  467. BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
  468. }
  469. else if ( bmp->Header.BitsPerPixel != 8 )
  470. {
  471. BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
  472. }
  473. else
  474. {
  475. *( bmp->Palette + index * 4 + 2 ) = r;
  476. *( bmp->Palette + index * 4 + 1 ) = g;
  477. *( bmp->Palette + index * 4 + 0 ) = b;
  478. BMP_LAST_ERROR_CODE = BMP_OK;
  479. }
  480. }
  481. /**************************************************************
  482. Returns the last error code.
  483. **************************************************************/
  484. BMP_STATUS BMP_GetError()
  485. {
  486. return BMP_LAST_ERROR_CODE;
  487. }
  488. /**************************************************************
  489. Returns a description of the last error code.
  490. **************************************************************/
  491. const char* BMP_GetErrorDescription()
  492. {
  493. if ( BMP_LAST_ERROR_CODE > 0 && BMP_LAST_ERROR_CODE < BMP_ERROR_NUM )
  494. {
  495. return BMP_ERROR_STRING[ BMP_LAST_ERROR_CODE ];
  496. }
  497. else
  498. {
  499. return NULL;
  500. }
  501. }
  502. /*********************************** Private methods **********************************/
  503. /**************************************************************
  504. Reads the BMP file's header into the data structure.
  505. Returns BMP_OK on success.
  506. **************************************************************/
  507. int ReadHeader( BMP* bmp, FILE* f )
  508. {
  509. if ( bmp == NULL || f == NULL )
  510. {
  511. return BMP_INVALID_ARGUMENT;
  512. }
  513. /* The header's fields are read one by one, and converted from the format's
  514. little endian to the system's native representation. */
  515. if ( !ReadUSHORT( &( bmp->Header.Magic ), f ) ) return BMP_IO_ERROR;
  516. if ( !ReadUINT( &( bmp->Header.FileSize ), f ) ) return BMP_IO_ERROR;
  517. if ( !ReadUSHORT( &( bmp->Header.Reserved1 ), f ) ) return BMP_IO_ERROR;
  518. if ( !ReadUSHORT( &( bmp->Header.Reserved2 ), f ) ) return BMP_IO_ERROR;
  519. if ( !ReadUINT( &( bmp->Header.DataOffset ), f ) ) return BMP_IO_ERROR;
  520. if ( !ReadUINT( &( bmp->Header.HeaderSize ), f ) ) return BMP_IO_ERROR;
  521. if ( !ReadUINT( &( bmp->Header.Width ), f ) ) return BMP_IO_ERROR;
  522. if ( !ReadUINT( &( bmp->Header.Height ), f ) ) return BMP_IO_ERROR;
  523. if ( !ReadUSHORT( &( bmp->Header.Planes ), f ) ) return BMP_IO_ERROR;
  524. if ( !ReadUSHORT( &( bmp->Header.BitsPerPixel ), f ) ) return BMP_IO_ERROR;
  525. if ( !ReadUINT( &( bmp->Header.CompressionType ), f ) ) return BMP_IO_ERROR;
  526. if ( !ReadUINT( &( bmp->Header.ImageDataSize ), f ) ) return BMP_IO_ERROR;
  527. if ( !ReadUINT( &( bmp->Header.HPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
  528. if ( !ReadUINT( &( bmp->Header.VPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
  529. if ( !ReadUINT( &( bmp->Header.ColorsUsed ), f ) ) return BMP_IO_ERROR;
  530. if ( !ReadUINT( &( bmp->Header.ColorsRequired ), f ) ) return BMP_IO_ERROR;
  531. return BMP_OK;
  532. }
  533. /**************************************************************
  534. Writes the BMP file's header into the data structure.
  535. Returns BMP_OK on success.
  536. **************************************************************/
  537. int WriteHeader( BMP* bmp, FILE* f )
  538. {
  539. if ( bmp == NULL || f == NULL )
  540. {
  541. return BMP_INVALID_ARGUMENT;
  542. }
  543. /* The header's fields are written one by one, and converted to the format's
  544. little endian representation. */
  545. if ( !WriteUSHORT( bmp->Header.Magic, f ) ) return BMP_IO_ERROR;
  546. if ( !WriteUINT( bmp->Header.FileSize, f ) ) return BMP_IO_ERROR;
  547. if ( !WriteUSHORT( bmp->Header.Reserved1, f ) ) return BMP_IO_ERROR;
  548. if ( !WriteUSHORT( bmp->Header.Reserved2, f ) ) return BMP_IO_ERROR;
  549. if ( !WriteUINT( bmp->Header.DataOffset, f ) ) return BMP_IO_ERROR;
  550. if ( !WriteUINT( bmp->Header.HeaderSize, f ) ) return BMP_IO_ERROR;
  551. if ( !WriteUINT( bmp->Header.Width, f ) ) return BMP_IO_ERROR;
  552. if ( !WriteUINT( bmp->Header.Height, f ) ) return BMP_IO_ERROR;
  553. if ( !WriteUSHORT( bmp->Header.Planes, f ) ) return BMP_IO_ERROR;
  554. if ( !WriteUSHORT( bmp->Header.BitsPerPixel, f ) ) return BMP_IO_ERROR;
  555. if ( !WriteUINT( bmp->Header.CompressionType, f ) ) return BMP_IO_ERROR;
  556. if ( !WriteUINT( bmp->Header.ImageDataSize, f ) ) return BMP_IO_ERROR;
  557. if ( !WriteUINT( bmp->Header.HPixelsPerMeter, f ) ) return BMP_IO_ERROR;
  558. if ( !WriteUINT( bmp->Header.VPixelsPerMeter, f ) ) return BMP_IO_ERROR;
  559. if ( !WriteUINT( bmp->Header.ColorsUsed, f ) ) return BMP_IO_ERROR;
  560. if ( !WriteUINT( bmp->Header.ColorsRequired, f ) ) return BMP_IO_ERROR;
  561. return BMP_OK;
  562. }
  563. /**************************************************************
  564. Reads a little-endian unsigned int from the file.
  565. Returns non-zero on success.
  566. **************************************************************/
  567. int ReadUINT( UINT* x, FILE* f )
  568. {
  569. UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
  570. if ( x == NULL || f == NULL )
  571. {
  572. return 0;
  573. }
  574. if ( fread( little, 4, 1, f ) != 1 )
  575. {
  576. return 0;
  577. }
  578. *x = ( little[ 3 ] << 24 | little[ 2 ] << 16 | little[ 1 ] << 8 | little[ 0 ] );
  579. return 1;
  580. }
  581. /**************************************************************
  582. Reads a little-endian unsigned short int from the file.
  583. Returns non-zero on success.
  584. **************************************************************/
  585. int ReadUSHORT( USHORT *x, FILE* f )
  586. {
  587. UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
  588. if ( x == NULL || f == NULL )
  589. {
  590. return 0;
  591. }
  592. if ( fread( little, 2, 1, f ) != 1 )
  593. {
  594. return 0;
  595. }
  596. *x = ( little[ 1 ] << 8 | little[ 0 ] );
  597. return 1;
  598. }
  599. /**************************************************************
  600. Writes a little-endian unsigned int to the file.
  601. Returns non-zero on success.
  602. **************************************************************/
  603. int WriteUINT( UINT x, FILE* f )
  604. {
  605. UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
  606. little[ 3 ] = (UCHAR)( ( x & 0xff000000 ) >> 24 );
  607. little[ 2 ] = (UCHAR)( ( x & 0x00ff0000 ) >> 16 );
  608. little[ 1 ] = (UCHAR)( ( x & 0x0000ff00 ) >> 8 );
  609. little[ 0 ] = (UCHAR)( ( x & 0x000000ff ) >> 0 );
  610. return ( f && fwrite( little, 4, 1, f ) == 1 );
  611. }
  612. /**************************************************************
  613. Writes a little-endian unsigned short int to the file.
  614. Returns non-zero on success.
  615. **************************************************************/
  616. int WriteUSHORT( USHORT x, FILE* f )
  617. {
  618. UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
  619. little[ 1 ] = (UCHAR)( ( x & 0xff00 ) >> 8 );
  620. little[ 0 ] = (UCHAR)( ( x & 0x00ff ) >> 0 );
  621. return ( f && fwrite( little, 2, 1, f ) == 1 );
  622. }