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