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")
-
\$\begingroup\$ Looks kind of cool, but might I ask why you want to convert images to "arrow images"? \$\endgroup\$holroy– holroy2017年05月14日 13:15:03 +00:00Commented May 14, 2017 at 13:15
-
2\$\begingroup\$ @holroy: it's an art project I'm doing. It's basically a mix of Escher, Above and Invaders. \$\endgroup\$redfast00– redfast002017年05月14日 13:33:08 +00:00Commented May 14, 2017 at 13:33
1 Answer 1
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.