Skip to content

Commit

Permalink
Canvas: Handle drawing images with opacity < 1
Browse files Browse the repository at this point in the history
  • Loading branch information
encukou committed Oct 28, 2013
1 parent fed976e commit 5b5d13a
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 6 deletions.
30 changes: 26 additions & 4 deletions tmxlib/canvas.py
Expand Up @@ -43,7 +43,7 @@ class Canvas(PilImage):

def __init__(self, size=(0, 0), commands=()):
self.size = size
self.pil_image = Image.new('RGBA', size)
self.pil_image = Image.new('RGBA', size, color=(0, 0, 0, 0))

for command in commands:
command.draw(self)
Expand All @@ -67,9 +67,11 @@ def trans(self, new_trans):
def _parent_info(self):
return 0, 0, self.to_image()

def draw_image(self, image, pos=(0, 0)):
def draw_image(self, image, pos=(0, 0), opacity=1):
"""Paste the given image at the given position
"""
if not opacity:
return
x, y = pos

try:
Expand All @@ -82,10 +84,30 @@ def draw_image(self, image, pos=(0, 0)):
pil_image = parent.pil_image
except AttributeError:
input = BytesIO(parent._repr_png_())
pil_image = Image.open(input)
pil_image = Image.open(input).convert('RGBA')
if crop:
pil_image = pil_image.crop((image.x, image.y,
image.x + image.width,
image.y + image.height))

self.pil_image.paste(pil_image, (x, y))
if opacity == 1:
alpha_channel = pil_image
self.pil_image.paste(pil_image, (x, y), mask=alpha_channel)
else:
# Create temporary image the same size as the canvas
bigger_image = Image.new('RGBA',
(self.width, self.height),
color=(0, 0, 0, 0))
# Blit into it
bigger_image.paste(pil_image, (x, y))
# Reduce its alpha
bands = bigger_image.split()
alpha_channel = bands[3]
alpha_channel = alpha_channel.point(
lambda x: int(x * opacity))
bigger_image = Image.merge('RGBA', bands[:3] + (alpha_channel, ))
# Finally, blit it to the canvas
self.pil_image = Image.alpha_composite(
self.pil_image,
bigger_image)
# Thanks, PIL, for making this so easy!
6 changes: 4 additions & 2 deletions tmxlib/draw.py
Expand Up @@ -35,9 +35,11 @@ class DrawImageCommand(DrawCommand):
"""
x, y = helpers.unpacked_properties('pos')

def __init__(self, image, pos=(0, 0)):
def __init__(self, image, pos=(0, 0), opacity=1):
self.image = image
self.pos = pos
self.opacity = opacity

def draw(self, canvas):
canvas.draw_image(self.image, self.pos)
canvas.draw_image(self.image, self.pos,
opacity=self.opacity)
1 change: 1 addition & 0 deletions tmxlib/layer.py
Expand Up @@ -248,6 +248,7 @@ def generate_draw_commands(self):
yield draw.DrawImageCommand(
image=tile.image,
pos=(tile.pixel_x, tile.pixel_y - tile.pixel_height),
opacity=self.opacity,
)

def _repr_png_(self):
Expand Down
Binary file added tmxlib_test/data/colorcorners-mid-alpha.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions tmxlib_test/test_image.py
Expand Up @@ -356,6 +356,33 @@ def test_canvas_draw_image(colorcorners_image, canvas_mod):
assert_png_repr_equal(canvas, 'colorcorners-x4.png')


def test_canvas_draw_image_alpha(image_class, colorcorners_image, canvas_mod):
canvas = canvas_mod.Canvas((32, 32))
scribble = load_image(image_class, 'scribble.png')
canvas.draw_image(scribble, opacity=0.5)
canvas.draw_image(colorcorners_image, pos=(8, 8), opacity=0.5)

assert_png_repr_equal(canvas, 'colorcorners-mid-alpha.png', epsilon=1)

canvas.draw_image(scribble, opacity=0)
assert_png_repr_equal(canvas, 'colorcorners-mid-alpha.png', epsilon=1)


def test_canvas_command_img_alpha(image_class, colorcorners_image, canvas_mod):
canvas = canvas_mod.Canvas((32, 32))
scribble = load_image(image_class, 'scribble.png')
for command in (
tmxlib.draw.DrawImageCommand(scribble, opacity=0.5),
tmxlib.draw.DrawImageCommand(colorcorners_image, pos=(8, 8),
opacity=0.5)):
command.draw(canvas)

assert_png_repr_equal(canvas, 'colorcorners-mid-alpha.png', epsilon=1)

tmxlib.draw.DrawImageCommand(scribble, opacity=0).draw(canvas)
assert_png_repr_equal(canvas, 'colorcorners-mid-alpha.png', epsilon=1)


def test_canvas_draw_overlap(image_class, canvas_mod):
canvas = canvas_mod.Canvas((32, 32))
canvas.draw_image(load_image(image_class, 'scribble.png'))
Expand Down

0 comments on commit 5b5d13a

Please sign in to comment.