diff --git a/.travis.yml b/.travis.yml index a2f99a540..ac4c5193b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ matrix: - libxcursor-dev - libunistring-dev - libpng-dev + - python3-pil - os: linux dist: trusty @@ -40,6 +41,7 @@ matrix: - libxcursor-dev - libunistring-dev - libpng-dev + - python3-pil - os: linux dist: trusty @@ -60,6 +62,7 @@ matrix: - libxcursor-dev - libunistring-dev - libpng-dev + - python3-pil - clang - os: osx language: generic diff --git a/kitty_tests/graphics.py b/kitty_tests/graphics.py index d9dc9d8eb..c45719cc9 100644 --- a/kitty_tests/graphics.py +++ b/kitty_tests/graphics.py @@ -4,13 +4,20 @@ import os import tempfile +import unittest import zlib from base64 import standard_b64encode +from io import BytesIO from kitty.fast_data_types import parse_bytes from . import BaseTest +try: + from PIL import Image +except ImportError: + Image = None + def relpath(name): base = os.path.dirname(os.path.abspath(__file__)) @@ -31,33 +38,39 @@ def send_command(screen, cmd, payload=b''): return c.wtcbuf +def helpers(self): + s = self.create_screen() + g = s.grman + + def l(payload, **kw): + kw.setdefault('i', 1) + cmd = ','.join('%s=%s' % (k, v) for k, v in kw.items()) + res = send_command(s, cmd, payload) + if not res: + return + return res.decode('ascii').partition(';')[2].partition('\033')[0] + + def sl(payload, **kw): + if isinstance(payload, str): + payload = payload.encode('utf-8') + data = kw.pop('expecting_data', payload) + cid = kw.setdefault('i', 1) + self.ae('OK', l(payload, **kw)) + img = g.image_for_client_id(cid) + self.ae(img['client_id'], cid) + self.ae(img['data'], data) + if 's' in kw: + self.ae((kw['s'], kw['v']), (img['width'], img['height'])) + self.ae(img['is_4byte_aligned'], kw.get('f') != 24) + return img + + return s, g, l, sl + + class TestGraphics(BaseTest): def test_load_images(self): - s = self.create_screen() - g = s.grman - - def l(payload, **kw): - kw.setdefault('i', 1) - cmd = ','.join('%s=%s' % (k, v) for k, v in kw.items()) - res = send_command(s, cmd, payload) - if not res: - return - return res.decode('ascii').partition(';')[2].partition('\033')[0] - - def sl(payload, **kw): - if isinstance(payload, str): - payload = payload.encode('utf-8') - data = kw.pop('expecting_data', payload) - cid = kw.setdefault('i', 1) - self.ae('OK', l(payload, **kw)) - img = g.image_for_client_id(cid) - self.ae(img['client_id'], cid) - self.ae(img['data'], data) - if 's' in kw: - self.ae((kw['s'], kw['v']), (img['width'], img['height'])) - self.ae(img['is_4byte_aligned'], kw.get('f') != 24) - return img + s, g, l, sl = helpers(self) # Test simple load for f in 32, 24: @@ -76,7 +89,13 @@ class TestGraphics(BaseTest): # Test compression random_data = os.urandom(3 * 1024) compressed_random_data = zlib.compress(random_data) - sl(compressed_random_data, s=24, v=32, o='z', expecting_data=random_data) + sl( + compressed_random_data, + s=24, + v=32, + o='z', + expecting_data=random_data + ) # Test loading from file f = tempfile.NamedTemporaryFile() @@ -85,10 +104,38 @@ class TestGraphics(BaseTest): self.assertTrue(os.path.exists(f.name)) f.seek(0), f.truncate(), f.write(compressed_random_data), f.flush() sl(f.name, s=24, v=32, t='t', o='z', expecting_data=random_data) - self.assertRaises(FileNotFoundError, f.close) # check that file was deleted + self.assertRaises( + FileNotFoundError, f.close + ) # check that file was deleted # Test loading from POSIX SHM name = '/kitty-test-shm' g.shm_write(name, random_data) sl(name, s=24, v=32, t='s', expecting_data=random_data) - self.assertRaises(FileNotFoundError, g.shm_unlink, name) # check that file was deleted + self.assertRaises( + FileNotFoundError, g.shm_unlink, name + ) # check that file was deleted + + @unittest.skipIf(Image is None, 'PIL not available, skipping PNG tests') + def test_load_png(self): + s, g, l, sl = helpers(self) + w, h = 5, 3 + img = Image.new('RGBA', (w, h), 'red') + rgba_data = img.tobytes() + + def png(mode='RGBA'): + buf = BytesIO() + i = img + if mode != i.mode: + i = img.convert(mode) + i.save(buf, 'PNG') + return buf.getvalue() + + for mode in 'RGBA RGB P'.split(): + data = png(mode) + sl(data, f=100, S=len(data), expecting_data=rgba_data) + + img = img.convert('L') + rgba_data = img.convert('RGBA').tobytes() + data = png('L') + sl(data, f=100, S=len(data), expecting_data=rgba_data)