[comp.graphics] bugfix for showpic and performance enhancement

ingwa@teorix.liu.se (Inge Wallin) (10/05/88)

Unfortunately, a bug crept into showpic. In the Floyd-Steinberg function
floydfunc(), height and width were switched in the loop control. This
didn't matter as long as one only used the program to view quadratic
images, but would have resulted in very strange behaviours, and maybe
even a core dump, if you had tried to look at rectangular ones.

While I was at it, I made the program some 40% faster by skipping
the calls to pr_put. I also fixed some grammar errors in the
README and manual.

Unfortunately the diffs were bigger than the entire posting of version
1.0, so I decided to send it all out again. 

---------------------------clip here----------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Makefile README showpic.1 showpic.c showpic.icon
# Wrapped by ingwa@teorix on Wed Oct  5 00:05:56 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(310 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X#
X# Makefile for showpic
X#
X
X#CFLAGS = -g
XCFLAGS = -O
X
XLIBS = -lsuntool -lsunwindow -lpixrect
X
XOBJS = showpic.o
X
Xshowpic: $(OBJS)
X	$(CC) -o showpic $(CFLAGS) $(OBJS) $(LIBS)
X
Xshowpic.o: showpic.c showpic.icon
X
X
Xshar:
X	shar Makefile README showpic.1 showpic.c showpic.icon >showpic.shar
X
X
Xclean:
X	rm -f *.o core
END_OF_Makefile
if test 310 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(2002 characters\)
sed "s/^X//" >README <<'END_OF_README'
X*******************************************************************
X             showpic  1.1  --  show ray traced images
X
X             by         Inge Wallin       ingwa@majestix.liu.se
X                        Jonas Yngvesson   jonas-y@joakim.liu.se
X
X             Linkoping Institute of Technology
X             Sweden
X*******************************************************************
X
XThis is the README file for the showpic program. Showpic takes as input
Xan image file, generated by Mark VandeWettering's ray tracer, and 
Xdisplays it on a SUN workstation. Unlike other programs which
Xhave been posted lately, showpic shows the image in a standard 
Xsunview window.
X
XThe program is extremely simple and was developed because of the
Xlack of SUNs with colour screens at this university. (Actually,
Xthere are a few of those also, but they are mainly out of our reach.)
XThus, there is no support for colour or gray scales in it.
X
XInstead, we have put in two half-toning algorithms, ordered dithering
Xand the Floyd-Steinberg method. There is also a choise of a number of
Xdither matrixes (currently 3) for those of you who don't like the
Xstandard one. See the manual for further details!
X
XThe gray scale conversion used was provided on comp.graphics about a
Xyear ago by Edward Falk.
X
XUnfortunately, no one of us have any great artistical talents, so the
Xicon is not very beautiful. If anybody should feel like making a nicer
Xone, we would be grateful if we could have a copy of it.
X
XDifferences between 1.1 and 1.0:
X* A bug fixed. (switch of width and height in floydfunc())
X* Faster program. Use own bit fiddling instead of pr_put.
X* Possibility of looking at files which are not finished. This
X  was made while waiting for a major ray tracing to finish.
X* Some grammar errors in this file and the manual were corrected.
X  (Very possibly some others have been introduced.)
X
XAs before, please send any enhancements, bug reports and fixes to us.
X
XLinkoping 4 Oct 1988
X
X                enjoy! /Inge & Jonas
END_OF_README
if test 2002 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f showpic.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"showpic.1\"
else
echo shar: Extracting \"showpic.1\" \(1741 characters\)
sed "s/^X//" >showpic.1 <<'END_OF_showpic.1'
X.\" Copyright 1988, Inge Wallin, Jonas Yngvesson
X.\" This program and documentation may be distributed freely for
X.\" non-commercial use only.  
X.TH SHOWPIC 1 "October 4, 1988" 1
X.UC 4 
X.SH NAME
Xshowpic \- show ray traced images on a SUN
X.SH SYNOPSIS
X\fBshowpic\fR [\fB\-u\fR]
X[\fB\-f\fR]
X[\fB\-d\fR[\fIn\fR]]
X\fB\-\fR | \fIfilename\fR
X.SH DESCRIPTION
XShowpic shows an image, generated by Mark VandeWettering's ray tracer,
Xin a sunview window. The program does not return, except when the \fB\-u\fR
Xoption is given.
X.PP
XThe program look for \fIEOF\fR, so it is possible to look at images which
Xare not finished.
X.SH OPTIONS
X.IP \fB\-u\fR
XShow program usage and exit.
X.IP \fB\-f\fR
XUse the Floyd\-Steinberg algorithm for halftoning. This is the default.
X.IP \fB\-d\fIn\fR
XUse ordered dithering for halftoning. \fIn\fR is the number of the
Xdither matrix you want to use. Currently there are 3 matrixes
Xavailable so \fIn\fR has to be in the range 1 to 3. If no \fIn\fR
Xis given, the program chooses a standard dither (number 1).
X.PP
XThe options \fB\-f\fR and \fB\-d\fR are exclusive and if both are
Xpresent, the program uses the last one.
X.PP
XIf showpic sees a \fIfilename\fR as its last argument, it tries to show
Xthat file. If a hyphen is given as the last argument, the image
Xis read from stdin. This is useful, for instance, if you want to
Xview compressed images, and use \fBzcat\fR(1) to uncompress them.
X.SH AUTHORS
XInge Wallin 
X.br
XJonas Yngvesson
X.SH BUGS
XNo checks are made to see if the image is bigger than the screen.
X.PP
XIf you use the standard input feature, there is no way to stop the
Xprogram with CTRL\-C. The reason for this is not entirely clear.
X.PP
XThe program should be expanded to handle gray scales and colour 
Xscreens.
END_OF_showpic.1
if test 1741 -ne `wc -c <showpic.1`; then
    echo shar: \"showpic.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f showpic.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"showpic.c\"
else
echo shar: Extracting \"showpic.c\" \(7915 characters\)
sed "s/^X//" >showpic.c <<'END_OF_showpic.c'
X/*
X * showpic.c - show ray traced images on a SUN
X *
X * Copyright 1988 Inge Wallin and Jonas Yngvesson.
X *
X * Use it as you like, but don't try to sell it or use it for
X * other commercial purposes.
X */
X
X#include <stdio.h>
X#include <string.h>
X#include <suntool/sunview.h>
X#include <suntool/canvas.h>
X
X#define VERSION "1.1"
X
X#ifndef TRUE			/* is sometimes defined by sunview */
X#define TRUE   1
X#define FALSE  0
X#endif
X
X#define INFILE  0		/* input from file */
X#define STDIN   1		/* input from stdin */
X
X/* typedef unsigned short u_short; */  /* already exists!!!??! */
X
Xextern char *malloc();
X
XFrame     frame;
XCanvas    picture_canvas;
XPixrect   *picture_pr;
X
Xu_short   *picture;
X
X
Xtypedef struct dither {
X    int   size;
X    int   shift;
X    int   *table;
X} Dither;
X
X
Xint dithmat1[8][8] = {
X    {  0, 32,  8, 40,  2, 34, 10, 42 },
X    { 48, 16, 56, 24, 50, 18, 58, 26 },
X    { 12, 44,  4, 36, 14, 46,  6, 38 },
X    { 60, 28, 52, 20, 62, 30, 54, 22 },
X    {  3, 35, 11, 43,  1, 33,  9, 41 },
X    { 51, 19, 59, 27, 49, 17, 57, 25 },
X    { 15, 47,  7, 39, 13, 45,  5, 37 },
X    { 63, 31, 55, 23, 61, 29, 53, 21 }};
X
Xint dithmat2[8][8] = {
X    {  52,  44,  36, 124, 132, 140, 148, 156 },
X    {  60,   4,  28, 116, 220, 228, 236, 164 },
X    {  68,  12,  20, 108, 212, 252, 244, 172 },
X    {  76,  84,  92, 100, 204, 196, 188, 180 },
X    { 132, 140, 148, 156,  52,  44,  36, 124 },
X    { 220, 228, 236, 164,  60,   4,  28, 116 },
X    { 212, 252, 244, 172,  68,  12,  20, 108 },
X    { 204, 196, 188, 180,  76,  84,  92, 100 }};
X
Xint dithmat3[4][4] = {
X    {  0,  8,  3, 11 },
X    { 12,  4, 14,  7 },
X    {  2, 10,  1,  9 },
X    { 13,  6, 15,  5 }};
X
XDither dithers[] = {
X    {8, 2, (int *) dithmat1},
X    {8, 0, (int *) dithmat2},
X    {4, 4, (int *) dithmat3},
X};
Xint numdithers = sizeof(dithers) / sizeof(Dither);
X
X
Xint redtab[256];		/* lookup tables for gray scale conversion */
Xint greentab[256];
Xint bluetab[256];
X
Xchar *programname;
X
X
Xvoid usage(exitstatus)
Xint   exitstatus;
X{
X    fprintf(stderr, "Usage: %s [-u] [-d[n]] [-f] - | filename\n", programname);
X    fprintf(stderr, "n between 1 and %d\n", numdithers);
X    exit(exitstatus);
X}
X
X
X
Xvoid error(message)
Xchar   *message;
X{
X    fprintf(stderr, "%s: %s\n", programname, message);
X    exit(1);
X}
X
X
X
X/* The icon */
Xshort icon_image[] = {
X#include "showpic.icon"
X};
XDEFINE_ICON_FROM_IMAGE(showpic_icon, icon_image);
X
X
Xvoid create_windows(infilename, width, height)
Xchar   *infilename;
Xint    width;
Xint    height;
X{
X    char   header[80];
X
X    sprintf(header, "showpic %s - %s", VERSION, infilename);
X    frame = window_create(NULL, FRAME,
X			  FRAME_LABEL,   header,
X			  FRAME_ICON,    &showpic_icon,
X			  0);
X
X    picture_canvas = window_create(frame, CANVAS,
X				   WIN_HEIGHT,          height,
X				   WIN_WIDTH,           width,
X				   CANVAS_AUTO_SHRINK,  FALSE,
X				   CANVAS_AUTO_EXPAND,  FALSE,
X				   0);
X
X    window_fit(frame);
X
X}
X
X
X
Xvoid ditherfunc(infile, dithernum, width, height)
XFILE  *infile;
Xint   dithernum;
Xint   width, height;
X{
X    int   y, x;
X    int   red, green, blue;
X    int   gray;
X    int   *dithermat;
X    int   dithersize;
X    int   dithershifts;
X    u_short   mask;
X    int   offset;
X
X    dithermat = dithers[dithernum].table;
X    dithersize = dithers[dithernum].size;
X    dithershifts = 8 + dithers[dithernum].shift;
X
X    offset = 0;
X    for (y = 0; y < height; y++) {
X	mask = 0x8000;
X	for (x = 0; x < width; x++) {
X	    red = getc(infile);
X	    if (red == EOF) {
X		x = width;
X		y = height;
X	    } else {
X		green = getc(infile);
X		blue = getc(infile);
X		gray = (redtab[red] + greentab[green] + bluetab[blue]) >>
X		    dithershifts;
X		if ( gray < *(dithermat + (y % dithersize) * dithersize +
X			      (x % dithersize)) ) {
X		    *(picture + offset) |= mask;
X		}
X		
X		if ((mask >>= 1) == 0) {
X		    mask = 0x8000;
X		    offset++;
X		}
X	    }
X	}
X
X	if (mask != 0x8000) {
X	    mask = 0x8000;
X	    offset++;
X	}
X    }
X}
X
X
X
Xvoid floydfunc(infile, width, height)
XFILE  *infile;
Xint   width;
Xint   height;
X{
X    int   y, x;
X    int   red, green, blue;
X    int   gray;
X    int   err;
X    char  *buffer1;
X    char  *buffer2;
X    char  *temp;
X    u_short   mask;
X    int   offset;
X
X    int   alphatab[256];
X    int   betatab[256];
X    int   gammatab[256];
X    int   deltatab[256];
X
X    buffer1 = malloc(width + 2);
X    buffer2 = malloc(width + 2);
X    if ((buffer1 == NULL) || (buffer2 == NULL)) {
X	error("Couldn't allocate buffers for error distribution.");
X    }
X
X    /* Distribute the error as follows: */
X    /*    current pixel = A[y,x]        */
X    /*    A[y,   x+1] += err*7/16       */
X    /*    A[y+1, x-1] += err*3/16       */
X    /*    A[y+1, x  ] += err*5/16       */
X    /*    A[y+1, x+1] += err*1/16       */
X    for (y = 0; y < 256; y++) {
X	alphatab[y] = ((y - 128) * 7) / 16;
X	betatab[y] =  ((y - 128) * 3) / 16;
X	gammatab[y] = ((y - 128) * 5) / 16;
X	deltatab[y] = ((y - 128) * 1) / 16;
X    }
X    
X    offset = 0;
X    for (y = 0; y < height; y++) {
X	err = 0;
X	for (x = 0; x < width + 2; x++)
X	    *(buffer2 + x) = 0;
X
X	mask = 0x8000;
X	for (x = 0; x < width; x++) {
X	    red = getc(infile);
X	    if (red == EOF) {
X		x = width;
X		y = height;
X	    } else {
X		green = getc(infile);
X		blue = getc(infile);
X		gray = ((redtab[red] + greentab[green] + bluetab[blue]) >> 8) +
X		    *(buffer1 + x + 1);
X		
X		if (gray < 128) {
X		    *(picture + offset) |= mask;
X		    err = gray;
X		} else {
X		    err = gray - 256;
X		}
X
X		if ((mask >>= 1) == 0) {
X		    mask = 0x8000;
X		    offset++;
X		}
X
X		*(buffer1 + x + 2) += alphatab[err + 128];
X		*(buffer2 + x )    += betatab[err + 128];
X		*(buffer2 + x + 1) += gammatab[err + 128];
X		*(buffer2 + x + 2) += deltatab[err + 128];
X	    }
X	}
X	temp = buffer1;
X	buffer1 = buffer2;
X	buffer2 = temp;
X
X	if (mask != 0x8000) {
X	    mask = 0x8000;
X	    offset++;
X	}
X    }
X}
X
X
X
Xvoid main(argc, argv)
Xint   argc;
Xchar  *argv[];
X{
X    int   i, j;
X    int   width, height;
X    int   ditherflag = FALSE;
X    int   dithernum = 0;
X    int   floydflag = TRUE;
X    int   inputflag = INFILE;
X    char  *infilename;
X    FILE  *infile;
X
X    programname = argv[0];
X    for (i = 1; (i < argc) && (*argv[i] == '-'); i++) {
X	switch (*(argv[i] + 1)) {
X
X	  /* usage */
X	  case 'u':
X	    usage(0);
X	    break;		/* not reached */
X
X          /* dithering */
X	  case 'd':
X	    if (*(argv[i] + 2) != '\0') {
X		if ((*(argv[i] + 2) < '1') ||
X		    (*(argv[i] + 2) > numdithers + '0'))
X		    usage(1);
X		else
X		    dithernum = *(argv[i] + 2) - '1';
X	    }
X	    ditherflag = TRUE;
X	    floydflag = FALSE;
X	    break;
X
X	  /* Floyd-Steinberg */
X	  case 'f':
X	    ditherflag = FALSE;
X	    floydflag = TRUE;
X	    break;
X
X	  /* input from stdin */
X	  case '\0':
X	    inputflag = STDIN;
X	    break;
X	    
X	  default:
X	    usage(1);
X	}
X    }
X
X    if ((ditherflag + floydflag != 1) || /* better safe than sorry */
X	((i == argc) && (inputflag == INFILE)))
X	usage(1);
X    
X    if (inputflag == INFILE) {
X	infilename = argv[i];
X	if ((infile = fopen(infilename, "r")) == NULL) {
X	    error( "Couldn't open infile.");
X	}
X    } else {
X	infilename = "standard input";
X	infile = stdin;
X    }
X
X    if (fscanf(infile, "%d %d\n", &width, &height) != 2) {
X	error("Couldn't read image size.");
X    }
X
X    picture = (u_short *) malloc(height * (width / 16 + 1) * sizeof(u_short));
X    if (picture == NULL)
X	error("Couldn't allocate buffer for the picture");
X    
X    /* uses the equation  gray = 0.30*red + 0.59*green + 0.11*blue  */
X    for (i = 0; i < 256; i++) {
X	redtab[i] =    77 * i;
X	greentab[i] = 151 * i;
X	bluetab[i] =   28 * i;
X    }
X    
X    if (ditherflag) {
X	ditherfunc(infile, dithernum, width, height);
X    } else if (floydflag) {
X	floydfunc(infile, width, height);
X    }
X    fclose(infile);
X
X    create_windows(infilename, width, height);
X    picture_pr = mem_point(width, height, 1, picture);
X    pw_write(canvas_pixwin(picture_canvas), 0, 0, width, height,
X	     PIX_SRC, picture_pr, 0, 0);
X
X    window_main_loop(frame);
X    exit(0);
X}
X
X
X
END_OF_showpic.c
if test 7915 -ne `wc -c <showpic.c`; then
    echo shar: \"showpic.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f showpic.icon -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"showpic.icon\"
else
echo shar: Extracting \"showpic.icon\" \(1933 characters\)
sed "s/^X//" >showpic.icon <<'END_OF_showpic.icon'
X/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
X */
X	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
X	0xC000,0x0000,0x0000,0x0003,0xC000,0x0000,0x0000,0x0003,
X	0xC000,0x0000,0x0000,0x0003,0xC000,0x0000,0x0000,0x0003,
X	0xC000,0x0000,0x0000,0x0003,0xC000,0x5000,0x0000,0x0003,
X	0xC000,0xA800,0x0000,0x0003,0xC001,0x5600,0x0000,0x0003,
X	0xC000,0xA800,0x0000,0x0003,0xC001,0x5500,0x0000,0x0003,
X	0xC000,0xA880,0x0000,0x0003,0xC002,0x5200,0x0020,0x0003,
X	0xC000,0x4400,0x0068,0x0003,0xC001,0x1115,0x0054,0x0003,
X	0xC000,0x88AA,0x88AA,0x0003,0xC000,0x2055,0x4154,0x0003,
X	0xC000,0x04C6,0xA44C,0x0003,0xC000,0x0151,0x5110,0x0003,
X	0xC000,0x0AA8,0xA888,0x0003,0xC000,0x0652,0x5620,0x0003,
X	0xC000,0x00AC,0x2840,0x0003,0xC000,0x1551,0x5510,0x0003,
X	0xC00A,0x0888,0xAA80,0x0003,0xC035,0x2622,0x5420,0x0003,
X	0xC04A,0x4A44,0xAA40,0x0003,0xC115,0x1511,0x5510,0x0003,
X	0xC08A,0x8A8A,0xA888,0x0003,0xC022,0x2555,0x5620,0x0003,
X	0xC044,0x46AA,0xAC40,0x4003,0xC010,0x1155,0x5111,0x5003,
X	0xC008,0x88AA,0xA88A,0xA803,0xC000,0x2255,0x6221,0x4003,
X	0xC000,0x444A,0x4446,0xA403,0xC000,0x1111,0x1111,0x5003,
X	0xC002,0x8888,0x8888,0x8803,0xC005,0x4222,0x1202,0x2003,
X	0xC04A,0xA444,0xAA44,0x4003,0xC085,0x5111,0x5501,0x1003,
X	0xC00A,0xA888,0xAA80,0x8003,0xC041,0x4223,0x5520,0x0003,
X	0xC204,0x8444,0xAA40,0x0003,0xC861,0x1011,0x5500,0x0003,
X	0xCE40,0x8C00,0xAA80,0x0003,0xDA02,0x2442,0x1220,0x0003,
X	0xE540,0x4004,0x4440,0x0003,0xC110,0x1151,0x1100,0x0003,
X	0xC800,0x0000,0x0000,0x0003,0xE218,0x0000,0x0000,0x0003,
X	0xC640,0x0400,0x0000,0x1003,0xD310,0x0400,0x0000,0x0003,
X	0xC889,0xC587,0x112C,0x7073,0xE222,0x2648,0x9132,0x108B,
X	0xC442,0x0448,0x9522,0x1083,0xE051,0xC448,0x9522,0x1083,
X	0xC908,0x2448,0x9522,0x1083,0xE102,0x2448,0x9532,0x108B,
X	0xC401,0xC447,0x0A2C,0x1073,0xC010,0x0000,0x0020,0x0003,
X	0xD000,0x0000,0x0020,0x0003,0xF620,0x0000,0x0020,0x0003,
X	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF
END_OF_showpic.icon
if test 1933 -ne `wc -c <showpic.icon`; then
    echo shar: \"showpic.icon\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
 -- 
Inge Wallin               | Thus spake the master programmer:               |
                          |      "After three days without programming,     |
ingwa@majestix.liu.se     |       life becomes meaningless."                |
                          | Geoffrey James: The Tao of Programming.         |