Python image art project This program takes in an image, and saves an "arrowed" version of that image to /tmp/image.png. Example input and output is below the code.

from PIL import Image, ImageDraw
import operator
from pprint import pprint
import sys

base_width = 10
arrow_base_height = 15
arrow_point_height = 15
margin = (20,20)
do_outline = True
outline = (0, 0, 0) # black
background_color  = (255, 255, 255) # white

arrow_width = base_width / 2
total_arrow_height = arrow_base_height + arrow_point_height
total_arrow_width = 2 * base_width

def drawArrow(coords, color):
    if do_outline:
        draw.polygon(coords, fill=color, outline=outline)
    else:
        draw.polygon(coords, fill=color)

def to_real_coordinates(coords):
    # translates the coords to pixels on the picture
    return translate(coords, margin)

def translate(coords, vector):
    # Translates a list of coordinate tuples over a vector tuple
    t_coords = []
    for cord in coords:
        t_coords.append(tuple(map(operator.add, cord, vector)))
    return t_coords

def mirror(coords):
    # Takes a list of coordinate tuples and mirrors it across the first element of
    #    the first tuple
    # Formula: 2 * base - original
    m_coords = []
    base = coords[0]
    double_base = tuple(map(operator.mul, base, len(base)* (2,) ))
    for cord in coords:
        m_coords.append(tuple(map(operator.sub, double_base, cord)))
    return m_coords

def get_arrow_coords():
    coords = [
        (0, 0),
        (arrow_base_height, 0),
        (arrow_base_height, arrow_width),
        (arrow_base_height + arrow_point_height, - arrow_width),
        (arrow_base_height, -3 * arrow_width),
        (arrow_base_height, - base_width),
        (0, - base_width)
    ]
    return coords

if __name__ == "__main__":
    orig = Image.open(sys.argv[1]).transpose(Image.ROTATE_90)
    pix = orig.load()
    new_size = (1024,1024)
    actual_size = (new_size[0] + 2 * margin[0], new_size[1] + 2*margin[1])
    im = Image.new("RGB", actual_size, background_color)
    draw = ImageDraw.Draw(im)
    arrow = get_arrow_coords()
    m_arrow = mirror(arrow)
    for i in range(new_size[0] / total_arrow_height):
        for j in range((new_size[1] / total_arrow_width)):
            color = pix[
                i * total_arrow_height * orig.size[0] / new_size[0],
                j * total_arrow_width * orig.size[1] / new_size[1]
            ]
            # calculate and draw arrow
            coords = translate(arrow, (i * total_arrow_height, j * total_arrow_width))
            real_coords = to_real_coordinates(coords)
            drawArrow(real_coords, color)
            # calculate and draw mirrored arrow
            coords = translate(m_arrow, (arrow_base_height + i * total_arrow_height, j * total_arrow_width))
            real_coords = to_real_coordinates(coords)
            drawArrow(real_coords, color)

    im = im.transpose(Image.ROTATE_270)
    im.show()
    im.save("/tmp/image.png")
Be consistent and pythonic in naming functions.

draw_arrow instead of drawArrow

Use comprehensions instead of creating empty list and appending to it in a for loop. It's both faster and easier to read.

def translate(coords, vector):
    # Translates a list of coordinate tuples over a vector tuple
    return tuple(tuple(map(operator.add, c, vector)) for c in coords)

def mirror(coords):
    # Takes a list of coordinate tuples and mirrors it across the first element of
    #    the first tuple
    # Formula: 2 * base - original
    base = coords[0]
    double_base = tuple(map(operator.mul, base, len(base) * (2,) ))
    return tuple(tuple(map(operator.sub, double_base, cord)) for c in coords)


Why have a function that returns a constant value. Why creating a variable when you can just return the value.

def get_arrow_coords():
    return [...]
# or if you worry about mutability - use tuples. They actually faster if you wouldn't try to modify them (creating new ones from old ones) a lot.

arrow_coords = ...


You can also use collections.namedtuple('Size', 'height width') instead of using plain tuples for sizes. This would improve readability a little.

And I'm not sure, but maybe you would benefit from using numpy as it seems that you're doing some matrices work.