]> git.saurik.com Git - apple/xnu.git/blame - osfmk/console/panic_ui/qtif2kraw.c
xnu-792.tar.gz
[apple/xnu.git] / osfmk / console / panic_ui / qtif2kraw.c
CommitLineData
91447636
A
1/* converts a QT RAW 8-bit image file into format the kernel panic ui expects.
2 *
3 * to build: cc -o qtif2kraw qtif2kraw.c
4*/
5
6#include <stdio.h>
7#include <unistd.h>
8#include <stdlib.h>
9#include <sys/types.h>
10#include <fcntl.h>
11#include <string.h>
12
13int EncodeImage( unsigned char * data, int pixels, unsigned char * fileArr );
14int findIndexNearMatch( unsigned int color24 );
15unsigned int findColor24NearMatch( unsigned int color24 );
16unsigned char findIndexMatch( unsigned int color24 );
17int convert8toGrey( unsigned char * data, unsigned int size );
18int convert8bitIndexto8( unsigned char * data, int height, int width, unsigned char ** dout );
19unsigned int * CreateCLUTarry( unsigned char * raw_clut );
20unsigned int * ReplaceCLUT( char * iname );
21
22#define offsetof(type, field) ((size_t)(&((type *)0)->field))
23
24struct panicimage {
25 unsigned int pd_sum;
26 unsigned int pd_dataSize;
27 unsigned int pd_tag;
28 unsigned short pd_width;
29 unsigned short pd_height;
30 unsigned char pd_depth;
31 unsigned char pd_info_height;
32 unsigned char pd_info_color[2];
33 unsigned char data[];
34};
35
36
37void
38usage( int type ) {
39printf(
40"\n"
41"Usage:\n"
42"\tqtif2kraw -i <.qtif> -o <.kraw> [operands ...]\n\n"
43"\tThe following operands are available\n\n"
44"\t-h\t\tDisplay full help information\n"
45"\t-i <file>\tUse file containing QuickTime uncompressed raw image as\n"
46"\t\t\tthe panic dialog (8 bit only)\n"
47"\t-o <file>\tWrite the output as a compressed kernel RAW image suitable\n"
48"\t\t\tfor loading into the kernel\n"
49"\t-c <file>\tUse file containing 256 RGB values for 8-bit indexed \n"
50"\t\t\tlookups, overrides built-in appleClut8\n"
51"\t-fg <color>\tForeground color of font used for panic information in\n"
52"\t\t\t24-bits, default 0xFFFFFF (100%% white)\n"
53"\t-bg <color>\tBackground color of font used for panic information in\n"
54"\t\t\t24-bits, default 0x222222 (13%% white, dark gray)\n"
55"\t-n <lines>\tNumber of lines that have been reserved to display the\n"
56"\t\t\tpanic information, must be at least 20\n"
57"\n\n" );
58}
59
60
61#include "appleclut8.h"
62#include "../iso_font.c"
63
64struct QTHeader {
65 long idSize; /* total size of ImageDescription including extra data ( CLUTs and other per sequence data ) */
66 long cType; /* 'raw '; what kind of codec compressed this data */
67 long resvd1; /* reserved for Apple use */
68 short resvd2; /* reserved for Apple use */
69 short dataRefIndex; /* set to zero */
70 short version; /* which version is this data */
71 short revisionLevel; /* what version of that codec did this */
72 long vendor; /* whose codec compressed this data */
73 long temporalQuality; /* what was the temporal quality factor */
74 long spatialQuality; /* what was the spatial quality factor */
75 short width; /* how many pixels wide is this data */
76 short height; /* how many pixels high is this data */
77 long hRes; /* horizontal resolution */
78 long vRes; /* vertical resolution */
79 long dataSize; /* if known, the size of data for this image descriptor */
80 short frameCount; /* number of frames this description applies to */
81 char name[32]; /* name of codec ( in case not installed ) */
82 short depth; /* what depth is this data (1-32) or ( 33-40 grayscale ) */
83 short clutID; /* clut id or if 0 clut follows or -1 if no clut */
84} image_header;
85
86static unsigned int mismatchClut[256];
87static int nextmis = -1, neargrey = 0, cvt2grey = 0, exactmatch=0;
88static int grey = 0, debug = 0;
89static unsigned char fg, bg;
90unsigned int * panic_clut = NULL;
91static char * clutin = NULL;
92
93union colors {
94 unsigned int c24;
95 unsigned char rgb[4];
96 struct {
97 unsigned char dummy;
98 unsigned char red;
99 unsigned char green;
100 unsigned char blue;
101 } clut;
102};
103
104int
105main( int argc, char *argv[] )
106{
107 char *file = NULL;
108 char *kraw = NULL;
109 FILE * stream;
110 unsigned char * data;
111 unsigned short width = 0, height = 0;
112 unsigned char depth = 0, lines = 20;
113 unsigned int i, pixels, sum, encodedSize, fg24= 0xFFFFFF, bg24=0x222222;
114 unsigned char *fileArr;
115 int next;
116
117
118 // pull apart the arguments
119 for( next = 1; next < argc; next++ )
120 {
121 if (strcmp(argv[next], "-i") == 0) // image file in raw QT uncompressed format (.qtif)
122 file = argv[++next];
123
124 else if (strcmp(argv[next], "-o") == 0) // output file for WHD image
125 kraw = argv[++next];
126
127 else if (strcmp(argv[next], "-n") == 0) // numbers of reserved lines
128 lines = atoi(argv[++next]);
129 else if (strcmp(argv[next], "-fg") == 0) // foreground color in 24 bits
130 sscanf(argv[++next], "%i", &fg24);
131 else if (strcmp(argv[next], "-bg") == 0) // background color in 24 bits
132 sscanf(argv[++next], "%i", &bg24);
133 else if (strcmp(argv[next], "-c") == 0) // input file for clut
134 clutin = argv[++next];
135 else if (strcmp(argv[next], "-h") == 0) // display more help
136 { usage(1); exit(1); }
137
138 else if (strcmp(argv[next], "-debug") == 0) // verbose
139 debug++;
140 }
141
142 if (!(file || kraw) ) {
143 usage(0);
144 exit(1);
145 }
146
147 printf("\n");
148
149 panic_clut = appleClut8;
150
151 if ( clutin )
152 {
153 panic_clut = ReplaceCLUT( clutin );
154 printf("Built-in CLUT has been replaced with %s...\n", clutin);
155 }
156
157 fg = findIndexNearMatch(fg24);
158 bg = findIndexNearMatch(bg24);
159
160 // Begin to process the image
161
162 if( file == NULL)
163 {
164 printf("No image file was processed...\n\n");
165 exit(0);
166 }
167
168
169 printf("Verifing image file...\n");
170 if ( file != NULL )
171 {
172 stream = fopen(file, "r");
173 if (!stream) {
174 fprintf(stderr, "Err: could not open .qtif image file.\n\n");
175 exit(1);
176 }
177
178 {
179 long hdr_off;
180 long hdr_type;
181 int rc;
182
183 if ( ! fread((void *) &hdr_off, sizeof(long), 1, stream) ) goto errQTimage;
184 if ( ! fread((void *) &hdr_type, sizeof(long), 1, stream) ) goto errQTimage;
185
186 if ( hdr_type != 'idat' ) goto errQTimage;
187
188 if ( fseek(stream, hdr_off, SEEK_SET) ) goto errQTimage;
189 if ( ! fread((void *) &hdr_off, sizeof(long), 1, stream) ) goto errQTimage;
190 if ( ! fread((void *) &hdr_type, sizeof(long), 1, stream) ) goto errQTimage;
191
192 if ( hdr_type != 'idsc' ) goto errQTimage;
193
194 rc = fread((void *) &image_header, sizeof(image_header), 1, stream);
195 if ( !rc && !feof(stream) ) goto errQTimage;
196 if ( image_header.cType != 'raw ' ) goto errQTimage;
197 if ( image_header.depth != 8 ) goto errQTimage;
198
199
200 width = image_header.width;
201 height = image_header.height;
202 depth = image_header.depth;
203
204 printf("Image info: width: %d height: %d depth: %d...\n", width, height, depth);
205
206 if (!(width && height && depth)) {
207 fprintf(stderr,"Err: Invalid image file header (width, height, or depth is 0)\n");
208 exit(1);
209 }
210 }
211
212 if ( !(data = (char *)malloc(image_header.dataSize))) {
213 fprintf(stderr,"Err: Couldn't malloc file data (%ld bytes)... bailing.\n", image_header.dataSize);
214 exit(1);
215 }
216
217 // Read the image data
218 if ( fseek(stream, 8, SEEK_SET) ) goto errQTimage;
219 if ( ! fread((void *) data, image_header.dataSize, 1, stream) ) goto errQTimage;
220 fclose( stream );
221
222 pixels = image_header.dataSize;
223
224 if ( grey == 1 )
225 pixels = convert8toGrey( data, image_header.dataSize );
226
227 printf("Converting image file to 8 bit raw...\n");
228 pixels = convert8bitIndexto8( data, height, width, &data );
229 image_header.dataSize = pixels;
230 depth = 1;
231
232 printf("Converted %d pixels%s...\n", pixels/depth, ((grey==1)?" to grayscale":""));
233 if ( exactmatch > 0 )
234 printf("Found %d color mathces in CLUT...\n", exactmatch);
235 if ( cvt2grey > 0 )
236 printf("Converted %d colors to gray...\n", cvt2grey);
237 if ( neargrey > 0 )
238 printf("Adjusted %d grays to best match...\n", neargrey);
239 if ( nextmis > 0 )
240 printf("Total of %d seperate color mismatches...\n", nextmis);
241 }
242
243 printf("Encoding image file...\n");
244
245 if (!(fileArr = (unsigned char *) malloc(pixels))) {
246 fprintf(stderr,"Err: Couldn't malloc fileArr (%d pixels)... bailing.\n", pixels);
247 exit(1);
248 }
249
250 encodedSize = EncodeImage( data, pixels, fileArr );
251
252 if ( encodedSize >= pixels )
253 {
254 printf("Skipping encoding...\n");
255 }
256
257 for (sum=0,i=0; i<encodedSize; i++)
258 {
259 sum += fileArr[i];
260 sum <<= sum&1;
261 }
262
263 // write raw image suitable for kernel panic dialog
264 if ( kraw )
265 {
266 FILE * ostream;
267 unsigned int tag;
268
269 if ( (ostream = fopen(kraw, "wb")) == NULL ) {
270 fprintf(stderr,"Err: Could not open output file %s.\n\n", kraw);
271 exit(1);
272 }
273
274 printf("Writing to binary panic dialog file %s, which is suitable for loading into kernel...\n", kraw);
275
276 tag = 'RNMp'; // Raw NMage for Panic dialog
277 depth = 1; // only CLUT is supported
278
279 fwrite(&sum, sizeof(sum), 1, ostream);
280 sum = encodedSize;
281 encodedSize += (256*3);
282 fwrite(&encodedSize, sizeof(encodedSize), 1, ostream);
283 encodedSize = sum;
284 fwrite(&tag, sizeof(tag), 1, ostream);
285 fwrite(&width, sizeof(width), 1, ostream);
286 fwrite(&height, sizeof(height), 1, ostream);
287 fwrite(&depth, sizeof(depth), 1, ostream);
288 fwrite(&lines, sizeof(lines), 1, ostream);
289 fwrite(&fg, sizeof(fg), 1, ostream);
290 fwrite(&bg, sizeof(bg), 1, ostream);
291 fwrite(fileArr, encodedSize, 1, ostream);
292
293 for ( i=0; i<256; i++)
294 {
295 union colors c;
296 unsigned char arr[3];
297
298 c.c24 = panic_clut[i];
299
300 arr[0] = c.clut.red;
301 arr[1] = c.clut.green;
302 arr[2] = c.clut.blue;
303 fwrite(arr, 3, 1, ostream);
304 }
305 fclose(ostream);
306 }
307
308 return 0;
309
310errQTimage:
311 fprintf(stderr,"Err: Input image must be in the QuickTime Raw Uncompressed 256 Colors format\n");
312 exit(1);
313}
314
315
316
317#define RUN_MAX ((1<<20)-1)
318
319union RunData {
320 unsigned int i;
321 unsigned char c[4];
322};
323
324unsigned int encode_rle(
325 unsigned char * fileArr,
326 unsigned int filePos,
327 unsigned int quantity,
328 union RunData * value,
329 int depth);
330
331int
332compareruns( unsigned char * data, unsigned int * index, unsigned int max, union RunData * currP, int * depth )
333{
334 union RunData * nextP;
335 static int retc = 0;
336
337 if ( currP == NULL || data == NULL )
338 {
339 retc = 0;
340 goto Leave;
341 }
342
343 if ( (*index+*depth) > max )
344 {
345 *depth = 1;
346 retc = 0;
347 goto Leave;
348 }
349
350 nextP = (union RunData *) &data[*index];
351
352 if ( retc == 1 )
353 {
354 // check current data against current depth
355 switch ( *depth )
356 {
357 case 1:
358 if ( nextP->c[0] == currP->c[0] )
359 goto Leave;
360 break;
361 case 2:
362 if ( nextP->c[0] == currP->c[0] &&
363 nextP->c[1] == currP->c[1] )
364 goto Leave;
365 break;
366 case 3:
367 if ( nextP->c[0] == currP->c[0] &&
368 nextP->c[1] == currP->c[1] &&
369 nextP->c[2] == currP->c[2] )
370 goto Leave;
371 break;
372 case 4:
373 if ( nextP->c[0] == currP->c[0] &&
374 nextP->c[1] == currP->c[1] &&
375 nextP->c[2] == currP->c[2] &&
376 nextP->c[3] == currP->c[3] )
377 goto Leave;
378 break;
379 }
380
381 retc = 0;
382 goto Leave;
383 }
384
385 // start of a new pattern match begine with depth = 1
386
387 if ( (*index+6) <= max )
388 {
389 // We have at least 8 bytes left in the buffer starting from currP
390#if 1
391 nextP = (union RunData *) &data[*index+3];
392 if ( nextP->c[0] == currP->c[0] &&
393 nextP->c[1] == currP->c[1] &&
394 nextP->c[2] == currP->c[2] &&
395 nextP->c[3] == currP->c[3] )
396 {
397 // check if they are all the same value
398 if ( currP->c[0] == currP->c[1] &&
399 currP->c[1] == currP->c[2] &&
400 currP->c[2] == currP->c[3] )
401 { // if so, leave at depth = 1
402 retc = 1;
403 *depth = 1;
404 goto Leave;
405 }
406
407 if (debug>2) printf("Found 4 at %x\n", *index);
408 retc = 1;
409 *depth = 4;
410 *index += 3;
411 goto Leave;
412 }
413
414 nextP = (union RunData *) &data[*index+2];
415 if ( nextP->c[0] == currP->c[0] &&
416 nextP->c[1] == currP->c[1] &&
417 nextP->c[2] == currP->c[2] )
418 {
419 // check if they are all the same value
420 if ( currP->c[0] == currP->c[1] &&
421 currP->c[1] == currP->c[2] )
422 { // if so, leave at depth = 1
423 retc = 1;
424 *depth = 1;
425 goto Leave;
426 }
427
428 if (debug>2) printf("Found 3 at %x\n", *index);
429 retc = 1;
430 *depth = 3;
431 *index += 2;
432 goto Leave;
433 }
434
435 nextP = (union RunData *) &data[*index+1];
436 if ( nextP->c[0] == currP->c[0] &&
437 nextP->c[1] == currP->c[1] )
438 {
439 // check if they are all the same value
440 if ( currP->c[0] == currP->c[1] )
441 { // if so, leave at depth = 1
442 retc = 1;
443 *depth = 1;
444 goto Leave;
445 }
446
447 if (debug>2) printf("Found 2 at %x\n", *index);
448 retc = 1;
449 *depth = 2;
450 *index += 1;
451 goto Leave;
452 }
453
454#endif
455 nextP = (union RunData *) &data[*index];
456
457 }
458
459 if ( nextP->c[0] == currP->c[0] )
460 retc = 1;
461 else
462 retc = 0;
463
464Leave:
465
466 if ( retc == 1 )
467 *index += *depth;
468
469 return retc;
470}
471
472int
473EncodeImage( unsigned char * data, int pixels, unsigned char * fileArr )
474{
475 union RunData * currP, * norunP ;
476 int i, depth;
477 unsigned int filePos, run, nomatchrun;
478
479 currP = NULL;
480 norunP = NULL;
481 nomatchrun = 0;
482 filePos = 0; // position in the file we're writing out
483 run = 1;
484 depth = 1;
485
486 currP = (union RunData *)&data[0]; // start a new run
487 for (i=1; i<pixels;) {
488 if ( compareruns( data, &i, pixels, currP, &depth ) )
489 run++;
490 else {
491 if ( (run*depth) > 2 ) {
492 unsigned char * p = (unsigned char *)norunP;
493
494 if( nomatchrun ) {
495 while (nomatchrun) {
496 int cnt;
497
498 cnt = (nomatchrun > 127) ? 127 : nomatchrun;
499 fileArr[filePos++] = cnt;
500 nomatchrun -= cnt;
501
502 while ( cnt-- )
503 fileArr[filePos++] = *p++;
504 }
505 }
506
507 filePos += encode_rle(fileArr, filePos, run, currP, depth);
508
509 norunP = NULL;
510 } else {
511 nomatchrun+=run;
512 }
513
514 currP = (union RunData *)&data[i]; // start a new run
515
516 if( norunP == NULL ) {
517 nomatchrun = 0;
518 norunP = currP;
519 }
520
521 depth = 1; // switch back to a single byte depth
522 run = 1; // thee is always at least one entry
523 i++; // point to next byte
524 }
525 }
526
527 if( nomatchrun ) {
528 unsigned char * p = (unsigned char *)norunP;
529 while (nomatchrun) {
530 int cnt;
531
532 cnt = (nomatchrun > 127) ? 127 : nomatchrun;
533 fileArr[filePos++] = cnt;
534 nomatchrun -= cnt;
535
536 while ( cnt-- )
537 fileArr[filePos++] = *p++;
538 }
539 }
540
541 // write out any run that was in progress
542 if (run > 0) {
543 filePos += encode_rle(fileArr, filePos, run, currP, depth);
544 }
545
546 return filePos;
547}
548
549/* encode_rle applies a "modified-RLE encoding to a given image. The encoding works as follows:
550
551 The quantity is described in the first byte. If the MSB is zero, then the next seven bits
552 are the quantity. If the MSB is set, bits 0-3 of the quantity are in the least significant bits.
553 If bit 5 is set, then the quantity is further described in the next byte, where an additional
554 7 bits (4-10) worth of quantity will be found. If the MSB of this byte is set, then an additional
555 7 bits (11-17) worth of quantity will be found in the next byte. This repeats until the MSB of
556 a quantity byte is zero, thus ending the chain.
557
558 The value is described in the first byte. If the MSB is zero, then the value is in the next byte.
559 If the MSB is set, then bits 5/6 describe the number of value bytes following the quantity bytes.
560
561 encodings are: (q = quantity, v = value, c = quantity continues)
562
563 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 Byte 7 Byte 8
564 case 1: [ 0 q6-q0 ] [ v7-v0 ]
565 case 2: [ 1 0 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ]
566 case 3: [ 1 0 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ]
567 case 4: [ 1 1 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
568 case 5: [ 1 1 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
569*/
570
571unsigned int
572encode_length(unsigned char * fileArr, unsigned int filePos, unsigned int quantity, unsigned int mask)
573{
574 unsigned char single_mask = 0x0F;
575 unsigned char double_mask = 0x7F;
576 unsigned int slots_used = 0;
577
578 fileArr[filePos] = mask | (quantity & single_mask); // low bits (plus mask)
579 slots_used++;
580
581 if (quantity >>= 4) {
582 fileArr[filePos++] |= 0x10; // set length continuation bit
583 fileArr[filePos] = quantity & double_mask;
584 slots_used++;
585
586 while (quantity >>= 7) {
587 fileArr[filePos++] |= 0x80; // set length continuation bit
588 fileArr[filePos] = quantity & double_mask;
589 slots_used++;
590 }
591 }
592
593 return slots_used;
594}
595
596
597unsigned int
598encode_rle(unsigned char * fileArr, unsigned int filePos, unsigned int quantity, union RunData * value, int depth)
599{
600 unsigned char slots_used = 0;
601
602
603 switch ( depth ) {
604 case 1:
605 slots_used += encode_length( fileArr, filePos, quantity, 0x80 );
606 fileArr[filePos+slots_used++] = value->c[0];
607 break;
608
609 case 2:
610 slots_used += encode_length( fileArr, filePos, quantity, 0xA0 );
611 fileArr[filePos+slots_used++] = value->c[0];
612 fileArr[filePos+slots_used++] = value->c[1];
613 break;
614
615 case 3:
616 slots_used += encode_length( fileArr, filePos, quantity, 0xC0 );
617 fileArr[filePos+slots_used++] = value->c[0];
618 fileArr[filePos+slots_used++] = value->c[1];
619 fileArr[filePos+slots_used++] = value->c[2];
620 break;
621
622 case 4:
623 slots_used += encode_length( fileArr, filePos, quantity, 0xE0 );
624 fileArr[filePos+slots_used++] = value->c[0];
625 fileArr[filePos+slots_used++] = value->c[1];
626 fileArr[filePos+slots_used++] = value->c[2];
627 fileArr[filePos+slots_used++] = value->c[3];
628 break;
629 }
630
631 return slots_used;
632}
633
634
635int
636findIndexNearMatch( unsigned int color24 )
637{
638 union colors color8;
639 union colors clut8;
640 int isGrey = 0;
641
642 color8.c24 = color24;
643
644 if ( color8.clut.red == color8.clut.green && color8.clut.green == color8.clut.blue )
645 isGrey = 1;
646
647 if ( isGrey ) {
648 int i;
649 unsigned int bestIndex = 0, rel, bestMatch = -1;
650
651 for (i=0; i<256; i++) {
652 clut8.c24 = panic_clut[i];
653
654 if ( clut8.clut.red != clut8.clut.green || clut8.clut.green != clut8.clut.blue )
655 continue;
656
657 if ( clut8.clut.red > color8.clut.red) continue;
658 rel = abs(color8.clut.red - clut8.clut.red);
659 if ( rel < bestMatch ) {
660 bestMatch = rel;
661 bestIndex = i;
662 }
663 }
664
665 return bestIndex;
666 }
667
668 // we must have a non-grey color
669 return -1;
670}
671
672unsigned int
673color24toGrey( unsigned int color24 )
674{
675 float R, G, B;
676 float Grey;
677 union colors c;
678 unsigned char grey8;
679 unsigned int grey24;
680
681 c.c24 = color24;
682
683 R = (c.clut.red & 0xFF) ;
684 G = (c.clut.green & 0xFF) ;
685 B = (c.clut.blue & 0xFF) ;
686
687 Grey = (R*.30) + (G*.59) + (B*.11);
688 grey8 = (unsigned char) ( Grey + .5);
689 grey24 = (grey8<<16) | (grey8<<8) | grey8;
690 return grey24;
691}
692
693
694int
695convert8toGrey( unsigned char * data, unsigned int size )
696{
697 int i;
698 unsigned int c24;
699 union colors c;
700
701 for ( i=0; i<size; i++) {
702 c.c24 = panic_clut[data[i]];
703 c24 = color24toGrey( c.c24 );
704 data[i] = findIndexMatch( c24 );
705 }
706
707 return size;
708}
709
710unsigned int
711findColor24NearMatch( unsigned int color24 )
712{
713 union colors c;
714 unsigned char prim;
715 static unsigned int last_c = -1, last_co = -1, last_p = -1;
716
717 if ( last_c == color24 )
718 return last_co;
719
720 c.c24 = color24;
721
722 if ( c.rgb[1] > c.rgb[2] && c.rgb[1] > c.rgb[3] )
723 prim = 1;
724 else if ( c.rgb[2] > c.rgb[1] && c.rgb[2] > c.rgb[3] )
725 prim = 2;
726 else if ( c.rgb[3] > c.rgb[1] && c.rgb[3] > c.rgb[2] )
727 prim = 3;
728 else if ( c.rgb[1] == c.rgb[2] && c.rgb[1] == c.rgb[3] )
729 prim = 0; // gray
730 else if ( c.rgb[1] == c.rgb[2] )
731 prim = 0x12; // red green
732 else if ( c.rgb[1] == c.rgb[3] )
733 prim = 0x13; // red blue
734 else if ( c.rgb[2] == c.rgb[3] )
735 prim = 0x23; // green blue
736 else
737 printf("cannot tell color %06x\n", color24);
738
739 last_c = color24;
740 last_p = prim;
741
742 if ( prim == 0 || prim > 3 )
743 {
744 last_co = -1;
745 return last_co;
746 }
747
748 return -1;
749}
750
751
752unsigned char
753findIndexMatch( unsigned int color24 )
754{
755 int i;
756 unsigned char ri;
757 static unsigned char last = 0;
758
759retry:
760 if ( panic_clut[last] == color24 )
761 {
762 exactmatch++;
763 return last;
764 }
765
766 for (i=0; i<256; i++)
767 {
768 if ( panic_clut[i] == color24 ) {
769 last = i;
770 exactmatch++;
771 return last;
772 }
773 }
774
775 if ( nextmis == -1 ) {
776 for (i=0; i<256; i++) mismatchClut[i] = -1;
777 nextmis = 0;
778 }
779
780 i = findIndexNearMatch(color24);
781
782 if ( i == -1 ) // found a color that is not grey
783 {
784 unsigned int colormatch = findColor24NearMatch( color24 );
785
786 if ( colormatch == -1 ) // cannot convert color
787 {
788 cvt2grey++;
789 if (debug>1) printf("color %06X not matched at all\n", color24);
790 color24 = color24toGrey(color24);
791 if (debug>1) printf("now grey %06X\n", color24);
792 }
793 else
794 color24 = colormatch;
795
796 goto retry;
797 }
798
799 if (debug>1) printf("color %06X now matched at %x\n", color24, i);
800
801 ri = i;
802
803 neargrey++;
804
805 // keep track of missed repeats
806 for ( i=0; i<nextmis; i++)
807 if ( mismatchClut[i] == color24 )
808 return ri;
809
810 if ( debug) printf("closest match for %06X is at index %d %06X\n", color24, ri, panic_clut[ri]);
811 if ( nextmis < 256 )
812 mismatchClut[nextmis++] = color24;
813
814 if ( debug && (nextmis >= 256) )
815 {
816 fprintf(stderr,"Err: Too many color mismatches detected with this CLUT\n");
817 exit(1);
818 }
819
820 return ri;
821}
822
823/*
824 * Convert 8 bit mode to 8 bit, We have to strip off the alignment bytes
825 */
826
827int
828convert8bitIndexto8( unsigned char * data, int height, int width, unsigned char ** dout )
829{
830 unsigned int row, col, i, i8, size, adj;
831 unsigned char index;
832 unsigned char * ddata;
833 union colors color24;
834
835 adj=(4-(width%4))%4; // adjustment needed to strip off the word alignment padding
836 size = height * width;
837 ddata = (unsigned char *) calloc( size, 1);
838
839 for (i8=0,row=0; row<height; row++)
840 {
841 for (col=0; col<width; col++)
842 {
843 index = *data++;
844 color24.c24 = panic_clut[index];
845 index = findIndexMatch( color24.c24 );
846 ddata[i8++] = index;
847 }
848
849 for (i=0; i<adj; i++)
850 data++;
851 }
852
853 * dout = ddata;
854
855 return (i8);
856}
857
858
859unsigned int *
860CreateCLUTarry( unsigned char * raw_clut )
861{
862 unsigned int * new_clut, index, i;
863
864 new_clut = (unsigned int *) calloc(256, sizeof(unsigned int));
865 for ( index=0,i=0; i<256; index+=3,i++ )
866 new_clut[i] = (raw_clut[index] << 16) | (raw_clut[index+1] << 8) | raw_clut[index+2];
867
868 return new_clut;
869}
870
871
872unsigned int *
873ReplaceCLUT( char * iname )
874{
875 FILE * stream;
876 unsigned char * raw_clut;
877 unsigned int * new_clut;
878
879 if ( (stream = fopen(iname, "rb")) == NULL ) {
880 fprintf(stderr,"Err: Could not open input clut file %s.\n\n", iname);
881 exit(1);
882 }
883
884 raw_clut = (char *) calloc(256, 3);
885 fread(raw_clut, 256, 3, stream);
886 fclose(stream);
887
888 new_clut = CreateCLUTarry( raw_clut );
889
890 free(raw_clut);
891 return new_clut;
892}