Subject: VideoPix to icon

From: [email-masked] (Dick Keene {Systems Eng} Sun Rochester)
Date: Fri, 26 Apr 91 14:26:33 EDT

Here is a program that converts 8 bit snapshots from the video pix board 
to sun icons.  It does a scale, and a histogram equalization.  Then you can
convert the icon to face format with the face compressor.
	R. Keene
-------- CUT vpxtoicon.c ----------
/* This program is for converting the output of VideoPix
 * for use in faces.  It converts the output of a B&W image (0 to 127)
 * to a ~/.faces type file
 *
 * By Dick Keene, Sun Microsystems, April 1991
 * [email-masked]
 */

#include <stdio.h>
#include <strings.h>
#include <pixrect/pixrect_hs.h>

#define SCALEFP 256

char *command_name;

prusage()
{
    fprintf(stderr, 
	"\007Usage is: %s [options] <in raster> <out icon>\n", command_name);
    fprintf(stderr, "Options are:\n");
    fprintf(stderr, "    -x xsize, how big to make result. (default is 48)\n");
    fprintf(stderr, "    -y ysize, how big to make result. (default is 48)\n");
    fprintf(stderr, "    -n +-noise level, how much noise to inject to smooth the dither. (default is 2)\n");
    fprintf(stderr, "    -v, verbose (default is off)\n");
    fprintf(stderr, "    -c, don't contrast stretch. (default is to do stretch)\n");
    fprintf(stderr, "    -8, Don't dither, dump 8 bit rastefile. (default is to dump 1 bit icon)\n");
    fprintf(stderr, "    -1, Dump as 1 bit rasterfile. (default is to dump 1 bit icon)\n");
    fprintf(stderr, "    - for a file name means stdin or stdout.\n");
    exit(1);
}

/* a histogram equalization, so there ! */
void
histeq(pr)
Pixrect *pr;
{
    int hist[256];
    int integ[256];
    int i;
    int x, y;
    int sum;

    if(pr->pr_depth != 8) {
	fprintf(stderr, "\007histeq: Pixrect must be depth = 8 bits/pixel\n");
	prusage();
    }

    for(i=0; i<256; i++)
	hist[i] = 0;

    /* do histogram ... */
    for(y=0; y<pr->pr_size.y; y++) {
	for(x=0; x<pr->pr_size.x; x++) {
	    hist[pr_get(pr, x, y)] += 1;
	}
    }

    /* integrate ... */
    for(i=0, sum=0; i<256; i++) {
	sum += hist[i];
	integ[i] = (sum * 255) / (pr->pr_size.y * pr->pr_size.x);
	if(integ[i] > 255)
	    integ[i] = 255;
    }

    /* convert pixels ... */
    for(y=0; y<pr->pr_size.y; y++) {
	for(x=0; x<pr->pr_size.x; x++) {
	    pr_put(pr, x, y, integ[pr_get(pr, x, y)]);
	}
    }
}

main(argc, argv)
int argc;
char *argv[];
{
    int e;
    int p;
    int x,y; /* for scaleing */
    int xscale;
    int yscale;
    short bits;
    Pixrect *pr_orig; /* the orriginal loaded pixrect */
    Pixrect *pr; /* The 48 x 48 8 bit pixrect */
    Pixrect *pr1; /* The 1 bit result */
    char iname[256];
    char oname[256];
    FILE *ifp;
    FILE *ofp;
    int argcnt;
    char *argp;
    int minpix, maxpix; /* for contrast stretch */
    int facex;
    int facey;
    int verbose;
    int noise;
    int nostretch;
    int dump8bit;
    int dump1bit;

    command_name = argv[0];

    /* setup defaults */
    strcpy(iname, "");
    strcpy(oname, "");
    verbose = 0;
    facex = 48;
    facey = 48;
    noise = 2;
    verbose = 0;
    nostretch = 0;
    dump8bit = 0;
    dump1bit = 0;

    /* read command line if there */
    /* format is <argv[0]> [-v (verbose)] <in raster> <outfile> */
    for(argcnt = 1; argcnt < argc; argcnt++) {
	if(*argv[argcnt] == '-') {
	    argp = argv[argcnt] + 1;
	    if(*argp == '\0') { /* was just a "-" */
		if(*iname == '\0')
		    strcpy(iname, "-"); /* stdin */
		else if(*oname == '\0')
		    strcpy(oname, "-"); /* stdout */
		else {
			fprintf(stderr, "Too many dashes '-'\n");
			prusage();
		}
	    }
	    while(*argp != '\0') {
		if(*argp == 'v') {
		    verbose = 1;
		} else if(*argp == 'c') { /* don't contrast stretch */
		    nostretch = 1;
		} else if(*argp == '8') { /* Dump the 8 bit raster file */
		    dump8bit = 1;
		} else if(*argp == '1') { /* Dump the 1 bit raster file */
		    dump1bit = 1;
		} else if(*argp == 'x') { /* result x size */
		    if((argcnt + 1) >= argc) {
			fprintf(stderr, "-x needs a number after it, eg. -x 64\n");
			prusage();
		    }
		    argcnt++;
		    sscanf(argv[argcnt], "%d", &facex);
		} else if(*argp == 'y') { /* result y size */
		    if((argcnt + 1) >= argc) {
			fprintf(stderr, "-y needs a number after it, eg. -y 64\n");
			prusage();
		    }
		    argcnt++;
		    sscanf(argv[argcnt], "%d", &facey);
		} else if(*argp == 'n') { /* noise level */
		    if((argcnt + 1) >= argc) {
			fprintf(stderr, "-n needs a number after it, eg. -n 4\n");
			prusage();
		    }
		    argcnt++;
		    sscanf(argv[argcnt], "%d", &noise);
		} else {
		    fprintf(stderr, "Bad flag `%c` in %s\n", *argp, argv[argcnt]);
		    prusage();
		}
		argp++;
	    }
	} else { /* it's a file name */
	    if(*iname == '\0')
		strcpy(iname, argv[argcnt]);
	    else if(*oname == '\0')
		strcpy(oname, argv[argcnt]);
	    else {
		fprintf(stderr, "Too many file names.\n");
		prusage();
	    }
	}
    }
    
    /* open input file */
    if((strcmp(iname, "") == 0) || (strcmp(iname, "-") == 0)) {
	ifp = stdin;
    } else {
	ifp = fopen(iname, "r");
	if(ifp == NULL) {
	    fprintf(stderr, "\007%s unable to open input file %s\n", 
			argv[0], iname);
	    prusage();
	}
    }

    /* open output file */
    if((strcmp(oname, "-") == 0) || (strcmp(oname, "") == 0)) {
	ofp = stdout;
    } else {
	ofp = fopen(oname, "w");
	if(ofp == NULL) {
	    fprintf(stderr, "\007%s unable to open output file %s\n", 
			argv[0], oname);
	    prusage();
	}
    }

    /* load the original image */
    pr_orig = pr_load(ifp, NULL);
    if(pr_orig == NULL) {
	fprintf(stderr, "\007%s: Error loading raster file %s\n", argv[0], iname);
	prusage();
    }

    if(pr_orig->pr_depth != 8) {
	fprintf(stderr, "\007Must be 8 bits/pixel, %s is %d bits/pixel.\n",
		iname, pr_orig->pr_depth);
	prusage();
    }

    /* too small ? */
    if((pr_orig->pr_size.x < facex) || (pr_orig->pr_size.y < facey)) {
	fprintf(stderr, "\007%s:Raster file too small, must be at least %d x %d\n",
		 argv[0], facex, facey);
	fprintf(stderr, "(File is %d x %d)\n", pr_orig->pr_size.x, pr_orig->pr_size.y);
	prusage();
    }

    /* scale to facex x facey */
    if((pr_orig->pr_size.x > facex) || (pr_orig->pr_size.y > facey)) { /* scale it down */
	xscale = (facex * SCALEFP) / pr_orig->pr_size.x;
	yscale = (facey * SCALEFP) / pr_orig->pr_size.y;
	if(verbose)
	    fprintf(stderr, "Scaleing down to 48 x 48, scale factor = %lf x %lf\n", 
					(double)xscale / (double)SCALEFP,
					(double)yscale / (double)SCALEFP);
	pr = (Pixrect *)mem_create(facex, facey, 8);
	if(pr == NULL) {
	    fprintf(stderr,
		"\007%s: OUT OF MEMORY, unable to create scaled image\n", argv[0]);
	    prusage();
 	}
	for(y=0; y<facey; y++) {
	    for(x=0; x<facex; x++) {
		pr_put(pr, x, y, 
		    pr_get(pr_orig, (x * SCALEFP) / xscale, (y * SCALEFP) / yscale));
	    }
	}
    } else {
	pr = pr_orig;
    }

    /* contrast stretch */
    if(nostretch == 0) {
	histeq(pr);
    }

    if(dump8bit) {
        pr_dump(pr, ofp, NULL, RT_STANDARD, 0);
        exit(0);
   }

    /* error diffuse down to 1 bit/pixel */
    pr1 = (Pixrect *)mem_create(facex, facey, 1);
    if(pr1 == NULL) {
	fprintf(stderr, "\007%s: OUT OF MEMORY, unable to create output image\n", argv[0]);
	prusage();
    }

    e = 0;
    for(y=0; y<facey; y++) {
	for(x=0; x<facex; x++) {
	    p = pr_get(pr, x, y);
	    if((p + e) > 63) {
		pr_put(pr1, x, y, 0);
		e = p + e - 255 + (random() % (noise * 2 + 1)) - noise;
	    } else {
		pr_put(pr1, x, y, 1);
		e = p + e + (random() % (noise * 2 + 1)) - noise;
	    }
	}
    }

    if(dump1bit) {
        pr_dump(pr1, ofp, NULL, RT_STANDARD, 0);
        exit(0);
    }
    
    /* dump as icon */
    if((facex >= 64) || (facey >= 64)) {
	fprintf(stderr, "Icons can't be bigger than 64x64, cropping...\n");
    }

   fprintf(ofp, 
	"/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16\n");
    fprintf(ofp, " */");
    fprintf(ofp, "\n\t");
    bits = 0;
    for(y=0; y<64; y++) {
	for(x=0; x<64; x++) {
	    if(pr_get(pr1, x, y) == 0) {
		bits <<= 1;
	    } else {
		bits <<= 1;
		bits |= 0x01;
	    }
	    if((x % 16) == 15) {
		fprintf(ofp, "0x%04x", 0x0000ffff & bits);
	   	bits = 0;
	        if((x == 63) && (y == 63)) {
		    exit(0); /* done */
	        }
	        if((x % 64) == 63)
		    fprintf(ofp, ",\n\t");
	        else
		    fprintf(ofp, ",");
	    }
	}
    }   
    exit(0); /* should never get here */
}