il_pal.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-2009 by Denton Woods
  5. // Last modified: 02/14/2009
  6. //
  7. // Filename: src-IL/src/il_pal.c
  8. //
  9. // Description: Loads palettes from different file formats
  10. //
  11. //-----------------------------------------------------------------------------
  12. #include "il_internal.h"
  13. #include "il_pal.h"
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <limits.h>
  17. //! Loads a palette from FileName into the current image's palette.
  18. ILboolean ILAPIENTRY ilLoad_PAL(ILconst_string FileName)
  19. {
  20. FILE *f;
  21. ILboolean IsPsp;
  22. char Head[8];
  23. if (FileName == NULL) {
  24. ilSetError(IL_INVALID_PARAM);
  25. return IL_FALSE;
  26. }
  27. if (iCheckExtension(FileName, IL_TEXT("col"))) {
  28. return ilLoad_COL_PAL(FileName);
  29. }
  30. if (iCheckExtension(FileName, IL_TEXT("act"))) {
  31. return ilLoad_ACT_PAL(FileName);
  32. }
  33. if (iCheckExtension(FileName, IL_TEXT("plt"))) {
  34. return ilLoad_PLT_PAL(FileName);
  35. }
  36. #ifndef _UNICODE
  37. f = fopen(FileName, "rt");
  38. #else
  39. f = _wfopen(FileName, L"rt");
  40. #endif//_UNICODE
  41. if (f == NULL) {
  42. ilSetError(IL_COULD_NOT_OPEN_FILE);
  43. return IL_FALSE;
  44. }
  45. fread(Head, 1, 8, f);
  46. if (!strncmp(Head, "JASC-PAL", 8))
  47. IsPsp = IL_TRUE;
  48. else
  49. IsPsp = IL_FALSE;
  50. fclose(f);
  51. if (IsPsp)
  52. return ilLoad_JASC_PAL(FileName);
  53. return ilLoad_HALO_PAL(FileName);
  54. }
  55. //! Loads a Paint Shop Pro formatted palette (.pal) file.
  56. ILboolean ilLoad_JASC_PAL(ILconst_string FileName)
  57. {
  58. FILE *PalFile;
  59. ILuint NumColours, i, c;
  60. ILubyte Buff[BUFFLEN];
  61. ILboolean Error = IL_FALSE;
  62. ILpal *Pal = &iCurImage->Pal;
  63. if (!iCheckExtension(FileName, IL_TEXT("pal"))) {
  64. ilSetError(IL_INVALID_EXTENSION);
  65. return IL_FALSE;
  66. }
  67. if (iCurImage == NULL) {
  68. ilSetError(IL_ILLEGAL_OPERATION);
  69. return IL_FALSE;
  70. }
  71. #ifndef _UNICODE
  72. PalFile = fopen(FileName, "rt");
  73. #else
  74. PalFile = _wfopen(FileName, L"rt");
  75. #endif//_UNICODE
  76. if (PalFile == NULL) {
  77. ilSetError(IL_COULD_NOT_OPEN_FILE);
  78. return IL_FALSE;
  79. }
  80. if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize > 0 && iCurImage->Pal.PalType != IL_PAL_NONE) {
  81. ifree(iCurImage->Pal.Palette);
  82. iCurImage->Pal.Palette = NULL;
  83. }
  84. iFgetw(Buff, BUFFLEN, PalFile);
  85. if (stricmp((const char*)Buff, "JASC-PAL")) {
  86. Error = IL_TRUE;
  87. }
  88. iFgetw(Buff, BUFFLEN, PalFile);
  89. if (stricmp((const char*)Buff, "0100")) {
  90. Error = IL_TRUE;
  91. }
  92. iFgetw(Buff, BUFFLEN, PalFile);
  93. NumColours = atoi((const char*)Buff);
  94. if (NumColours == 0 || Error) {
  95. ilSetError(IL_INVALID_FILE_HEADER);
  96. fclose(PalFile);
  97. return IL_FALSE;
  98. }
  99. Pal->PalSize = NumColours * PALBPP;
  100. Pal->PalType = IL_PAL_RGB24;
  101. Pal->Palette = (ILubyte*)ialloc(NumColours * PALBPP);
  102. if (Pal->Palette == NULL) {
  103. fclose(PalFile);
  104. return IL_FALSE;
  105. }
  106. for (i = 0; i < NumColours; i++) {
  107. for (c = 0; c < PALBPP; c++) {
  108. iFgetw(Buff, BUFFLEN, PalFile);
  109. Pal->Palette[i * PALBPP + c] = atoi((const char*)Buff);
  110. }
  111. }
  112. fclose(PalFile);
  113. return IL_TRUE;
  114. }
  115. // File Get Word
  116. // MaxLen must be greater than 1, because the trailing NULL is always stored.
  117. char *iFgetw(ILubyte *Buff, ILint MaxLen, FILE *File)
  118. {
  119. ILint Temp;
  120. ILint i;
  121. if (Buff == NULL || File == NULL || MaxLen < 2) {
  122. ilSetError(IL_INVALID_PARAM);
  123. return NULL;
  124. }
  125. for (i = 0; i < MaxLen - 1; i++) {
  126. Temp = fgetc(File);
  127. if (Temp == 'n' || Temp == '' || Temp == IL_EOF || feof(File)) {
  128. break;
  129. }
  130. if (Temp == ' ') {
  131. while (Temp == ' ') {  // Just to get rid of any extra spaces
  132. Temp = fgetc(File);
  133. }
  134. fseek(File, -1, IL_SEEK_CUR);  // Go back one
  135. break;
  136. }
  137. if (!isprint(Temp)) {  // Skips any non-printing characters
  138. while (!isprint(Temp)) {
  139. Temp = fgetc(File);
  140. }
  141. fseek(File, -1, IL_SEEK_CUR);
  142. break;
  143. }
  144. Buff[i] = Temp;
  145. }
  146. Buff[i] = '';
  147. return (char *)Buff;
  148. }
  149. ILboolean ILAPIENTRY ilSave_PAL(ILconst_string FileName)
  150. {
  151. ILstring Ext = iGetExtension(FileName);
  152. if (iCurImage == NULL) {
  153. ilSetError(IL_ILLEGAL_OPERATION);
  154. return IL_FALSE;
  155. }
  156. #ifndef _UNICODE
  157. if (FileName == NULL || strlen(FileName) < 1 || Ext == NULL) {
  158. #else
  159. if (FileName == NULL || wcslen(FileName) < 1 || Ext == NULL) {
  160. #endif//_UNICODE
  161. ilSetError(IL_INVALID_PARAM);
  162. return IL_FALSE;
  163. }
  164. if (!iCurImage->Pal.Palette || !iCurImage->Pal.PalSize || iCurImage->Pal.PalType == IL_PAL_NONE) {
  165. ilSetError(IL_ILLEGAL_OPERATION);
  166. return IL_FALSE;
  167. }
  168. if (!iStrCmp(Ext, IL_TEXT("pal"))) {
  169. return ilSavePal_JASC(FileName);
  170. }
  171. ilSetError(IL_INVALID_EXTENSION);
  172. return IL_FALSE;
  173. }
  174. //! Saves a Paint Shop Pro formatted palette (.pal) file.
  175. ILboolean ilSavePal_JASC(ILconst_string FileName)
  176. {
  177. FILE *PalFile;
  178. ILuint i, PalBpp, NumCols = ilGetInteger(IL_PALETTE_NUM_COLS);
  179. ILubyte *CurPal;
  180. if (iCurImage == NULL || NumCols == 0 || NumCols > 256) {
  181. ilSetError(IL_ILLEGAL_OPERATION);
  182. return IL_FALSE;
  183. }
  184. #ifndef _UNICODE
  185. if (FileName == NULL || strlen(FileName) < 5) {
  186. #else
  187. if (FileName == NULL || wcslen(FileName) < 5) {
  188. #endif//_UNICODE
  189. ilSetError(IL_INVALID_VALUE);
  190. return IL_FALSE;
  191. }
  192. if (!iCheckExtension(FileName, IL_TEXT("pal"))) {
  193. ilSetError(IL_INVALID_EXTENSION);
  194. return IL_FALSE;
  195. }
  196. if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
  197. if (iFileExists(FileName)) {
  198. ilSetError(IL_FILE_ALREADY_EXISTS);
  199. return IL_FALSE;
  200. }
  201. }
  202. // Create a copy of the current palette and convert it to RGB24 format.
  203. CurPal = iCurImage->Pal.Palette;
  204. iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
  205. if (!iCurImage->Pal.Palette) {
  206. iCurImage->Pal.Palette = CurPal;
  207. return IL_FALSE;
  208. }
  209. memcpy(iCurImage->Pal.Palette, CurPal, iCurImage->Pal.PalSize);
  210. if (!ilConvertPal(IL_PAL_RGB24)) {
  211. ifree(iCurImage->Pal.Palette);
  212. iCurImage->Pal.Palette = CurPal;
  213. return IL_FALSE;
  214. }
  215. #ifndef _UNICODE
  216. PalFile = fopen(FileName, "wt");
  217. #else
  218. PalFile = _wfopen(FileName, L"wt");
  219. #endif//_UNICODE
  220. if (!PalFile) {
  221. ilSetError(IL_COULD_NOT_OPEN_FILE);
  222. return IL_FALSE;
  223. }
  224. // Header needed on all .pal files
  225. fputs("JASC-PALn0100n256n", PalFile);
  226. PalBpp = ilGetBppPal(iCurImage->Pal.PalType);
  227. for (i = 0; i < iCurImage->Pal.PalSize; i += PalBpp) {
  228. fprintf(PalFile, "%d %d %dn",
  229. iCurImage->Pal.Palette[i], iCurImage->Pal.Palette[i+1], iCurImage->Pal.Palette[i+2]);
  230. }
  231. NumCols = 256 - NumCols;
  232. for (i = 0; i < NumCols; i++) {
  233. fprintf(PalFile, "0 0 0n");
  234. }
  235. ifree(iCurImage->Pal.Palette);
  236. iCurImage->Pal.Palette = CurPal;
  237. fclose(PalFile);
  238. return IL_TRUE;
  239. }
  240. //! Loads a Halo formatted palette (.pal) file.
  241. ILboolean ilLoad_HALO_PAL(ILconst_string FileName)
  242. {
  243. ILHANDLE HaloFile;
  244. HALOHEAD HaloHead;
  245. ILushort *TempPal;
  246. ILuint i, Size;
  247. if (!iCheckExtension(FileName, IL_TEXT("pal"))) {
  248. ilSetError(IL_INVALID_EXTENSION);
  249. return IL_FALSE;
  250. }
  251. if (iCurImage == NULL) {
  252. ilSetError(IL_ILLEGAL_OPERATION);
  253. return IL_FALSE;
  254. }
  255. HaloFile = iopenr(FileName);
  256. if (HaloFile == NULL) {
  257. ilSetError(IL_COULD_NOT_OPEN_FILE);
  258. return IL_FALSE;
  259. }
  260. if (iread(&HaloHead, sizeof(HALOHEAD), 1) != 1)
  261. return IL_FALSE;
  262. if (HaloHead.Id != 'A' + ('H' << 8) || HaloHead.Version != 0xe3) {
  263. icloser(HaloFile);
  264. ilSetError(IL_ILLEGAL_FILE_VALUE);
  265. return IL_FALSE;
  266. }
  267. Size = (HaloHead.MaxIndex + 1) * 3;
  268. TempPal = (ILushort*)ialloc(Size * sizeof(ILushort));
  269. if (TempPal == NULL) {
  270. icloser(HaloFile);
  271. return IL_FALSE;
  272. }
  273. if (iread(TempPal, sizeof(ILushort), Size) != Size) {
  274. icloser(HaloFile);
  275. ifree(TempPal);
  276. return IL_FALSE;
  277. }
  278. if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize > 0 && iCurImage->Pal.PalType != IL_PAL_NONE) {
  279. ifree(iCurImage->Pal.Palette);
  280. iCurImage->Pal.Palette = NULL;
  281. }
  282. iCurImage->Pal.PalType = IL_PAL_RGB24;
  283. iCurImage->Pal.PalSize = Size;
  284. iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
  285. if (iCurImage->Pal.Palette == NULL) {
  286. icloser(HaloFile);
  287. return IL_FALSE;
  288. }
  289. for (i = 0; i < iCurImage->Pal.PalSize; i++, TempPal++) {
  290. iCurImage->Pal.Palette[i] = (ILubyte)*TempPal;
  291. }
  292. TempPal -= iCurImage->Pal.PalSize;
  293. ifree(TempPal);
  294. icloser(HaloFile);
  295. return IL_TRUE;
  296. }
  297. // Hasn't been tested
  298. // @TODO: Test the thing!
  299. //! Loads a .col palette file
  300. ILboolean ilLoad_COL_PAL(ILconst_string FileName)
  301. {
  302. ILuint RealFileSize, FileSize;
  303. ILushort Version;
  304. ILHANDLE ColFile;
  305. if (!iCheckExtension(FileName, IL_TEXT("col"))) {
  306. ilSetError(IL_INVALID_EXTENSION);
  307. return IL_FALSE;
  308. }
  309. if (iCurImage == NULL) {
  310. ilSetError(IL_ILLEGAL_OPERATION);
  311. return IL_FALSE;
  312. }
  313. ColFile = iopenr(FileName);
  314. if (ColFile == NULL) {
  315. ilSetError(IL_COULD_NOT_OPEN_FILE);
  316. return IL_FALSE;
  317. }
  318. if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize > 0 && iCurImage->Pal.PalType != IL_PAL_NONE) {
  319. ifree(iCurImage->Pal.Palette);
  320. iCurImage->Pal.Palette = NULL;
  321. }
  322. iseek(0, IL_SEEK_END);
  323. RealFileSize = ftell((FILE*)ColFile);
  324. iseek(0, IL_SEEK_SET);
  325. if (RealFileSize > 768) {  // has a header
  326. fread(&FileSize, 4, 1, (FILE*)ColFile);
  327. if ((FileSize - 8) % 3 != 0) {  // check to make sure an even multiple of 3!
  328. icloser(ColFile);
  329. ilSetError(IL_ILLEGAL_FILE_VALUE);
  330. return IL_FALSE;
  331. }
  332. if (iread(&Version, 2, 1) != 1) {
  333. icloser(ColFile);
  334. return IL_FALSE;
  335. }
  336. if (Version != 0xB123) {
  337. icloser(ColFile);
  338. ilSetError(IL_ILLEGAL_FILE_VALUE);
  339. return IL_FALSE;
  340. }
  341. if (iread(&Version, 2, 1) != 1) {
  342. icloser(ColFile);
  343. return IL_FALSE;
  344. }
  345. if (Version != 0) {
  346. icloser(ColFile);
  347. ilSetError(IL_ILLEGAL_FILE_VALUE);
  348. return IL_FALSE;
  349. }
  350. }
  351. iCurImage->Pal.Palette = (ILubyte*)ialloc(768);
  352. if (iCurImage->Pal.Palette == NULL) {
  353. icloser(ColFile);
  354. return IL_FALSE;
  355. }
  356. if (iread(iCurImage->Pal.Palette, 1, 768) != 768) {
  357. icloser(ColFile);
  358. ifree(iCurImage->Pal.Palette);
  359. iCurImage->Pal.Palette = NULL;
  360. return IL_FALSE;
  361. }
  362. iCurImage->Pal.PalSize = 768;
  363. iCurImage->Pal.PalType = IL_PAL_RGB24;
  364. icloser(ColFile);
  365. return IL_TRUE;
  366. }
  367. //! Loads an .act palette file.
  368. ILboolean ilLoad_ACT_PAL(ILconst_string FileName)
  369. {
  370. ILHANDLE ActFile;
  371. if (!iCheckExtension(FileName, IL_TEXT("act"))) {
  372. ilSetError(IL_INVALID_EXTENSION);
  373. return IL_FALSE;
  374. }
  375. if (iCurImage == NULL) {
  376. ilSetError(IL_ILLEGAL_OPERATION);
  377. return IL_FALSE;
  378. }
  379. ActFile = iopenr(FileName);
  380. if (ActFile == NULL) {
  381. ilSetError(IL_COULD_NOT_OPEN_FILE);
  382. return IL_FALSE;
  383. }
  384. if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize > 0 && iCurImage->Pal.PalType != IL_PAL_NONE) {
  385. ifree(iCurImage->Pal.Palette);
  386. iCurImage->Pal.Palette = NULL;
  387. }
  388. iCurImage->Pal.PalType = IL_PAL_RGB24;
  389. iCurImage->Pal.PalSize = 768;
  390. iCurImage->Pal.Palette = (ILubyte*)ialloc(768);
  391. if (!iCurImage->Pal.Palette) {
  392. icloser(ActFile);
  393. return IL_FALSE;
  394. }
  395. if (iread(iCurImage->Pal.Palette, 1, 768) != 768) {
  396. icloser(ActFile);
  397. return IL_FALSE;
  398. }
  399. icloser(ActFile);
  400. return IL_TRUE;
  401. }
  402. //! Loads an .plt palette file.
  403. ILboolean ilLoad_PLT_PAL(ILconst_string FileName)
  404. {
  405. ILHANDLE PltFile;
  406. if (!iCheckExtension(FileName, IL_TEXT("plt"))) {
  407. ilSetError(IL_INVALID_EXTENSION);
  408. return IL_FALSE;
  409. }
  410. if (iCurImage == NULL) {
  411. ilSetError(IL_ILLEGAL_OPERATION);
  412. return IL_FALSE;
  413. }
  414. PltFile = iopenr(FileName);
  415. if (PltFile == NULL) {
  416. ilSetError(IL_COULD_NOT_OPEN_FILE);
  417. return IL_FALSE;
  418. }
  419. if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize > 0 && iCurImage->Pal.PalType != IL_PAL_NONE) {
  420. ifree(iCurImage->Pal.Palette);
  421. iCurImage->Pal.Palette = NULL;
  422. }
  423. iCurImage->Pal.PalSize = GetLittleUInt();
  424. if (iCurImage->Pal.PalSize == 0) {
  425. ilSetError(IL_INVALID_FILE_HEADER);
  426. return IL_FALSE;
  427. }
  428. iCurImage->Pal.PalType = IL_PAL_RGB24;
  429. iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
  430. if (!iCurImage->Pal.Palette) {
  431. icloser(PltFile);
  432. return IL_FALSE;
  433. }
  434. if (iread(iCurImage->Pal.Palette, iCurImage->Pal.PalSize, 1) != 1) {
  435. ifree(iCurImage->Pal.Palette);
  436. iCurImage->Pal.Palette = NULL;
  437. icloser(PltFile);
  438. return IL_FALSE;
  439. }
  440. icloser(PltFile);
  441. return IL_TRUE;
  442. }
  443. // Assumes that Dest has nothing in it.
  444. ILboolean iCopyPalette(ILpal *Dest, ILpal *Src)
  445. {
  446. if (Src->Palette == NULL || Src->PalSize == 0)
  447. return IL_FALSE;
  448. Dest->Palette = (ILubyte*)ialloc(Src->PalSize);
  449. if (Dest->Palette == NULL)
  450. return IL_FALSE;
  451. memcpy(Dest->Palette, Src->Palette, Src->PalSize);
  452. Dest->PalSize = Src->PalSize;
  453. Dest->PalType = Src->PalType;
  454. return IL_TRUE;
  455. }
  456. ILAPI ILpal* ILAPIENTRY iCopyPal()
  457. {
  458. ILpal *Pal;
  459. if (iCurImage == NULL || iCurImage->Pal.Palette == NULL ||
  460. iCurImage->Pal.PalSize == 0 || iCurImage->Pal.PalType == IL_PAL_NONE) {
  461. ilSetError(IL_ILLEGAL_OPERATION);
  462. return NULL;
  463. }
  464. Pal = (ILpal*)ialloc(sizeof(ILpal));
  465. if (Pal == NULL) {
  466. return NULL;
  467. }
  468. if (!iCopyPalette(Pal, &iCurImage->Pal)) {
  469. ifree(Pal);
  470. return NULL;
  471. }
  472. return Pal;
  473. }
  474. // Converts the palette to the DestFormat format.
  475. ILAPI ILpal* ILAPIENTRY iConvertPal(ILpal *Pal, ILenum DestFormat)
  476. {
  477. ILpal *NewPal = NULL;
  478. ILuint i, j, NewPalSize;
  479. // Checks to see if the current image is valid and has a palette
  480. if (Pal == NULL || Pal->PalSize == 0 || Pal->Palette == NULL || Pal->PalType == IL_PAL_NONE) {
  481. ilSetError(IL_ILLEGAL_OPERATION);
  482. return NULL;
  483. }
  484. /*if (Pal->PalType == DestFormat) {
  485. return NULL;
  486. }*/
  487. NewPal = (ILpal*)ialloc(sizeof(ILpal));
  488. if (NewPal == NULL) {
  489. return NULL;
  490. }
  491. NewPal->PalSize = Pal->PalSize;
  492. NewPal->PalType = Pal->PalType;
  493. switch (DestFormat)
  494. {
  495. case IL_PAL_RGB24:
  496. case IL_PAL_BGR24:
  497. switch (Pal->PalType)
  498. {
  499. case IL_PAL_RGB24:
  500. NewPal->Palette = (ILubyte*)ialloc(Pal->PalSize);
  501. if (NewPal->Palette == NULL)
  502. goto alloc_error;
  503. if (DestFormat == IL_PAL_BGR24) {
  504. j = ilGetBppPal(Pal->PalType);
  505. for (i = 0; i < Pal->PalSize; i += j) {
  506. NewPal->Palette[i] = Pal->Palette[i+2];
  507. NewPal->Palette[i+1] = Pal->Palette[i+1];
  508. NewPal->Palette[i+2] = Pal->Palette[i];
  509. }
  510. }
  511. else {
  512. memcpy(NewPal->Palette, Pal->Palette, Pal->PalSize);
  513. }
  514. NewPal->PalType = DestFormat;
  515. break;
  516. case IL_PAL_BGR24:
  517. NewPal->Palette = (ILubyte*)ialloc(Pal->PalSize);
  518. if (NewPal->Palette == NULL)
  519. goto alloc_error;
  520. if (DestFormat == IL_PAL_RGB24) {
  521. j = ilGetBppPal(Pal->PalType);
  522. for (i = 0; i < Pal->PalSize; i += j) {
  523. NewPal->Palette[i] = Pal->Palette[i+2];
  524. NewPal->Palette[i+1] = Pal->Palette[i+1];
  525. NewPal->Palette[i+2] = Pal->Palette[i];
  526. }
  527. }
  528. else {
  529. memcpy(NewPal->Palette, Pal->Palette, Pal->PalSize);
  530. }
  531. NewPal->PalType = DestFormat;
  532. break;
  533. case IL_PAL_BGR32:
  534. case IL_PAL_BGRA32:
  535. NewPalSize = (ILuint)((ILfloat)Pal->PalSize * 3.0f / 4.0f);
  536. NewPal->Palette = (ILubyte*)ialloc(NewPalSize);
  537. if (NewPal->Palette == NULL)
  538. goto alloc_error;
  539. if (DestFormat == IL_PAL_RGB24) {
  540. for (i = 0, j = 0; i < Pal->PalSize; i += 4, j += 3) {
  541. NewPal->Palette[j]   = Pal->Palette[i+2];
  542. NewPal->Palette[j+1] = Pal->Palette[i+1];
  543. NewPal->Palette[j+2] = Pal->Palette[i];
  544. }
  545. }
  546. else {
  547. for (i = 0, j = 0; i < Pal->PalSize; i += 4, j += 3) {
  548. NewPal->Palette[j]   = Pal->Palette[i];
  549. NewPal->Palette[j+1] = Pal->Palette[i+1];
  550. NewPal->Palette[j+2] = Pal->Palette[i+2];
  551. }
  552. }
  553. NewPal->PalSize = NewPalSize;
  554. NewPal->PalType = DestFormat;
  555. break;
  556. case IL_PAL_RGB32:
  557. case IL_PAL_RGBA32:
  558. NewPalSize = (ILuint)((ILfloat)Pal->PalSize * 3.0f / 4.0f);
  559. NewPal->Palette = (ILubyte*)ialloc(NewPalSize);
  560. if (NewPal->Palette == NULL)
  561. goto alloc_error;
  562. if (DestFormat == IL_PAL_RGB24) {
  563. for (i = 0, j = 0; i < Pal->PalSize; i += 4, j += 3) {
  564. NewPal->Palette[j]   = Pal->Palette[i];
  565. NewPal->Palette[j+1] = Pal->Palette[i+1];
  566. NewPal->Palette[j+2] = Pal->Palette[i+2];
  567. }
  568. }
  569. else {
  570. for (i = 0, j = 0; i < Pal->PalSize; i += 4, j += 3) {
  571. NewPal->Palette[j]   = Pal->Palette[i+2];
  572. NewPal->Palette[j+1] = Pal->Palette[i+1];
  573. NewPal->Palette[j+2] = Pal->Palette[i];
  574. }
  575. }
  576. NewPal->PalSize = NewPalSize;
  577. NewPal->PalType = DestFormat;
  578. break;
  579. default:
  580. ilSetError(IL_INVALID_PARAM);
  581. return NULL;
  582. }
  583. break;
  584. case IL_PAL_RGB32:
  585. case IL_PAL_RGBA32:
  586. case IL_PAL_BGR32:
  587. case IL_PAL_BGRA32:
  588. switch (Pal->PalType)
  589. {
  590. case IL_PAL_RGB24:
  591. case IL_PAL_BGR24:
  592. NewPalSize = Pal->PalSize * 4 / 3;
  593. NewPal->Palette = (ILubyte*)ialloc(NewPalSize);
  594. if (NewPal->Palette == NULL)
  595. goto alloc_error;
  596. if ((Pal->PalType == IL_PAL_BGR24 && (DestFormat == IL_PAL_RGB32 || DestFormat == IL_PAL_RGBA32)) ||
  597. (Pal->PalType == IL_PAL_RGB24 && (DestFormat == IL_PAL_BGR32 || DestFormat == IL_PAL_BGRA32))) {
  598. for (i = 0, j = 0; i < Pal->PalSize; i += 3, j += 4) {
  599. NewPal->Palette[j]   = Pal->Palette[i+2];
  600. NewPal->Palette[j+1] = Pal->Palette[i+1];
  601. NewPal->Palette[j+2] = Pal->Palette[i];
  602. NewPal->Palette[j+3] = 255;
  603. }
  604. }
  605. else {
  606. for (i = 0, j = 0; i < Pal->PalSize; i += 3, j += 4) {
  607. NewPal->Palette[j]   = Pal->Palette[i];
  608. NewPal->Palette[j+1] = Pal->Palette[i+1];
  609. NewPal->Palette[j+2] = Pal->Palette[i+2];
  610. NewPal->Palette[j+3] = 255;
  611. }
  612. }
  613. NewPal->PalSize = NewPalSize;
  614. NewPal->PalType = DestFormat;
  615. break;
  616. case IL_PAL_RGB32:
  617. NewPal->Palette = (ILubyte*)ialloc(Pal->PalSize);
  618. if (NewPal->Palette == NULL)
  619. goto alloc_error;
  620. if (DestFormat == IL_PAL_BGR32 || DestFormat == IL_PAL_BGRA32) {
  621. for (i = 0; i < Pal->PalSize; i += 4) {
  622. NewPal->Palette[i]   = Pal->Palette[i+2];
  623. NewPal->Palette[i+1] = Pal->Palette[i+1];
  624. NewPal->Palette[i+2] = Pal->Palette[i];
  625. NewPal->Palette[i+3] = 255;
  626. }
  627. }
  628. else {
  629. for (i = 0; i < Pal->PalSize; i += 4) {
  630. NewPal->Palette[i]   = Pal->Palette[i];
  631. NewPal->Palette[i+1] = Pal->Palette[i+1];
  632. NewPal->Palette[i+2] = Pal->Palette[i+2];
  633. NewPal->Palette[i+3] = 255;
  634. }
  635. }
  636. NewPal->PalType = DestFormat;
  637. break;
  638. case IL_PAL_RGBA32:
  639. NewPal->Palette = (ILubyte*)ialloc(Pal->PalSize);
  640. if (NewPal->Palette == NULL)
  641. goto alloc_error;
  642. if (DestFormat == IL_PAL_BGR32 || DestFormat == IL_PAL_BGRA32) {
  643. for (i = 0; i < Pal->PalSize; i += 4) {
  644. NewPal->Palette[i]   = Pal->Palette[i+2];
  645. NewPal->Palette[i+1] = Pal->Palette[i+1];
  646. NewPal->Palette[i+2] = Pal->Palette[i];
  647. NewPal->Palette[i+3] = Pal->Palette[i+3];
  648. }
  649. }
  650. else {
  651. memcpy(NewPal->Palette, Pal->Palette, Pal->PalSize);
  652. }
  653. NewPal->PalType = DestFormat;
  654. break;
  655. case IL_PAL_BGR32:
  656. NewPal->Palette = (ILubyte*)ialloc(Pal->PalSize);
  657. if (NewPal->Palette == NULL)
  658. goto alloc_error;
  659. if (DestFormat == IL_PAL_RGB32 || DestFormat == IL_PAL_RGBA32) {
  660. for (i = 0; i < Pal->PalSize; i += 4) {
  661. NewPal->Palette[i]   = Pal->Palette[i+2];
  662. NewPal->Palette[i+1] = Pal->Palette[i+1];
  663. NewPal->Palette[i+2] = Pal->Palette[i];
  664. NewPal->Palette[i+3] = 255;
  665. }
  666. }
  667. else {
  668. for (i = 0; i < Pal->PalSize; i += 4) {
  669. NewPal->Palette[i]   = Pal->Palette[i];
  670. NewPal->Palette[i+1] = Pal->Palette[i+1];
  671. NewPal->Palette[i+2] = Pal->Palette[i+2];
  672. NewPal->Palette[i+3] = 255;
  673. }
  674. }
  675. NewPal->PalType = DestFormat;
  676. break;
  677. case IL_PAL_BGRA32:
  678. NewPal->Palette = (ILubyte*)ialloc(Pal->PalSize);
  679. if (NewPal->Palette == NULL)
  680. goto alloc_error;
  681. if (DestFormat == IL_PAL_RGB32 || DestFormat == IL_PAL_RGBA32) {
  682. for (i = 0; i < Pal->PalSize; i += 4) {
  683. NewPal->Palette[i]   = Pal->Palette[i+2];
  684. NewPal->Palette[i+1] = Pal->Palette[i+1];
  685. NewPal->Palette[i+2] = Pal->Palette[i];
  686. NewPal->Palette[i+3] = Pal->Palette[i+3];
  687. }
  688. }
  689. else {
  690. memcpy(NewPal->Palette, Pal->Palette, Pal->PalSize);
  691. }
  692. NewPal->PalType = DestFormat;
  693. break;
  694. default:
  695. ilSetError(IL_INVALID_PARAM);
  696. return NULL;
  697. }
  698. break;
  699. default:
  700. ilSetError(IL_INVALID_PARAM);
  701. return NULL;
  702. }
  703. NewPal->PalType = DestFormat;
  704. return NewPal;
  705. alloc_error:
  706. ifree(NewPal);
  707. return NULL;
  708. }
  709. //! Converts the current image to the DestFormat format.
  710. ILboolean ILAPIENTRY ilConvertPal(ILenum DestFormat)
  711. {
  712. ILpal *Pal;
  713. if (iCurImage == NULL || iCurImage->Pal.Palette == NULL ||
  714. iCurImage->Pal.PalSize == 0 || iCurImage->Pal.PalType == IL_PAL_NONE) {
  715. ilSetError(IL_ILLEGAL_OPERATION);
  716. return IL_FALSE;
  717. }
  718. Pal = iConvertPal(&iCurImage->Pal, DestFormat);
  719. if (Pal == NULL)
  720. return IL_FALSE;
  721. ifree(iCurImage->Pal.Palette);
  722. iCurImage->Pal.PalSize = Pal->PalSize;
  723. iCurImage->Pal.PalType = Pal->PalType;
  724. iCurImage->Pal.Palette = (ILubyte*)ialloc(Pal->PalSize);
  725. if (iCurImage->Pal.Palette == NULL) {
  726. return IL_FALSE;
  727. }
  728. memcpy(iCurImage->Pal.Palette, Pal->Palette, Pal->PalSize);
  729. ifree(Pal->Palette);
  730. ifree(Pal);
  731. return IL_TRUE;
  732. }
  733. // Sets the current palette.
  734. ILAPI void ILAPIENTRY ilSetPal(ILpal *Pal)
  735. {
  736. if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize && iCurImage->Pal.PalType != IL_PAL_NONE) {
  737. ifree(iCurImage->Pal.Palette);
  738. }
  739. if (Pal->Palette && Pal->PalSize && Pal->PalType != IL_PAL_NONE) {
  740. iCurImage->Pal.Palette = (ILubyte*)ialloc(Pal->PalSize);
  741. if (iCurImage->Pal.Palette == NULL)
  742. return;
  743. memcpy(iCurImage->Pal.Palette, Pal->Palette, Pal->PalSize);
  744. iCurImage->Pal.PalSize = Pal->PalSize;
  745. iCurImage->Pal.PalType = Pal->PalType;
  746. }
  747. else {
  748. iCurImage->Pal.Palette = NULL;
  749. iCurImage->Pal.PalSize = 0;
  750. iCurImage->Pal.PalType = IL_PAL_NONE;
  751. }
  752. return;
  753. }
  754. ILuint CurSort = 0;
  755. typedef struct COL_CUBE
  756. {
  757. ILubyte Min[3];
  758. ILubyte Val[3];
  759. ILubyte Max[3];
  760. } COL_CUBE;
  761. int sort_func(void *e1, void *e2)
  762. {
  763. return ((COL_CUBE*)e1)->Val[CurSort] - ((COL_CUBE*)e2)->Val[CurSort];
  764. }
  765. ILboolean ILAPIENTRY ilApplyPal(ILconst_string FileName)
  766. {
  767. ILimage Image, *CurImage = iCurImage;
  768. ILubyte *NewData;
  769. ILuint *PalInfo, NumColours, NumPix, MaxDist, DistEntry=0, i, j;
  770. ILint Dist1, Dist2, Dist3;
  771. ILboolean Same;
  772. ILenum Origin;
  773. // COL_CUBE *Cubes;
  774.     if( iCurImage == NULL || (iCurImage->Format != IL_BYTE || iCurImage->Format != IL_UNSIGNED_BYTE) ) {
  775.      ilSetError(IL_ILLEGAL_OPERATION);
  776.         return IL_FALSE;
  777.     }
  778. NewData = (ILubyte*)ialloc(iCurImage->Width * iCurImage->Height * iCurImage->Depth);
  779. if (NewData == NULL) {
  780. return IL_FALSE;
  781. }
  782. iCurImage = &Image;
  783. imemclear(&Image, sizeof(ILimage));
  784. // IL_PAL_RGB24, because we don't want to make parts transparent that shouldn't be.
  785. if (!ilLoad_PAL(FileName) || !ilConvertPal(IL_PAL_RGB24)) {
  786. ifree(NewData);
  787. iCurImage = CurImage;
  788. return IL_FALSE;
  789. }
  790. NumColours = Image.Pal.PalSize / 3;  // RGB24 is 3 bytes per entry.
  791. PalInfo = (ILuint*)ialloc(NumColours * sizeof(ILuint));
  792. if (PalInfo == NULL) {
  793. ifree(NewData);
  794. iCurImage = CurImage;
  795. return IL_FALSE;
  796. }
  797. NumPix = CurImage->SizeOfData / ilGetBppFormat(CurImage->Format);
  798. switch (CurImage->Format)
  799. {
  800. case IL_COLOUR_INDEX:
  801. iCurImage = CurImage;
  802. if (!ilConvertPal(IL_PAL_RGB24)) {
  803. ifree(NewData);
  804. ifree(PalInfo);
  805. return IL_FALSE;
  806. }
  807. NumPix = iCurImage->Pal.PalSize / ilGetBppPal(iCurImage->Pal.PalType);
  808. for (i = 0; i < NumPix; i++) {
  809. for (j = 0; j < Image.Pal.PalSize; j += 3) {
  810. // No need to perform a sqrt.
  811. Dist1 = (ILint)iCurImage->Pal.Palette[i] - (ILint)Image.Pal.Palette[j];
  812. Dist2 = (ILint)iCurImage->Pal.Palette[i+1] - (ILint)Image.Pal.Palette[j+1];
  813. Dist3 = (ILint)iCurImage->Pal.Palette[i+2] - (ILint)Image.Pal.Palette[j+2];
  814. PalInfo[j / 3] = Dist1 * Dist1 + Dist2 * Dist2 + Dist3 * Dist3;
  815. }
  816. MaxDist = UINT_MAX;
  817. DistEntry = 0;
  818. for (j = 0; j < NumColours; j++) {
  819. if (PalInfo[j] < MaxDist) {
  820. DistEntry = j;
  821. MaxDist = PalInfo[j];
  822. }
  823. }
  824. iCurImage->Pal.Palette[i] = DistEntry;
  825. }
  826. for (i = 0; i < iCurImage->SizeOfData; i++) {
  827. NewData[i] = iCurImage->Pal.Palette[iCurImage->Data[i]];
  828. }
  829. break;
  830. case IL_RGB:
  831. case IL_RGBA:
  832. /*Cube = (COL_CUBE*)ialloc(NumColours * sizeof(COL_CUBE));
  833. // @TODO:  Check if ialloc failed here!
  834. for (i = 0; i < NumColours; i++)
  835. memcpy(&Cubes[i].Val, Image.Pal.Palette[i * 3], 3);
  836. for (j = 0; j < 3; j++) {
  837. qsort(Cubes, NumColours, sizeof(COL_CUBE), sort_func);
  838. Cubes[0].Min = 0;
  839. Cubes[NumColours-1] = UCHAR_MAX;
  840. NumColours--;
  841. for (i = 1; i < NumColours; i++) {
  842. Cubes[i].Min[CurSort] = Cubes[i-1].Val[CurSort] + 1;
  843. Cubes[i-1].Max[CurSort] = Cubes[i].Val[CurSort] - 1;
  844. }
  845. CurSort++;
  846. NumColours++;
  847. }*/
  848. for (i = 0; i < CurImage->SizeOfData; i += CurImage->Bpp) {
  849. Same = IL_TRUE;
  850. if (i != 0) {
  851. for (j = 0; j < CurImage->Bpp; j++) {
  852. if (CurImage->Data[i-CurImage->Bpp+j] != CurImage->Data[i+j]) {
  853. Same = IL_FALSE;
  854. break;
  855. }
  856. }
  857. }
  858. if (Same) {
  859. NewData[i / CurImage->Bpp] = DistEntry;
  860. continue;
  861. }
  862. for (j = 0; j < Image.Pal.PalSize; j += 3) {
  863. // No need to perform a sqrt.
  864. Dist1 = (ILint)CurImage->Data[i] - (ILint)Image.Pal.Palette[j];
  865. Dist2 = (ILint)CurImage->Data[i+1] - (ILint)Image.Pal.Palette[j+1];
  866. Dist3 = (ILint)CurImage->Data[i+2] - (ILint)Image.Pal.Palette[j+2];
  867. PalInfo[j / 3] = Dist1 * Dist1 + Dist2 * Dist2 + Dist3 * Dist3;
  868. }
  869. MaxDist = UINT_MAX;
  870. DistEntry = 0;
  871. for (j = 0; j < NumColours; j++) {
  872. if (PalInfo[j] < MaxDist) {
  873. DistEntry = j;
  874. MaxDist = PalInfo[j];
  875. }
  876. }
  877. NewData[i / CurImage->Bpp] = DistEntry;
  878. }
  879. break;
  880. case IL_BGR:
  881. case IL_BGRA:
  882. for (i = 0; i < CurImage->SizeOfData; i += CurImage->Bpp) {
  883. for (j = 0; j < NumColours; j++) {
  884. // No need to perform a sqrt.
  885. PalInfo[j] = ((ILint)CurImage->Data[i+2] - (ILint)Image.Pal.Palette[j * 3]) *
  886. ((ILint)CurImage->Data[i+2] - (ILint)Image.Pal.Palette[j * 3]) + 
  887. ((ILint)CurImage->Data[i+1] - (ILint)Image.Pal.Palette[j * 3 + 1]) *
  888. ((ILint)CurImage->Data[i+1] - (ILint)Image.Pal.Palette[j * 3 + 1]) +
  889. ((ILint)CurImage->Data[i] - (ILint)Image.Pal.Palette[j * 3 + 2]) *
  890. ((ILint)CurImage->Data[i] - (ILint)Image.Pal.Palette[j * 3 + 2]);
  891. }
  892. MaxDist = UINT_MAX;
  893. DistEntry = 0;
  894. for (j = 0; j < NumColours; j++) {
  895. if (PalInfo[j] < MaxDist) {
  896. DistEntry = j;
  897. MaxDist = PalInfo[j];
  898. }
  899. }
  900. NewData[i / CurImage->Bpp] = DistEntry;
  901. }
  902. break;
  903. case IL_LUMINANCE:
  904. case IL_LUMINANCE_ALPHA:
  905. for (i = 0; i < CurImage->SizeOfData; i += CurImage->Bpp ) {
  906. for (j = 0; j < NumColours; j++) {
  907. // No need to perform a sqrt.
  908. PalInfo[j] = ((ILuint)CurImage->Data[i] - (ILuint)Image.Pal.Palette[j * 3]) *
  909. ((ILuint)CurImage->Data[i] - (ILuint)Image.Pal.Palette[j * 3]) + 
  910. ((ILuint)CurImage->Data[i] - (ILuint)Image.Pal.Palette[j * 3 + 1]) *
  911. ((ILuint)CurImage->Data[i] - (ILuint)Image.Pal.Palette[j * 3 + 1]) +
  912. ((ILuint)CurImage->Data[i] - (ILuint)Image.Pal.Palette[j * 3 + 2]) *
  913. ((ILuint)CurImage->Data[i] - (ILuint)Image.Pal.Palette[j * 3 + 2]);
  914. }
  915. MaxDist = UINT_MAX;
  916. DistEntry = 0;
  917. for (j = 0; j < NumColours; j++) {
  918. if (PalInfo[j] < MaxDist) {
  919. DistEntry = j;
  920. MaxDist = PalInfo[j];
  921. }
  922. }
  923. NewData[i] = DistEntry;
  924. }
  925. break;
  926. default:  // Should be no other!
  927. ilSetError(IL_INTERNAL_ERROR);
  928. return IL_FALSE;
  929. }
  930. iCurImage = CurImage;
  931. Origin = iCurImage->Origin;
  932. if (!ilTexImage(iCurImage->Width, iCurImage->Height, iCurImage->Depth, 1,
  933. IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NewData)) {
  934. ifree(Image.Pal.Palette);
  935. ifree(PalInfo);
  936. ifree(NewData);
  937. return IL_FALSE;
  938. }
  939. iCurImage->Origin = Origin;
  940. iCurImage->Pal.Palette = Image.Pal.Palette;
  941. iCurImage->Pal.PalSize = Image.Pal.PalSize;
  942. iCurImage->Pal.PalType = Image.Pal.PalType;
  943. ifree(PalInfo);
  944. ifree(NewData);
  945. return IL_TRUE;
  946. }