leue@galen.crd.ge.com (Bill Leue) (06/20/91)
Does anyone know of a halftone filter which could be used to take an 8-bit-deep sun Raster file and print it on an ordinary Apple LaserWriter or other PS printer? I would like to generate some "lab notebook quality" prints of grayscale information which I am rendering on an X canvas. I would prefer to have a Floyd-Steinberg Error Diffusion-type halftoning algorithm, but beggars can't be choosers. Source code would be preferred, since then I could incorporate the print snapshot capability directly into my X display tool, but an executable filter which could be inserted into a pipeline like "cat snapshot.rs | halftone | suntops | lpr" or some such would be fine. Thanks! -Bill Leue leue@crd.ge.com
falk@peregrine.Sun.COM (Ed Falk) (06/22/91)
In article <20764@crdgw1.crd.ge.com> leue@galen.crd.ge.com (Bill Leue) writes: >Does anyone know of a halftone filter which could be used to take >an 8-bit-deep sun Raster file and print it on an ordinary Apple >LaserWriter or other PS printer? Don't halftone it at all! The laser printer can do a better job of halftoning than any offline filter ever will. There's half a dozen programs out on the net (see the pbm and fbm packages for starters) that will convert an 8-bit image to a (big!) postscript file. Just print that postscript file (takes about 20-40 minutes) and there you are. -ed falk, sun microsystems sun!falk, falk@sun.com In the future, somebody will quote Andy Warhol every 15 minutes.
steve@hanauma.stanford.edu (Steve Cole) (06/22/91)
In article <15643@exodus.Eng.Sun.COM> falk@peregrine.Sun.COM (Ed Falk) writes: >In article <20764@crdgw1.crd.ge.com> leue@galen.crd.ge.com (Bill Leue) writes: >>Does anyone know of a halftone filter which could be used to take >>an 8-bit-deep sun Raster file and print it on an ordinary Apple >>LaserWriter or other PS printer? > >Don't halftone it at all! The laser printer can do a better job of >halftoning than any offline filter ever will. There's half a dozen >programs out on the net (see the pbm and fbm packages for starters) >that will convert an 8-bit image to a (big!) postscript file. Just >print that postscript file (takes about 20-40 minutes) and there you are. > Ed, you have missed a chance to plug your own company. A big 8 bit raster that might take that long to come out on some laser printers will come out in 2-3 minutes on the Sun SPARCprinter. But generally speaking, halftoning it yourself is not such a bad idea. If you do have a slow printer, then perhaps you can do the halftoning yourself much faster than it can, and not wait 20 minutes. This is the principle behind the SPARCprinter; the workstation does the halftoning. After all, it has a better cpu than most laser printers. Halftoning it yourself also opens up new possibilities. Bill Leue asked about Floyd-Steinberg dithering in his original posting. I wrote the following routine as part of the vplot graphics package, developed at Stanford. (Aside: vplot is a device-independent graphics package that includes a library of routines for application programs to call, and filters that then can display the output on a wide variety of devices. It is available for anonymous ftp from hanauma.stanford.edu) Anyway, this routine does the 8 bit to 1 bit halftoning conversion using one of four methods - random dither, ordered dither, Floyd-Steinberg, and a halftoning scheme similar to what a PostScript printer will do. The latter two are the best methods. A good reference for such work: Digital Halftoning by Robert Ulichney, MIT Press (hope I have that right). Here is the code for anyone who is interested. There are some vplot-isms, such as the fact that the program returns 8 bits/pixel, but with the values 0 or 7. And you have to call the routine for each line in the raster instead of just once. There are reasons for such weirdnesses, but if you want to use the code I'm sure you can deal with these things. ----------begin dither.c----------- /* * Copyright 1987 the Board of Trustees of the Leland Stanford Junior * University. Official permission to use this software is included in * the documentation. It authorizes you to use this file for any * non-commercial purpose, provided that this copyright notice is not * removed and that any modifications made to this file are commented * and dated in the style of my example below. */ /* * * source file: ./filters/utilities/dither.c * * Joe Dellinger (SEP), June 11 1987 * Inserted this sample edit history entry. * Please log any further modifications made to this file: * Steve Cole (SEP), September 1 1987 * Added method 4 (digital halftoning). * Joe Dellinger March 28 1988 * Move invras out of here and into greycorr, where it belonged * in the first place. * Steve Cole (SEP), June 10 1988 * Replaced if blocks for each dithering method with a single switch. */ /* * this subroutine converts a single raster line to single bit * using one of the following algorithms: * * 1 random threshold * 2 256 element ordered dither (oriented at 0 degrees) * 3 Floyd-Steinberg minimized average error method * 4 32 element halftone (oriented at 45 degrees) * * Steve Cole, April 1987 * */ #include <stdio.h> #include "../include/err.h" #include "../include/params.h" #include "../include/extern.h" static int pix_on = 0, pix_off = 7; char *malloc (); static float *errline; static int ialloc; static float alpha = 0.4375; static float beta = 0.1875; static float gamma = 0.3125; static float delta = 0.0625; static int dith256[256] = { 1, 128, 32, 160, 8, 136, 40, 168, 2, 130, 34, 162, 10, 138, 42, 170, 192, 64, 224, 96, 200, 72, 232, 104, 194, 66, 226, 98, 202, 74, 234, 106, 48, 176, 16, 144, 56, 184, 24, 152, 50, 178, 18, 146, 58, 186, 26, 154, 240, 112, 208, 80, 248, 120, 216, 88, 242, 114, 210, 82, 250, 122, 218, 90, 12, 140, 44, 172, 4, 132, 36, 164, 14, 142, 46, 174, 6, 134, 38, 166, 204, 76, 236, 108, 196, 68, 228, 100, 206, 78, 238, 110, 198, 70, 230, 102, 60, 188, 28, 156, 52, 180, 20, 148, 62, 190, 30, 158, 54, 182, 22, 150, 252, 124, 220, 92, 244, 116, 212, 84, 254, 126, 222, 94, 246, 118, 214, 86, 3, 131, 35, 163, 11, 139, 43, 171, 1, 129, 33, 161, 9, 137, 41, 169, 195, 67, 227, 99, 203, 75, 235, 107, 193, 65, 225, 97, 201, 73, 233, 105, 51, 179, 19, 147, 59, 187, 27, 155, 49, 177, 17, 145, 57, 185, 25, 153, 243, 115, 211, 83, 251, 123, 219, 91, 241, 113, 209, 81, 249, 121, 217, 89, 15, 143, 47, 175, 7, 135, 39, 167, 13, 141, 45, 173, 5, 133, 37, 165, 207, 79, 239, 111, 199, 71, 231, 103, 205, 77, 237, 109, 197, 69, 229, 101, 63, 191, 31, 159, 55, 183, 23, 151, 61, 189, 29, 157, 53, 181, 21, 149, 254, 127, 223, 95, 247, 119, 215, 87, 253, 125, 221, 93, 245, 117, 213, 85 }; static int halftone32[64] = { 92, 100, 124, 148, 164, 156, 132, 108, 28, 20, 76, 220, 228, 236, 180, 36, 4, 12, 84, 212, 252, 244, 172, 44, 52, 60, 116, 188, 204, 196, 140, 68, 164, 156, 132, 108, 92, 100, 124, 148, 228, 236, 180, 36, 28, 20, 76, 220, 252, 244, 172, 44, 4, 12, 84, 212, 204, 196, 140, 68, 52, 60, 116, 188 }; dithline (inpline, outline, npixels, linenum, imethod) unsigned char *inpline, *outline; int npixels, linenum, imethod; { int greydata; int i1, ipoint, jpoint; float pixel, pixerr, nexterr; int irand; switch (imethod) { /* Random Dither */ case 1: for (i1 = 0; i1 < npixels; i1++) { greydata = inpline[i1]; irand = (random () & 255); if (greydata > irand) { outline[i1] = pix_off; } else { outline[i1] = pix_on; } } break; /* Ordered Dither */ case 2: for (i1 = 0; i1 < npixels; i1++) { greydata = inpline[i1]; ipoint = i1 % 16; jpoint = linenum % 16; ipoint = ipoint * 16 + jpoint; if (greydata > dith256[ipoint]) { outline[i1] = pix_off; } else { outline[i1] = pix_on; } } break; /* Floyd-Steinberg */ case 3: if (ialloc != 1) { if ((errline = (float *) malloc ((unsigned) npixels * sizeof (float))) == NULL) { ERR (FATAL, name, "Can't allocate space for Floyd-Steinberg\n"); return; } ialloc = 1; for (i1 = 0; i1 < npixels; i1++) { errline[i1] = 0.; } } nexterr = errline[0]; for (i1 = 0; i1 < npixels; i1++) { pixel = inpline[i1]; pixel += nexterr; if (pixel < 128) { outline[i1] = pix_on; pixerr = pixel; } else { outline[i1] = pix_off; pixerr = pixel - 255; } if (i1 < npixels) { nexterr = errline[i1 + 1] + pixerr * alpha; errline[i1 + 1] = pixerr * delta; } if (i1 > 0) { errline[i1 - 1] += pixerr * beta; } errline[i1] += pixerr * gamma; if (i1 == 0) errline[i1] = pixerr * gamma; } break; /* 32 element halftone at 45 degrees */ case 4: default: for (i1 = 0; i1 < npixels; i1++) { greydata = inpline[i1]; ipoint = i1 % 8; jpoint = linenum % 8; ipoint = ipoint * 8 + jpoint; if (greydata > halftone32[ipoint]) { outline[i1] = pix_off; } else { outline[i1] = pix_on; } } break; } } ----------end dither.c----------- ----------------------------------------------------------------- Steve Cole (steve@hanauma.stanford.edu, apple!hanauma!steve) Department of Geophysics, Stanford University, Stanford, CA 94305