File: compositeops.py

package info (click to toggle)
mypaint 2.0.1-14
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 27,884 kB
  • sloc: python: 43,893; cpp: 6,931; xml: 2,475; sh: 473; makefile: 25
file content (140 lines) | stat: -rw-r--r-- 5,164 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/env python
# Tests the layer compositing/blending code for correctness of its
# advertized optimization flags.

from __future__ import division, print_function
from random import random
import unittest

import numpy as np

from . import paths
from lib import mypaintlib
from lib.tiledsurface import N
from lib.modes import MODE_STRINGS
from lib.pycompat import xrange


ALPHA_VALUES = (0.0, 0.5, 1.0)
GREY_VALUES = (0.0, 0.25, 0.5, 0.75, 1.0)
COLOR_COMPONENT_VALUES = (0.333, 0.666)
FIX15_ONE = 1 << 15


class Ops (unittest.TestCase):

    def tearDown(self):
        pass

    def setUp(self):
        if not mypaintlib.heavy_debug:
            self.skipTest("not compiled with HEAVY_DEBUG")

        # Unpremultiplied floating-point RGBA tuples
        self.sample_data = []

        # Make some alpha/grey/color combinations
        for a in ALPHA_VALUES:
            for v in GREY_VALUES:
                self.sample_data.append((v, v, v, a))
            for r in COLOR_COMPONENT_VALUES:
                for g in COLOR_COMPONENT_VALUES:
                    for b in COLOR_COMPONENT_VALUES:
                        self.sample_data.append((r, g, b, a))
        assert len(self.sample_data) < N

        # What the hell, have some random junk too
        for i in xrange(len(self.sample_data), N):
            fuzz = (random(), random(), random(), random())
            self.sample_data.append(fuzz)
        assert len(self.sample_data) == N

        # Prepare striped test data in a tile array
        self.src = np.empty((N, N, 4), dtype='uint16')
        self.dst_orig = np.empty((N, N, 4), dtype='uint16')
        for i, rgba1 in enumerate(self.sample_data):
            r1 = int(FIX15_ONE * rgba1[0] * rgba1[3])
            g1 = int(FIX15_ONE * rgba1[1] * rgba1[3])
            b1 = int(FIX15_ONE * rgba1[2] * rgba1[3])
            a1 = int(FIX15_ONE * rgba1[3])

            assert r1 <= FIX15_ONE
            assert r1 >= 0
            assert g1 <= FIX15_ONE
            assert g1 >= 0
            assert b1 <= FIX15_ONE
            assert b1 >= 0
            assert a1 <= FIX15_ONE
            assert a1 >= 0

            assert r1 <= a1
            assert g1 <= a1
            assert b1 <= a1
            for j in xrange(len(self.sample_data)):
                self.src[i, j, :] = (r1, g1, b1, a1)
                self.dst_orig[j, i, :] = (r1, g1, b1, a1)

    def test_all_modes_correctness(self):
        """Test that all modes work the way they advertise"""
        # Test each mode in turn
        for mode in xrange(mypaintlib.NumCombineModes):
            mode_info = mypaintlib.combine_mode_get_info(mode)
            mode_name = mode_info["name"]

            src = self.src
            dst = np.empty((N, N, 4), dtype='uint16')
            dst[...] = self.dst_orig[...]

            # Combine using the current mode
            mypaintlib.tile_combine(mode, src, dst, True, 1.0)

            # Tests
            zero_alpha_has_effect = False
            zero_alpha_clears_backdrop = True  # means: "*always* clears b."
            can_decrease_alpha = False
            for i in xrange(len(self.sample_data)):
                for j in xrange(len(self.sample_data)):
                    old = tuple(self.dst_orig[i, j])
                    new = tuple(dst[i, j])
                    if src[i][j][3] == 0:
                        if new[3] != 0 and old[3] != 0:
                            zero_alpha_clears_backdrop = False
                        if old != new:
                            zero_alpha_has_effect = True
                    if (not can_decrease_alpha) and (new[3] < old[3]):
                        can_decrease_alpha = True
                    self.assertFalse(
                        (new[0] > new[3] or
                         new[1] > new[3] or
                         new[2] > new[3]),
                        msg="%s isn't writing premultiplied data properly"
                            % (mode_name,),
                    )
                    self.assertFalse(
                        (new[0] > FIX15_ONE or new[1] > FIX15_ONE or
                         new[2] > FIX15_ONE or new[3] > FIX15_ONE),
                        msg="%s isn't writing fix15 data properly"
                            % (mode_name,),
                    )

            flag_test_results = [
                ("zero_alpha_has_effect", zero_alpha_has_effect),
                ("zero_alpha_clears_backdrop", zero_alpha_clears_backdrop),
                ("can_decrease_alpha", can_decrease_alpha),
            ]
            for info_str, tested_value in flag_test_results:
                current_value = bool(mode_info[info_str])
                self.assertEqual(
                    current_value, tested_value,
                    msg="%s's %r is wrong: should be %r, not %r"
                        % (mode_name, info_str, tested_value, current_value),
                )
            self.assertTrue(
                mode in MODE_STRINGS,
                msg="%s needs localizable UI strings" % (mode_name,),
            )


if __name__ == "__main__":
    assert paths  # to avoid a flake8 warning, nothing more
    unittest.main()