Algorithms to "anti-alias" (or somehow improve) binary 1-bit drawings and fonts These days anti-aliasing uses gray scale pixel values on displays with high pixel counts.

I'd like to take a step back in time and learn what is available for anti-aliasting or at least improving the quality of curved lines and fonts drawn on bindary (on/off) 1-bit displays, such as these low cost OLED displays shown below.

I don't know if the procedure would be called anti-aliasing, or something else. Ideally an explanation or a link/reference to a mathematical procedure or algorithm would be most helpful, or if something exists in Python, that would be great as well.

PIL, the Python Image Library is wonderful but I have a hunch it is mostly useful for gray scale or RGB continuous tone images rather than binary 1-bit images.

See for example the question Drawing multilingual text using PIL and saving as 1-bit and 8-bit bitmaps, where PIL turned this gray scale image:



into this 1-bit binary image:



and similar things would happen if I drew circles in PIL and then converted to 1-bit. The antialiasing is designed for continuous tone display, and so the subsequent thresholding just makes a mess.



Example of a 1-bit binary OLED display (128x64 pixels) cropped from this image from the AdaFruit Page Monochrome 0.96" 128x64 OLED graphic display, Product ID: 326.
PIL's Image.convert function performs dithering by default when you convert the image to 1-bit—not simply thresholding. That's what creates the noise along the edges of the shapes; the antialiasing isn't the problem. Unfortunately, at such a low resolution, the dithering does more harm than good.

I grabbed your original image from your other question and did a straight threshold at 128, and it comes out looking a lot better:



That's probably about as good as you'll be able to do on a low-resolution 1-bit display, absent a bitmap font that's specifically designed for those circumstances.

In PIL this operation can be implemented using Image.point, as follows:

image1Bit = image8Bit.point(lambda x: 0 if x &lt; 128 else 1, mode='1')