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