[comp.graphics] Image Conversion 8bits to 1

segel@quanta.eng.ohio-state.edu (VAXEN Assasin) (02/10/89)

	I have been working on a small project which involves
capturing an image via a camera and then converting its image
to a raster format. I was wondering if anyone knew
of a better dithering program than rasfilter8to1.

The time required to calculate the conversion should not
be a factor. I am looking to achieve the highest quality
of output. Part of this project is to develop rasters
for the backrounds on the suns and as well as to create
brush images.

Can anyone also recommend any free toolkits? (I don't have
a budget)

-mike S.

PS I would like to thank cyrus.pprg.unm.edu for answering
my questions among other things!



-- 
-Mike Segel         segel@icarus.eng.ohio-state.edu   (614) 294-3350
"These opinions are my own and in no way reflect those of the University
or the E E Dept.(Although there are those who probably share them!)

jonathan@jvc.UUCP (Jonathan Hue) (02/17/89)

In article <1747@quanta.eng.ohio-state.edu>, segel@quanta.eng.ohio-state.edu (VAXEN Assasin) writes:
> 
> 	I have been working on a small project which involves
> capturing an image via a camera and then converting its image
> to a raster format. I was wondering if anyone knew
> of a better dithering program than rasfilter8to1.


I took the "grey.c" program posted here a while ago and wedged in my
Floyd-Steinberg (error diffusion) dither routine, to come up with a new
program I call "bw".  You'll need the pr_stream.c and ntsc.h from that posting
to compile.  In case it's not obvious, type cc -O -o bw bw.c pr_stream.c 
-lpixrect.  I've never tried this with an image which wasn't a multiple of
8 in width, so I don't know if it works - it's supposed to.

If you want really good images, you'll probably want to apply some unsharp
masking while it's in 8-bit greyscale before you apply "bw" to it.  Also,
it's probably not a linear function between % of white pixels
and intensity, so you may want to pass the data through a look-up
table before calling FsDither().


Jonathan Hue		uunet!jvc!jonathan

----------------------------Cut Here------------------------------
echo x - bw.c
sed 's/^X//' >bw.c <<'*-*-END-of-bw.c-*-*'
X#include <sys/types.h>
X#include <stdio.h>
X#include <pixrect/pixrect_hs.h>
X#include <memory.h>
X#include "ntsc.h"
X    
X    
Xstatic char *usage = "usage: \"bw [ infile [ outfile]]\"\n";
X
Xextern int errno;
Xextern char *sys_errlist[];
Xextern char *malloc();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    char *infile, *outfile;
X    struct rasterfile header, outheader;
X    colormap_t colormap;
X    int linebytes, outlinebytes;
X    unsigned char *inline, *outline;
X    register int i, j;
X    register unsigned char *inptr;
X    short *TempLine, *TempErrors;
X    register short *TempPtr;
X    int TempPixels;
X    
X    infile = outfile = NULL;
X    
X    while (--argc)
X    {
X	++argv;
X	if (!infile)
X	    infile = *argv;
X	else if (!outfile)
X	    outfile = *argv;
X	else
X	{
X	    fprintf(stderr, usage);
X	    exit(1);
X	}
X    }
X    
X    if (infile != NULL)
X	if (freopen(infile, "r", stdin) == NULL)
X	{
X	    fprintf(stderr, "bw: can't open input file %s, %s\n%s",
X		    infile, sys_errlist[errno], usage);
X	    exit(1);
X	}
X    if (outfile != NULL)
X	if (freopen(outfile, "w", stdout) == NULL)
X	{
X	    fprintf(stderr, "bw: can't open output file %s, %s\n%s",
X		    outfile, sys_errlist[errno], usage);
X	    exit(1);
X	}
X    if (pr_load_header(stdin, &header) != 0 ||
X	pr_load_colormap(stdin, &header, &colormap) != 0)
X    {
X	fprintf(stderr, "error reading rasterfile header\n");
X	exit(1);
X    }
X    switch (header.ras_depth)
X    {
X      case 8:
X	linebytes = header.ras_width;
X	break;
X      case 24:
X	linebytes = header.ras_width * 3;
X	break;
X      case 32:
X	linebytes = header.ras_width * 4;
X	break;
X      default:
X	fprintf(stderr, "bw: only works with 32, 24 or 8 bit images\n");
X	exit(1);
X    }
X    linebytes += linebytes % 2;
X    
X    TempPixels = header.ras_width;
X    outlinebytes = (header.ras_width + 7) >> 3;
X    if (outlinebytes & 0x1)
X	outlinebytes++;		/* always pad to 16 bits */
X    
X    
X    outheader = header;
X    outheader.ras_depth = 1;
X    outheader.ras_type = RT_STANDARD;
X    outheader.ras_maptype = RMT_NONE;
X    outheader.ras_length = outlinebytes * outheader.ras_height;
X    
X    
X    pr_dump_header(stdout, &outheader, (colormap_t *) NULL);
X    
X    pr_read_init(&header);
X    
X    inline = (unsigned char *) malloc((u_int) linebytes);
X    outline = (unsigned char *) malloc((u_int) outlinebytes);
X    
X    /* the +2 is for one pixel borders on each side */
X    TempLine = (short *) malloc((u_int) ((TempPixels + 2) * sizeof(short)));
X    TempErrors = (short *) malloc((u_int) ((TempPixels + 2) * sizeof(short)));
X    memset((char *) TempErrors, 0, ((TempPixels + 2) * sizeof(short)));
X    
X    for (i = 0; i < outheader.ras_height; ++i)
X    {
X	pr_get_bytes(stdin, &header, linebytes, inline);
X	inptr = inline;
X	TempPtr = TempLine + 1;
X	
X	for (j = 0; j < TempPixels; ++j)
X	{
X	    register int r, g, b;
X	    switch (header.ras_depth)
X	    {
X	      case 8:
X		r = g = b = *inptr++;
X		break;
X	      case 32:
X		++inptr;
X	      case 24:
X		b = *inptr++;
X		g = *inptr++;
X		r = *inptr++;
X		break;
X	    }
X	    if (header.ras_maptype == RMT_EQUAL_RGB)
X	    {
X		r = colormap.map[0][r];
X		g = colormap.map[1][g];
X		b = colormap.map[2][b];
X	    }
X	    /* NTSC weights (.3,.59,.11) */
X	    *TempPtr++ = ((ntscr[r] + ntscg[g] + ntscb[b]) / 256) +
X		          TempErrors[j + 1];
X	}
X	memset((char *) TempErrors, 0, ((TempPixels + 2) * sizeof(short)));
X	memset((char *) outline, 0, outlinebytes);
X	FsDither(TempLine, TempErrors, outline, i, TempPixels);
X	fwrite((char *) outline, 1, outlinebytes, stdout);
X    }
X    fclose(stdout);
X}
X
X
X
X/*
X * Apply Floyd-Steinberg dither to 8-bit data
X */
XFsDither(EightBitPtr, ErrorTerms, OneBitPtr, row, nbytes)
Xregister short *EightBitPtr;	/* Line of input data with 1 pixel borders */
Xregister short *ErrorTerms;	/* Line of error terms with 1 pixel borders */
Xregister u_char *OneBitPtr;	/* Line of output data */
Xint row, nbytes;		/* row (for going -> or <-) */
X{
X    register int i, error;
X    register u_char pattern;
X    
X    if (row & 1)		/* go right to left */
X    {
X	if ((nbytes & 7) == 0)
X	    pattern = 0x01;
X	else
X	    pattern = 1 << (8 - (nbytes & 7));
X	EightBitPtr += nbytes;
X	OneBitPtr += ((nbytes + 7) >> 3) - 1;
X	for (i = nbytes; i > 0; i--)
X	{
X	    if (*EightBitPtr < 127)
X	    {
X		error = *EightBitPtr;
X		*OneBitPtr |= pattern;
X	    }
X	    else
X		error = *EightBitPtr - 255;
X	    *(EightBitPtr - 1) += (error * 7) / 16;
X	    ErrorTerms[i + 1] += (error * 3) / 16;
X	    ErrorTerms[i] += (error * 5) / 16;
X	    ErrorTerms[i - 1] += error / 16;
X	    if (pattern == 0x80)
X	    {
X		pattern = 0x1;
X		OneBitPtr--;
X	    }
X	    else
X		pattern <<= 1;
X	    EightBitPtr--;
X	}
X    }
X    else				/* go left to right */
X    {
X	EightBitPtr++;
X	pattern = 0x80;
X	for (i = 1; i <= nbytes; i++)
X	{
X	    if (*EightBitPtr < 127)
X	    {
X		error = *EightBitPtr;
X		*OneBitPtr |= pattern;
X	    }
X	    else
X		error = *EightBitPtr - 255;
X	    *(EightBitPtr + 1) += (error * 7) / 16;
X	    ErrorTerms[i - 1] += (error * 3) / 16;
X	    ErrorTerms[i] += (error * 5) / 16;
X	    ErrorTerms[i + 1] += error / 16;
X	    if (pattern == 0x01)
X	    {
X		pattern = 0x80;
X		OneBitPtr++;
X	    }
X	    else
X		pattern >>= 1;
X	    EightBitPtr++;
X	}
X    }
X}
X
*-*-END-of-bw.c-*-*
exit

jonathan@jvc.UUCP (Jonathan Hue) (02/17/89)

I screwed up.  A lot of raster file loaders pay attention to ras_maplength
even when ras_maptype is RMT_NONE.  It should always be 0 for these 1-bit
images, so here's a patch.  The program as distributed uses the maplength
of the original.  The bug only shows up when your original has a colormap.
Sorry for the inconvenience.


*** bw.dist	Thu Feb 16 16:19:40 1989
--- bw.c	Thu Feb 16 16:24:52 1989
***************
*** 90,96 ****
      outheader.ras_type = RT_STANDARD;
      outheader.ras_maptype = RMT_NONE;
      outheader.ras_length = outlinebytes * outheader.ras_height;
!     
      
      pr_dump_header(stdout, &outheader, (colormap_t *) NULL);
      
--- 90,96 ----
      outheader.ras_type = RT_STANDARD;
      outheader.ras_maptype = RMT_NONE;
      outheader.ras_length = outlinebytes * outheader.ras_height;
!     outheader.ras_maplength = 0;		/* no color map */    
      
      pr_dump_header(stdout, &outheader, (colormap_t *) NULL);
      

-Jonathan	uunet!jvc!jonathan