summaryrefslogtreecommitdiffstats
path: root/share/extensions/tests/test_inkex_gui_pixmaps.py
diff options
context:
space:
mode:
Diffstat (limited to 'share/extensions/tests/test_inkex_gui_pixmaps.py')
-rw-r--r--share/extensions/tests/test_inkex_gui_pixmaps.py232
1 files changed, 232 insertions, 0 deletions
diff --git a/share/extensions/tests/test_inkex_gui_pixmaps.py b/share/extensions/tests/test_inkex_gui_pixmaps.py
new file mode 100644
index 0000000..6e9c9ec
--- /dev/null
+++ b/share/extensions/tests/test_inkex_gui_pixmaps.py
@@ -0,0 +1,232 @@
+# coding=utf-8
+#
+# Copyright 2022 Martin Owens <doctormo@geek-2.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>
+#
+"""
+Test pixmap and image handling from various sources.
+"""
+
+import os
+import sys
+import time
+import pytest
+
+from inkex.tester import TestCase
+from inkex.utils import DependencyError
+
+try:
+ from inkex.gui.tester import MainLoopProtection
+ from inkex.gui.pixmap import (
+ PixmapLoadError,
+ PixmapFilter,
+ OverlayFilter,
+ PadFilter,
+ SizeFilter,
+ SIZE_ASPECT,
+ SIZE_ASPECT_GROW,
+ SIZE_ASPECT_CROP,
+ SIZE_STRETCH,
+ )
+ from inkex.gui import PixmapManager
+except DependencyError:
+ PixmapFilter = object
+ PixmapManager = None
+
+
+class NullFilter(PixmapFilter):
+ required = ["underpants"]
+
+
+@pytest.mark.skipif(PixmapManager is None, reason="PyGObject is required")
+class GtkPixmapsTest(TestCase):
+ """Tests all the pixmaps functionality"""
+
+ def construct_manager(self, **kwargs):
+ """Create a gtk app based on some inputs"""
+ return type(
+ "_PixMan",
+ (PixmapManager,),
+ {
+ "pixmap_dir": self.datadir(),
+ "missing_image": kwargs.pop("missing_image", None),
+ "default_image": kwargs.pop("default_image", None),
+ **kwargs,
+ },
+ )
+
+ def test_filter(self):
+ """Test building filters and errors"""
+ null_filter = NullFilter(underpants=True)
+ self.assertRaises(NotImplementedError, null_filter.filter, "not")
+ self.assertRaises(ValueError, OverlayFilter().filter, None)
+
+ def test_manager_filter_overlay(self):
+ """Test overlay filter in use"""
+ pixmaps = self.construct_manager(filters=[OverlayFilter])("svg")
+ self.assertTrue(pixmaps.get("colors.svg", overlay="application-default-icon"))
+
+ def test_manger_filter_size(self):
+ """Test resizing a file pixmap"""
+ pixmaps = self.construct_manager(filters=[SizeFilter])("svg", size=150)
+ ret = pixmaps.get("colors.svg")
+ self.assertEqual(ret.get_width(), 150)
+ self.assertEqual(ret.get_height(), 50)
+ self.assertRaises(PixmapLoadError, pixmaps.load_from_name, "no-file.svg")
+ self.assertRaises(
+ PixmapLoadError,
+ pixmaps.load_from_name,
+ os.path.join(self.datadir(), "ui", "window-test.ui"),
+ )
+
+ def test_missing_image(self):
+ pixmaps = PixmapManager("svg", filters=[SizeFilter(size=25)])
+ img_a = pixmaps.get("NeverExisted.svg")
+ img_b = pixmaps.get(PixmapManager.missing_image)
+ self.assertEqual(img_a.get_width(), 25)
+ self.assertPixbuf(img_a, img_b)
+
+ def test_overlay_filter(self):
+ """Test overlay filter"""
+ pixmaps = self.construct_manager()("svg")
+ start = pixmaps.get("gradient_with_mixed_offsets.svg")
+
+ # 1. Simple overlay
+ ret = OverlayFilter().filter(start, manager=pixmaps, overlay="colors.svg")
+ comp = pixmaps.get("img/color_overlay_a.png")
+ self.assertPixbuf(ret, comp)
+
+ # 2. Overlay at bottom
+ ret = OverlayFilter(position=1).filter(
+ start, manager=pixmaps, overlay="colors.svg"
+ )
+ comp = pixmaps.get("img/color_overlay_b.png")
+ self.assertPixbuf(ret, comp)
+
+ def test_pad_filter(self):
+ """Test padding filter"""
+ pixmaps = self.construct_manager()("svg")
+ start = pixmaps.get("colors.svg")
+
+ # 1. Add no padding
+ ret = PadFilter(size=(300, 100)).filter(start)
+ self.assertPixbuf(ret, start)
+
+ # 2a. Add padding at top-left
+ ret = PadFilter(size=300, padding=0.0).filter(start)
+ comp = pixmaps.get("img/color_pad_a.png")
+ self.assertPixbuf(ret, comp)
+
+ # 12b. Add padding at top-left
+ ret = PadFilter(size=300, padding=1.0).filter(start)
+ comp = pixmaps.get("img/color_pad_b.png")
+ self.assertPixbuf(ret, comp)
+
+ # 12c. Add padding at top-left
+ ret = PadFilter(size=300, padding=0.5).filter(start)
+ comp = pixmaps.get("img/color_pad_c.png")
+ self.assertPixbuf(ret, comp)
+
+ # 3. Take image and pad to 1px x 150px
+ ret = PadFilter(size=(1, 150)).filter(start)
+ self.assertEqual((ret.get_width(), ret.get_height()), (300, 150))
+
+ def test_size_filter(self):
+ """Test the size pixbuf filter"""
+ pixmaps = self.construct_manager()("svg")
+ start = pixmaps.get("colors.svg")
+ self.assertEqual((start.get_width(), start.get_height()), (300, 100))
+
+ ret = SizeFilter().filter(start)
+ self.assertEqual((ret.get_width(), ret.get_height()), (300, 100))
+
+ ret = SizeFilter(size=600, resize_mode=SIZE_ASPECT).filter(start)
+ self.assertEqual((ret.get_width(), ret.get_height()), (300, 100))
+ self.assertEqual((start.get_width(), start.get_height()), (300, 100))
+
+ ret = SizeFilter(size=60, resize_mode=SIZE_ASPECT).filter(start)
+ self.assertEqual((ret.get_width(), ret.get_height()), (60, 20))
+ self.assertEqual((start.get_width(), start.get_height()), (300, 100))
+
+ ret = SizeFilter(size=600, resize_mode=SIZE_ASPECT_GROW).filter(start)
+ self.assertEqual((ret.get_width(), ret.get_height()), (600, 200))
+ self.assertEqual((start.get_width(), start.get_height()), (300, 100))
+
+ ret = SizeFilter(size=60, resize_mode=SIZE_ASPECT_CROP).filter(start)
+ self.assertEqual((ret.get_width(), ret.get_height()), (180, 60))
+ self.assertEqual((start.get_width(), start.get_height()), (300, 100))
+
+ ret = SizeFilter(size=600, resize_mode=SIZE_STRETCH).filter(start)
+ self.assertEqual((ret.get_width(), ret.get_height()), (600, 600))
+ self.assertEqual((start.get_width(), start.get_height()), (300, 100))
+
+ def test_load_file(self):
+ """Test loading a filename"""
+ pixmaps = self.construct_manager()("svg")
+ self.assertTrue(pixmaps.get("colors.svg"))
+ self.assertFalse(pixmaps.get("colors-no-file.svg"))
+
+ def test_load_name(self):
+ """Test loading from a Gtk named theme icon"""
+ pixmaps = self.construct_manager()()
+ self.assertTrue(pixmaps.get("image-missing"))
+
+ def test_load_data_svg(self):
+ """Test loading a data svg"""
+ pixmaps = self.construct_manager()(size=None, load_size=(128, 128))
+ with open(os.path.join(self.datadir(), "svg", "colors.svg"), "r") as fhl:
+ self.assertTrue(pixmaps.get(fhl.read()))
+ self.assertRaises(PixmapLoadError, pixmaps.load_from_data, "<svg bad")
+
+ def test_load_data_png(self):
+ """Test loading a data png"""
+ pixmaps = self.construct_manager()()
+ with open(os.path.join(self.datadir(), "svg", "img", "green.png"), "rb") as fhl:
+ self.assertPixbuf(pixmaps.get(fhl.read()), pixmaps.get("svg/img/green.png"))
+
+ def test_load_default(self):
+ pixmaps = self.construct_manager()()
+ self.assertFalse(pixmaps.get(None))
+ pixmaps = self.construct_manager(default_image="image-missing")()
+ self.assertTrue(pixmaps.get(None))
+ pixmaps = self.construct_manager(missing_image="image-missing")()
+ self.assertTrue(pixmaps.get("bad-image"))
+
+ def assertPixbuf(self, img_a, img_b, forgive=0.02):
+ """Compare to Gobject pixbufs"""
+ try:
+ self._assert_pixbuf(img_a, img_b, forgive)
+ except Exception:
+ img_a.savev("image_a.png", "png", [], [])
+ img_b.savev("image_b.png", "png", [], [])
+ raise
+
+ def _assert_pixbuf(self, img_a, img_b, forgive):
+ self.assertEqual(img_a.get_colorspace(), img_b.get_colorspace())
+ self.assertEqual(img_a.get_width(), img_b.get_width(), "Width is different")
+ self.assertEqual(img_a.get_height(), img_b.get_height(), "Height is different")
+
+ # Bitmap comparison
+ array = zip(img_a.get_pixels(), img_b.get_pixels())
+ delta, size = 0, 0
+ for a, b in array:
+ delta += a - b
+ size += 1
+
+ pcent = int(forgive * 100)
+ ret = int((delta / 256 / float(size)) * 100)
+ self.assertLess(
+ ret, pcent, f"Result image is not as expected; {ret}% > {pcent}%"
+ )