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}
893