il_bmp.c
Upload User: wmy0603
Upload Date: 2022-05-02
Package Size: 1808k
Code Size: 27k
Development Platform:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. //
  3. // ImageLib Sources
  4. // Copyright (C) 2000-2008 by Denton Woods
  5. // Last modified: 02/09/2009
  6. //
  7. // Filename: src-IL/src/il_bmp.c
  8. //
  9. // Description: Reads from and writes to a bitmap (.bmp) file.
  10. //
  11. //-----------------------------------------------------------------------------
  12. #define IL_BMP_C
  13. #include "il_internal.h"
  14. #ifndef IL_NO_BMP
  15. #include "il_bmp.h"
  16. //#include "il_manip.h"
  17. #include "il_endian.h"
  18. #include <stdio.h>
  19. void GetShiftFromMask(const ILuint Mask, ILuint * CONST_RESTRICT ShiftLeft, ILuint * CONST_RESTRICT ShiftRight);
  20. //! Checks if the file specified in FileName is a valid .bmp file.
  21. ILboolean ilIsValid_BMP(ILconst_string CONST_RESTRICT FileName)
  22. {
  23. ILHANDLE BitmapFile;
  24. ILboolean bBitmap = IL_FALSE;
  25. if (!iCheckExtension(FileName, IL_TEXT("bmp"))) {
  26. ilSetError(IL_INVALID_EXTENSION);
  27. return bBitmap;
  28. }
  29. BitmapFile = iopenr(FileName);
  30. if (BitmapFile == NULL) {
  31. ilSetError(IL_COULD_NOT_OPEN_FILE);
  32. return bBitmap;
  33. }
  34. bBitmap = ilIsValidF_BMP(BitmapFile);
  35. icloser(BitmapFile);
  36. return bBitmap;
  37. }
  38. //! Checks if the ILHANDLE contains a valid .bmp file at the current position.
  39. ILboolean ilIsValidF_BMP(ILHANDLE File)
  40. {
  41. ILuint FirstPos;
  42. ILboolean bRet;
  43. iSetInputFile(File);
  44. FirstPos = itell();
  45. bRet = iIsValidBmp();
  46. iseek(FirstPos, IL_SEEK_SET);
  47. return bRet;
  48. }
  49. //! Checks if Lump is a valid .bmp lump.
  50. ILboolean ilIsValidL_BMP(const void * Lump, ILuint Size)
  51. {
  52. iSetInputLump(Lump, Size);
  53. return iIsValidBmp();
  54. }
  55. // Internal function used to get the .bmp header from the current file.
  56. ILboolean iGetBmpHead(BMPHEAD * const Header)
  57. {
  58. Header->bfType = GetLittleUShort();
  59. Header->bfSize = GetLittleInt();
  60. Header->bfReserved = GetLittleUInt();
  61. Header->bfDataOff = GetLittleInt();
  62. Header->biSize = GetLittleInt();
  63. Header->biWidth = GetLittleInt();
  64. Header->biHeight = GetLittleInt();
  65. Header->biPlanes = GetLittleShort();
  66. Header->biBitCount = GetLittleShort();
  67. Header->biCompression = GetLittleInt();
  68. Header->biSizeImage = GetLittleInt();
  69. Header->biXPelsPerMeter = GetLittleInt();
  70. Header->biYPelsPerMeter = GetLittleInt();
  71. Header->biClrUsed = GetLittleInt();
  72. Header->biClrImportant = GetLittleInt();
  73. return IL_TRUE;
  74. }
  75. ILboolean iGetOS2Head(OS2_HEAD * const Header)
  76. {
  77. if (iread(Header, sizeof(OS2_HEAD), 1) != 1)
  78. return IL_FALSE;
  79. UShort(&Header->bfType);
  80. UInt(&Header->biSize);
  81. Short(&Header->xHotspot);
  82. Short(&Header->yHotspot);
  83. UInt(&Header->DataOff);
  84. UInt(&Header->cbFix);
  85. //2003-09-01 changed to UShort according to MSDN
  86. UShort(&Header->cx);
  87. UShort(&Header->cy);
  88. UShort(&Header->cPlanes);
  89. UShort(&Header->cBitCount);
  90. iseek((ILint)Header->cbFix - 12, IL_SEEK_CUR);  // Skip rest of header, if any.
  91. return IL_TRUE;
  92. }
  93. // Internal function to get the header and check it.
  94. ILboolean iIsValidBmp()
  95. {
  96. BMPHEAD Head;
  97. OS2_HEAD Os2Head;
  98. ILboolean IsValid;
  99. iGetBmpHead(&Head);
  100. iseek(-(ILint)sizeof(BMPHEAD), IL_SEEK_CUR);  // Go ahead and restore to previous state
  101. IsValid = iCheckBmp(&Head);
  102. if (!IsValid) {
  103. iGetOS2Head(&Os2Head);
  104. iseek(-(ILint)sizeof(BMPHEAD), IL_SEEK_CUR);
  105. IsValid = iCheckOS2(&Os2Head);
  106. }
  107. return IsValid;
  108. }
  109. // Internal function used to check if the HEADER is a valid .bmp header.
  110. ILboolean iCheckBmp (const BMPHEAD * CONST_RESTRICT Header)
  111. {
  112. //if ((Header->bfType != ('B'|('M'<<8))) || ((Header->biSize != 0x28) && (Header->biSize != 0x0C)))
  113. if ((Header->bfType != ('B'|('M'<<8))) || (Header->biSize != 0x28))
  114. return IL_FALSE;
  115. if (Header->biHeight == 0 || Header->biWidth < 1)
  116. return IL_FALSE;
  117. if (Header->biPlanes > 1)  // Not sure...
  118. return IL_FALSE;
  119. if(Header->biCompression != 0 && Header->biCompression != 1 &&
  120. Header->biCompression != 2 && Header->biCompression != 3)
  121. return IL_FALSE;
  122. if(Header->biCompression == 3 && Header->biBitCount != 16 && Header->biBitCount != 32)
  123. return IL_FALSE;
  124. if (Header->biBitCount != 1 && Header->biBitCount != 4 && Header->biBitCount != 8 &&
  125. Header->biBitCount != 16 && Header->biBitCount != 24 && Header->biBitCount != 32)
  126. return IL_FALSE;
  127. return IL_TRUE;
  128. }
  129. ILboolean iCheckOS2 (const OS2_HEAD * CONST_RESTRICT Header)
  130. {
  131. if ((Header->bfType != ('B'|('M'<<8))) || (Header->DataOff < 26) || (Header->cbFix < 12))
  132. return IL_FALSE;
  133. if (Header->cPlanes != 1)
  134. return IL_FALSE;
  135. if (Header->cx == 0 || Header->cy == 0)
  136. return IL_FALSE;
  137. if (Header->cBitCount != 1 && Header->cBitCount != 4 && Header->cBitCount != 8 &&
  138.  Header->cBitCount != 24)
  139.  return IL_FALSE;
  140. return IL_TRUE;
  141. }
  142. //! Reads a .bmp file
  143. ILboolean ilLoad_BMP(ILconst_string FileName) {
  144. ILHANDLE BitmapFile;
  145. ILboolean bBitmap = IL_FALSE;
  146. BitmapFile = iopenr(FileName);
  147. if (BitmapFile == NULL) {
  148. ilSetError(IL_COULD_NOT_OPEN_FILE);
  149. return bBitmap;
  150. }
  151. bBitmap = ilLoadF_BMP(BitmapFile);
  152. icloser(BitmapFile);
  153. return bBitmap;
  154. }
  155. //! Reads an already-opened .bmp file
  156. ILboolean ilLoadF_BMP(ILHANDLE File)
  157. {
  158. ILuint FirstPos;
  159. ILboolean bRet;
  160. iSetInputFile(File);
  161. FirstPos = itell();
  162. bRet = iLoadBitmapInternal();
  163. iseek(FirstPos, IL_SEEK_SET);
  164. return bRet;
  165. }
  166. //! Reads from a memory "lump" that contains a .bmp
  167. ILboolean ilLoadL_BMP(const void *Lump, ILuint Size)
  168. {
  169. iSetInputLump(Lump, Size);
  170. return iLoadBitmapInternal();
  171. }
  172. // Internal function used to load the .bmp.
  173. ILboolean iLoadBitmapInternal()
  174. {
  175. BMPHEAD Header;
  176. OS2_HEAD Os2Head;
  177. ILboolean bBitmap;
  178. if (iCurImage == NULL) {
  179. ilSetError(IL_ILLEGAL_OPERATION);
  180. return IL_FALSE;
  181. }
  182. iGetBmpHead(&Header);
  183. if (!iCheckBmp(&Header)) {
  184. iseek(-(ILint)sizeof(BMPHEAD), IL_SEEK_CUR);
  185. iGetOS2Head(&Os2Head);
  186. if (!iCheckOS2(&Os2Head)) {
  187. ilSetError(IL_INVALID_FILE_HEADER);
  188. return IL_FALSE;
  189. }
  190. else {
  191. return iGetOS2Bmp(&Os2Head);
  192. }
  193. }
  194. // Don't know what to do if it has more than one plane...
  195. if (Header.biPlanes != 1) {
  196. ilSetError(IL_INVALID_FILE_HEADER);
  197. return IL_FALSE;
  198. }
  199. switch (Header.biCompression)
  200. {
  201. case 0: // No compression
  202. case 3: // BITFIELDS compression is handled in 16 bit
  203. // and 32 bit code in ilReadUncompBmp()
  204. bBitmap = ilReadUncompBmp(&Header);
  205. break;
  206. case 1:  // RLE 8-bit / pixel (BI_RLE8)
  207. bBitmap = ilReadRLE8Bmp(&Header);
  208. break;
  209. case 2:  // RLE 4-bit / pixel (BI_RLE4)
  210. bBitmap = ilReadRLE4Bmp(&Header);
  211. break;
  212. default:
  213. ilSetError(IL_INVALID_FILE_HEADER);
  214. return IL_FALSE;
  215. }
  216. if (!ilFixImage())
  217. return IL_FALSE;
  218. return bBitmap;
  219. }
  220. // Reads an uncompressed .bmp
  221. // One of the absolute ugliest functions I've ever written!
  222. ILboolean ilReadUncompBmp(BMPHEAD * Header)
  223. {
  224. ILuint i, j, k, c, Read;
  225. ILubyte Bpp, ByteData, PadSize, Padding[4];
  226. ILuint rMask, gMask, bMask; //required for bitfields packing
  227. ILuint rShiftR, gShiftR, bShiftR; //required for bitfields packing
  228. ILuint rShiftL, gShiftL, bShiftL; //required for bitfields packing
  229. ILushort Read16; //used for 16bit bmp loading
  230. if (Header->biBitCount < 8)
  231. Bpp = 1;  // We can't have an integral number less than one and greater than 0
  232. else
  233. Bpp = (ILubyte)(Header->biBitCount >> 3);  // Convert to bytes per pixel
  234. if(Bpp == 2 || Bpp == 4)
  235. Bpp = 3;
  236. // Update the current image with the new dimensions
  237. if (!ilTexImage(Header->biWidth, abs(Header->biHeight), 1, Bpp, 0, IL_UNSIGNED_BYTE, NULL)) {
  238. return IL_FALSE;
  239. }
  240. iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  241. switch (Header->biBitCount)
  242. {
  243. case 1:
  244. //iCurImage->Format = IL_LUMINANCE;
  245. iCurImage->Format = IL_COLOUR_INDEX;
  246. iCurImage->Pal.PalType = IL_PAL_BGR32;
  247. iCurImage->Pal.PalSize = 2 * 4;
  248. iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
  249. if (iCurImage->Pal.Palette == NULL) {
  250. return IL_FALSE;
  251. }
  252. break;
  253. case 4:
  254. case 8:
  255. iCurImage->Format = IL_COLOUR_INDEX;
  256. iCurImage->Pal.PalType = IL_PAL_BGR32;
  257. // if there are 256 colors biClrUsed is 0
  258. iCurImage->Pal.PalSize = Header->biClrUsed ? 
  259. Header->biClrUsed * 4 : 256 * 4;
  260. if (Header->biBitCount == 4)  // biClrUsed is 0 for 4-bit bitmaps
  261. iCurImage->Pal.PalSize = 16 * 4;
  262. iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
  263. if (iCurImage->Pal.Palette == NULL) {
  264. return IL_FALSE;
  265. }
  266. break;
  267. case 16:
  268. case 24:
  269. case 32:
  270. iCurImage->Format = IL_BGR;
  271. break;
  272. default:
  273. ilSetError(IL_ILLEGAL_FILE_VALUE);
  274. return IL_FALSE;
  275. }
  276. // A height of 0 is illegal
  277. if (Header->biHeight == 0) {
  278. ilSetError(IL_ILLEGAL_FILE_VALUE);
  279. if (iCurImage->Pal.Palette)
  280. ifree(iCurImage->Pal.Palette);
  281. return IL_FALSE;
  282. }
  283. // If the image height is negative, then the image is flipped
  284. // (Normal is IL_ORIGIN_LOWER_LEFT)
  285. if (Header->biHeight < 0) {
  286. iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
  287. }
  288. else {
  289. iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  290. }
  291. // Read the palette
  292. iseek(sizeof(BMPHEAD), IL_SEEK_SET);
  293. if (iread(iCurImage->Pal.Palette, 1, iCurImage->Pal.PalSize) != iCurImage->Pal.PalSize)
  294. return IL_FALSE;
  295. // Seek to the data from the "beginning" of the file
  296. iseek(Header->bfDataOff, IL_SEEK_SET);
  297. // We have to handle 1 and 4-bit images separately, because we have to expand them.
  298. switch (Header->biBitCount)
  299. {
  300. case 1:
  301. //changed 2003-09-01
  302. if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
  303. iPreCache(iCurImage->Width / 8 * iCurImage->Height);
  304. PadSize = ((32 - (iCurImage->Width % 32)) / 8) % 4;  // Has to truncate
  305. for (j = 0; j < iCurImage->Height; j++) {
  306. Read = 0;
  307. for (i = 0; i < iCurImage->Width; ) {
  308. if (iread(&ByteData, 1, 1) != 1) {
  309. iUnCache();
  310. return IL_FALSE;
  311. }
  312. Read++;
  313. k = 128;
  314. for (c = 0; c < 8; c++) {
  315. iCurImage->Data[j * iCurImage->Width + i] = 
  316. (!!(ByteData & k) == 1 ? 1 : 0);
  317. k >>= 1;
  318. if (++i >= iCurImage->Width)
  319. break;
  320. }
  321. }
  322. //iseek(PadSize, IL_SEEK_CUR);
  323. iread(Padding, 1, PadSize);
  324. }
  325. iUnCache();
  326. break;
  327. case 4:
  328. //changed 2003-09-01
  329. if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
  330. iPreCache(iCurImage->Width / 2 * iCurImage->Height);
  331. PadSize = ((8 - (iCurImage->Width % 8)) / 2) % 4;  // Has to truncate
  332. for (j = 0; j < iCurImage->Height; j++) {
  333. for (i = 0; i < iCurImage->Width; i++) {
  334. if (iread(&ByteData, 1, 1) != 1) {
  335. iUnCache();
  336. return IL_FALSE;
  337. }
  338. iCurImage->Data[j * iCurImage->Width + i] = ByteData >> 4;
  339. if (++i == iCurImage->Width)
  340. break;
  341. iCurImage->Data[j * iCurImage->Width + i] = ByteData & 0x0F;
  342. }
  343. iread(Padding, 1, PadSize);//iseek(PadSize, IL_SEEK_CUR);
  344. }
  345. iUnCache();
  346. break;
  347. case 16: 
  348. //padding
  349. //2003-09-09: changed iCurImage->Bps to iCurImage->Width*2,
  350. //because iCurImage->Bps refers to the 24 bit devil image
  351. PadSize = (4 - (iCurImage->Width*2 % 4)) % 4;
  352. //check if bitfield compression is used
  353. rMask = 0x7C00;
  354. gMask = 0x03E0;
  355. bMask = 0x001F;
  356. rShiftR = 10;
  357. gShiftR = 5;
  358. bShiftR = 0;
  359. rShiftL = 3;
  360. gShiftL = 3;
  361. bShiftL = 3;
  362. if (Header->biCompression == 3) //bitfields
  363. {
  364. iseek(Header->bfDataOff - 12, IL_SEEK_SET); //seek to bitfield data
  365. iread(&rMask, 4, 1);
  366. iread(&gMask, 4, 1);
  367. iread(&bMask, 4, 1);
  368. UInt(&rMask);
  369. UInt(&gMask);
  370. UInt(&bMask);
  371. GetShiftFromMask(rMask, &rShiftL, &rShiftR);
  372. GetShiftFromMask(gMask, &gShiftL, &gShiftR);
  373. GetShiftFromMask(bMask, &bShiftL, &bShiftR);
  374. }
  375. k = 0;
  376. //changed 2003-09-01
  377. if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
  378. iPreCache(iCurImage->Width * iCurImage->Height);
  379. //@TODO: This may not be safe for Big Endian.
  380. for (j = 0; j < iCurImage->Height; j++) {
  381. for(i = 0; i < iCurImage->Width; i++, k += 3) {
  382. if (iread(&Read16, 2, 1) != 1) {
  383. iUnCache();
  384. return IL_FALSE;
  385. }
  386. iCurImage->Data[k] = ((Read16 & bMask) >> bShiftR) << bShiftL;
  387. iCurImage->Data[k + 1] = ((Read16 & gMask) >> gShiftR)  << gShiftL;
  388. iCurImage->Data[k + 2] = ((Read16 & rMask) >> rShiftR) << rShiftL;
  389. }
  390. iread(Padding, 1, PadSize);
  391. }
  392. iUnCache();
  393. break;
  394. case 8:
  395. case 24:
  396.             // For 8 and 24 bit, Bps is equal to the bmps bps
  397. PadSize = (4 - (iCurImage->Bps % 4)) % 4;
  398. if (PadSize == 0) {
  399. if (iread(iCurImage->Data, 1, iCurImage->SizeOfPlane) != iCurImage->SizeOfPlane)
  400. return IL_FALSE;
  401. }
  402. else { // Microsoft requires lines to be padded if the widths aren't multiples of 4.
  403. //changed 2003-09-01
  404. if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
  405. iPreCache(iCurImage->Width * iCurImage->Height);
  406. PadSize = (4 - (iCurImage->Bps % 4));
  407. for (i = 0; i < iCurImage->SizeOfPlane; i += iCurImage->Bps) {
  408. if (iread(iCurImage->Data + i, 1, iCurImage->Bps) != iCurImage->Bps) {
  409. iUnCache();
  410. return IL_FALSE;
  411. }
  412. //iseek(PadSize, IL_SEEK_CUR);
  413. iread(Padding, 1, PadSize);
  414. }
  415. iUnCache();
  416. }
  417. break;
  418. case 32: 
  419. //32bit files are always padded to 4 byte...
  420. //check if bitfield compression is used
  421. rMask = 0xFF0000;
  422. gMask = 0x00FF00;
  423. bMask = 0x0000FF;
  424. rShiftR = 16;
  425. gShiftR = 8;
  426. bShiftR = 0;
  427. rShiftL = 0;
  428. gShiftL = 0;
  429. bShiftL = 0;
  430. if (Header->biCompression == 3) //bitfields
  431. {
  432. iseek(Header->bfDataOff - 12, IL_SEEK_SET); //seek to bitfield data
  433. iread(&rMask, 4, 1);
  434. iread(&gMask, 4, 1);
  435. iread(&bMask, 4, 1);
  436. UInt(&rMask);
  437. UInt(&gMask);
  438. UInt(&bMask);
  439. GetShiftFromMask(rMask, &rShiftL, &rShiftR);
  440. GetShiftFromMask(gMask, &gShiftL, &gShiftR);
  441. GetShiftFromMask(bMask, &bShiftL, &bShiftR);
  442. }
  443. //TODO: win98 supports per-pixel alpha, so
  444. //load to rgba????
  445. //changed 2003-09-01
  446. if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
  447. iPreCache(iCurImage->Width * iCurImage->Height);
  448. for(i = 0; i < iCurImage->SizeOfData; i += 3) {
  449. if (iread(&Read, 4, 1) != 1) {
  450. iUnCache();
  451. return IL_FALSE;
  452. }
  453. iCurImage->Data[i] = ((Read & bMask) >> bShiftR) << bShiftL;
  454. iCurImage->Data[i + 1] = ((Read & gMask) >> gShiftR) << gShiftL;
  455. iCurImage->Data[i + 2] = ((Read & rMask) >> rShiftR) << rShiftL;
  456. }
  457. iUnCache();
  458. break;
  459. default:
  460. return IL_FALSE; //shouldn't happen, we checked that before
  461. }
  462. return IL_TRUE;
  463. }
  464. ILboolean ilReadRLE8Bmp(BMPHEAD *Header)
  465. {
  466. ILubyte Bytes[2];
  467. size_t offset = 0, count, endOfLine = Header->biWidth;
  468. // Update the current image with the new dimensions
  469. if (!ilTexImage(Header->biWidth, abs(Header->biHeight), 1, 1, 0, IL_UNSIGNED_BYTE, NULL))
  470. return IL_FALSE;
  471. iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  472. // A height of 0 is illegal
  473. if (Header->biHeight == 0)
  474. return IL_FALSE;
  475. iCurImage->Format = IL_COLOUR_INDEX;
  476. iCurImage->Pal.PalType = IL_PAL_BGR32;
  477. iCurImage->Pal.PalSize = Header->biClrUsed * 4;  // 256 * 4 for most images
  478. if (iCurImage->Pal.PalSize == 0)
  479. iCurImage->Pal.PalSize = 256 * 4;
  480. iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
  481. if (iCurImage->Pal.Palette == NULL)
  482. return IL_FALSE;
  483. // If the image height is negative, then the image is flipped
  484. // (Normal is IL_ORIGIN_LOWER_LEFT)
  485. iCurImage->Origin = Header->biHeight < 0 ?
  486.  IL_ORIGIN_UPPER_LEFT : IL_ORIGIN_LOWER_LEFT;
  487. // Read the palette
  488. iseek(sizeof(BMPHEAD), IL_SEEK_SET);
  489. if (iread(iCurImage->Pal.Palette, iCurImage->Pal.PalSize, 1) != 1)
  490. return IL_FALSE;
  491. // Seek to the data from the "beginning" of the file
  492. iseek(Header->bfDataOff, IL_SEEK_SET);
  493.     while (offset < iCurImage->SizeOfData) {
  494. if (iread(Bytes, sizeof(Bytes), 1) != 1)
  495. return IL_FALSE;
  496. if (Bytes[0] == 0x00) {  // Escape sequence
  497. switch (Bytes[1])
  498. {
  499. case 0x00:  // End of line
  500. offset = endOfLine;
  501. endOfLine += iCurImage->Width;
  502. break;
  503. case 0x01:  // End of bitmap
  504. offset = iCurImage->SizeOfData;
  505. break;
  506. case 0x2:
  507. if (iread(Bytes, sizeof(Bytes), 1) != 1)
  508. return IL_FALSE;
  509. offset += Bytes[0] + Bytes[1] * iCurImage->Width;
  510. endOfLine += Bytes[1] * iCurImage->Width;
  511. break;
  512. default:
  513. count = IL_MIN(Bytes[1], iCurImage->SizeOfData-offset);
  514. if (iread(iCurImage->Data + offset, (ILuint)count, 1) != 1)
  515. return IL_FALSE;
  516. offset += count;
  517. if ((count & 1) == 1)  // Must be on a word boundary
  518. if (iread(Bytes, 1, 1) != 1)
  519. return IL_FALSE;
  520. break;
  521. }
  522. } else {
  523. count = IL_MIN (Bytes[0], iCurImage->SizeOfData-offset);
  524. memset(iCurImage->Data + offset, Bytes[1], count);
  525. offset += count;
  526. }
  527. }
  528. return IL_TRUE;
  529. }
  530. //changed 2003-09-01
  531. //deleted ilReadRLE8Bmp() USE_POINTER version
  532. ILboolean ilReadRLE4Bmp(BMPHEAD *Header)
  533. {
  534. ILubyte Bytes[2];
  535. ILuint i;
  536.     size_t offset = 0, count, endOfLine = Header->biWidth;
  537. // Update the current image with the new dimensions
  538. if (!ilTexImage(Header->biWidth, abs(Header->biHeight), 1, 1, 0, IL_UNSIGNED_BYTE, NULL))
  539. return IL_FALSE;
  540. iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  541. // A height of 0 is illegal
  542. if (Header->biHeight == 0) {
  543. ilSetError(IL_ILLEGAL_FILE_VALUE);
  544. return IL_FALSE;
  545. }
  546. iCurImage->Format = IL_COLOUR_INDEX;
  547. iCurImage->Pal.PalType = IL_PAL_BGR32;
  548. iCurImage->Pal.PalSize = 16 * 4; //Header->biClrUsed * 4;  // 16 * 4 for most images
  549. iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
  550. if (iCurImage->Pal.Palette == NULL)
  551. return IL_FALSE;
  552. // If the image height is negative, then the image is flipped
  553. // (Normal is IL_ORIGIN_LOWER_LEFT)
  554. iCurImage->Origin = Header->biHeight < 0 ?
  555.  IL_ORIGIN_UPPER_LEFT : IL_ORIGIN_LOWER_LEFT;
  556. // Read the palette
  557. iseek(sizeof(BMPHEAD), IL_SEEK_SET);
  558. if (iread(iCurImage->Pal.Palette, iCurImage->Pal.PalSize, 1) != 1)
  559. return IL_FALSE;
  560. // Seek to the data from the "beginning" of the file
  561. iseek(Header->bfDataOff, IL_SEEK_SET);
  562. while (offset < iCurImage->SizeOfData) {
  563.       int align;
  564. if (iread(&Bytes[0], sizeof(Bytes), 1) != 1)
  565. return IL_FALSE;
  566. if (Bytes[0] == 0x0) { // Escape sequence
  567.          switch (Bytes[1]) {
  568.          case 0x0: // End of line
  569.             offset = endOfLine;
  570.             endOfLine += iCurImage->Width;
  571.             break;
  572.          case 0x1: // End of bitmap
  573.             offset = iCurImage->SizeOfData;
  574.             break;
  575.          case 0x2:
  576. if (iread(&Bytes[0], sizeof(Bytes), 1) != 1)
  577. return IL_FALSE;
  578.             offset += Bytes[0] + Bytes[1] * iCurImage->Width;
  579.             endOfLine += Bytes[1] * iCurImage->Width;
  580.             break;
  581.          default:   // Run of pixels
  582.             count = IL_MIN (Bytes[1], iCurImage->SizeOfData-offset);
  583. for (i = 0; i < count; i++) {
  584. int byte;
  585. if ((i & 0x01) == 0) {
  586. if (iread(&Bytes[0], sizeof(Bytes[0]), 1) != 1)
  587. return IL_FALSE;
  588. byte = (Bytes[0] >> 4);
  589. }
  590. else
  591. byte = (Bytes[0] & 0x0F);
  592. iCurImage->Data[offset++] = byte;
  593. }
  594. align = Bytes[1] % 4;
  595. if (align == 1 || align == 2) // Must be on a word boundary
  596. if (iread(&Bytes[0], sizeof(Bytes[0]), 1) != 1)
  597. return IL_FALSE;
  598. }
  599. } else {
  600.          count = IL_MIN (Bytes[0], iCurImage->SizeOfData-offset);
  601.          Bytes[0] = (Bytes[1] >> 4);
  602. Bytes[1] &= 0x0F;
  603. for (i = 0; i < count; i++)
  604. iCurImage->Data[offset++] = Bytes [i & 1];
  605. }
  606. }
  607.    return IL_TRUE;
  608. }
  609. //changed 2003-09-01
  610. //deleted ilReadRLE4Bmp() USE_POINTER version
  611. ILboolean iGetOS2Bmp(OS2_HEAD *Header)
  612. {
  613. ILuint PadSize, Read, i, j, k, c;
  614. ILubyte ByteData;
  615. if (Header->cBitCount == 1) {
  616. if (!ilTexImage(Header->cx, Header->cy, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) {
  617. return IL_FALSE;
  618. }
  619. iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  620. iCurImage->Pal.Palette = (ILubyte*)ialloc(2 * 3);
  621. if (iCurImage->Pal.Palette == NULL) {
  622. return IL_FALSE;
  623. }
  624. iCurImage->Pal.PalSize = 2 * 3;
  625. iCurImage->Pal.PalType = IL_PAL_BGR24;
  626. if (iread(iCurImage->Pal.Palette, 1, 2 * 3) != 6)
  627. return IL_FALSE;
  628. PadSize = ((32 - (iCurImage->Width % 32)) / 8) % 4;  // Has to truncate.
  629. iseek(Header->DataOff, IL_SEEK_SET);
  630. for (j = 0; j < iCurImage->Height; j++) {
  631. Read = 0;
  632. for (i = 0; i < iCurImage->Width; ) {
  633. if (iread(&ByteData, 1, 1) != 1)
  634. return IL_FALSE;
  635. Read++;
  636. k = 128;
  637. for (c = 0; c < 8; c++) {
  638. iCurImage->Data[j * iCurImage->Width + i] =
  639. (!!(ByteData & k) == 1 ? 1 : 0);
  640. k >>= 1;
  641. if (++i >= iCurImage->Width)
  642. break;
  643. }
  644. }
  645. iseek(PadSize, IL_SEEK_CUR);
  646. }
  647. return IL_TRUE;
  648. }
  649. if (Header->cBitCount == 4) {
  650. if (!ilTexImage(Header->cx, Header->cy, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) {
  651. return IL_FALSE;
  652. }
  653. iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  654. iCurImage->Pal.Palette = (ILubyte*)ialloc(16 * 3);
  655. if (iCurImage->Pal.Palette == NULL) {
  656. return IL_FALSE;
  657. }
  658. iCurImage->Pal.PalSize = 16 * 3;
  659. iCurImage->Pal.PalType = IL_PAL_BGR24;
  660. if (iread(iCurImage->Pal.Palette, 1, 16 * 3) != 16*3)
  661. return IL_FALSE;
  662. PadSize = ((8 - (iCurImage->Width % 8)) / 2) % 4;  // Has to truncate
  663. iseek(Header->DataOff, IL_SEEK_SET);
  664. for (j = 0; j < iCurImage->Height; j++) {
  665. for (i = 0; i < iCurImage->Width; i++) {
  666. if (iread(&ByteData, 1, 1) != 1)
  667. return IL_FALSE;
  668. iCurImage->Data[j * iCurImage->Width + i] = ByteData >> 4;
  669. if (++i == iCurImage->Width)
  670. break;
  671. iCurImage->Data[j * iCurImage->Width + i] = ByteData & 0x0F;
  672. }
  673. iseek(PadSize, IL_SEEK_CUR);
  674. }
  675. return IL_TRUE;
  676. }
  677. if (Header->cBitCount == 8) {
  678. //added this line 2003-09-01...strange no-one noticed before...
  679. if (!ilTexImage(Header->cx, Header->cy, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
  680. return IL_FALSE;
  681. iCurImage->Pal.Palette = (ILubyte*)ialloc(256 * 3);
  682. if (iCurImage->Pal.Palette == NULL) {
  683. return IL_FALSE;
  684. }
  685. iCurImage->Pal.PalSize = 256 * 3;
  686. iCurImage->Pal.PalType = IL_PAL_BGR24;
  687. if (iread(iCurImage->Pal.Palette, 1, 256 * 3) != 256*3)
  688. return IL_FALSE;
  689. }
  690. else { //has to be 24 bpp
  691. if (!ilTexImage(Header->cx, Header->cy, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL))
  692. return IL_FALSE;
  693. }
  694. iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  695. iseek(Header->DataOff, IL_SEEK_SET);
  696. PadSize = (4 - (iCurImage->Bps % 4)) % 4;
  697. if (PadSize == 0) {
  698. if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData)
  699. return IL_FALSE;
  700. }
  701. else {
  702. for (i = 0; i < iCurImage->Height; i++) {
  703. if (iread(iCurImage->Data + i * iCurImage->Bps, 1, iCurImage->Bps) != iCurImage->Bps)
  704. return IL_FALSE;
  705. iseek(PadSize, IL_SEEK_CUR);
  706. }
  707. }
  708. return IL_TRUE;
  709. }
  710. //! Writes a Bmp file
  711. ILboolean ilSave_BMP(ILconst_string FileName)
  712. {
  713. ILHANDLE BitmapFile;
  714. ILuint BitmapSize;
  715. if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
  716. if (iFileExists(FileName)) {
  717. ilSetError(IL_FILE_ALREADY_EXISTS);
  718. return IL_FALSE;
  719. }
  720. }
  721. BitmapFile = iopenw(FileName);
  722. if (BitmapFile == NULL) {
  723. ilSetError(IL_COULD_NOT_OPEN_FILE);
  724. return IL_FALSE;
  725. }
  726. BitmapSize = ilSaveF_BMP(BitmapFile);
  727. iclosew(BitmapFile);
  728. if (BitmapSize == 0)
  729. return IL_FALSE;
  730. return IL_TRUE;
  731. }
  732. //! Writes a Bmp to an already-opened file
  733. ILuint ilSaveF_BMP(ILHANDLE File)
  734. {
  735. ILuint Pos;
  736. iSetOutputFile(File);
  737. Pos = itellw();
  738. if (iSaveBitmapInternal() == IL_FALSE)
  739. return 0;  // Error occurred
  740. return itellw() - Pos;  // Return the number of bytes written.
  741. }
  742. //! Writes a Bmp to a memory "lump"
  743. ILuint ilSaveL_BMP(void *Lump, ILuint Size)
  744. {
  745. ILuint Pos;
  746. iSetOutputLump(Lump, Size);
  747. Pos = itellw();
  748. if (iSaveBitmapInternal() == IL_FALSE)
  749. return 0;  // Error occurred
  750. return itellw() - Pos;  // Return the number of bytes written.
  751. }
  752. // Internal function used to save the .bmp.
  753. ILboolean iSaveBitmapInternal()
  754. {
  755. //int compress_rle8 = ilGetInteger(IL_BMP_RLE);
  756. int compress_rle8 = IL_FALSE; // disabled BMP RLE compression. broken
  757. ILuint FileSize, i, PadSize, Padding = 0;
  758. ILimage *TempImage = NULL;
  759. ILpal *TempPal;
  760. ILubyte *TempData;
  761. if (iCurImage == NULL) {
  762. ilSetError(IL_ILLEGAL_OPERATION);
  763. return IL_FALSE;
  764. }
  765. iputc('B');  // Comprises the
  766. iputc('M');  //  "signature"
  767. SaveLittleUInt(0);  // Will come back and change later in this function (filesize)
  768. SaveLittleUInt(0);  // Reserved
  769. if (compress_rle8 == IL_TRUE)
  770. {
  771. TempImage = iConvertImage(iCurImage, IL_COLOR_INDEX, IL_UNSIGNED_BYTE);
  772. if (TempImage == NULL)
  773. return IL_FALSE;
  774. TempPal = iConvertPal(&TempImage->Pal, IL_PAL_BGR32);
  775. if (TempPal == NULL)
  776. {
  777. ilCloseImage(TempImage);
  778. return IL_FALSE;
  779. }
  780. }
  781. // If the current image has a palette, take care of it
  782. TempPal = &iCurImage->Pal;
  783. if( iCurImage->Pal.PalSize && iCurImage->Pal.Palette && iCurImage->Pal.PalType != IL_PAL_NONE ) {
  784. // If the palette in .bmp format, write it directly
  785. if (iCurImage->Pal.PalType == IL_PAL_BGR32) {
  786. TempPal = &iCurImage->Pal;
  787. } else {
  788. TempPal = iConvertPal(&iCurImage->Pal, IL_PAL_BGR32);
  789. if (TempPal == NULL) {
  790. return IL_FALSE;
  791. }
  792. }
  793. }
  794. SaveLittleUInt(54 + TempPal->PalSize);  // Offset of the data
  795. //Changed 20040923: moved this block above writing of
  796. //BITMAPINFOHEADER, so that the written header refers to
  797. //TempImage instead of the original image
  798. // @TODO LUMINANCE converted to BGR insteaf of beign saved to luminance
  799. if (iCurImage->Format != IL_BGR && iCurImage->Format != IL_BGRA && iCurImage->Format != IL_COLOUR_INDEX) {
  800. if (iCurImage->Format == IL_RGBA) {
  801. TempImage = iConvertImage(iCurImage, IL_BGRA, IL_UNSIGNED_BYTE);
  802. } else {
  803. TempImage = iConvertImage(iCurImage, IL_BGR, IL_UNSIGNED_BYTE);
  804. }
  805. if (TempImage == NULL)
  806. return IL_FALSE;
  807. } else if (iCurImage->Bpc > 1) {
  808. TempImage = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_BYTE);
  809. if (TempImage == NULL)
  810. return IL_FALSE;
  811. } else {
  812. TempImage = iCurImage;
  813. }
  814. if (TempImage->Origin != IL_ORIGIN_LOWER_LEFT) {
  815. TempData = iGetFlipped(TempImage);
  816. if (TempData == NULL) {
  817. ilCloseImage(TempImage);
  818. return IL_FALSE;
  819. }
  820. } else {
  821. TempData = TempImage->Data;
  822. }
  823. SaveLittleUInt(0x28);  // Header size
  824. SaveLittleUInt(iCurImage->Width);
  825. // Removed because some image viewers don't like the negative height.
  826. // even if it is standard. @TODO should be enabled or disabled
  827. // usually enabled.
  828. /*if (iCurImage->Origin == IL_ORIGIN_UPPER_LEFT)
  829. SaveLittleInt(-(ILint)iCurImage->Height);
  830. else*/
  831. SaveLittleInt(TempImage->Height);
  832. SaveLittleUShort(1);  // Number of planes
  833. SaveLittleUShort((ILushort)((ILushort)TempImage->Bpp << 3));  // Bpp
  834. if( compress_rle8 == IL_TRUE ) {
  835. SaveLittleInt(1); // rle8 compression
  836. } else {
  837. SaveLittleInt(0);
  838. }
  839. SaveLittleInt(0);  // Size of image (Obsolete)
  840. SaveLittleInt(0);  // (Obsolete)
  841. SaveLittleInt(0);  // (Obsolete)
  842. if (TempImage->Pal.PalType != IL_PAL_NONE) {
  843. SaveLittleInt(ilGetInteger(IL_PALETTE_NUM_COLS));  // Num colours used
  844. } else {
  845. SaveLittleInt(0);
  846. }
  847. SaveLittleInt(0);  // Important colour (none)
  848. iwrite(TempPal->Palette, 1, TempPal->PalSize);
  849. if( compress_rle8 == IL_TRUE ) {
  850. //@TODO compress and save
  851. ILubyte *Dest = (ILubyte*)ialloc((long)((double)TempImage->SizeOfPlane*130/127));
  852. FileSize = ilRleCompress(TempImage->Data,TempImage->Width,TempImage->Height,
  853. TempImage->Depth,TempImage->Bpp,Dest,IL_BMPCOMP,NULL);
  854. iwrite(Dest,1,FileSize);
  855. } else {
  856. PadSize = (4 - (TempImage->Bps % 4)) % 4;
  857. // No padding, so write data directly.
  858. if (PadSize == 0) {
  859. iwrite(TempData, 1, TempImage->SizeOfPlane);
  860. } else {  // Odd width, so we must pad each line.
  861. for (i = 0; i < TempImage->SizeOfPlane; i += TempImage->Bps) {
  862. iwrite(TempData + i, 1, TempImage->Bps); // Write data
  863. iwrite(&Padding, 1, PadSize); // Write pad byte(s)
  864. }
  865. }
  866. }
  867. // Write the filesize
  868. FileSize = itellw();
  869. iseekw(2, IL_SEEK_SET);
  870. SaveLittleUInt(FileSize);
  871. if (TempPal != &iCurImage->Pal) {
  872. ifree(TempPal->Palette);
  873. ifree(TempPal);
  874. }
  875. if (TempData != TempImage->Data)
  876. ifree(TempData);
  877. if (TempImage != iCurImage)
  878. ilCloseImage(TempImage);
  879. iseekw(FileSize, IL_SEEK_SET);
  880. return IL_TRUE;
  881. }
  882. #endif//IL_NO_BMP