1/* converts a QT RAW image file into the c structure that the
2 * kernel panic ui system expects.
3 *
4 * to build: cc -o genimage genimage.c
5*/
6
7#include <stdio.h>
8#include <unistd.h>
9#include <stdlib.h>
10#include <sys/types.h>
11#include <fcntl.h>
12#include <string.h>
13
14int EncodeImage(
15					unsigned char * data,
16					int pixels,
17					unsigned char * fileArr );
18int decode_rle(
19					unsigned char * dataPtr,
20					unsigned int * quantity,
21					unsigned int * depth,
22					unsigned char ** value );
23int findIndexNearMatch(
24					unsigned int color24 );
25unsigned char findIndexMatch(
26					unsigned int color24 );
27int convert24toGrey(
28					unsigned char * data,
29					unsigned int size );
30int convert8toGrey(
31					unsigned char * data,
32					unsigned int size );
33int convert8bitIndexto24(
34					unsigned char * data,
35					int height,
36					int width,
37					unsigned char ** dout );
38int convert8bitIndexto8(
39					unsigned char * data,
40					int height,
41					int width,
42					unsigned char ** dout );
43int convert24to8bitIndex(
44					unsigned char * data,
45					int height,
46					int width,
47					unsigned char ** dout );
48unsigned int * CreateCLUTarry(
49					unsigned char * raw_clut );
50unsigned int *  ReplaceCLUT(
51					char * iname );
52void GenerateCLUT(
53					char * oname );
54void WriteQTRawFile(
55					FILE * ostream,
56					unsigned char * data,
57					int height,
58					int width,
59					int depth,
60					unsigned int size );
61void CreateRawQTFont(
62					void );
63void CreateRawQTCLUT(
64					int type );
65
66#define offsetof(type, field) ((size_t)(&((type *)0)->field))
67
68struct panicimage {
69	unsigned int	pd_sum;
70	unsigned int	pd_dataSize;
71	unsigned int	pd_tag;
72	unsigned short	pd_width;
73	unsigned short	pd_height;
74	unsigned char	pd_depth;
75	unsigned char	pd_info_height;
76	unsigned char	pd_info_color[2];
77	unsigned char	data[];
78};
79
80
81
82
83void
84usage( int type ) {
85printf(
86"\n"
87"Usage:\n"
88"\tgenimage -i <.qtif> [operands ...]\n\n"
89"\tThe following operands are available\n\n"
90"\t-h\t\tDisplay full help information\n"
91"\t-i  <file>\tUse file containing QuickTime uncompressed raw image as\n"
92"\t\t\tthe panic dialog (8 or 24 bit)\n"
93"\t-o  <file>\tWrite the output as a compressed WHD RAW image suitable\n"
94"\t\t\tfor loading into the kernel\n"
95"\t-c  <file>\tUse file containing 256 RGB values for 8-bit indexed \n"
96"\t\t\tlookups, overrides built-in appleClut8\n"
97"\t-fg <color>\tForeground color of font used for panic information in\n"
98"\t\t\t24-bits, default 0xFFFFFF (100%% white)\n"
99"\t-bg <color>\tBackground color of font used for panic information in\n"
100"\t\t\t24-bits, default 0x222222 (13%% white, dark gray)\n"
101"\t-n  <lines>\tNumber of lines that have been reserved to display the\n"
102"\t\t\tpanic information, must be at least 20\n"
103"\n\tThese are useful options for testing\n"
104"\t-io <file>\tUse <file> to override the default C source filename\n"
105"\t-bw\t\tConvert the input image to shades of gray\n"
106"\t-n24\t\tConvert an image from 8 bit to 24 bit mode before\n"
107"\t\t\tprocessing\n"
108"\t-n8\t\tDon't convert an image from 24 bit to 8 bit mode before \n"
109"\t\t\tprocessing, default is to convert\n"
110"\t-qt <file>\t(requires -i) Write QuickTime uncompressed raw .gtif\n"
111"\t\t\tfile containing the input image in 8-bit format\n"
112"\t-r\t\tCreate a Quicktime uncompressed image of the 8-bit\n"
113"\t\t\tsystem CLUT named appleclut8.qtif <debugging>\n"
114"\t-f\t\tCreate a Quicktime uncompressed image of the 8x16\n"
115"\t\t\tbit panic info font named font.qtif <debugging>\n"
116"\n\n" );
117if ( type > 0 )
118printf(
119"\
120This utility is used to convert a panic dialog from .qtif format, into\n\
121one that is suitable for the kernel to display.  The .qtif image file\n\
122can be in either 24 or 8 bit mode, but must be in an uncompressed raw\n\
123format.  8 bit mode is preferred, as it requires no conversion to the\n\
124colors that are contained in the CLUT.  If a color cannot be found in\n\
125the CLUT, it will be converted to the nearest gray.  The default CLUT\n\
126is the same as the system CLUT. If needed, this can be overridden by\n\
127providing a new CLUT with the -c option.\n\
128\n\
129However, if you override the default CLUT.  The panic UI may not appear\n\
130as you intended, when the systme is in 8 bit mode.  Colors that are not\n\
131present in the active CLUT, will be converted to the nearest gray.\n\
132\n\
133The panic dialog must have a number of lines reserved at the bottom for\n\
134displaying additional panic information.  The minimum number of lines\n\
135is 20.  The font use to display this information needs to have the\n\
136foreground and background colors defined.  The defaults are full white\n\
137on dark gray.  This can be changed by using the -fg and/or -bg options to\n\
138provide new 24 bit colors.  These colors must be contained in the CLUT.\n\
139\n\
140There are two possible output results.  The default is to create a C\n\
141source file named panic_image.c that contains the panic image in a 8 bit\n\
142modified RLE compressed format and the CLUT that was used to create the\n\
143image.  The second possibility is to create a binary version of the same\n\
144information by using the -o option.  This file can then be used to replace\n\
145the panic dialog that is currently active in the kernel by using\n\
146sysctl(KERN_PANIC_INFO).\n\
147\n\n");
148}
149
150
151#include "appleclut8.h"
152#include "../iso_font.c"
153
154struct QTHeader {
155	long	idSize;			/* total size of ImageDescription including extra data ( CLUTs and other per sequence data ) */
156	long	cType;			/* 'raw '; what kind of codec compressed this data */
157	long	resvd1;			/* reserved for Apple use */
158	short	resvd2;			/* reserved for Apple use */
159	short	dataRefIndex;		/* set to zero  */
160	short	version;		/* which version is this data */
161	short	revisionLevel;		/* what version of that codec did this */
162	long	vendor;			/* whose  codec compressed this data */
163	long	temporalQuality;	/* what was the temporal quality factor  */
164	long	spatialQuality;		/* what was the spatial quality factor */
165	short	width;			/* how many pixels wide is this data */
166	short	height;			/* how many pixels high is this data */
167	long	hRes;			/* horizontal resolution */
168	long	vRes;			/* vertical resolution */
169	long	dataSize;		/* if known, the size of data for this image descriptor */
170	short	frameCount;		/* number of frames this description applies to */
171	char	name[32];		/* name of codec ( in case not installed )  */
172	short	depth;			/* what depth is this data (1-32) or ( 33-40 grayscale ) */
173	short	clutID;			/* clut id or if 0 clut follows  or -1 if no clut */
174} image_header;
175
176static unsigned int mismatchClut[256];
177static int nextmis = -1, neargrey = 0, cvt2grey = 0, exactmatch=0;
178static int grey = 0, debug = 0, testfont = 0, testclut = 0;
179static int convert = 8; // default is to convert image to 8 bit uncompressed .tgif
180static unsigned char fg, bg;
181unsigned int * panic_clut = NULL;
182static char  * clutin = NULL;
183
184union colors {
185	unsigned int c24;
186	unsigned char rgb[4];
187	struct {
188		unsigned char dummy;
189		unsigned char red;
190		unsigned char green;
191		unsigned char blue;
192	} clut;
193};
194
195int
196main( int argc, char *argv[] )
197{
198	char	*file = NULL;
199	char	*out = NULL;
200	char	*kraw = NULL;
201	char	*qtraw = NULL;
202	char	*clutout = NULL;
203	char	*whdname = NULL;
204	FILE *  stream, *out_stream;
205	unsigned char * data;
206	unsigned short	width = 0, height = 0;
207	unsigned char	depth = 0, lines = 20;
208	unsigned int i, pixels, sum, encodedSize, fg24= 0xFFFFFF, bg24=0x222222;
209	unsigned char *fileArr;
210	int chars_this_line, next, runindex;
211
212
213	// pull apart the arguments
214	for( next = 1; next < argc; next++ )
215	{
216		if (strcmp(argv[next], "-i") == 0) // image file in raw QT uncompressed format (.qtif)
217			file = argv[++next];
218
219		else if (strcmp(argv[next], "-o") == 0) // output file for WHD image
220			kraw = argv[++next];
221		else if (strcmp(argv[next], "-io") == 0) // output file for image
222			out = argv[++next];
223
224		else if (strcmp(argv[next], "-n") == 0) // numbers of reserved lines
225			lines = atoi(argv[++next]);
226		else if (strcmp(argv[next], "-fg") == 0) // foreground color in 24 bits
227			sscanf(argv[++next], "%i", &fg24);
228		else if (strcmp(argv[next], "-bg") == 0) // background color in 24 bits
229			sscanf(argv[++next], "%i", &bg24);
230		else if (strcmp(argv[next], "-c") == 0) // input file for clut
231			clutin = argv[++next];
232		else if (strcmp(argv[next], "-h") == 0) // display more help
233			{ usage(1); exit(1); }
234
235		// useful testing options
236		else if (strcmp(argv[next], "-co") == 0) // output file for generating appleClut8.h array included in this file
237			clutout = argv[++next];
238		else if (strcmp(argv[next], "-a8") == 0) // output file for testing system CLUT 8 in QT RAW (test)
239			testclut = 8;
240		else if (strcmp(argv[next], "-r") == 0) // output file for QT clut RAW (test)
241			testclut = 1;
242		else if (strcmp(argv[next], "-qt") == 0) // output file for QT RAW (test)
243			qtraw = argv[++next];
244		else if (strcmp(argv[next], "-bw") == 0) // use only shades of grey (test)
245			grey = 1;
246		else if (strcmp(argv[next], "-n8") == 0) // don't convert to 8 by default (test)
247			convert = 0;
248		else if (strcmp(argv[next], "-n24") == 0) // convert to 8 to 24 (test)
249			convert = 24;
250		else if (strcmp(argv[next], "-f") == 0) // test font (test)
251			testfont = 1;
252		else if (strcmp(argv[next], "-w") == 0) // read WHD raw file and output 8 bit tqif
253			whdname = argv[++next];
254
255		else if (strcmp(argv[next], "-debug") == 0) // verbose
256			debug++;
257	}
258
259	if (!(file || clutout || testfont || testclut || whdname) ) {
260		usage(0);
261		exit(1);
262	}
263
264	printf("\n");
265
266	panic_clut = appleClut8;
267
268	if ( clutin )
269	{
270		panic_clut = ReplaceCLUT( clutin );
271		printf("Built-in CLUT has been replaced with %s...\n", clutin);
272	} else
273	{
274		if ( whdname )
275			printf("Using CLUT from %s...\n", whdname);
276		else
277			printf("Using Built-in CLUT...\n");
278	}
279
280	if ( clutout )
281	{
282		GenerateCLUT( clutout );
283		printf("Created C source file of %s...\n", clutout);
284	}
285
286	fg = findIndexNearMatch(fg24);
287	bg = findIndexNearMatch(bg24);
288
289	if ( testclut )
290		CreateRawQTCLUT(testclut);
291
292	if ( testfont )
293		CreateRawQTFont();
294
295	// Begin to process the image
296
297	if( file == NULL)
298	{
299		if ( whdname == NULL )
300		{
301			if ( debug)
302				printf("No image file was processed...\n\n");
303			exit(0);
304		}
305	}
306
307
308	printf("Verifing image file...\n");
309	if ( file != NULL )
310	{
311		stream = fopen(file, "r");
312		if (!stream) {
313			fprintf(stderr, "Err: could not open .qtif image file.\n\n");
314			exit(1);
315		}
316
317		{
318			long	hdr_off;
319			long	hdr_type;
320
321			fread((void *) &hdr_off, sizeof(long), 1, stream);
322			fread((void *) &hdr_type, sizeof(long), 1, stream);
323
324			if ( hdr_type != 'idat' ) goto errQTimage;
325
326			fseek(stream, hdr_off, SEEK_SET);
327			fread((void *) &hdr_off, sizeof(long), 1, stream);
328			fread((void *) &hdr_type, sizeof(long), 1, stream);
329
330			if ( hdr_type != 'idsc' ) goto errQTimage;
331
332			fread((void *) &image_header, sizeof(image_header), 1, stream);
333			if ( image_header.cType != 'raw ' ) goto errQTimage;
334			if (( image_header.depth != 8 ) && ( image_header.depth != 24 )) goto errQTimage;
335
336			width = image_header.width;
337			height = image_header.height;
338			depth = image_header.depth;
339
340			printf("Image info: width: %d height: %d depth: %d...\n", width, height, depth);
341
342			if (!(width && height && depth)) {
343				fprintf(stderr,"Err: Invalid image file header (width, height, or depth is 0)\n");
344				exit(1);
345			}
346		}
347
348		if ( !(data = (char *)malloc(image_header.dataSize))) {
349			fprintf(stderr,"Err: Couldn't malloc file data (%ld bytes)... bailing.\n", image_header.dataSize);
350			exit(1);
351		}
352
353		// Read the image data
354		fseek(stream, 8, SEEK_SET);
355		fread((void *) data, image_header.dataSize, 1, stream);
356		fclose( stream );
357
358		if ( kraw && image_header.depth == 24 )
359		{
360			fprintf(stderr, "Err: The WHD raw file (%s) will not be created when input in is millions of colors\n", kraw);
361			kraw = NULL;
362		}
363
364		pixels = image_header.dataSize;
365
366		if ( image_header.depth == 24 )
367		{
368			if ( grey == 1 )
369				pixels = convert24toGrey( data, image_header.dataSize);
370
371			if ( convert == 8 )
372			{
373				printf("Converting image file to 8 bit...\n");
374				pixels = convert24to8bitIndex( data, height, width, &data );
375				image_header.dataSize = pixels;
376				depth = 1;
377			} else
378				depth = 3;
379		} else {
380			if ( grey == 1 )
381				pixels = convert8toGrey( data, image_header.dataSize );
382
383			if ( convert == 24 )
384			{
385				printf("Converting image file to 24 bit...\n");
386				pixels = convert8bitIndexto24( data, height, width, &data );
387				image_header.dataSize = pixels;
388				depth = 3;
389			} else
390			{
391				printf("Converting image file to 8 bit raw...\n");
392				pixels = convert8bitIndexto8( data, height, width, &data );
393				image_header.dataSize = pixels;
394				depth = 1;
395			}
396		}
397
398		printf("Converted %d pixels%s...\n", pixels/depth, ((grey==1)?" to grayscale":""));
399		if ( exactmatch > 0 )
400			printf("Found %d color mathces in CLUT...\n", exactmatch);
401		if ( cvt2grey > 0 )
402			printf("Converted %d colors to gray...\n", cvt2grey);
403		if ( neargrey > 0 )
404			printf("Adjusted %d grays to best match...\n", neargrey);
405		if ( nextmis > 0 )
406			printf("Total of %d seperate color mismatches...\n", nextmis);
407	}
408	else
409	{
410		unsigned int pixels_out;
411		struct panicimage image;
412
413		stream = fopen(whdname, "r");
414		if (!stream) {
415			fprintf(stderr, "Err: could not open WHD raw image file.\n\n");
416			exit(1);
417		}
418
419		fread(&image, sizeof(image), 1, stream);
420
421		if ( image.pd_tag != 'RNMp' )
422			goto errWHDimage;
423
424		if ( image.pd_depth != 1 )
425			goto errWHDimage;
426
427		width = image.pd_width;
428		height = image.pd_height;
429		depth = image.pd_depth;
430
431		printf("Image info: width: %d height: %d depth: %d...\n", image.pd_width, image.pd_height, image.pd_depth);
432
433		if (!(width && height && depth)) {
434			fprintf(stderr,"Err: Invalid image file header (width, height, or depth is 0)\n");
435			exit(1);
436		}
437
438		if ( !(fileArr = (char *)malloc(image.pd_dataSize))) {
439			fprintf(stderr,"Err: Couldn't malloc file data (%ld bytes)... bailing.\n", image.pd_dataSize);
440			exit(1);
441		}
442
443		/* read the data into a buffer */
444		fread(fileArr, image.pd_dataSize, 1, stream);
445		fclose(stream);
446
447		encodedSize = image.pd_dataSize - (256 * 3);
448
449		for(sum=0,i=0; i<encodedSize; i++)
450		{
451			sum += fileArr[i];
452			sum <<= sum&1;
453		}
454
455		if (debug) printf("WHD sum = %x\n", sum);
456
457		if ( sum != image.pd_sum )
458			goto errWHDimage;
459
460		for(pixels=0,i=0; i<encodedSize;)
461		{
462			unsigned int quantity, depth;
463			unsigned char * value;
464
465			i += decode_rle( &fileArr[i], &quantity, &depth, &value );
466			pixels += quantity * depth;
467		}
468
469		if ( debug) printf("pixels = %d sum = %x\n", pixels, sum);
470		if ( debug) printf("es = %d H*W = %d sum = %x\n", encodedSize, image.pd_height*image.pd_width, image.pd_sum);
471
472		if ( !(data = (char *)malloc(pixels))) {
473			fprintf(stderr,"Err: Couldn't malloc file data (%ld bytes)... bailing.\n", pixels);
474			exit(1);
475		}
476
477		{
478			unsigned int quantity, line, col, depth, sum;
479			unsigned char * dataIn, * value;
480
481			sum = 0;
482			pixels_out = 0;
483			dataIn = fileArr;
484			quantity = 0;
485			for (line=0; line < height; line++) {
486				for (col=0; col < width; col++) {
487
488					if ( quantity == 0 ) {
489						dataIn += decode_rle( dataIn, &quantity, &depth, &value );
490						i = 0;
491						sum += quantity * depth;
492					}
493					data[pixels_out++] = value[i++];
494
495					if ( i == depth )
496					{
497						i = 0;
498						quantity--;
499					}
500				}
501			}
502			if (debug) printf("total Q*D = %d\n", sum);
503		}
504
505		if( pixels_out != pixels )
506		{
507			printf("Err: miscalclulated pixels %d pixels_out %d\n", pixels, pixels_out);
508			exit(1);
509		}
510
511		panic_clut = CreateCLUTarry( &fileArr[image.pd_dataSize-(256*3)] );
512
513		qtraw = "panic_image.qtif";
514	}
515
516	if ( qtraw )
517	{
518		FILE * ostream;
519
520		if ( (ostream = fopen(qtraw, "wb")) == NULL ) {
521			fprintf(stderr,"Err: Could not open output file %s.\n\n", qtraw);
522			exit(1);
523		}
524
525		printf("Creating image %s in QuickTime No Compression %s %s format...\n", qtraw,
526						(depth==3)?"Millions of":"256", (grey==0)?"colors":"grays");
527
528		WriteQTRawFile( ostream, data, height, width, depth, pixels );
529		fclose(ostream);
530	}
531
532	if ( depth != 1 )
533	{
534		printf("Depth != 1 (8-bit), skipping writing output..\n");
535		goto leaveOK;
536	}
537
538	printf("Encoding image file...\n");
539
540	if (!(fileArr = (unsigned char *) malloc(pixels))) {
541		fprintf(stderr,"Err: Couldn't malloc fileArr (%d pixels)... bailing.\n", pixels);
542		exit(1);
543	}
544
545	encodedSize = EncodeImage( data, pixels, fileArr );
546	if ( encodedSize >= pixels )
547	{
548		printf("Skipping encoding...\n");
549	}
550
551	for (sum=0,i=0; i<encodedSize; i++)
552	{
553		sum += fileArr[i];
554		sum <<= sum&1;
555	}
556
557	// write raw image suitable for kernel panic dialog
558	if ( kraw )
559	{
560		FILE * ostream;
561		unsigned int tag;
562
563		if ( (ostream = fopen(kraw, "wb")) == NULL ) {
564			fprintf(stderr,"Err: Could not open output file %s.\n\n", kraw);
565			exit(1);
566		}
567
568		printf("Writing to binary panic dialog file %s, which is suitable for loading into kernel...\n", kraw);
569
570		tag = 'RNMp';	// Raw NMage for Panic dialog
571		depth = 1;	// only CLUT is supported
572
573		fwrite(&sum, sizeof(sum), 1, ostream);
574		sum = encodedSize;
575		encodedSize += (256*3);
576		fwrite(&encodedSize, sizeof(encodedSize), 1, ostream);
577		encodedSize = sum;
578		fwrite(&tag, sizeof(tag), 1, ostream);
579		fwrite(&width, sizeof(width), 1, ostream);
580		fwrite(&height, sizeof(height), 1, ostream);
581		fwrite(&depth, sizeof(depth), 1, ostream);
582		fwrite(&lines, sizeof(lines), 1, ostream);
583		fwrite(&fg, sizeof(fg), 1, ostream);
584		fwrite(&bg, sizeof(bg), 1, ostream);
585		fwrite(fileArr, encodedSize, 1, ostream);
586
587		for ( i=0; i<256; i++)
588		{
589			union colors c;
590			unsigned char arr[3];
591
592			c.c24 = panic_clut[i];
593
594			arr[0] = c.clut.red;
595			arr[1] = c.clut.green;
596			arr[2] = c.clut.blue;
597			fwrite(arr, 3, 1, ostream);
598		}
599		fclose(ostream);
600		if ( out == NULL ) goto leaveOK;
601	}
602
603	// it's ok to generate the c file
604
605	if ( out == NULL ) out = "panic_image.c";
606	out_stream = fopen(out, "w");
607
608	if(out_stream == NULL) {
609		fprintf(stderr,"Err: Couldn't open out file %s.\n\n", out);
610		exit(1);
611	}
612
613	printf("Writing C source %s, suitable for including into kernel build...\n", out);
614
615	fprintf( out_stream, "/* autogenerated with genimage.c using %s as image input */\n", file);
616	{
617		char * s = "the built-in appleClut8";
618		if ( clutin )
619			s = clutin;
620		fprintf( out_stream, "/* and %s for the color look up table (CLUT) */\n\n", s);
621	}
622
623	fprintf( out_stream, "static const struct panicimage {\n");
624	fprintf( out_stream, "\tunsigned int\tpd_sum;\n");
625	fprintf( out_stream, "\tunsigned int\tpd_dataSize;\n");
626	fprintf( out_stream, "\tunsigned int\tpd_tag;\n");
627	fprintf( out_stream, "\tunsigned short\tpd_width;\n");
628	fprintf( out_stream, "\tunsigned short\tpd_height;\n");
629	fprintf( out_stream, "\tunsigned char\tpd_depth;\n");
630	fprintf( out_stream, "\tunsigned char\tpd_info_height;\n");
631	fprintf( out_stream, "\tunsigned char\tpd_info_color[2];\n");
632	fprintf( out_stream, "\tunsigned char\tdata[];\n");
633
634	fprintf( out_stream, "} panic_dialog_default = {\n\t");
635	fprintf( out_stream, "0x%08x, ", sum);		/* panic dialog x */
636	fprintf( out_stream, "0x%08x, ", encodedSize+(256*3));		/* panic dialog x */
637	fprintf( out_stream, "0x%08x, ", 'RNMp');		/* panic dialog x */
638	fprintf( out_stream, "%d, ", width);		/* panic dialog x */
639	fprintf( out_stream, "%d, ", height);		/* panic dialog y */
640	fprintf( out_stream, "%d, ", depth);		/* bytes per pixel */
641	fprintf( out_stream, "%d, ", lines);		/* lines reserved for panic info */
642	fprintf( out_stream, "0x%02x, ", fg);		/* font foreground color: indexed */
643	fprintf( out_stream, "0x%02x, ", bg);		/* font background color: indexed */
644
645	fprintf( out_stream, "\n");
646
647	chars_this_line = 0;
648	fprintf( out_stream, "{\n");
649
650	for( i=0; i < encodedSize;)
651	{
652		chars_this_line += fprintf( out_stream, "0x%.2x,", fileArr[i++]);
653
654		if (i >= encodedSize) // this is the last element
655			break;
656
657		if(chars_this_line >= 80) {
658			fprintf( out_stream, "\n");
659			chars_this_line = 0;
660		}
661	}
662
663
664	if (debug)
665	{
666		printf("Encoded size = %d\n", encodedSize);
667		printf("Decoded size = %d\n", pixels);
668	}
669
670	fprintf(out_stream, "\n\n");
671	for ( i=0; i<256; i+=4)
672	{
673		union colors c;
674
675		if ( (i % 16) == 0 ) fprintf(out_stream, "// %02X\n", i);
676		c.c24 = panic_clut[i+0];
677		fprintf(out_stream, "\t0x%02X,0x%02X,0x%02X, ", c.clut.red, c.clut.green, c.clut.blue);
678		c.c24 = panic_clut[i+1];
679		fprintf(out_stream, "0x%02X,0x%02X,0x%02X, ", c.clut.red, c.clut.green, c.clut.blue);
680		c.c24 = panic_clut[i+2];
681		fprintf(out_stream, "0x%02X,0x%02X,0x%02X, ", c.clut.red, c.clut.green, c.clut.blue);
682		c.c24 = panic_clut[i+3];
683		fprintf(out_stream, "0x%02X,0x%02X,0x%02X%s\n", c.clut.red, c.clut.green, c.clut.blue, ((i!=(256-4))?",":""));
684	}
685
686	fprintf(out_stream, "}\n");
687	fprintf(out_stream, "};\n");
688
689	fclose( out_stream );
690
691leaveOK:
692	printf("\n");
693	return 0;
694
695errQTimage:
696	fprintf(stderr,"Err: Image must be in the QuickTime Raw Uncompressed Millions or 256 Colors format\n");
697	exit(1);
698errWHDimage:
699	fprintf(stderr,"Err: Image must be in the WHD Raw 256 Colors format\n");
700	exit(1);
701}
702
703
704
705#define RUN_MAX ((1<<20)-1)
706
707union RunData {
708	unsigned int i;
709	unsigned char c[4];
710};
711
712unsigned int encode_rle(
713		unsigned char * fileArr,
714		unsigned int filePos,
715		unsigned int quantity,
716		union RunData * value,
717		int depth);
718
719int
720compareruns( unsigned char * data, unsigned int * index, unsigned int max, union RunData * currP, int * depth )
721{
722	unsigned int i = *index;
723	union RunData * nextP;
724	static int retc = 0;
725
726	if ( currP == NULL || data == NULL )
727	{
728		retc = 0;
729		goto Leave;
730	}
731
732	if ( (*index+*depth) > max )
733	{
734		*depth = 1;
735		retc = 0;
736		goto Leave;
737	}
738
739	nextP = (union RunData *) &data[*index];
740
741	if ( retc == 1 )
742	{
743		// check current data against current depth
744		switch ( *depth )
745		{
746			case 1:
747				if ( nextP->c[0] == currP->c[0] )
748					goto Leave;
749				break;
750			case 2:
751				if ( nextP->c[0] == currP->c[0] &&
752				     nextP->c[1] == currP->c[1] )
753					goto Leave;
754				break;
755			case 3:
756				if ( nextP->c[0] == currP->c[0] &&
757				     nextP->c[1] == currP->c[1] &&
758				     nextP->c[2] == currP->c[2] )
759					goto Leave;
760				break;
761			case 4:
762				if ( nextP->c[0] == currP->c[0] &&
763				     nextP->c[1] == currP->c[1] &&
764				     nextP->c[2] == currP->c[2] &&
765				     nextP->c[3] == currP->c[3] )
766					goto Leave;
767				break;
768		}
769
770		retc = 0;
771		goto Leave;
772	}
773
774	// start of a new pattern match begine with depth = 1
775
776	if ( (*index+6) <= max )
777	{
778		// We have at least 8 bytes left in the buffer starting from currP
779#if 1
780		nextP = (union RunData *) &data[*index+3];
781		if ( nextP->c[0] == currP->c[0] &&
782		     nextP->c[1] == currP->c[1] &&
783		     nextP->c[2] == currP->c[2] &&
784		     nextP->c[3] == currP->c[3] )
785		{
786			// check if they are all the same value
787			if ( currP->c[0] == currP->c[1] &&
788			     currP->c[1] == currP->c[2] &&
789			     currP->c[2] == currP->c[3] )
790			{  // if so, leave at depth = 1
791				retc = 1;
792				*depth = 1;
793				goto Leave;
794			}
795
796			if (debug>2) printf("Found 4 at %x\n", *index);
797			retc = 1;
798			*depth = 4;
799			*index += 3;
800			goto Leave;
801		}
802
803		nextP = (union RunData *) &data[*index+2];
804		if ( nextP->c[0] == currP->c[0] &&
805		     nextP->c[1] == currP->c[1] &&
806		     nextP->c[2] == currP->c[2] )
807		{
808			// check if they are all the same value
809			if ( currP->c[0] == currP->c[1] &&
810			     currP->c[1] == currP->c[2] )
811			{  // if so, leave at depth = 1
812				retc = 1;
813				*depth = 1;
814				goto Leave;
815			}
816
817			if (debug>2) printf("Found 3 at %x\n", *index);
818			retc = 1;
819			*depth = 3;
820			*index += 2;
821			goto Leave;
822		}
823
824		nextP = (union RunData *) &data[*index+1];
825		if ( nextP->c[0] == currP->c[0] &&
826		     nextP->c[1] == currP->c[1] )
827		{
828			// check if they are all the same value
829			if ( currP->c[0] == currP->c[1] )
830			{  // if so, leave at depth = 1
831				retc = 1;
832				*depth = 1;
833				goto Leave;
834			}
835
836			if (debug>2) printf("Found 2 at %x\n", *index);
837			retc = 1;
838			*depth = 2;
839			*index += 1;
840			goto Leave;
841		}
842
843#endif
844		nextP = (union RunData *) &data[*index];
845
846	}
847
848	if ( nextP->c[0] == currP->c[0] )
849		retc = 1;
850	else
851		retc = 0;
852
853Leave:
854
855	if ( retc == 1 )
856		*index += *depth;
857
858	return retc;
859}
860
861int
862EncodeImage( unsigned char * data, int pixels, unsigned char * fileArr )
863{
864	union RunData * currP, * norunP ;
865	int i, match, depth;
866	unsigned int filePos, run, nomatchrun;
867
868	currP = NULL;
869	norunP = NULL;
870	nomatchrun = 0;
871	filePos = 0; // position in the file we're writing out
872	run = 1;
873	depth = 1;
874
875	currP = (union RunData *)&data[0]; // start a new run
876	for (i=1; i<pixels;)
877	{
878		if ( compareruns( data, &i, pixels, currP, &depth ) )
879			run++;
880		else
881		{
882			if ( (run*depth) > 2 )
883			{
884				unsigned char * p = (unsigned char *)norunP;
885
886				if( nomatchrun )
887				{
888					while (nomatchrun)
889					{
890						int cnt;
891
892						cnt = (nomatchrun > 127) ? 127 : nomatchrun;
893						fileArr[filePos++] = cnt;
894						nomatchrun -= cnt;
895
896						while ( cnt-- )
897							fileArr[filePos++] = *p++;
898					}
899				}
900
901				filePos += encode_rle(fileArr, filePos, run, currP, depth);
902
903				norunP = NULL;
904			}
905			else
906			{
907				nomatchrun+=run;
908			}
909
910			currP = (union RunData *)&data[i]; // start a new run
911
912			if( norunP == NULL )
913			{
914				nomatchrun = 0;
915				norunP = currP;
916			}
917
918			depth = 1;		// switch back to a single byte depth
919			run = 1;		// thee is always at least one entry
920			i++;			// point to next byte
921		}
922	}
923
924	if( nomatchrun )
925	{
926		unsigned char * p = (unsigned char *)norunP;
927		while (nomatchrun)
928		{
929			int cnt;
930
931			cnt = (nomatchrun > 127) ? 127 : nomatchrun;
932			fileArr[filePos++] = cnt;
933			nomatchrun -= cnt;
934
935			while ( cnt-- )
936				fileArr[filePos++] = *p++;
937		}
938	}
939
940	// write out any run that was in progress
941	if (run > 0) {
942		filePos += encode_rle(fileArr, filePos, run, currP, depth);
943	}
944
945	return filePos;
946}
947
948/*  encode_rle applies a "modified-RLE encoding to a given image. The encoding works as follows:
949
950	The quantity is described in the first byte.  If the MSB is zero, then the next seven bits
951	are the quantity. If the MSB is set, bits 0-3 of the quantity are in the least significant bits.
952	If bit 5 is set, then the quantity is further described in the next byte, where an additional
953	7 bits (4-10) worth of quantity will be found.  If the MSB of this byte is set, then an additional
954	7 bits (11-17) worth of quantity will be found in the next byte. This repeats until the MSB of
955	a quantity byte is zero, thus ending the chain.
956
957	The value is described in the first byte.  If the MSB is zero, then the value is in the next byte.
958	If the MSB is set, then bits 5/6 describe the number of value bytes following the quantity bytes.
959
960	encodings are: (q = quantity, v = value, c = quantity continues)
961
962               Byte 1	     Byte 2          Byte 3      Byte 4      Byte 5    Byte 6    Byte 7   Byte 8
963  case 1: [ 0       q6-q0 ] [ v7-v0 ]
964  case 2: [ 1 0 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ]
965  case 3: [ 1 0 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ]
966  case 4: [ 1 1 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
967  case 5: [ 1 1 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
968*/
969
970unsigned int
971encode_length(unsigned char * fileArr, unsigned int filePos, unsigned int quantity, unsigned int mask)
972{
973	unsigned char single_mask = 0x0F;
974	unsigned char double_mask = 0x7F;
975	unsigned int slots_used = 0;
976
977	fileArr[filePos] = mask | (quantity & single_mask); // low bits (plus mask)
978	slots_used++;
979
980	if (quantity >>= 4)
981	{
982		fileArr[filePos++] |= 0x10;	// set length continuation bit
983		fileArr[filePos] = quantity & double_mask;
984		slots_used++;
985
986		while (quantity >>= 7)
987		{
988			fileArr[filePos++] |= 0x80;	// set length continuation bit
989			fileArr[filePos] = quantity & double_mask;
990			slots_used++;
991		}
992	}
993
994	return slots_used;
995}
996
997
998unsigned int
999encode_rle(unsigned char * fileArr, unsigned int filePos, unsigned int quantity, union RunData * value, int depth)
1000{
1001	unsigned char single_mask = 0x0F;
1002	unsigned char double_mask = 0x7F;
1003	unsigned char slots_used = 0;
1004
1005
1006	switch ( depth )
1007	{
1008		case 1:
1009			slots_used += encode_length( fileArr, filePos, quantity, 0x80 );
1010			fileArr[filePos+slots_used++] = value->c[0];
1011			break;
1012
1013		case 2:
1014			slots_used += encode_length( fileArr, filePos, quantity, 0xA0 );
1015			fileArr[filePos+slots_used++] = value->c[0];
1016			fileArr[filePos+slots_used++] = value->c[1];
1017			break;
1018
1019		case 3:
1020			slots_used += encode_length( fileArr, filePos, quantity, 0xC0 );
1021			fileArr[filePos+slots_used++] = value->c[0];
1022			fileArr[filePos+slots_used++] = value->c[1];
1023			fileArr[filePos+slots_used++] = value->c[2];
1024			break;
1025
1026		case 4:
1027			slots_used += encode_length( fileArr, filePos, quantity, 0xE0 );
1028			fileArr[filePos+slots_used++] = value->c[0];
1029			fileArr[filePos+slots_used++] = value->c[1];
1030			fileArr[filePos+slots_used++] = value->c[2];
1031			fileArr[filePos+slots_used++] = value->c[3];
1032			break;
1033	}
1034
1035	return slots_used;
1036}
1037
1038int
1039decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * depth, unsigned char ** value )
1040{
1041	unsigned int mask;
1042	int i, runlen, runsize;
1043
1044	i = 0;
1045	mask = dataPtr[i] & 0xF0;
1046
1047	if ( mask & 0x80 )
1048	{
1049		runsize = ((mask & 0x60) >> 5) + 1;
1050		runlen = dataPtr[i++] & 0x0F;
1051
1052		if ( mask & 0x10 )
1053		{
1054			int shift = 4;
1055
1056			do
1057			{
1058				mask = dataPtr[i] & 0x80;
1059				runlen |= ((dataPtr[i++] & 0x7F) << shift);
1060				shift+=7;
1061			} while (mask);
1062		}
1063	} else
1064	{
1065		runlen = 1;
1066		runsize = dataPtr[i++];
1067	}
1068
1069	*depth = runsize;
1070	*quantity = runlen;
1071	*value = &dataPtr[i];
1072
1073	return i+runsize;
1074}
1075
1076int
1077findIndexNearMatch( unsigned int color24 )
1078{
1079	union colors color8;
1080	union colors clut8;
1081	int isGrey = 0;
1082
1083	color8.c24 = color24;
1084
1085	if ( color8.clut.red == color8.clut.green && color8.clut.green == color8.clut.blue )
1086		isGrey = 1;
1087
1088	if ( isGrey ) {
1089		int i;
1090		unsigned int bestIndex = 0, rel, bestMatch = -1;
1091
1092		for (i=0; i<256; i++)
1093		{
1094			clut8.c24 = panic_clut[i];
1095
1096			if ( clut8.clut.red != clut8.clut.green || clut8.clut.green != clut8.clut.blue )
1097				continue;
1098
1099			if ( clut8.clut.red > color8.clut.red) continue;
1100			rel = abs(color8.clut.red - clut8.clut.red);
1101			if ( rel < bestMatch ) {
1102				bestMatch = rel;
1103				bestIndex = i;
1104			}
1105		}
1106
1107		return bestIndex;
1108	}
1109
1110	// we must have a non-grey color
1111	return -1;
1112}
1113
1114unsigned int
1115color24toGrey( unsigned int color24 )
1116{
1117	float R, G, B;
1118	float Grey;
1119	union colors c;
1120	unsigned char grey8;
1121	unsigned int grey24;
1122
1123	c.c24 = color24;
1124
1125	R = (c.clut.red & 0xFF) ;
1126	G = (c.clut.green & 0xFF) ;
1127	B = (c.clut.blue & 0xFF) ;
1128
1129	Grey = (R*.30) + (G*.59) + (B*.11);
1130	grey8 = (unsigned char) ( Grey + .5);
1131	grey24 = (grey8<<16) | (grey8<<8) | grey8;
1132	return grey24;
1133}
1134
1135int
1136convert24toGrey( unsigned char * data, unsigned int size )
1137{
1138	float R, G, B;
1139	float Grey;
1140	unsigned int grey8;
1141	int i24;
1142
1143
1144	for ( i24=0; i24<size; i24+=3)
1145	{
1146		R = ((data[i24+0]) & 0xFF) ;
1147		G = ((data[i24+1]) & 0xFF) ;
1148		B = ((data[i24+2]) & 0xFF) ;
1149
1150		Grey = (R*.30) + (G*.59) + (B*.11);
1151		grey8 = (unsigned int) ( Grey + .5);
1152
1153		data[i24+0] = grey8;
1154		data[i24+1] = grey8;
1155		data[i24+2] = grey8;
1156	}
1157
1158	return size;
1159}
1160
1161int
1162convert8toGrey( unsigned char * data, unsigned int size )
1163{
1164	int i;
1165	unsigned int c24;
1166	union colors c;
1167
1168	for ( i=0; i<size; i++)
1169	{
1170		c.c24 = panic_clut[data[i]];
1171		c24 = color24toGrey( c.c24 );
1172		data[i] = findIndexMatch( c24 );
1173	}
1174
1175	return size;
1176}
1177
1178unsigned int
1179findColor24NearMatch( unsigned int color24 )
1180{
1181	union colors c, i_color;
1182	unsigned char d=0xff, d_red, d_green, d_blue, i, prim;
1183	static unsigned int last_c = -1, last_co = -1, last_p = -1;
1184
1185	if ( last_c == color24 )
1186		return last_co;
1187
1188	c.c24 = color24;
1189
1190	if ( c.rgb[1] > c.rgb[2] && c.rgb[1] > c.rgb[3] )
1191		prim = 1;
1192	else if ( c.rgb[2] > c.rgb[1] && c.rgb[2] > c.rgb[3] )
1193		prim = 2;
1194	else if ( c.rgb[3] > c.rgb[1] && c.rgb[3] > c.rgb[2] )
1195		prim = 3;
1196	else if ( c.rgb[1] == c.rgb[2] && c.rgb[1] == c.rgb[3] )
1197		prim = 0;	// gray
1198	else if ( c.rgb[1] == c.rgb[2] )
1199		prim = 0x12;	// red green
1200	else if ( c.rgb[1] == c.rgb[3] )
1201		prim = 0x13;	// red blue
1202	else if ( c.rgb[2] == c.rgb[3] )
1203		prim = 0x23;	// green blue
1204	else
1205		printf("cannot tell color %06x\n", color24);
1206
1207	last_c = color24;
1208	last_p = prim;
1209
1210	if ( prim == 0 || prim > 3 )
1211	{
1212		last_co = -1;
1213		return last_co;
1214	}
1215
1216#if 0
1217	for (i=0; i<256; i++)
1218	{
1219
1220		break;
1221	}
1222#endif
1223
1224	return -1;
1225}
1226
1227
1228unsigned char
1229findIndexMatch( unsigned int color24 )
1230{
1231	int i;
1232	unsigned char ri;
1233	static unsigned char last = 0;
1234
1235retry:
1236	if ( panic_clut[last] == color24 )
1237	{
1238		exactmatch++;
1239		return last;
1240	}
1241
1242	for (i=0; i<256; i++)
1243	{
1244		if ( panic_clut[i] == color24 ) {
1245			last = i;
1246			exactmatch++;
1247			return last;
1248		}
1249	}
1250
1251	if ( nextmis == -1 ) {
1252		for (i=0; i<256; i++) mismatchClut[i] = -1;
1253		nextmis = 0;
1254	}
1255
1256	i = findIndexNearMatch(color24);
1257
1258	if ( i == -1 )  // found a color that is not grey
1259	{
1260		unsigned int colormatch = findColor24NearMatch( color24 );
1261
1262		if ( colormatch == -1 )		// cannot convert color
1263		{
1264			cvt2grey++;
1265			if (debug>1) printf("color %06X not matched at all\n", color24);
1266			color24 = color24toGrey(color24);
1267			if (debug>1) printf("now grey %06X\n", color24);
1268		}
1269		else
1270			color24 = colormatch;
1271
1272		goto retry;
1273	}
1274
1275	if (debug>1) printf("color %06X now matched at %x\n", color24, i);
1276
1277	ri = i;
1278
1279	neargrey++;
1280
1281	// keep track of missed repeats
1282	for ( i=0; i<nextmis; i++)
1283		if ( mismatchClut[i] == color24 )
1284			return ri;
1285
1286	if ( debug) printf("closest match for %06X is at index %d %06X\n", color24, ri, panic_clut[ri]);
1287	if ( nextmis < 256 )
1288		mismatchClut[nextmis++] = color24;
1289
1290	if ( debug && (nextmis >= 256) )
1291	{
1292		fprintf(stderr,"Err: Too many color mismatches detected with this CLUT\n");
1293		exit(1);
1294	}
1295
1296	return ri;
1297}
1298
1299/*
1300 * Convert 24 bit mode to 8 bit.  We do not do any alignment conversions
1301 */
1302
1303int
1304convert24to8bitIndex( unsigned char * data, int height, int width, unsigned char ** dout )
1305{
1306	unsigned int row, col, i, i24, i8, size;
1307	unsigned char index;
1308	unsigned char * ddata;
1309	union colors color24;
1310
1311	size = height * width;
1312
1313	ddata = (unsigned char *) calloc( size, 1);
1314
1315	for (i24=0,i8=0,row=0; row<height; row++)
1316	{
1317		for (col=0; col<width; col++)
1318		{
1319			color24.clut.red = data[i24++];
1320			color24.clut.green = data[i24++];
1321			color24.clut.blue = data[i24++];
1322
1323			index = findIndexMatch( color24.c24 );
1324			ddata[i8++] = index;
1325		}
1326	}
1327
1328	* dout = ddata;
1329
1330	return (i8);
1331}
1332
1333/*
1334 * Convert 8 bit mode to 8 bit, We have to strip off the alignment bytes
1335 */
1336
1337int
1338convert8bitIndexto8( unsigned char * data, int height, int width, unsigned char ** dout )
1339{
1340	unsigned int row, col, i, i8, size, adj;
1341	unsigned char index;
1342	unsigned char * ddata;
1343	union colors color24;
1344
1345	adj=(4-(width%4))%4;	// adjustment needed to strip off the word alignment padding
1346	size = height * width;
1347	ddata = (unsigned char *) calloc( size, 1);
1348
1349	for (i8=0,row=0; row<height; row++)
1350	{
1351		for (col=0; col<width; col++)
1352		{
1353			index = *data++;
1354			color24.c24 = panic_clut[index];
1355			index = findIndexMatch( color24.c24 );
1356			ddata[i8++] = index;
1357		}
1358
1359		for (i=0; i<adj; i++)
1360			data++;
1361	}
1362
1363	* dout = ddata;
1364
1365	return (i8);
1366}
1367/*
1368 * Convert 8 bit mode to 24 bit, We have to strip off the alignment bytes
1369 */
1370
1371int
1372convert8bitIndexto24( unsigned char * data, int height, int width, unsigned char ** dout )
1373{
1374	unsigned int row, col, i, i24, i8, size, adj;
1375	unsigned char index;
1376	unsigned char * ddata;
1377	union colors color24;
1378
1379	adj=(4-(width%4))%4;	// adjustment needed to strip off the word alignment padding
1380	size = height * width;
1381	ddata = (unsigned char *) calloc( size, 3);
1382
1383	for (i24=0,i8=0,row=0; row<height; row++)
1384	{
1385		for (col=0; col<width; col++)
1386		{
1387			index = data[i8++];
1388			color24.c24 = panic_clut[index];
1389
1390			ddata[i24++] = color24.clut.red;
1391			ddata[i24++] = color24.clut.green;
1392			ddata[i24++] = color24.clut.blue;
1393		}
1394
1395		for (i=0; i<adj; i++)
1396			i8++;
1397	}
1398
1399	* dout = ddata;
1400
1401	return (i24);
1402}
1403
1404
1405unsigned int *
1406CreateCLUTarry( unsigned char * raw_clut )
1407{
1408	unsigned int * new_clut, index, i;
1409
1410	new_clut = (unsigned int *) calloc(256, sizeof(unsigned int));
1411	for ( index=0,i=0; i<256; index+=3,i++ )
1412		new_clut[i] = (raw_clut[index] << 16) | (raw_clut[index+1] << 8) | raw_clut[index+2];
1413
1414	return new_clut;
1415}
1416
1417
1418unsigned int *
1419ReplaceCLUT( char * iname )
1420{
1421	FILE  * stream;
1422	unsigned char * raw_clut;
1423	unsigned int * new_clut, index, i;
1424
1425	if ( (stream = fopen(iname, "rb")) == NULL ) {
1426		fprintf(stderr,"Err: Could not open input clut file %s.\n\n", iname);
1427		exit(1);
1428	}
1429
1430	raw_clut = (char *) calloc(256, 3);
1431	fread(raw_clut, 256, 3, stream);
1432	fclose(stream);
1433
1434	new_clut = CreateCLUTarry( raw_clut );
1435
1436	free(raw_clut);
1437	return new_clut;
1438}
1439
1440
1441void
1442GenerateCLUT( char * oname )
1443{
1444	FILE  * ostream;
1445	int i;
1446
1447
1448	if ( (ostream = fopen(oname, "w")) == NULL ) {
1449		fprintf(stderr,"Err: Could not open output clut file %s.\n\n", oname);
1450		exit(1);
1451	}
1452
1453	printf("Generating new CLUT array named %s\n", oname);
1454	fprintf(ostream, "// This Clut was generated from %s\n", (clutin)?clutin:"built-in appleClut8");
1455	fprintf(ostream, "unsigned int appleClut8[256] = {\n");
1456	for ( i=0; i<256; i+=8)
1457	{
1458		if ( (i % 16) == 0 ) fprintf(ostream, "// %02X\n", i);
1459		fprintf(ostream, "\t0x%06X, 0x%06X, 0x%06X, 0x%06X, 0x%06X, 0x%06X, 0x%06X, 0x%06X%s\n",
1460				panic_clut[i+0], panic_clut[i+1], panic_clut[i+2], panic_clut[i+3],
1461				panic_clut[i+4], panic_clut[i+5], panic_clut[i+6], panic_clut[i+7], ((i!=(256-8))?",":""));
1462	}
1463	fprintf(ostream, "};\n");
1464	fclose(ostream);
1465}
1466
1467void
1468WriteQTRawFile( FILE * ostream, unsigned char * data, int height, int width, int depth, unsigned int size )
1469{
1470	unsigned int i, adj, csize, tmp, col, line;
1471
1472
1473	if ( depth == 1)
1474		adj=(4-(width%4))%4;	// adjustment needed to add the word alignment padding
1475	else
1476		adj = 0;
1477
1478	csize = height*depth*(width+adj);
1479
1480	if( debug && csize != size )
1481		printf("Adjusted Computed size (%d=H*W*D) to account to account for word alignment %d(%d)\n", size,csize,csize-size);
1482
1483	tmp = csize + ( 2 * sizeof(unsigned int) );
1484	fwrite(&tmp, sizeof(unsigned int), 1, ostream);
1485
1486	tmp = 'idat';
1487	fwrite(&tmp, sizeof(unsigned int), 1, ostream);
1488
1489	if ( depth == 1)
1490	{
1491		for (line=0; line<height; line++)
1492		{
1493			for (col=0; col<width; col++)
1494				fwrite(data++, 1, 1, ostream);
1495
1496			for (i=0; i<adj; i++)
1497				fwrite(&data[-1], 1, 1, ostream);
1498		}
1499	} else
1500			fwrite(data, csize, 1, ostream);
1501
1502	tmp = 0x5e;
1503	fwrite(&tmp, sizeof(unsigned int), 1, ostream);
1504	tmp = 'idsc';
1505	fwrite(&tmp, sizeof(unsigned int), 1, ostream);
1506
1507	image_header.idSize = sizeof(image_header) - 2;
1508	image_header.cType = 'raw ';
1509	image_header.dataRefIndex = 0;
1510	image_header.version = 1;
1511	image_header.revisionLevel = 1;
1512	image_header.vendor = 'appl';
1513	image_header.temporalQuality = 0;
1514	image_header.spatialQuality = 1024-1;
1515	image_header.width = width;
1516	image_header.height = height;
1517	image_header.hRes = 72 << 16;
1518	image_header.vRes =  72 << 16;
1519	image_header.dataSize = csize;
1520	image_header.frameCount = 1;
1521	strlcpy(image_header.name, " None", sizeof(image_header.name));
1522	image_header.name[0] = 4;
1523	image_header.depth = depth*8;
1524	image_header.clutID = (depth==1) ? 8 : -1;
1525
1526	fwrite(&image_header, sizeof(image_header)-2, 1, ostream);
1527}
1528
1529
1530void
1531CreateRawQTCLUT( int type )
1532{
1533	FILE  * ostream;
1534	char * name;
1535	unsigned char * raw_clut, * p;
1536	int row, i;
1537	int H=32, W=32, D;
1538
1539	if ( type == 8 )
1540	{
1541		name = "appleclut8.qtif";
1542		D = 1;
1543	}
1544	else
1545	{
1546		name = "unknownclut.qtif";
1547		D = 3;
1548	}
1549
1550	if ( (ostream = fopen(name, "wb")) == NULL ) {
1551		fprintf(stderr,"Err: Could not open output index file %s.\n\n", name);
1552		exit(1);
1553	}
1554
1555	raw_clut = (unsigned char *) malloc(H*W*D*256);
1556
1557	for (p=raw_clut, row=0; row<H; row++)
1558	{
1559		for (i=0; i<256; i++)
1560		{
1561			int j;
1562			union colors c;
1563
1564			if ( D == 3 )
1565				c.c24 = panic_clut[i];
1566
1567			for (j=0; j<W; j++)
1568			{
1569				if ( D == 1 )
1570					*p++ = i;
1571				else
1572				{
1573					*p++ = c.clut.red;
1574					*p++ = c.clut.green;
1575					*p++ = c.clut.blue;
1576				}
1577			}
1578		}
1579	}
1580	WriteQTRawFile( ostream, (unsigned char *) raw_clut, H, 256*W, D, H*256*W*D );
1581
1582	fclose(ostream);
1583}
1584
1585
1586void
1587CreateRawQTFont( void )
1588{
1589	FILE  * ostream;
1590	unsigned char fonts[16][256][8];
1591	int row, i;
1592
1593	if ( (ostream = fopen("font.qtif", "wb")) == NULL ) {
1594		fprintf(stderr,"Err: Could not open output index file %s.\n\n", "font.qtif");
1595		exit(1);
1596	}
1597
1598	for (row=0; row<16; row++)
1599	{
1600		for (i=0; i<256; i++)
1601		{
1602			int j;
1603			unsigned char * c;
1604			unsigned char bits;
1605
1606			c = &iso_font[i*16];
1607			bits = c[row];
1608			for (j=7; j>=0; j--)
1609			{
1610				if ( bits & 0x80)
1611					fonts[row][i][j] = fg;
1612				else
1613					fonts[row][i][j] = bg;
1614				bits <<= 1;
1615			}
1616		}
1617	}
1618
1619	WriteQTRawFile( ostream, (unsigned char *) fonts, 16, 256*8, 1, 16*256*8 );
1620	fclose(ostream);
1621}
1622