Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!csd4.milw.wisc.edu!leah!itsgw!steinmetz!uunet!jvc!jonathan From: jonathan@jvc.UUCP (Jonathan Hue) Newsgroups: comp.graphics Subject: Re: Image Conversion 8bits to 1 Summary: here's one Message-ID: <313@jvc.UUCP> Date: 16 Feb 89 20:11:59 GMT References: <1747@quanta.eng.ohio-state.edu> Organization: JVC Laboratory of America Lines: 249 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 X#include X#include X#include 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