/* converts a QT RAW 8-bit image file into format the kernel panic ui expects. * * to build: cc -o qtif2kraw qtif2kraw.c */ #include #include #include #include #include #include int EncodeImage( unsigned char * data, int pixels, unsigned char * fileArr ); int findIndexNearMatch( unsigned int color24 ); unsigned int findColor24NearMatch( unsigned int color24 ); unsigned char findIndexMatch( unsigned int color24 ); int convert8toGrey( unsigned char * data, unsigned int size ); int convert8bitIndexto8( unsigned char * data, int height, int width, unsigned char ** dout ); unsigned int * CreateCLUTarry( unsigned char * raw_clut ); unsigned int * ReplaceCLUT( char * iname ); #define offsetof(type, field) ((size_t)(&((type *)0)->field)) struct panicimage { unsigned int pd_sum; unsigned int pd_dataSize; unsigned int pd_tag; unsigned short pd_width; unsigned short pd_height; unsigned char pd_depth; unsigned char pd_info_height; unsigned char pd_info_color[2]; unsigned char data[]; }; void usage( int type ) { printf( "\n" "Usage:\n" "\tqtif2kraw -i <.qtif> -o <.kraw> [operands ...]\n\n" "\tThe following operands are available\n\n" "\t-h\t\tDisplay full help information\n" "\t-i \tUse file containing QuickTime uncompressed raw image as\n" "\t\t\tthe panic dialog (8 bit only)\n" "\t-o \tWrite the output as a compressed kernel RAW image suitable\n" "\t\t\tfor loading into the kernel\n" "\t-c \tUse file containing 256 RGB values for 8-bit indexed \n" "\t\t\tlookups, overrides built-in appleClut8\n" "\t-fg \tForeground color of font used for panic information in\n" "\t\t\t24-bits, default 0xFFFFFF (100%% white)\n" "\t-bg \tBackground color of font used for panic information in\n" "\t\t\t24-bits, default 0x222222 (13%% white, dark gray)\n" "\t-n \tNumber of lines that have been reserved to display the\n" "\t\t\tpanic information, must be at least 20\n" "\n\n" ); } #include "appleclut8.h" #include "../iso_font.c" struct QTHeader { long idSize; /* total size of ImageDescription including extra data ( CLUTs and other per sequence data ) */ long cType; /* 'raw '; what kind of codec compressed this data */ long resvd1; /* reserved for Apple use */ short resvd2; /* reserved for Apple use */ short dataRefIndex; /* set to zero */ short version; /* which version is this data */ short revisionLevel; /* what version of that codec did this */ long vendor; /* whose codec compressed this data */ long temporalQuality; /* what was the temporal quality factor */ long spatialQuality; /* what was the spatial quality factor */ short width; /* how many pixels wide is this data */ short height; /* how many pixels high is this data */ long hRes; /* horizontal resolution */ long vRes; /* vertical resolution */ long dataSize; /* if known, the size of data for this image descriptor */ short frameCount; /* number of frames this description applies to */ char name[32]; /* name of codec ( in case not installed ) */ short depth; /* what depth is this data (1-32) or ( 33-40 grayscale ) */ short clutID; /* clut id or if 0 clut follows or -1 if no clut */ } image_header; static unsigned int mismatchClut[256]; static int nextmis = -1, neargrey = 0, cvt2grey = 0, exactmatch=0; static int grey = 0, debug = 0; static unsigned char fg, bg; unsigned int * panic_clut = NULL; static char * clutin = NULL; union colors { unsigned int c24; unsigned char rgb[4]; struct { unsigned char dummy; unsigned char red; unsigned char green; unsigned char blue; } clut; }; int main( int argc, char *argv[] ) { char *file = NULL; char *kraw = NULL; FILE * stream; unsigned char * data; unsigned short width = 0, height = 0; unsigned char depth = 0, lines = 20; unsigned int i, pixels, sum, encodedSize, fg24= 0xFFFFFF, bg24=0x222222; unsigned char *fileArr; int next; // pull apart the arguments for( next = 1; next < argc; next++ ) { if (strcmp(argv[next], "-i") == 0) // image file in raw QT uncompressed format (.qtif) file = argv[++next]; else if (strcmp(argv[next], "-o") == 0) // output file for WHD image kraw = argv[++next]; else if (strcmp(argv[next], "-n") == 0) // numbers of reserved lines lines = atoi(argv[++next]); else if (strcmp(argv[next], "-fg") == 0) // foreground color in 24 bits sscanf(argv[++next], "%i", &fg24); else if (strcmp(argv[next], "-bg") == 0) // background color in 24 bits sscanf(argv[++next], "%i", &bg24); else if (strcmp(argv[next], "-c") == 0) // input file for clut clutin = argv[++next]; else if (strcmp(argv[next], "-h") == 0) // display more help { usage(1); exit(1); } else if (strcmp(argv[next], "-debug") == 0) // verbose debug++; } if (!(file || kraw) ) { usage(0); exit(1); } printf("\n"); panic_clut = appleClut8; if ( clutin ) { panic_clut = ReplaceCLUT( clutin ); printf("Built-in CLUT has been replaced with %s...\n", clutin); } fg = findIndexNearMatch(fg24); bg = findIndexNearMatch(bg24); // Begin to process the image if( file == NULL) { printf("No image file was processed...\n\n"); exit(0); } printf("Verifing image file...\n"); if ( file != NULL ) { stream = fopen(file, "r"); if (!stream) { fprintf(stderr, "Err: could not open .qtif image file.\n\n"); exit(1); } { long hdr_off; long hdr_type; int rc; if ( ! fread((void *) &hdr_off, sizeof(long), 1, stream) ) goto errQTimage; if ( ! fread((void *) &hdr_type, sizeof(long), 1, stream) ) goto errQTimage; if ( hdr_type != 'idat' ) goto errQTimage; if ( fseek(stream, hdr_off, SEEK_SET) ) goto errQTimage; if ( ! fread((void *) &hdr_off, sizeof(long), 1, stream) ) goto errQTimage; if ( ! fread((void *) &hdr_type, sizeof(long), 1, stream) ) goto errQTimage; if ( hdr_type != 'idsc' ) goto errQTimage; rc = fread((void *) &image_header, sizeof(image_header), 1, stream); if ( !rc && !feof(stream) ) goto errQTimage; if ( image_header.cType != 'raw ' ) goto errQTimage; if ( image_header.depth != 8 ) goto errQTimage; width = image_header.width; height = image_header.height; depth = image_header.depth; printf("Image info: width: %d height: %d depth: %d...\n", width, height, depth); if (!(width && height && depth)) { fprintf(stderr,"Err: Invalid image file header (width, height, or depth is 0)\n"); exit(1); } } if ( !(data = (char *)malloc(image_header.dataSize))) { fprintf(stderr,"Err: Couldn't malloc file data (%ld bytes)... bailing.\n", image_header.dataSize); exit(1); } // Read the image data if ( fseek(stream, 8, SEEK_SET) ) goto errQTimage; if ( ! fread((void *) data, image_header.dataSize, 1, stream) ) goto errQTimage; fclose( stream ); pixels = image_header.dataSize; if ( grey == 1 ) pixels = convert8toGrey( data, image_header.dataSize ); printf("Converting image file to 8 bit raw...\n"); pixels = convert8bitIndexto8( data, height, width, &data ); image_header.dataSize = pixels; depth = 1; printf("Converted %d pixels%s...\n", pixels/depth, ((grey==1)?" to grayscale":"")); if ( exactmatch > 0 ) printf("Found %d color mathces in CLUT...\n", exactmatch); if ( cvt2grey > 0 ) printf("Converted %d colors to gray...\n", cvt2grey); if ( neargrey > 0 ) printf("Adjusted %d grays to best match...\n", neargrey); if ( nextmis > 0 ) printf("Total of %d seperate color mismatches...\n", nextmis); } printf("Encoding image file...\n"); if (!(fileArr = (unsigned char *) malloc(pixels))) { fprintf(stderr,"Err: Couldn't malloc fileArr (%d pixels)... bailing.\n", pixels); exit(1); } encodedSize = EncodeImage( data, pixels, fileArr ); if ( encodedSize >= pixels ) { printf("Skipping encoding...\n"); } for (sum=0,i=0; i max ) { *depth = 1; retc = 0; goto Leave; } nextP = (union RunData *) &data[*index]; if ( retc == 1 ) { // check current data against current depth switch ( *depth ) { case 1: if ( nextP->c[0] == currP->c[0] ) goto Leave; break; case 2: if ( nextP->c[0] == currP->c[0] && nextP->c[1] == currP->c[1] ) goto Leave; break; case 3: if ( nextP->c[0] == currP->c[0] && nextP->c[1] == currP->c[1] && nextP->c[2] == currP->c[2] ) goto Leave; break; case 4: if ( nextP->c[0] == currP->c[0] && nextP->c[1] == currP->c[1] && nextP->c[2] == currP->c[2] && nextP->c[3] == currP->c[3] ) goto Leave; break; } retc = 0; goto Leave; } // start of a new pattern match begine with depth = 1 if ( (*index+6) <= max ) { // We have at least 8 bytes left in the buffer starting from currP #if 1 nextP = (union RunData *) &data[*index+3]; if ( nextP->c[0] == currP->c[0] && nextP->c[1] == currP->c[1] && nextP->c[2] == currP->c[2] && nextP->c[3] == currP->c[3] ) { // check if they are all the same value if ( currP->c[0] == currP->c[1] && currP->c[1] == currP->c[2] && currP->c[2] == currP->c[3] ) { // if so, leave at depth = 1 retc = 1; *depth = 1; goto Leave; } if (debug>2) printf("Found 4 at %x\n", *index); retc = 1; *depth = 4; *index += 3; goto Leave; } nextP = (union RunData *) &data[*index+2]; if ( nextP->c[0] == currP->c[0] && nextP->c[1] == currP->c[1] && nextP->c[2] == currP->c[2] ) { // check if they are all the same value if ( currP->c[0] == currP->c[1] && currP->c[1] == currP->c[2] ) { // if so, leave at depth = 1 retc = 1; *depth = 1; goto Leave; } if (debug>2) printf("Found 3 at %x\n", *index); retc = 1; *depth = 3; *index += 2; goto Leave; } nextP = (union RunData *) &data[*index+1]; if ( nextP->c[0] == currP->c[0] && nextP->c[1] == currP->c[1] ) { // check if they are all the same value if ( currP->c[0] == currP->c[1] ) { // if so, leave at depth = 1 retc = 1; *depth = 1; goto Leave; } if (debug>2) printf("Found 2 at %x\n", *index); retc = 1; *depth = 2; *index += 1; goto Leave; } #endif nextP = (union RunData *) &data[*index]; } if ( nextP->c[0] == currP->c[0] ) retc = 1; else retc = 0; Leave: if ( retc == 1 ) *index += *depth; return retc; } int EncodeImage( unsigned char * data, int pixels, unsigned char * fileArr ) { union RunData * currP, * norunP ; int i, depth; unsigned int filePos, run, nomatchrun; currP = NULL; norunP = NULL; nomatchrun = 0; filePos = 0; // position in the file we're writing out run = 1; depth = 1; currP = (union RunData *)&data[0]; // start a new run for (i=1; i 2 ) { unsigned char * p = (unsigned char *)norunP; if( nomatchrun ) { while (nomatchrun) { int cnt; cnt = (nomatchrun > 127) ? 127 : nomatchrun; fileArr[filePos++] = cnt; nomatchrun -= cnt; while ( cnt-- ) fileArr[filePos++] = *p++; } } filePos += encode_rle(fileArr, filePos, run, currP, depth); norunP = NULL; } else { nomatchrun+=run; } currP = (union RunData *)&data[i]; // start a new run if( norunP == NULL ) { nomatchrun = 0; norunP = currP; } depth = 1; // switch back to a single byte depth run = 1; // thee is always at least one entry i++; // point to next byte } } if( nomatchrun ) { unsigned char * p = (unsigned char *)norunP; while (nomatchrun) { int cnt; cnt = (nomatchrun > 127) ? 127 : nomatchrun; fileArr[filePos++] = cnt; nomatchrun -= cnt; while ( cnt-- ) fileArr[filePos++] = *p++; } } // write out any run that was in progress if (run > 0) { filePos += encode_rle(fileArr, filePos, run, currP, depth); } return filePos; } /* encode_rle applies a "modified-RLE encoding to a given image. The encoding works as follows: The quantity is described in the first byte. If the MSB is zero, then the next seven bits are the quantity. If the MSB is set, bits 0-3 of the quantity are in the least significant bits. If bit 5 is set, then the quantity is further described in the next byte, where an additional 7 bits (4-10) worth of quantity will be found. If the MSB of this byte is set, then an additional 7 bits (11-17) worth of quantity will be found in the next byte. This repeats until the MSB of a quantity byte is zero, thus ending the chain. The value is described in the first byte. If the MSB is zero, then the value is in the next byte. If the MSB is set, then bits 5/6 describe the number of value bytes following the quantity bytes. encodings are: (q = quantity, v = value, c = quantity continues) Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 Byte 7 Byte 8 case 1: [ 0 q6-q0 ] [ v7-v0 ] case 2: [ 1 0 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] case 3: [ 1 0 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] case 4: [ 1 1 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ] case 5: [ 1 1 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ] */ unsigned int encode_length(unsigned char * fileArr, unsigned int filePos, unsigned int quantity, unsigned int mask) { unsigned char single_mask = 0x0F; unsigned char double_mask = 0x7F; unsigned int slots_used = 0; fileArr[filePos] = mask | (quantity & single_mask); // low bits (plus mask) slots_used++; if (quantity >>= 4) { fileArr[filePos++] |= 0x10; // set length continuation bit fileArr[filePos] = quantity & double_mask; slots_used++; while (quantity >>= 7) { fileArr[filePos++] |= 0x80; // set length continuation bit fileArr[filePos] = quantity & double_mask; slots_used++; } } return slots_used; } unsigned int encode_rle(unsigned char * fileArr, unsigned int filePos, unsigned int quantity, union RunData * value, int depth) { unsigned char slots_used = 0; switch ( depth ) { case 1: slots_used += encode_length( fileArr, filePos, quantity, 0x80 ); fileArr[filePos+slots_used++] = value->c[0]; break; case 2: slots_used += encode_length( fileArr, filePos, quantity, 0xA0 ); fileArr[filePos+slots_used++] = value->c[0]; fileArr[filePos+slots_used++] = value->c[1]; break; case 3: slots_used += encode_length( fileArr, filePos, quantity, 0xC0 ); fileArr[filePos+slots_used++] = value->c[0]; fileArr[filePos+slots_used++] = value->c[1]; fileArr[filePos+slots_used++] = value->c[2]; break; case 4: slots_used += encode_length( fileArr, filePos, quantity, 0xE0 ); fileArr[filePos+slots_used++] = value->c[0]; fileArr[filePos+slots_used++] = value->c[1]; fileArr[filePos+slots_used++] = value->c[2]; fileArr[filePos+slots_used++] = value->c[3]; break; } return slots_used; } int findIndexNearMatch( unsigned int color24 ) { union colors color8; union colors clut8; int isGrey = 0; color8.c24 = color24; if ( color8.clut.red == color8.clut.green && color8.clut.green == color8.clut.blue ) isGrey = 1; if ( isGrey ) { int i; unsigned int bestIndex = 0, rel, bestMatch = -1; for (i=0; i<256; i++) { clut8.c24 = panic_clut[i]; if ( clut8.clut.red != clut8.clut.green || clut8.clut.green != clut8.clut.blue ) continue; if ( clut8.clut.red > color8.clut.red) continue; rel = abs(color8.clut.red - clut8.clut.red); if ( rel < bestMatch ) { bestMatch = rel; bestIndex = i; } } return bestIndex; } // we must have a non-grey color return -1; } unsigned int color24toGrey( unsigned int color24 ) { float R, G, B; float Grey; union colors c; unsigned char grey8; unsigned int grey24; c.c24 = color24; R = (c.clut.red & 0xFF) ; G = (c.clut.green & 0xFF) ; B = (c.clut.blue & 0xFF) ; Grey = (R*.30) + (G*.59) + (B*.11); grey8 = (unsigned char) ( Grey + .5); grey24 = (grey8<<16) | (grey8<<8) | grey8; return grey24; } int convert8toGrey( unsigned char * data, unsigned int size ) { int i; unsigned int c24; union colors c; for ( i=0; i c.rgb[2] && c.rgb[1] > c.rgb[3] ) prim = 1; else if ( c.rgb[2] > c.rgb[1] && c.rgb[2] > c.rgb[3] ) prim = 2; else if ( c.rgb[3] > c.rgb[1] && c.rgb[3] > c.rgb[2] ) prim = 3; else if ( c.rgb[1] == c.rgb[2] && c.rgb[1] == c.rgb[3] ) prim = 0; // gray else if ( c.rgb[1] == c.rgb[2] ) prim = 0x12; // red green else if ( c.rgb[1] == c.rgb[3] ) prim = 0x13; // red blue else if ( c.rgb[2] == c.rgb[3] ) prim = 0x23; // green blue else printf("cannot tell color %06x\n", color24); last_c = color24; last_p = prim; if ( prim == 0 || prim > 3 ) { last_co = -1; return last_co; } return -1; } unsigned char findIndexMatch( unsigned int color24 ) { int i; unsigned char ri; static unsigned char last = 0; retry: if ( panic_clut[last] == color24 ) { exactmatch++; return last; } for (i=0; i<256; i++) { if ( panic_clut[i] == color24 ) { last = i; exactmatch++; return last; } } if ( nextmis == -1 ) { for (i=0; i<256; i++) mismatchClut[i] = -1; nextmis = 0; } i = findIndexNearMatch(color24); if ( i == -1 ) // found a color that is not grey { unsigned int colormatch = findColor24NearMatch( color24 ); if ( colormatch == -1 ) // cannot convert color { cvt2grey++; if (debug>1) printf("color %06X not matched at all\n", color24); color24 = color24toGrey(color24); if (debug>1) printf("now grey %06X\n", color24); } else color24 = colormatch; goto retry; } if (debug>1) printf("color %06X now matched at %x\n", color24, i); ri = i; neargrey++; // keep track of missed repeats for ( i=0; i= 256) ) { fprintf(stderr,"Err: Too many color mismatches detected with this CLUT\n"); exit(1); } return ri; } /* * Convert 8 bit mode to 8 bit, We have to strip off the alignment bytes */ int convert8bitIndexto8( unsigned char * data, int height, int width, unsigned char ** dout ) { unsigned int row, col, i, i8, size, adj; unsigned char index; unsigned char * ddata; union colors color24; adj=(4-(width%4))%4; // adjustment needed to strip off the word alignment padding size = height * width; ddata = (unsigned char *) calloc( size, 1); for (i8=0,row=0; row