]>
Commit | Line | Data |
---|---|---|
91447636 A |
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 | ||
14 | int EncodeImage( | |
15 | unsigned char * data, | |
16 | int pixels, | |
17 | unsigned char * fileArr ); | |
18 | int decode_rle( | |
19 | unsigned char * dataPtr, | |
20 | unsigned int * quantity, | |
21 | unsigned int * depth, | |
22 | unsigned char ** value ); | |
23 | int findIndexNearMatch( | |
24 | unsigned int color24 ); | |
25 | unsigned char findIndexMatch( | |
26 | unsigned int color24 ); | |
27 | int convert24toGrey( | |
28 | unsigned char * data, | |
29 | unsigned int size ); | |
30 | int convert8toGrey( | |
31 | unsigned char * data, | |
32 | unsigned int size ); | |
33 | int convert8bitIndexto24( | |
34 | unsigned char * data, | |
35 | int height, | |
36 | int width, | |
37 | unsigned char ** dout ); | |
38 | int convert8bitIndexto8( | |
39 | unsigned char * data, | |
40 | int height, | |
41 | int width, | |
42 | unsigned char ** dout ); | |
43 | int convert24to8bitIndex( | |
44 | unsigned char * data, | |
45 | int height, | |
46 | int width, | |
47 | unsigned char ** dout ); | |
48 | unsigned int * CreateCLUTarry( | |
49 | unsigned char * raw_clut ); | |
50 | unsigned int * ReplaceCLUT( | |
51 | char * iname ); | |
52 | void GenerateCLUT( | |
53 | char * oname ); | |
54 | void WriteQTRawFile( | |
55 | FILE * ostream, | |
56 | unsigned char * data, | |
57 | int height, | |
58 | int width, | |
59 | int depth, | |
60 | unsigned int size ); | |
61 | void CreateRawQTFont( | |
62 | void ); | |
63 | void CreateRawQTCLUT( | |
64 | int type ); | |
65 | ||
66 | #define offsetof(type, field) ((size_t)(&((type *)0)->field)) | |
67 | ||
68 | struct 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 | ||
83 | void | |
84 | usage( int type ) { | |
85 | printf( | |
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" ); | |
117 | if ( type > 0 ) | |
118 | printf( | |
119 | "\ | |
120 | This utility is used to convert a panic dialog from .qtif format, into\n\ | |
121 | one that is suitable for the kernel to display. The .qtif image file\n\ | |
122 | can be in either 24 or 8 bit mode, but must be in an uncompressed raw\n\ | |
123 | format. 8 bit mode is preferred, as it requires no conversion to the\n\ | |
124 | colors that are contained in the CLUT. If a color cannot be found in\n\ | |
125 | the CLUT, it will be converted to the nearest gray. The default CLUT\n\ | |
126 | is the same as the system CLUT. If needed, this can be overridden by\n\ | |
127 | providing a new CLUT with the -c option.\n\ | |
128 | \n\ | |
129 | However, if you override the default CLUT. The panic UI may not appear\n\ | |
130 | as you intended, when the systme is in 8 bit mode. Colors that are not\n\ | |
131 | present in the active CLUT, will be converted to the nearest gray.\n\ | |
132 | \n\ | |
133 | The panic dialog must have a number of lines reserved at the bottom for\n\ | |
134 | displaying additional panic information. The minimum number of lines\n\ | |
135 | is 20. The font use to display this information needs to have the\n\ | |
136 | foreground and background colors defined. The defaults are full white\n\ | |
137 | on dark gray. This can be changed by using the -fg and/or -bg options to\n\ | |
138 | provide new 24 bit colors. These colors must be contained in the CLUT.\n\ | |
139 | \n\ | |
140 | There are two possible output results. The default is to create a C\n\ | |
141 | source file named panic_image.c that contains the panic image in a 8 bit\n\ | |
142 | modified RLE compressed format and the CLUT that was used to create the\n\ | |
143 | image. The second possibility is to create a binary version of the same\n\ | |
144 | information by using the -o option. This file can then be used to replace\n\ | |
145 | the panic dialog that is currently active in the kernel by using\n\ | |
146 | sysctl(KERN_PANIC_INFO).\n\ | |
147 | \n\n"); | |
148 | } | |
149 | ||
150 | ||
151 | #include "appleclut8.h" | |
152 | #include "../iso_font.c" | |
153 | ||
154 | struct 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 | ||
176 | static unsigned int mismatchClut[256]; | |
177 | static int nextmis = -1, neargrey = 0, cvt2grey = 0, exactmatch=0; | |
178 | static int grey = 0, debug = 0, testfont = 0, testclut = 0; | |
179 | static int convert = 8; // default is to convert image to 8 bit uncompressed .tgif | |
180 | static unsigned char fg, bg; | |
181 | unsigned int * panic_clut = NULL; | |
182 | static char * clutin = NULL; | |
183 | ||
184 | union 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 | ||
195 | int | |
196 | main( 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 | ||
691 | leaveOK: | |
692 | printf("\n"); | |
693 | return 0; | |
694 | ||
695 | errQTimage: | |
696 | fprintf(stderr,"Err: Image must be in the QuickTime Raw Uncompressed Millions or 256 Colors format\n"); | |
697 | exit(1); | |
698 | errWHDimage: | |
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 | ||
707 | union RunData { | |
708 | unsigned int i; | |
709 | unsigned char c[4]; | |
710 | }; | |
711 | ||
712 | unsigned int encode_rle( | |
713 | unsigned char * fileArr, | |
714 | unsigned int filePos, | |
715 | unsigned int quantity, | |
716 | union RunData * value, | |
717 | int depth); | |
718 | ||
719 | int | |
720 | compareruns( 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 | ||
853 | Leave: | |
854 | ||
855 | if ( retc == 1 ) | |
856 | *index += *depth; | |
857 | ||
858 | return retc; | |
859 | } | |
860 | ||
861 | int | |
862 | EncodeImage( 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 | ||
970 | unsigned int | |
971 | encode_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 | ||
998 | unsigned int | |
999 | encode_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 | ||
1038 | int | |
1039 | decode_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 | ||
1076 | int | |
1077 | findIndexNearMatch( 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 | ||
1114 | unsigned int | |
1115 | color24toGrey( 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 | ||
1135 | int | |
1136 | convert24toGrey( 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 | ||
1161 | int | |
1162 | convert8toGrey( 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 | ||
1178 | unsigned int | |
1179 | findColor24NearMatch( 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 | ||
1228 | unsigned char | |
1229 | findIndexMatch( unsigned int color24 ) | |
1230 | { | |
1231 | int i; | |
1232 | unsigned char ri; | |
1233 | static unsigned char last = 0; | |
1234 | ||
1235 | retry: | |
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 | ||
1303 | int | |
1304 | convert24to8bitIndex( 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 | ||
1337 | int | |
1338 | convert8bitIndexto8( 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 | ||
1371 | int | |
1372 | convert8bitIndexto24( 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 | ||
1405 | unsigned int * | |
1406 | CreateCLUTarry( 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 | ||
1418 | unsigned int * | |
1419 | ReplaceCLUT( 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 | ||
1441 | void | |
1442 | GenerateCLUT( 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 | ||
1467 | void | |
1468 | WriteQTRawFile( 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 | strcpy(image_header.name, " None"); | |
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 | ||
1530 | void | |
1531 | CreateRawQTCLUT( 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 | ||
1586 | void | |
1587 | CreateRawQTFont( 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 | } |