Example #1
0
int
main(int argc, char **argv)
{
    int i;
    unsigned char *scanbuf;
    unsigned char **rows;
    png_structp png_p;
    png_infop info_p;

    if ( !get_args( argc, argv ) )  {
	(void)fputs(usage, stderr);
	bu_exit ( 1, NULL );
    }

    /* autosize input? */
    if ( fileinput && autosize ) {
	unsigned long int	w, h;
	if ( fb_common_file_size(&w, &h, file_name, 1) ) {
	    file_width = (long)w;
	    file_height = (long)h;
	} else {
	    fprintf(stderr, "bw-png: unable to autosize\n");
	}
    }

    png_p = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
    if ( !png_p )
	bu_exit( EXIT_FAILURE, "Could not create PNG write structure\n" );

    info_p = png_create_info_struct( png_p );
    if ( !info_p )
	bu_exit( EXIT_FAILURE, "Could not create PNG info structure\n" );

    /* allocate space for the image */
    scanbuf = (unsigned char *)bu_calloc( SIZE, sizeof( unsigned char ), "scanbuf" );

    /* create array of pointers to rows for libpng */
    rows = (unsigned char **)bu_calloc( file_height, sizeof( unsigned char *), "rows" );
    for ( i=0; i<file_height; i++ )
	rows[i] = scanbuf + ((file_height-i-1)*ROWSIZE);

    /* read the bw file */
    if ( fread( scanbuf, SIZE, 1, infp ) != 1 )
	bu_exit( EXIT_FAILURE, "bw-png: Short read\n");

    png_init_io( png_p, stdout );
    png_set_filter( png_p, 0, PNG_FILTER_NONE );
    png_set_compression_level( png_p, Z_BEST_COMPRESSION );
    png_set_IHDR( png_p, info_p, file_width, file_height, 8,
		  PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
		  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );

    png_write_info( png_p, info_p );
    png_write_image( png_p, rows );
    png_write_end( png_p, NULL );
    return 0;
}
Example #2
0
int
main(int argc, char **argv)
{
    int	ret = 0;
    int	nsamp;

    if ( !get_args( argc, argv ) || bytes_per_sample <= 0 )  {
	(void)fputs(usage, stderr);
	return 1;
    }

    if ( !file_name && file_length <= 0 )  {
	(void)fputs(usage, stderr);
	return 1;
    }

    if ( file_name ) {
	if ( !fb_common_file_size(&width, &height, file_name, bytes_per_sample) ) {
	    fprintf(stderr, "pixautosize: unable to autosize file '%s'\n", file_name);
	    ret = 1;		/* ERROR */
	}
    } else {
	nsamp = file_length/bytes_per_sample;
	if ( !fb_common_image_size(&width, &height, nsamp) ) {
	    fprintf(stderr, "pixautosize: unable to autosize nsamples=%d\n", nsamp);
	    ret = 2;		/* ERROR */
	}
    }

    /*
     *  Whether or not an error message was printed to stderr above,
     *  print out the width and height on stdout.
     *  They will be zero on error.
     */
    printf("WIDTH=%lu; HEIGHT=%lu\n", width, height);
    return ret;
}
Example #3
0
int
main(int argc, char **argv)
{
    int c;
    long int cur_width = 0;
    long int cur_height = 0;

    if (!get_args(argc, argv)) {
	(void) fputs(usage, stderr);
	bu_exit (1, NULL);
    }

    /* autosize the input? */
    if (fileinput && autosize) {
	size_t w, h;
	if (fb_common_file_size(&w, &h, file_name, 1)) {
	    file_width = (long)w;
	} else {
	    fprintf(stderr, "bw-a: unable to autosize\n");
	}
    }

    while ((c=getc(infp)) != EOF) {
	if (c < 127) {
	    putchar('#');
	} else {
	    putchar('-');
	}
	if (++cur_width >= file_width) {
	    putchar('\n');
	    cur_width=0L;
	    cur_height++;
	}
    }
    return 0;
}
Example #4
0
/*
 *			M A I N
 */
int
main(int argc, char **argv)
{
    unsigned char	*inbuf;
    unsigned char	*outbuf;
    int	*rout, *gout, *bout;
    long int	out_width;
    long int	i;
    int	eof_seen;

    if ( !get_args( argc, argv ) )  {
	(void)fputs(usage, stderr);
	bu_exit ( 1, NULL );
    }

    /* autosize input? */
    if ( fileinput && autosize ) {
	unsigned long int	w, h;
	if ( fb_common_file_size(&w, &h, file_name, 3) ) {
	    file_width = (long)w;
	} else {
	    fprintf(stderr, "pixhalve: unable to autosize\n");
	}
    }
    out_width = file_width/2;

    /* Allocate 1-scanline input & output buffers */
    inbuf = malloc( 3*file_width+8 );
    outbuf = malloc( 3*(out_width+2)+8 );

    /* Allocate 5 integer arrays for each color */
    /* each width+2 elements wide */
    for ( i=0; i<5; i++ )  {
	rlines[i] = (int *)bu_calloc( (file_width+4)+1, sizeof(long), "rlines" );
	glines[i] = (int *)bu_calloc( (file_width+4)+1, sizeof(long), "glines" );
	blines[i] = (int *)bu_calloc( (file_width+4)+1, sizeof(long), "blines" );
    }

    /* Allocate an integer array for each color, for output */
    rout = (int *)bu_malloc( out_width * sizeof(long) + 8, "rout" );
    gout = (int *)bu_malloc( out_width * sizeof(long) + 8, "gout" );
    bout = (int *)bu_malloc( out_width * sizeof(long) + 8, "bout" );

    /*
     *  Prime the pumps with 5 lines of image.
     *  Repeat the bottom most line three times to generate a "fill"
     *  line on the bottom.  This will have to be matched on the top.
     */
    if ( fread( inbuf, 3, file_width, infp ) != file_width )  {
	perror(file_name);
	fprintf(stderr, "pixhalve:  fread error\n");
	bu_exit (1, NULL);
    }
    separate( &rlines[0][2], &glines[0][2], &blines[0][2], inbuf, file_width );
    separate( &rlines[1][2], &glines[1][2], &blines[1][2], inbuf, file_width );
    separate( &rlines[2][2], &glines[2][2], &blines[2][2], inbuf, file_width );
    for ( i=3; i<5; i++ )  {
	if ( fread( inbuf, 3, file_width, infp ) != file_width )  {
	    perror(file_name);
	    fprintf(stderr, "pixhalve:  fread error\n");
	    bu_exit (1, NULL);
	}
	separate( &rlines[i][2], &glines[i][2], &blines[i][2],
		  inbuf, file_width );
    }

    eof_seen = 0;
    for (;;)  {
	filter3( rout, rlines, out_width );
	filter5( gout, glines, out_width );
	filter5( bout, blines, out_width );
	combine( outbuf, rout, gout, bout, out_width );
	if ( fwrite( (void*)outbuf, 3, out_width, stdout ) != out_width )  {
	    perror("stdout");
	    bu_exit (2, NULL);
	}

	/* Ripple down two scanlines, and acquire two more */
	if ( fread( inbuf, 3, file_width, infp ) != file_width )  {
	    if ( eof_seen >= 2 )  break;
	    /* EOF, repeat last line 2x for final output line */
	    eof_seen++;
	    /* Fall through */
	}
	ripple( rlines, 5 );
	ripple( glines, 5 );
	ripple( blines, 5 );
	separate( &rlines[4][2], &glines[4][2], &blines[4][2],
		  inbuf, file_width );

	if ( fread( inbuf, 3, file_width, infp ) != file_width )  {
	    if ( eof_seen >= 2 )  break;
	    /* EOF, repeat last line 2x for final output line */
	    eof_seen++;
	    /* Fall through */
	}
	ripple( rlines, 5 );
	ripple( glines, 5 );
	ripple( blines, 5 );
	separate( &rlines[4][2], &glines[4][2], &blines[4][2],
		  inbuf, file_width );
    }

    bu_free(rlines, "rlines");
    bu_free(glines, "glines");
    bu_free(blines, "blines");
    bu_free(rout, "rout");
    bu_free(gout, "gout");
    bu_free(bout, "bout");
}
Example #5
0
int
main (int argc, char **argv)
{
    unsigned char *buffer;
    unsigned char *bp;
    double *value;
    int bufsiz;		/* buffer size (in bytes) */
    int l_per_b;	/* buffer size (in output lines) */
    int line_nm;	/* number of current line */
    int num;		/* number of bytes read */
    int i;
    int row, col;	/* coords within input stream */

    if (!get_args(argc, argv)) {
	print_usage(1);
    }

    /* autosize input? */
    if (fileinput && autosize) {
	size_t w, h;

	if (fb_common_file_size(&w, &h, file_name, d_per_l * 8)) {
	    file_width = (long)w;
	    file_height = (long)h;
	} else
	    bu_log("double-asc: unable to autosize\n");
    }
    bu_log("OK, file is %ld wide and %ld high\n", file_width, file_height);

    /*
     * Choose an input-buffer size as close as possible to 64 kbytes,
     * while still an integral multiple of the size of an output line.
     */
    l_per_b = ((1 << 16) / (d_per_l * 8));
    bufsiz = l_per_b * (d_per_l * 8);

    buffer = (unsigned char *) bu_malloc(bufsiz, "char buffer");
    value = (double *) bu_malloc(d_per_l * 8, "doubles");
    col = row = 0;
    while ((num = read(infd, buffer, bufsiz)) > 0) {
	bp = buffer;
	l_per_b = num / (d_per_l * 8);
	for (line_nm = 0; line_nm < l_per_b; ++line_nm) {
	    if (make_cells)
		printf("%d %d", col, row);
	    bu_cv_ntohd((unsigned char *)value, bp, d_per_l);
	    bp += d_per_l * 8;
	    for (i = 0; i < d_per_l; ++i)
		printf(format, value[i]);
	    printf("\n");
	    if (++col % file_width == 0) {
		col = 0;
		++row;
	    }
	}
    }
    if (num < 0) {
	perror("double-asc");
	bu_exit (1, NULL);
    }
    return 0;
}
Example #6
0
int
main(int argc, char **argv)
{
    char *picAname, *picBname, *linesfilename;
    FILE *picA, *picB, *linesfile;
    size_t pa_width = 0, pa_height = 0;
    int dissolvefrac;
    double warpfrac;
    unsigned char *pa, *pb, *wa, *wb, *morph;
    double a, b, p;
    long int numlines;
    struct lineseg *lines;
    long int i;
    long int autosize;

    autosize = 1L;
    pa_width = pa_height = 0;
    if (get_args(argc, argv, &picAname, &picBname, &linesfilename,
		 &warpfrac, &dissolvefrac, &autosize, &pa_width, &pa_height) == 0
	|| isatty(fileno(stdout))) {
	fprintf(stderr,
		"Usage: pixmorph [-w width] [-n height] picA.pix picB.pix linesfile warpfrac dissolvefrac > out.pix\n");
	return 1;
    }

    picA = fopen(picAname, "r");
    if (picA == NULL) {
	fprintf(stderr, "pixmorph: cannot open %s\n", picAname);
	return 1;
    }
    picB = fopen(picBname, "r");
    if (picB == NULL) {
	fprintf(stderr, "pixmorph: cannot open %s\n", picBname);
	return 1;
    }
    linesfile = fopen(linesfilename, "r");
    if (linesfile == NULL) {
	fprintf(stderr, "pixmorph: cannot open %s\n", linesfilename);
	return 1;
    }

    if (warpfrac < 0.0 || warpfrac > 1.0) {
	fprintf(stderr, "pixmorph: warpfrac must be between 0 and 1\n");
	return 1;
    }

    if (dissolvefrac < 0 || dissolvefrac > 255) {
	fprintf(stderr, "pixmorph: dissolvefrac must be between 0 and 1\n");
	return 1;
    }

    if (autosize) {
	if (fb_common_file_size(&pa_width, &pa_height, argv[1], 3) == 0) {
	    fprintf(stderr, "pixmorph: unable to autosize\n");
	    return 1;
	}
    } else {
	struct stat sb;

	if (stat(picAname, &sb) < 0) {
	    perror("pixmorph: unable to stat file:");
	    return 1;
	}

	if (pa_width > 0) {
	    pa_height = sb.st_size/(3*pa_width);
	    fprintf(stderr, "width = %lu, size = %ld, so height = %lu\n",
		    (unsigned long)pa_width, (long)sb.st_size, (unsigned long)pa_height);
	} else if (pa_height > 0) pa_width = sb.st_size/(3*pa_height);

	if (pa_width <= 0 || pa_height <= 0) {
	    fprintf(stderr, "pixmorph: Bogus image dimensions: %lu %lu\n",
		    (unsigned long)pa_width, (unsigned long)pa_height);
	    return 1;
	}
    }

    /* Allocate memory for our bag o' pixels. */

    pa = (unsigned char *)malloc(pa_width*pa_height*3);
    pb = (unsigned char *)malloc(pa_width*pa_height*3);
    wa = (unsigned char *)malloc(pa_width*pa_height*3);
    wb = (unsigned char *)malloc(pa_width*pa_height*3);
    morph = (unsigned char *)malloc(pa_width*pa_height*3);

    if (pa == NULL || pb == NULL || wa == NULL ||  wb == NULL ||
	morph == NULL) {
	fprintf(stderr, "pixmorph: memory allocation failure\n");
	bu_free(pa, "pa alloc from malloc");
	bu_free(pb, "pb alloc from malloc");
	bu_free(wa, "wa alloc from malloc");
	bu_free(wb, "wb alloc from malloc");
	bu_free(morph, "morph alloc from malloc");
	return 1;
    }

    /* The following is our memorizing table for weight calculation. */

    for (i = 0; i < MAXLEN; i++)
	weightlookup[i] = -1.0;

    fprintf(stderr, "pixmorph: Reading images and lines file.\n");

    if (pix_readpixels(picA, pa_width*pa_height, pa) < pa_width*pa_height) {
	fprintf(stderr, "Error reading %lu pixels from %s\n",
		(unsigned long)pa_width*pa_height, picAname);
	return 1;
    }
    if (pix_readpixels(picB, pa_width*pa_height, pb) < pa_width*pa_height) {
	fprintf(stderr, "Error reading %lu pixels from %s\n",
		(unsigned long)pa_width*pa_height,  picBname);
	return 1;
    }
    fclose(picA);
    fclose(picB);

    /* Process the lines file. */

    lines_headerinfo(linesfile, &a, &b, &p, &numlines);
    lines = (struct lineseg *)malloc(numlines * sizeof(struct lineseg));
    numlines = lines_read(linesfile, numlines, lines,
			  pa_width, pa_height, warpfrac, p*b);
    fprintf(stderr, "pixmorph: %ld line segments read\n", numlines);

    /* Warp the images */

    fprintf(stderr,
	    "pixmorph: Warping first image into first intermediate image.\n");
    warp_image(wa, pa, lines, FIRST, pa_width, pa_height, numlines, a, b);
    fprintf(stderr,
	    "pixmorph: Warping second image into second intermediate image.\n");
    warp_image(wb, pb, lines, LAST, pa_width, pa_height, numlines, a, b);

    /* Do the dissolve */

    fprintf(stderr,
	    "pixmorph: Performing cross-dissolve between first and second\n");
    fprintf(stderr, "pixmorph: intermediate images.\n");
    cross_dissolve(morph, wa, wb, dissolvefrac, pa_width*pa_height);

    /* All done.  Write everything out to a file and quit. */

    pix_writepixels(pa_width*pa_height, morph);

    fprintf(stderr, "pixmorph: Morph complete.\n");

    /* System takes care of memory deallocation. */

    return 0;
}
Example #7
0
/*
 *			M A I N ( )
 */
int
main (int argc, char **argv)
{
    char		*inbuf;		/* The input scanline */
    char		*outbuf;	/*  "  output    "    */
    char		*in, *out;	/* Pointers into inbuf and outbuf */
    fastf_t		twice_r1r2;
    fastf_t		squares;
    fastf_t		scale_fac;
    fastf_t		theta;
    fastf_t		x;		/* Scale factor for pixel blending */
    int			i;		/* Pixel index in inbuf */
    int			j;		/*   "     "    " outbuf */
    long int		row;
    long int		row_width;

    if (!get_args( argc, argv ))
    {
	(void) fputs(usage, stderr);
	bu_exit (1, NULL);
    }

    if (solid_type == SPHERE)
    {
	(void) fprintf(stderr, "Sphere scaling not yet implemented\n");
	bu_exit (1, NULL);
    }
    else if (solid_type != TORUS)
    {
	(void) fprintf(stderr, "Illegal solid type %d\n", solid_type);
	bu_exit (0, NULL);
    }

    /*
     *	Autosize the input if appropriate
     */
    if (fileinput && autosize)
    {
	unsigned long int	w, h;

	if (fb_common_file_size(&w, &h, file_name, 3))
	{
	    file_width = (long)w;
	    file_height = (long)h;
	}
	else
	    (void) fprintf(stderr, "texturescale: unable to autosize\n");
    }

    /*
     *	Initialize some runtime constants
     */
    twice_r1r2 = 2 * r1 * r2;
    squares = r1 * r1 + r2 * r2;
    scale_fac = file_width / (r1 + r2);

    /*
     *	Allocate 1-scanline buffers for input and output
     */
    outbuf = bu_malloc(3*file_width, "outbuf");
    inbuf  = bu_malloc(3*file_width, "inbuf");

    /*
     *	Do the filtering
     */
    for (row = 0; row < file_height; ++row)
    {
	/*
	 *	Read an input scanline
	 */
	if (! read_row(inbuf, file_width, infp))
	{
	    perror(file_name);
	    (void) fprintf(stderr, "texturescale:  fread() error\n");
	    bu_exit (1, NULL);
	}

	/*
	 *	Determine how much of the input scanline we want
	 */
	theta = 2 * bn_pi * row / file_height;
	row_width = scale_fac * sqrt(squares - twice_r1r2 * cos(theta));
	in = inbuf + ((file_width - row_width) / 2) * 3;
	out = outbuf;

	/*
	 *	Scale the input scanline into the output scanline
	 */
	for (i = j = 1; j <= file_width; ++j)
	{
	    if (i * file_width < j * row_width)
	    {
		x = j - (i * file_width) / row_width;
		VBLEND2(out, (1.0 - x), in, x, in + 3);
		++i;
		in += 3;
	    }
	    else
		VMOVE(out, in);
	    out += 3;
	}

	/*
	 *	Write the output scanline
	 */
	if (fwrite(outbuf, 3, file_width, stdout) != file_width)
	{
	    perror("stdout");
	    bu_exit (2, NULL);
	}
    }

    bu_exit (1, NULL);
}
Example #8
0
int
main(int argc, char **argv)
{
    unsigned char *inbuf, *outbuf;
    unsigned char *buffer;
    long int i;
    unsigned char *cp;
    int finish, row, result;

    bu_log("DEPRECATED: pixcut is no longer being maintained.\n\tContact [email protected] if you still use this tool.\n");

    for (i=0; i<SIZEBACK; i++) background[i] = 0;
    background[2] = 1;

    if (!get_args(argc, argv)) {
        fprintf(stderr, "%s", usage);
        bu_exit (1, NULL);
    }
    /* Should we autosize the input? */
    if (isfile && autosize) {
        size_t w, h;
        if (fb_common_file_size(&w, &h, in_name, num_bytes)) {
            org_width = (long)w;
            org_height = (long)h;
        } else {
            (void) fprintf(stderr, "pixcut: unable to autosize\n");
        }
    }

    /*
     * On the assumption that there will be lots more input to paw
     * through than there will be output to write, give STDIO a
     * big input buffer to allow decent sized transfers from the
     * filesystem.
     */
    (void)setvbuf(input, stdiobuf, _IOFBF, sizeof(stdiobuf));

    /*
     * Make a buffer will hold a single scan line of assuming a worst
     * case cut of 1 pixel of the edge.
     */
    buffer = (unsigned char *)bu_malloc((org_width+new_width)*num_bytes, "buffer");

    /*
     * Spew at the user if they asked.
     */
    if (Verbose) {
        fprintf(stderr, "pixcut: Copyright (C) 1992 Paladin Software\n");
        fprintf(stderr, "pixcut: All rights reserved.\npixcut:\n");
        fprintf(stderr, "pixcut: original image %ldx%ld\n",
                org_width, org_height);
        fprintf(stderr, "pixcut: new image %ldx%ld\n",
                new_width, new_height);
        fprintf(stderr, "pixcut: offset %ldx%ld\n", base_x, base_y);
        fprintf(stderr, "pixcut: background color %d/%d/%d\n",
                background[0], background[1], background[2]);

        if (base_x < 0 || base_y < 0 ||
                base_x+new_width >org_width ||
                base_y+new_height > org_height) {
            int comma=0;
            char *last = 0;
            (void) fprintf(stderr,
                           "pixcut: adding background strip on the");

            if (base_x < 0) {
                last = "left";
            }
            if (base_y < 0) {
                if (last) {
                    (void) fprintf(stderr, " %s", last);
                    comma=1;
                }
                last = "bottom";
            }
            if (base_x+new_width >org_width) {
                if (last) {
                    if (comma) {
                        fprintf(stderr, ", %s", last);
                    } else {
                        fprintf(stderr, " %s", last);
                    }
                    comma=1;
                }
            }
            if (base_y+new_height > org_height) {
                if (last) {
                    if (comma) {
                        fprintf(stderr, ", %s", last);
                    } else {
                        fprintf(stderr, " %s", last);
                    }
                    comma = 1;
                }
                last = "top";
            }
            if (comma) {
                fprintf(stderr, " and %s.\n", last);
            } else {
                fprintf(stderr, " %s.\n", last);
            }
        }
    }
    /*
     * If the new image does not intersect the original, then set the base_x
     * so that it does not overlap the original but at the same time minimizes
     * the memory hit.
     */
    if (base_x + new_width < 0 || base_x > org_width) {
        base_x = org_width;
    }
    /*
     * Assign the inbuf and outbuf pointers so that reads and writes take place
     * from a consistent location.
     */
    if (base_x < 0) {
        outbuf = buffer;
        inbuf = buffer - base_x*num_bytes;	/* base_x < 0 so - not + */
    } else {
        outbuf = buffer + base_x*num_bytes;
        inbuf = buffer;
    }
    /*
     * Now fill the output buffer with the background color if needed.
     */
    if (base_x < 0 || base_y < 0 || base_x+new_width > org_width) {
        for (i=0, cp = outbuf; i<new_width; i++, cp+=num_bytes) {
            long int jj;
            for (jj=0; jj<num_bytes && jj<SIZEBACK; jj++) {
                cp[jj]=background[jj];
            }
        }
    }
    finish = base_y + new_height;
    if (base_y < 0) {
        row = base_y;
    } else {
        row = 0;
    }
    /*
     * Now sync the input file to the output file.
     */
    while (row < 0 && row < finish) {
        result = fwrite(outbuf, num_bytes, new_width, stdout);
        if (result != new_width) {
            perror("pixcut: fwrite");
            bu_exit (3, NULL);
        }
        row++;
    }

    while (row < base_y) {
        result = fread(inbuf, num_bytes, org_width, input);
        if (result != org_width) {
            perror("pixcut: fread");
            bu_exit (3, NULL);
        }
        row++;
    }
    /*
     * At this point "row" is an index into the original file.
     */
    while (row < finish && row < org_height) {
        result = fread(inbuf, num_bytes, org_width, input);
        if (result != org_width) {
            for (cp=inbuf+result*num_bytes; result < org_width; cp+=num_bytes, ++result) {
                long int jj;
                for (jj=0; jj<num_bytes && jj<SIZEBACK; jj++) {
                    cp[jj] = background[jj];
                }
            }
            org_height = row-1;
        }
        result = fwrite(outbuf, num_bytes, new_width, stdout);
        if (result != new_width) {
            perror("pixcut: fwrite");
            bu_exit (3, NULL);
        }
        row++;
    }
    /*
     * Refill the output buffer if we are going to be outputting background
     * lines.
     */
    if (row >= org_height) {
        for (cp=outbuf, i=0; i<new_width; cp+=num_bytes, i++) {
            long int jj;
            for (jj=0; jj<num_bytes && jj<SIZEBACK; jj++) {
                cp[jj] = background[jj];
            }
        }
    }
    /*
     * We've taken all we can from the input file, now it's time to
     * output the remaining background lines (if any).
     */
    while (row < finish) {
        result = fwrite(outbuf, num_bytes, new_width, stdout);
        if (result != new_width) {
            perror("pixcut: fwrite");
            bu_exit (3, NULL);
        }
        row++;
    }
    return 0;
}
Example #9
0
int
main(int argc, char **argv)
{
    int y;
    FBIO *fbp;
    int xout, yout, n, m, xstart, xskip;

    if (!get_args(argc, argv)) {
	(void)fputs(usage, stderr);
	bu_exit(1, NULL);
    }

    /* autosize input? */
    if (fileinput && autosize) {
	size_t w, h;
	if (fb_common_file_size(&w, &h, file_name, 3)) {
	    file_width = w;
	    file_height = h;
	} else {
	    fprintf(stderr, "pix-fb: unable to autosize\n");
	}
    }

    /* If screen size was not set, track the file size */
    if (scr_width == 0)
	scr_width = file_width;
    if (scr_height == 0)
	scr_height = file_height;

    if ((fbp = fb_open(framebuffer, scr_width, scr_height)) == NULL) {
	bu_exit(12, NULL);
    }

    /* Get the screen size we were given */
    scr_width = fb_getwidth(fbp);
    scr_height = fb_getheight(fbp);

    /* compute number of pixels to be output to screen */
    if (scr_xoff < 0) {
	xout = scr_width + scr_xoff;
	xskip = (-scr_xoff);
	xstart = 0;
    } else {
	xout = scr_width - scr_xoff;
	xskip = 0;
	xstart = scr_xoff;
    }

    if (xout < 0)
	bu_exit(0, NULL);			/* off screen */
    if ((size_t)xout > (file_width-file_xoff))
	xout = (file_width-file_xoff);
    scanpix = xout;				/* # pixels on scanline */

    if (inverse)
	scr_yoff = (-scr_yoff);

    yout = scr_height - scr_yoff;
    if (yout < 0)
	bu_exit(0, NULL);			/* off screen */
    if ((size_t)yout > (file_height-file_yoff))
	yout = (file_height-file_yoff);

    /* Only in the simplest case use multi-line writes */
    if (!one_line_only
	&& multiple_lines > 0
	&& !inverse
	&& !zoom
	&& (size_t)xout == file_width
	&& file_width <= (size_t)scr_width)
    {
	scanpix *= multiple_lines;
    }

    scanbytes = scanpix * sizeof(RGBpixel);
    if ((scanline = (unsigned char *)malloc(scanbytes)) == RGBPIXEL_NULL) {
	fprintf(stderr,
		"pix-fb:  malloc(%d) failure for scanline buffer\n",
		scanbytes);
	bu_exit(2, NULL);
    }

    if (clear) {
	fb_clear(fbp, PIXEL_NULL);
    }
    if (zoom) {
	/* Zoom in, and center the display.  Use square zoom. */
	int zoomit;
	zoomit = scr_width/xout;
	if (scr_height/yout < zoomit) zoomit = scr_height/yout;
	if (inverse) {
	    fb_view(fbp,
		    scr_xoff+xout/2, scr_height-1-(scr_yoff+yout/2),
		    zoomit, zoomit);
	} else {
	    fb_view(fbp,
		    scr_xoff+xout/2, scr_yoff+yout/2,
		    zoomit, zoomit);
	}
    }

    if (file_yoff != 0) skipbytes(infd, (off_t)file_yoff*(off_t)file_width*sizeof(RGBpixel));

    if (multiple_lines) {
	/* Bottom to top with multi-line reads & writes */
	unsigned long height;
	for (y = scr_yoff; y < scr_yoff + yout; y += multiple_lines) {
	    n = bu_mread(infd, (char *)scanline, scanbytes);
	    if (n <= 0) break;
	    height = multiple_lines;
	    if (n != scanbytes) {
		height = (n/sizeof(RGBpixel)+xout-1)/xout;
		if (height <= 0) break;
	    }
	    /* Don't over-write */
	    if ((size_t)(y + height) > (size_t)(scr_yoff + yout))
		height = scr_yoff + yout - y;
	    if (height <= 0) break;
	    m = fb_writerect(fbp, scr_xoff, y,
			     file_width, height,
			     scanline);
	    if ((size_t)m != file_width*height) {
		fprintf(stderr,
			"pix-fb: fb_writerect(x=%d, y=%d, w=%lu, h=%lu) failure, ret=%d, s/b=%d\n",
			scr_xoff, y,
			(unsigned long)file_width, height, m, scanbytes);
	    }
	}
    } else if (!inverse) {
	/* Normal way -- bottom to top */
	for (y = scr_yoff; y < scr_yoff + yout; y++) {
	    if (y < 0 || y > scr_height) {
		skipbytes(infd, (off_t)file_width*sizeof(RGBpixel));
		continue;
	    }
	    if (file_xoff+xskip != 0)
		skipbytes(infd, (off_t)(file_xoff+xskip)*sizeof(RGBpixel));
	    n = bu_mread(infd, (char *)scanline, scanbytes);
	    if (n <= 0) break;
	    m = fb_write(fbp, xstart, y, scanline, xout);
	    if (m != xout) {
		fprintf(stderr,
			"pix-fb: fb_write(x=%d, y=%d, npix=%d) ret=%d, s/b=%d\n",
			scr_xoff, y, xout,
			m, xout);
	    }
	    /* slop at the end of the line? */
	    if ((size_t)file_xoff+xskip+scanpix < file_width)
		skipbytes(infd, (off_t)(file_width-file_xoff-xskip-scanpix)*sizeof(RGBpixel));
	}
    } else {
	/* Inverse -- top to bottom */
	for (y = scr_height-1-scr_yoff; y >= scr_height-scr_yoff-yout; y--) {
	    if (y < 0 || y >= scr_height) {
		skipbytes(infd, (off_t)file_width*sizeof(RGBpixel));
		continue;
	    }
	    if (file_xoff+xskip != 0)
		skipbytes(infd, (off_t)(file_xoff+xskip)*sizeof(RGBpixel));
	    n = bu_mread(infd, (char *)scanline, scanbytes);
	    if (n <= 0) break;
	    m = fb_write(fbp, xstart, y, scanline, xout);
	    if (m != xout) {
		fprintf(stderr,
			"pix-fb: fb_write(x=%d, y=%d, npix=%d) ret=%d, s/b=%d\n",
			scr_xoff, y, xout,
			m, xout);
	    }
	    /* slop at the end of the line? */
	    if ((size_t)file_xoff+xskip+scanpix < file_width)
		skipbytes(infd, (off_t)(file_width-file_xoff-xskip-scanpix)*sizeof(RGBpixel));
	}
    }
    sleep(pause_sec);
    if (fb_close(fbp) < 0) {
	fprintf(stderr, "pix-fb: Warning: fb_close() error\n");
    }

    return 0;
}