Thumbnail.

Plane 0

Description

The Unicode bmp (Basic Multilingual Plane), represented by gnu Unifont (see reference image). Created with Chatgpt and Google Colab.

#!/usr/bin/env python3
"""
Deterministically recolor 'unifont-16.0.04-acj.png' by:
1. (Optional) median‐filter smoothing of the B/W mask
2. Counting black & white pixels
3. Generating all 24-bit RGB colors, sorting by luminance
4. Taking the darkest N and lightest M colors (no randomization)
5. Sorting each pool by Morton (Z-order) code to group similar colors
6. Rebuilding the image and saving as 'allrgb-plane0.png'
Ignores unknown CLI args (e.g. Jupyter’s -f).
"""

import argparse
import sys
from PIL import Image, ImageFilter

def luminance(color):
    r, g, b = color
    return 0.2126 * r + 0.7152 * g + 0.0722 * b

def morton_code(color):
    """Interleave the 8 bits of R, G, B into a 24-bit Morton (Z-order) code."""
    r, g, b = color
    code = 0
    for bit in range(8):
        # take bit (7-bit) down to 0
        shift = 7 - bit
        code <<= 3
        code |= ((r >> shift) & 1) << 2 \
              | ((g >> shift) & 1) << 1 \
              | ((b >> shift) & 1)
    return code

def parse_args():
    p = argparse.ArgumentParser(
        description="Deterministic recolor of B/W image with Morton-ordering",
        add_help=False
    )
    p.add_argument(
        "--median-filter-size", "-m",
        type=int, default=1,
        help="Size of median filter to smooth B/W mask (1 = no filter)"
    )
    p.add_argument(
        "-h", "--help",
        action="help",
        help="Show this help message and exit"
    )
    # ignore unknown args
    args, _ = p.parse_known_args()
    return args

def main():
    args       = parse_args()
    input_path = "unifont-16.0.04-acj.png"
    output_fn  = "allrgb-plane0.png"

    # Load & B/W convert
    try:
        img = Image.open(input_path)
    except IOError as e:
        print(f"Error opening '{input_path}': {e}", file=sys.stderr)
        sys.exit(1)
    if img.mode != "L":
        img = img.convert("L")

    # Optional median‐filter
    if args.median_filter_size > 1:
        img = img.filter(ImageFilter.MedianFilter(size=args.median_filter_size))

    w, h   = img.size
    pix_bw = img.load()

    # Count black vs. white
    black_count = white_count = 0
    for y in range(h):
        for x in range(w):
            v = pix_bw[x, y]
            if   v ==   0: black_count += 1
            elif v == 255: white_count += 1
            else:
                raise ValueError(f"Non-B/W pixel {v} at {(x,y)}")

    # Generate & sort all 24-bit colors by luminance
    all_colors = [(r, g, b)
                  for r in range(256)
                  for g in range(256)
                  for b in range(256)]
    all_colors.sort(key=luminance)

    # Deterministic pools
    darkest   = all_colors[:black_count]
    lightest  = all_colors[-white_count:] if white_count else []

    # Morton-order each pool to group similar colors
    darkest.sort(key=morton_code)
    lightest.sort(key=morton_code)

    # Rebuild recolored RGB image
    out = Image.new("RGB", (w, h))
    di = iter(darkest)
    li = iter(lightest)

    for y in range(h):
        for x in range(w):
            if pix_bw[x, y] == 0:
                out.putpixel((x, y), next(di))
            else:
                out.putpixel((x, y), next(li))

    out.save(output_fn)
    print(f"Recolored image saved to '{output_fn}'")

if __name__ == "__main__":
    main()

Author

ACJ
49 entries

Stats

Date
Colors16,777,216
Pixels16,777,216
Dimensions4,096 × 4,096
Bytes19,384,400