[Back to the 30 Days of Programming Overview Page]

Bresenham's Line Algorithm on TachibanaSite (Python 2 + Pillow)

Source Code

(bresenham.markdown.template)

[raw] [download]

<%
# vim: set filetype=python :
import base64
import io
import math

from PIL import Image, ImageDraw

width = 128
height = 72
im = Image.new('1', (width, height), 0)
debug = ImageDraw.Draw(im)

# Get parameters
try:
    x1, y1, x2, y2 = [int(_GET[key]) for key in ['x1', 'y1', 'x2', 'y2']]
    for x in (x1, x2):
        if x < 0 or x >= width:
            raise ValueError
        end
    end
    for y in (y1, y2):
        if y < 0 or y >= height:
            raise ValueError
        end
    end
except (ValueError, KeyError):
    debug.text((2, 0), 'INVALID', fill=1)
    x1 = y1 = x2 = y2 = 0
end

# Go from a to b inclusive with tep one regardless of direction
def xrange_inclusive(a, b):
    if a > b:
        return xrange(a, b - 1, -1)
    else:
        return xrange(a, b + 1)
    end
end

# Bresenham's line algorithm
dx = x2 - x1
dy = y2 - y1
high_slope = (abs(dy) > abs(dx))
#debug.text((2, 0), '{},{}'.format(dx, dy), fill=1)
if high_slope:
    x1, y1 = y1, x1
    x2, y2 = y2, x2
    dx, dy = dy, dx
end
derr = abs(float(dy) / dx)
error = 0.0
y = y1
for x in xrange_inclusive(x1, x2):
    im.putpixel((y, x) if high_slope else (x, y), 1)
    error += derr
    while error >= 0.5:
        y += int(math.copysign(1, dy))
        error -= 1
    end
end

# Output to the page
buffer = io.BytesIO()
(Image.eval(im, lambda p: 1 - p)
        .resize((width*10, height*10))
        .save(buffer, 'PNG'))
data = base64.b64encode(buffer.getvalue())
%>

<p style="margin: 0px;">
<img style="width: 100%;"
    src="data:image/png;base64,{{!data}}"
    />
</p>