#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
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 <file>\tUse file containing QuickTime uncompressed raw image as\n"
"\t\t\tthe panic dialog (8 bit only)\n"
"\t-o <file>\tWrite the output as a compressed kernel RAW image suitable\n"
"\t\t\tfor loading into the kernel\n"
"\t-c <file>\tUse file containing 256 RGB values for 8-bit indexed \n"
"\t\t\tlookups, overrides built-in appleClut8\n"
"\t-fg <color>\tForeground color of font used for panic information in\n"
"\t\t\t24-bits, default 0xFFFFFF (100%% white)\n"
"\t-bg <color>\tBackground color of font used for panic information in\n"
"\t\t\t24-bits, default 0x222222 (13%% white, dark gray)\n"
"\t-n <lines>\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;
long cType;
long resvd1;
short resvd2;
short dataRefIndex;
short version;
short revisionLevel;
long vendor;
long temporalQuality;
long spatialQuality;
short width;
short height;
long hRes;
long vRes;
long dataSize;
short frameCount;
char name[32];
short depth;
short clutID;
} 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;
for( next = 1; next < argc; next++ )
{
if (strcmp(argv[next], "-i") == 0) file = argv[++next];
else if (strcmp(argv[next], "-o") == 0) kraw = argv[++next];
else if (strcmp(argv[next], "-n") == 0) lines = atoi(argv[++next]);
else if (strcmp(argv[next], "-fg") == 0) sscanf(argv[++next], "%i", &fg24);
else if (strcmp(argv[next], "-bg") == 0) sscanf(argv[++next], "%i", &bg24);
else if (strcmp(argv[next], "-c") == 0) clutin = argv[++next];
else if (strcmp(argv[next], "-h") == 0) { usage(1); exit(1); }
else if (strcmp(argv[next], "-debug") == 0) 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);
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);
}
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<encodedSize; i++)
{
sum += fileArr[i];
sum <<= sum&1;
}
if ( kraw )
{
FILE * ostream;
unsigned int tag;
if ( (ostream = fopen(kraw, "wb")) == NULL ) {
fprintf(stderr,"Err: Could not open output file %s.\n\n", kraw);
exit(1);
}
printf("Writing to binary panic dialog file %s, which is suitable for loading into kernel...\n", kraw);
tag = 'RNMp'; depth = 1;
fwrite(&sum, sizeof(sum), 1, ostream);
sum = encodedSize;
encodedSize += (256*3);
fwrite(&encodedSize, sizeof(encodedSize), 1, ostream);
encodedSize = sum;
fwrite(&tag, sizeof(tag), 1, ostream);
fwrite(&width, sizeof(width), 1, ostream);
fwrite(&height, sizeof(height), 1, ostream);
fwrite(&depth, sizeof(depth), 1, ostream);
fwrite(&lines, sizeof(lines), 1, ostream);
fwrite(&fg, sizeof(fg), 1, ostream);
fwrite(&bg, sizeof(bg), 1, ostream);
fwrite(fileArr, encodedSize, 1, ostream);
for ( i=0; i<256; i++)
{
union colors c;
unsigned char arr[3];
c.c24 = panic_clut[i];
arr[0] = c.clut.red;
arr[1] = c.clut.green;
arr[2] = c.clut.blue;
fwrite(arr, 3, 1, ostream);
}
fclose(ostream);
}
return 0;
errQTimage:
fprintf(stderr,"Err: Input image must be in the QuickTime Raw Uncompressed 256 Colors format\n");
exit(1);
}
#define RUN_MAX ((1<<20)-1)
union RunData {
unsigned int i;
unsigned char c[4];
};
unsigned int encode_rle(
unsigned char * fileArr,
unsigned int filePos,
unsigned int quantity,
union RunData * value,
int depth);
int
compareruns( unsigned char * data, unsigned int * index, unsigned int max, union RunData * currP, int * depth )
{
union RunData * nextP;
static int retc = 0;
if ( currP == NULL || data == NULL )
{
retc = 0;
goto Leave;
}
if ( (*index+*depth) > max )
{
*depth = 1;
retc = 0;
goto Leave;
}
nextP = (union RunData *) &data[*index];
if ( retc == 1 )
{
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;
}
if ( (*index+6) <= max )
{
#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] )
{
if ( currP->c[0] == currP->c[1] &&
currP->c[1] == currP->c[2] &&
currP->c[2] == currP->c[3] )
{ 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] )
{
if ( currP->c[0] == currP->c[1] &&
currP->c[1] == currP->c[2] )
{ 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] )
{
if ( currP->c[0] == currP->c[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; run = 1;
depth = 1;
currP = (union RunData *)&data[0]; for (i=1; i<pixels;) {
if ( compareruns( data, &i, pixels, currP, &depth ) )
run++;
else {
if ( (run*depth) > 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];
if( norunP == NULL ) {
nomatchrun = 0;
norunP = currP;
}
depth = 1; run = 1; i++; }
}
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++;
}
}
if (run > 0) {
filePos += encode_rle(fileArr, filePos, run, currP, depth);
}
return filePos;
}
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); slots_used++;
if (quantity >>= 4) {
fileArr[filePos++] |= 0x10; fileArr[filePos] = quantity & double_mask;
slots_used++;
while (quantity >>= 7) {
fileArr[filePos++] |= 0x80; 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;
}
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<size; i++) {
c.c24 = panic_clut[data[i]];
c24 = color24toGrey( c.c24 );
data[i] = findIndexMatch( c24 );
}
return size;
}
unsigned int
findColor24NearMatch( unsigned int color24 )
{
union colors c;
unsigned char prim;
static unsigned int last_c = -1, last_co = -1, last_p = -1;
if ( last_c == color24 )
return last_co;
c.c24 = color24;
if ( c.rgb[1] > 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; else if ( c.rgb[1] == c.rgb[2] )
prim = 0x12; else if ( c.rgb[1] == c.rgb[3] )
prim = 0x13; else if ( c.rgb[2] == c.rgb[3] )
prim = 0x23; 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 ) {
unsigned int colormatch = findColor24NearMatch( color24 );
if ( colormatch == -1 ) {
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++;
for ( i=0; i<nextmis; i++)
if ( mismatchClut[i] == color24 )
return ri;
if ( debug) printf("closest match for %06X is at index %d %06X\n", color24, ri, panic_clut[ri]);
if ( nextmis < 256 )
mismatchClut[nextmis++] = color24;
if ( debug && (nextmis >= 256) )
{
fprintf(stderr,"Err: Too many color mismatches detected with this CLUT\n");
exit(1);
}
return ri;
}
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; size = height * width;
ddata = (unsigned char *) calloc( size, 1);
for (i8=0,row=0; row<height; row++)
{
for (col=0; col<width; col++)
{
index = *data++;
color24.c24 = panic_clut[index];
index = findIndexMatch( color24.c24 );
ddata[i8++] = index;
}
for (i=0; i<adj; i++)
data++;
}
* dout = ddata;
return (i8);
}
unsigned int *
CreateCLUTarry( unsigned char * raw_clut )
{
unsigned int * new_clut, index, i;
new_clut = (unsigned int *) calloc(256, sizeof(unsigned int));
for ( index=0,i=0; i<256; index+=3,i++ )
new_clut[i] = (raw_clut[index] << 16) | (raw_clut[index+1] << 8) | raw_clut[index+2];
return new_clut;
}
unsigned int *
ReplaceCLUT( char * iname )
{
FILE * stream;
unsigned char * raw_clut;
unsigned int * new_clut;
if ( (stream = fopen(iname, "rb")) == NULL ) {
fprintf(stderr,"Err: Could not open input clut file %s.\n\n", iname);
exit(1);
}
raw_clut = (char *) calloc(256, 3);
fread(raw_clut, 256, 3, stream);
fclose(stream);
new_clut = CreateCLUTarry( raw_clut );
free(raw_clut);
return new_clut;
}