from PIL import Image, ImageDraw, ImageFont

width  = 300   # 30mm @ 254 DPI
height = 1070  # 4 inches @ 254 DPI + padding top and bottom for labels
dpi    = (254, 254)

bottom = height - 1 - 20  # 20px bottom padding for "0" label
right  = width - 1

font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 20)

def draw_ticks(draw, centered=False, major_color='black'):
    if centered:
        # center of 1cm tick is x=40; center of 1" tick is right-40
        cm_5mm  = (15, 65)
        in_025  = (right - 50, right - 30)
        in_05   = (right - 65, right - 15)
    else:
        cm_5mm  = (0, 50)
        in_025  = (right - 20, right)
        in_05   = (right - 50, right)
    for i in range(0, 21):
        y = bottom - i * 50
        draw.line([(cm_5mm[0], y), (cm_5mm[1], y)], fill='black', width=3)
    for i in range(0, 11):
        y = bottom - i * 100
        draw.line([(0, y), (80, y)], fill=major_color, width=3)
    for i in range(0, 17):
        y = round(bottom - i * 254 / 4)
        draw.line([(in_025[0], y), (in_025[1], y)], fill='black', width=3)
    for i in range(0, 9):
        y = bottom - i * 127
        draw.line([(in_05[0], y), (in_05[1], y)], fill='black', width=3)
    for i in range(0, 5):
        y = bottom - i * 254
        draw.line([(right - 80, y), (right, y)], fill=major_color, width=3)

def draw_baselines(draw):
    draw.line([(0, bottom - 1000), (0, bottom)], fill='black', width=3)
    draw.line([(right, bottom - 4 * 254), (right, bottom)], fill='black', width=3)

def draw_numbers(draw, cm_step=1):
    ref_w = font.getbbox('10')[2] - font.getbbox('10')[0]
    for i in range(0, 11, cm_step):
        y = bottom - i * 100
        label = str(i)
        bbox = font.getbbox(label)
        text_w = bbox[2] - bbox[0]
        text_h = bbox[3] - bbox[1]
        draw.text((85 + ref_w - text_w, y - bbox[1] - text_h // 2), label, fill='black', font=font)
    digit_w = font.getbbox('1')[2] - font.getbbox('1')[0]
    extra = ref_w - digit_w
    for i in range(0, 5):
        y = bottom - i * 254
        label = str(i)
        bbox = font.getbbox(label)
        text_w = bbox[2] - bbox[0]
        text_h = bbox[3] - bbox[1]
        draw.text((right - 85 - text_w - extra, y - bbox[1] - text_h // 2), label, fill='black', font=font)

def make(filename, baselines, numbers, cm_step=1, centered=False, major_color='black'):
    img  = Image.new('RGB', (width, height), 'white')
    draw = ImageDraw.Draw(img)
    if baselines:
        draw_baselines(draw)
    draw_ticks(draw, centered=centered, major_color=major_color)
    if numbers:
        draw_numbers(draw, cm_step=cm_step)
    img.save(filename, dpi=dpi)

make('plain.png',  baselines=True,  numbers=False)
make('ruler.png',  baselines=True,  numbers=True)
make('plain2.png', baselines=False, numbers=False)
make('ruler2.png', baselines=False, numbers=True)
make('ruler3.png',  baselines=False, numbers=True,  cm_step=2)
make('simple.png',  baselines=False, numbers=False, centered=True)
# final: 240px wide (tick lengths unchanged)
width = 240
right = width - 1
make('final.png',   baselines=False, numbers=False, centered=True, major_color=(255, 0, 0))
width = 300
right = width - 1

print("Done")
