I recently toyed around with some halftone, a technique for simulating continuous tone images using solid dots. I can’t remember what specifically gave me the idea to try it out. Perhaps it was because it provided a good use-case for my newly discovered hot code replacement.

git clone git://github.com/skeeto/Halftone.git

Halftone dates back to the 19th century and was the first low-cost method for printing images because it didn’t require highly skilled artists. What made it so inexpensive was that producing the relief surface was an entirely mechanical process. Light is projected through a negative, through a mesh screen, and onto a plate containing light sensitive chemicals. Brighter parts of the image would form larger spots and dimmer parts smaller dots. The chemical on the plate would react to the light and rise up very slightly. The plate is then inked and used for printing.

Halftone printing is still used today, but, of course, the process for generating the halftone version of an image is all done with computers. Digital halftoning. Digital halftoning provides several different ways to arrange the dots: by size (amplitude modulation), by spacing (frequency modulation), by shape, or any combination of these. In my little demo above I took the simplest route, by size.

I scale the image down using bicubic interpolation (thanks to the handy AffineTransform). With it scaled down, each pixel becomes a single dot in my final image. Since I want the dots to fully fill their space at the most extreme, their maximum radius is the square root of two times the spacing. That is, the dots will just touch on the diagonal when full. To determine magnitude of the dot I used the [luma coefficients](http://en.wikipedia.org/wiki/Luma_(video%29). That makes the RGB values weighted more accurately to the way human sight perceives brightness.

Rotating the image would be an improvement over the flat grid it is now. A 45-degree rotation helps break up potential patterns. I tried to do this, but I couldn’t get the math right along with the correct parameters to the AffineTransform. Something was always getting clipped or padded incorrectly. Adding CMYK color would also be interesting, and would also require rotation of the dot grid — each color gets its own angle.

I also thought about having it dump out the image in vector form as a SVG or PostScript, which would make it start to behave like The Rasterbator. With that output, it would only need to split up that output into normal-sized pages and I could use it to produce large images from a cheap printer.

Have a comment on this article? Start a discussion in my public inbox by sending an email to ~skeeto/public-inbox@lists.sr.ht [mailing list etiquette] , or see existing discussions.

null program

Chris Wellons

wellons@nullprogram.com (PGP)
~skeeto/public-inbox@lists.sr.ht (view)