From 5b5d13a0df16218b0588cd74ac6c3420e8237646 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 28 Oct 2013 18:26:46 +0100 Subject: [PATCH] Canvas: Handle drawing images with opacity < 1 --- tmxlib/canvas.py | 30 +++++++++++++++++--- tmxlib/draw.py | 6 ++-- tmxlib/layer.py | 1 + tmxlib_test/data/colorcorners-mid-alpha.png | Bin 0 -> 1026 bytes tmxlib_test/test_image.py | 27 ++++++++++++++++++ 5 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 tmxlib_test/data/colorcorners-mid-alpha.png diff --git a/tmxlib/canvas.py b/tmxlib/canvas.py index fdda100..e4ca125 100644 --- a/tmxlib/canvas.py +++ b/tmxlib/canvas.py @@ -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) @@ -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: @@ -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! diff --git a/tmxlib/draw.py b/tmxlib/draw.py index 9a17734..5da88cd 100644 --- a/tmxlib/draw.py +++ b/tmxlib/draw.py @@ -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) diff --git a/tmxlib/layer.py b/tmxlib/layer.py index 5e717ee..ddaba48 100644 --- a/tmxlib/layer.py +++ b/tmxlib/layer.py @@ -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): diff --git a/tmxlib_test/data/colorcorners-mid-alpha.png b/tmxlib_test/data/colorcorners-mid-alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..5b1e6fd8f9f2600417025ebd01d788df281dd64c GIT binary patch literal 1026 zcmV+d1pWJoP)|lhgnJ03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00U-8L_t(o!_}A1ZW~n; z#((F`wPWH;1>_GUB`jD~>XH}W5s;cFk)p1;V$B-C!yr{eK^2>d6=H*U1QskRk<_6{ z9NIc|JTrIBVPQM6(j+rZD=LmOUW|Ot_nm*=JtHy3Z+VBNykq+3B;1j?q@M+LGBy|?>IyU)l-7{KMvuQ_l$xO;r$3j)qvbFWa(ZV%>QNed7`RS{7{ z4Al{ds;Q|ilnA!FOTM`|0#~Ku&R<#1ad+f&fPwls0f0us#+jI*2QFi2j~|n5ZJmSf ztFmWCC(GzYz#t#-9QSm<-DtOsW)oDe*N#v%g8hdNM>Q9rvnT}m0xHmAG7y;MT zIe{B1;okB+o}Zp@(ChL%b~z%_^PJ2Ka|eekGkQHo5}>J+^DXj)l(Te!l}q$tIt!IL z@CSE!!2$m;#|xm3Q4n!P^UnCU0Q%!Xl)xEq0(@Q}V3j)X=h1D3Ss*Wz+`s@4N7XRP zKpdS@Bo%BChD*lD(vZ_zB}c8Z*A($$7Ake%@52;#5E0xJ5L6)qaPL8*KvF?h6z)K= zRuESsgI{)#R4ea=${rXDnm~%Gjvq*p(Sr)K2e4ei9q=_L{{9GCEV0y~>6d~}XQ7fn zj0w<0RZtZ|fJOrv4M$tRVi*7Idx}qUiv39O)t6Y?@Sk?@&Gku})EA=HZ?PW`9LI3Y z@o`-pshlEP-NwBq7vQZ=hTsww!9bXi$SxXV>fM4f$ wI`uc{gTNcwO}6H@N}x)}stCPR0yinczgUg$;Z+%!a{vGU07*qoM6N<$f>M>wCIA2c literal 0 HcmV?d00001 diff --git a/tmxlib_test/test_image.py b/tmxlib_test/test_image.py index 38f660c..dc80fd0 100644 --- a/tmxlib_test/test_image.py +++ b/tmxlib_test/test_image.py @@ -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'))