]>
git.saurik.com Git - apple/xnu.git/blob - osfmk/console/panic_ui/qtif2kraw.c
1 /* converts a QT RAW 8-bit image file into format the kernel panic ui expects.
3 * to build: cc -o qtif2kraw qtif2kraw.c
13 int EncodeImage( unsigned char * data
, int pixels
, unsigned char * fileArr
);
14 int findIndexNearMatch( unsigned int color24
);
15 unsigned int findColor24NearMatch( unsigned int color24
);
16 unsigned char findIndexMatch( unsigned int color24
);
17 int convert8toGrey( unsigned char * data
, unsigned int size
);
18 int convert8bitIndexto8( unsigned char * data
, int height
, int width
, unsigned char ** dout
);
19 unsigned int * CreateCLUTarry( unsigned char * raw_clut
);
20 unsigned int * ReplaceCLUT( char * iname
);
22 #define offsetof(type, field) ((size_t)(&((type *)0)->field))
26 unsigned int pd_dataSize
;
28 unsigned short pd_width
;
29 unsigned short pd_height
;
30 unsigned char pd_depth
;
31 unsigned char pd_info_height
;
32 unsigned char pd_info_color
[2];
42 "\tqtif2kraw -i <.qtif> -o <.kraw> [operands ...]\n\n"
43 "\tThe following operands are available\n\n"
44 "\t-h\t\tDisplay full help information\n"
45 "\t-i <file>\tUse file containing QuickTime uncompressed raw image as\n"
46 "\t\t\tthe panic dialog (8 bit only)\n"
47 "\t-o <file>\tWrite the output as a compressed kernel RAW image suitable\n"
48 "\t\t\tfor loading into the kernel\n"
49 "\t-c <file>\tUse file containing 256 RGB values for 8-bit indexed \n"
50 "\t\t\tlookups, overrides built-in appleClut8\n"
51 "\t-fg <color>\tForeground color of font used for panic information in\n"
52 "\t\t\t24-bits, default 0xFFFFFF (100%% white)\n"
53 "\t-bg <color>\tBackground color of font used for panic information in\n"
54 "\t\t\t24-bits, default 0x222222 (13%% white, dark gray)\n"
55 "\t-n <lines>\tNumber of lines that have been reserved to display the\n"
56 "\t\t\tpanic information, must be at least 20\n"
61 #include "appleclut8.h"
62 #include "../iso_font.c"
65 long idSize
; /* total size of ImageDescription including extra data ( CLUTs and other per sequence data ) */
66 long cType
; /* 'raw '; what kind of codec compressed this data */
67 long resvd1
; /* reserved for Apple use */
68 short resvd2
; /* reserved for Apple use */
69 short dataRefIndex
; /* set to zero */
70 short version
; /* which version is this data */
71 short revisionLevel
; /* what version of that codec did this */
72 long vendor
; /* whose codec compressed this data */
73 long temporalQuality
; /* what was the temporal quality factor */
74 long spatialQuality
; /* what was the spatial quality factor */
75 short width
; /* how many pixels wide is this data */
76 short height
; /* how many pixels high is this data */
77 long hRes
; /* horizontal resolution */
78 long vRes
; /* vertical resolution */
79 long dataSize
; /* if known, the size of data for this image descriptor */
80 short frameCount
; /* number of frames this description applies to */
81 char name
[32]; /* name of codec ( in case not installed ) */
82 short depth
; /* what depth is this data (1-32) or ( 33-40 grayscale ) */
83 short clutID
; /* clut id or if 0 clut follows or -1 if no clut */
86 static unsigned int mismatchClut
[256];
87 static int nextmis
= -1, neargrey
= 0, cvt2grey
= 0, exactmatch
=0;
88 static int grey
= 0, debug
= 0;
89 static unsigned char fg
, bg
;
90 unsigned int * panic_clut
= NULL
;
91 static char * clutin
= NULL
;
105 main( int argc
, char *argv
[] )
110 unsigned char * data
;
111 unsigned short width
= 0, height
= 0;
112 unsigned char depth
= 0, lines
= 20;
113 unsigned int i
, pixels
, sum
, encodedSize
, fg24
= 0xFFFFFF, bg24
=0x222222;
114 unsigned char *fileArr
;
118 // pull apart the arguments
119 for( next
= 1; next
< argc
; next
++ )
121 if (strcmp(argv
[next
], "-i") == 0) // image file in raw QT uncompressed format (.qtif)
124 else if (strcmp(argv
[next
], "-o") == 0) // output file for WHD image
127 else if (strcmp(argv
[next
], "-n") == 0) // numbers of reserved lines
128 lines
= atoi(argv
[++next
]);
129 else if (strcmp(argv
[next
], "-fg") == 0) // foreground color in 24 bits
130 sscanf(argv
[++next
], "%i", &fg24
);
131 else if (strcmp(argv
[next
], "-bg") == 0) // background color in 24 bits
132 sscanf(argv
[++next
], "%i", &bg24
);
133 else if (strcmp(argv
[next
], "-c") == 0) // input file for clut
134 clutin
= argv
[++next
];
135 else if (strcmp(argv
[next
], "-h") == 0) // display more help
136 { usage(1); exit(1); }
138 else if (strcmp(argv
[next
], "-debug") == 0) // verbose
142 if (!(file
|| kraw
) ) {
149 panic_clut
= appleClut8
;
153 panic_clut
= ReplaceCLUT( clutin
);
154 printf("Built-in CLUT has been replaced with %s...\n", clutin
);
157 fg
= findIndexNearMatch(fg24
);
158 bg
= findIndexNearMatch(bg24
);
160 // Begin to process the image
164 printf("No image file was processed...\n\n");
169 printf("Verifing image file...\n");
172 stream
= fopen(file
, "r");
174 fprintf(stderr
, "Err: could not open .qtif image file.\n\n");
183 if ( ! fread((void *) &hdr_off
, sizeof(long), 1, stream
) ) goto errQTimage
;
184 if ( ! fread((void *) &hdr_type
, sizeof(long), 1, stream
) ) goto errQTimage
;
186 if ( hdr_type
!= 'idat' ) goto errQTimage
;
188 if ( fseek(stream
, hdr_off
, SEEK_SET
) ) goto errQTimage
;
189 if ( ! fread((void *) &hdr_off
, sizeof(long), 1, stream
) ) goto errQTimage
;
190 if ( ! fread((void *) &hdr_type
, sizeof(long), 1, stream
) ) goto errQTimage
;
192 if ( hdr_type
!= 'idsc' ) goto errQTimage
;
194 rc
= fread((void *) &image_header
, sizeof(image_header
), 1, stream
);
195 if ( !rc
&& !feof(stream
) ) goto errQTimage
;
196 if ( image_header
.cType
!= 'raw ' ) goto errQTimage
;
197 if ( image_header
.depth
!= 8 ) goto errQTimage
;
200 width
= image_header
.width
;
201 height
= image_header
.height
;
202 depth
= image_header
.depth
;
204 printf("Image info: width: %d height: %d depth: %d...\n", width
, height
, depth
);
206 if (!(width
&& height
&& depth
)) {
207 fprintf(stderr
,"Err: Invalid image file header (width, height, or depth is 0)\n");
212 if ( !(data
= (char *)malloc(image_header
.dataSize
))) {
213 fprintf(stderr
,"Err: Couldn't malloc file data (%ld bytes)... bailing.\n", image_header
.dataSize
);
217 // Read the image data
218 if ( fseek(stream
, 8, SEEK_SET
) ) goto errQTimage
;
219 if ( ! fread((void *) data
, image_header
.dataSize
, 1, stream
) ) goto errQTimage
;
222 pixels
= image_header
.dataSize
;
225 pixels
= convert8toGrey( data
, image_header
.dataSize
);
227 printf("Converting image file to 8 bit raw...\n");
228 pixels
= convert8bitIndexto8( data
, height
, width
, &data
);
229 image_header
.dataSize
= pixels
;
232 printf("Converted %d pixels%s...\n", pixels
/depth
, ((grey
==1)?" to grayscale":""));
233 if ( exactmatch
> 0 )
234 printf("Found %d color mathces in CLUT...\n", exactmatch
);
236 printf("Converted %d colors to gray...\n", cvt2grey
);
238 printf("Adjusted %d grays to best match...\n", neargrey
);
240 printf("Total of %d seperate color mismatches...\n", nextmis
);
243 printf("Encoding image file...\n");
245 if (!(fileArr
= (unsigned char *) malloc(pixels
))) {
246 fprintf(stderr
,"Err: Couldn't malloc fileArr (%d pixels)... bailing.\n", pixels
);
250 encodedSize
= EncodeImage( data
, pixels
, fileArr
);
252 if ( encodedSize
>= pixels
)
254 printf("Skipping encoding...\n");
257 for (sum
=0,i
=0; i
<encodedSize
; i
++)
263 // write raw image suitable for kernel panic dialog
269 if ( (ostream
= fopen(kraw
, "wb")) == NULL
) {
270 fprintf(stderr
,"Err: Could not open output file %s.\n\n", kraw
);
274 printf("Writing to binary panic dialog file %s, which is suitable for loading into kernel...\n", kraw
);
276 tag
= 'RNMp'; // Raw NMage for Panic dialog
277 depth
= 1; // only CLUT is supported
279 fwrite(&sum
, sizeof(sum
), 1, ostream
);
281 encodedSize
+= (256*3);
282 fwrite(&encodedSize
, sizeof(encodedSize
), 1, ostream
);
284 fwrite(&tag
, sizeof(tag
), 1, ostream
);
285 fwrite(&width
, sizeof(width
), 1, ostream
);
286 fwrite(&height
, sizeof(height
), 1, ostream
);
287 fwrite(&depth
, sizeof(depth
), 1, ostream
);
288 fwrite(&lines
, sizeof(lines
), 1, ostream
);
289 fwrite(&fg
, sizeof(fg
), 1, ostream
);
290 fwrite(&bg
, sizeof(bg
), 1, ostream
);
291 fwrite(fileArr
, encodedSize
, 1, ostream
);
293 for ( i
=0; i
<256; i
++)
296 unsigned char arr
[3];
298 c
.c24
= panic_clut
[i
];
301 arr
[1] = c
.clut
.green
;
302 arr
[2] = c
.clut
.blue
;
303 fwrite(arr
, 3, 1, ostream
);
311 fprintf(stderr
,"Err: Input image must be in the QuickTime Raw Uncompressed 256 Colors format\n");
317 #define RUN_MAX ((1<<20)-1)
324 unsigned int encode_rle(
325 unsigned char * fileArr
,
326 unsigned int filePos
,
327 unsigned int quantity
,
328 union RunData
* value
,
332 compareruns( unsigned char * data
, unsigned int * index
, unsigned int max
, union RunData
* currP
, int * depth
)
334 union RunData
* nextP
;
337 if ( currP
== NULL
|| data
== NULL
)
343 if ( (*index
+*depth
) > max
)
350 nextP
= (union RunData
*) &data
[*index
];
354 // check current data against current depth
358 if ( nextP
->c
[0] == currP
->c
[0] )
362 if ( nextP
->c
[0] == currP
->c
[0] &&
363 nextP
->c
[1] == currP
->c
[1] )
367 if ( nextP
->c
[0] == currP
->c
[0] &&
368 nextP
->c
[1] == currP
->c
[1] &&
369 nextP
->c
[2] == currP
->c
[2] )
373 if ( nextP
->c
[0] == currP
->c
[0] &&
374 nextP
->c
[1] == currP
->c
[1] &&
375 nextP
->c
[2] == currP
->c
[2] &&
376 nextP
->c
[3] == currP
->c
[3] )
385 // start of a new pattern match begine with depth = 1
387 if ( (*index
+6) <= max
)
389 // We have at least 8 bytes left in the buffer starting from currP
391 nextP
= (union RunData
*) &data
[*index
+3];
392 if ( nextP
->c
[0] == currP
->c
[0] &&
393 nextP
->c
[1] == currP
->c
[1] &&
394 nextP
->c
[2] == currP
->c
[2] &&
395 nextP
->c
[3] == currP
->c
[3] )
397 // check if they are all the same value
398 if ( currP
->c
[0] == currP
->c
[1] &&
399 currP
->c
[1] == currP
->c
[2] &&
400 currP
->c
[2] == currP
->c
[3] )
401 { // if so, leave at depth = 1
407 if (debug
>2) printf("Found 4 at %x\n", *index
);
414 nextP
= (union RunData
*) &data
[*index
+2];
415 if ( nextP
->c
[0] == currP
->c
[0] &&
416 nextP
->c
[1] == currP
->c
[1] &&
417 nextP
->c
[2] == currP
->c
[2] )
419 // check if they are all the same value
420 if ( currP
->c
[0] == currP
->c
[1] &&
421 currP
->c
[1] == currP
->c
[2] )
422 { // if so, leave at depth = 1
428 if (debug
>2) printf("Found 3 at %x\n", *index
);
435 nextP
= (union RunData
*) &data
[*index
+1];
436 if ( nextP
->c
[0] == currP
->c
[0] &&
437 nextP
->c
[1] == currP
->c
[1] )
439 // check if they are all the same value
440 if ( currP
->c
[0] == currP
->c
[1] )
441 { // if so, leave at depth = 1
447 if (debug
>2) printf("Found 2 at %x\n", *index
);
455 nextP
= (union RunData
*) &data
[*index
];
459 if ( nextP
->c
[0] == currP
->c
[0] )
473 EncodeImage( unsigned char * data
, int pixels
, unsigned char * fileArr
)
475 union RunData
* currP
, * norunP
;
477 unsigned int filePos
, run
, nomatchrun
;
482 filePos
= 0; // position in the file we're writing out
486 currP
= (union RunData
*)&data
[0]; // start a new run
487 for (i
=1; i
<pixels
;) {
488 if ( compareruns( data
, &i
, pixels
, currP
, &depth
) )
491 if ( (run
*depth
) > 2 ) {
492 unsigned char * p
= (unsigned char *)norunP
;
498 cnt
= (nomatchrun
> 127) ? 127 : nomatchrun
;
499 fileArr
[filePos
++] = cnt
;
503 fileArr
[filePos
++] = *p
++;
507 filePos
+= encode_rle(fileArr
, filePos
, run
, currP
, depth
);
514 currP
= (union RunData
*)&data
[i
]; // start a new run
516 if( norunP
== NULL
) {
521 depth
= 1; // switch back to a single byte depth
522 run
= 1; // thee is always at least one entry
523 i
++; // point to next byte
528 unsigned char * p
= (unsigned char *)norunP
;
532 cnt
= (nomatchrun
> 127) ? 127 : nomatchrun
;
533 fileArr
[filePos
++] = cnt
;
537 fileArr
[filePos
++] = *p
++;
541 // write out any run that was in progress
543 filePos
+= encode_rle(fileArr
, filePos
, run
, currP
, depth
);
549 /* encode_rle applies a "modified-RLE encoding to a given image. The encoding works as follows:
551 The quantity is described in the first byte. If the MSB is zero, then the next seven bits
552 are the quantity. If the MSB is set, bits 0-3 of the quantity are in the least significant bits.
553 If bit 5 is set, then the quantity is further described in the next byte, where an additional
554 7 bits (4-10) worth of quantity will be found. If the MSB of this byte is set, then an additional
555 7 bits (11-17) worth of quantity will be found in the next byte. This repeats until the MSB of
556 a quantity byte is zero, thus ending the chain.
558 The value is described in the first byte. If the MSB is zero, then the value is in the next byte.
559 If the MSB is set, then bits 5/6 describe the number of value bytes following the quantity bytes.
561 encodings are: (q = quantity, v = value, c = quantity continues)
563 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 Byte 7 Byte 8
564 case 1: [ 0 q6-q0 ] [ v7-v0 ]
565 case 2: [ 1 0 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ]
566 case 3: [ 1 0 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ]
567 case 4: [ 1 1 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
568 case 5: [ 1 1 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
572 encode_length(unsigned char * fileArr
, unsigned int filePos
, unsigned int quantity
, unsigned int mask
)
574 unsigned char single_mask
= 0x0F;
575 unsigned char double_mask
= 0x7F;
576 unsigned int slots_used
= 0;
578 fileArr
[filePos
] = mask
| (quantity
& single_mask
); // low bits (plus mask)
581 if (quantity
>>= 4) {
582 fileArr
[filePos
++] |= 0x10; // set length continuation bit
583 fileArr
[filePos
] = quantity
& double_mask
;
586 while (quantity
>>= 7) {
587 fileArr
[filePos
++] |= 0x80; // set length continuation bit
588 fileArr
[filePos
] = quantity
& double_mask
;
598 encode_rle(unsigned char * fileArr
, unsigned int filePos
, unsigned int quantity
, union RunData
* value
, int depth
)
600 unsigned char slots_used
= 0;
605 slots_used
+= encode_length( fileArr
, filePos
, quantity
, 0x80 );
606 fileArr
[filePos
+slots_used
++] = value
->c
[0];
610 slots_used
+= encode_length( fileArr
, filePos
, quantity
, 0xA0 );
611 fileArr
[filePos
+slots_used
++] = value
->c
[0];
612 fileArr
[filePos
+slots_used
++] = value
->c
[1];
616 slots_used
+= encode_length( fileArr
, filePos
, quantity
, 0xC0 );
617 fileArr
[filePos
+slots_used
++] = value
->c
[0];
618 fileArr
[filePos
+slots_used
++] = value
->c
[1];
619 fileArr
[filePos
+slots_used
++] = value
->c
[2];
623 slots_used
+= encode_length( fileArr
, filePos
, quantity
, 0xE0 );
624 fileArr
[filePos
+slots_used
++] = value
->c
[0];
625 fileArr
[filePos
+slots_used
++] = value
->c
[1];
626 fileArr
[filePos
+slots_used
++] = value
->c
[2];
627 fileArr
[filePos
+slots_used
++] = value
->c
[3];
636 findIndexNearMatch( unsigned int color24
)
642 color8
.c24
= color24
;
644 if ( color8
.clut
.red
== color8
.clut
.green
&& color8
.clut
.green
== color8
.clut
.blue
)
649 unsigned int bestIndex
= 0, rel
, bestMatch
= -1;
651 for (i
=0; i
<256; i
++) {
652 clut8
.c24
= panic_clut
[i
];
654 if ( clut8
.clut
.red
!= clut8
.clut
.green
|| clut8
.clut
.green
!= clut8
.clut
.blue
)
657 if ( clut8
.clut
.red
> color8
.clut
.red
) continue;
658 rel
= abs(color8
.clut
.red
- clut8
.clut
.red
);
659 if ( rel
< bestMatch
) {
668 // we must have a non-grey color
673 color24toGrey( unsigned int color24
)
683 R
= (c
.clut
.red
& 0xFF) ;
684 G
= (c
.clut
.green
& 0xFF) ;
685 B
= (c
.clut
.blue
& 0xFF) ;
687 Grey
= (R
*.30) + (G
*.59) + (B
*.11);
688 grey8
= (unsigned char) ( Grey
+ .5);
689 grey24
= (grey8
<<16) | (grey8
<<8) | grey8
;
695 convert8toGrey( unsigned char * data
, unsigned int size
)
701 for ( i
=0; i
<size
; i
++) {
702 c
.c24
= panic_clut
[data
[i
]];
703 c24
= color24toGrey( c
.c24
);
704 data
[i
] = findIndexMatch( c24
);
711 findColor24NearMatch( unsigned int color24
)
715 static unsigned int last_c
= -1, last_co
= -1, last_p
= -1;
717 if ( last_c
== color24
)
722 if ( c
.rgb
[1] > c
.rgb
[2] && c
.rgb
[1] > c
.rgb
[3] )
724 else if ( c
.rgb
[2] > c
.rgb
[1] && c
.rgb
[2] > c
.rgb
[3] )
726 else if ( c
.rgb
[3] > c
.rgb
[1] && c
.rgb
[3] > c
.rgb
[2] )
728 else if ( c
.rgb
[1] == c
.rgb
[2] && c
.rgb
[1] == c
.rgb
[3] )
730 else if ( c
.rgb
[1] == c
.rgb
[2] )
731 prim
= 0x12; // red green
732 else if ( c
.rgb
[1] == c
.rgb
[3] )
733 prim
= 0x13; // red blue
734 else if ( c
.rgb
[2] == c
.rgb
[3] )
735 prim
= 0x23; // green blue
737 printf("cannot tell color %06x\n", color24
);
742 if ( prim
== 0 || prim
> 3 )
753 findIndexMatch( unsigned int color24
)
757 static unsigned char last
= 0;
760 if ( panic_clut
[last
] == color24
)
766 for (i
=0; i
<256; i
++)
768 if ( panic_clut
[i
] == color24
) {
775 if ( nextmis
== -1 ) {
776 for (i
=0; i
<256; i
++) mismatchClut
[i
] = -1;
780 i
= findIndexNearMatch(color24
);
782 if ( i
== -1 ) // found a color that is not grey
784 unsigned int colormatch
= findColor24NearMatch( color24
);
786 if ( colormatch
== -1 ) // cannot convert color
789 if (debug
>1) printf("color %06X not matched at all\n", color24
);
790 color24
= color24toGrey(color24
);
791 if (debug
>1) printf("now grey %06X\n", color24
);
794 color24
= colormatch
;
799 if (debug
>1) printf("color %06X now matched at %x\n", color24
, i
);
805 // keep track of missed repeats
806 for ( i
=0; i
<nextmis
; i
++)
807 if ( mismatchClut
[i
] == color24
)
810 if ( debug
) printf("closest match for %06X is at index %d %06X\n", color24
, ri
, panic_clut
[ri
]);
812 mismatchClut
[nextmis
++] = color24
;
814 if ( debug
&& (nextmis
>= 256) )
816 fprintf(stderr
,"Err: Too many color mismatches detected with this CLUT\n");
824 * Convert 8 bit mode to 8 bit, We have to strip off the alignment bytes
828 convert8bitIndexto8( unsigned char * data
, int height
, int width
, unsigned char ** dout
)
830 unsigned int row
, col
, i
, i8
, size
, adj
;
832 unsigned char * ddata
;
833 union colors color24
;
835 adj
=(4-(width%4
))%4
; // adjustment needed to strip off the word alignment padding
836 size
= height
* width
;
837 ddata
= (unsigned char *) calloc( size
, 1);
839 for (i8
=0,row
=0; row
<height
; row
++)
841 for (col
=0; col
<width
; col
++)
844 color24
.c24
= panic_clut
[index
];
845 index
= findIndexMatch( color24
.c24
);
849 for (i
=0; i
<adj
; i
++)
860 CreateCLUTarry( unsigned char * raw_clut
)
862 unsigned int * new_clut
, index
, i
;
864 new_clut
= (unsigned int *) calloc(256, sizeof(unsigned int));
865 for ( index
=0,i
=0; i
<256; index
+=3,i
++ )
866 new_clut
[i
] = (raw_clut
[index
] << 16) | (raw_clut
[index
+1] << 8) | raw_clut
[index
+2];
873 ReplaceCLUT( char * iname
)
876 unsigned char * raw_clut
;
877 unsigned int * new_clut
;
879 if ( (stream
= fopen(iname
, "rb")) == NULL
) {
880 fprintf(stderr
,"Err: Could not open input clut file %s.\n\n", iname
);
884 raw_clut
= (char *) calloc(256, 3);
885 fread(raw_clut
, 256, 3, stream
);
888 new_clut
= CreateCLUTarry( raw_clut
);