Add comprehensive tests for image processing and mask functionalities
- Introduced tests for color image handling, ensuring source preservation and premultiplied alpha usage. - Implemented tests for brush stroke operations, validating segment boundaries and brush anti-aliasing. - Added tests for frame anti-aliasing, confirming correct rendering behavior with various alpha values and depth settings. - Created tests for frame projection, ensuring accurate overlap calculations and half-plane clipping. - Developed tests for image premultiplied retention, verifying behavior during loading and packing processes. - Added undo functionality tests for mask operations, ensuring single transaction behavior during edits.
This commit is contained in:
@@ -37,8 +37,6 @@ def reference_selection_mask(
|
||||
if antialias
|
||||
else mask.astype(np.float32)
|
||||
)
|
||||
if selection_path.invert:
|
||||
mask = 1.0 - mask
|
||||
bounds = selection._selection_canvas_bounds(
|
||||
image_size,
|
||||
selection_path,
|
||||
@@ -73,45 +71,25 @@ def assert_matches_reference(image_size, selection_path, **options):
|
||||
np.testing.assert_array_equal(actual.values, expected.values)
|
||||
|
||||
|
||||
def test_selection_path_json_contains_only_points_and_invert():
|
||||
def test_selection_path_json_contains_only_points():
|
||||
selection_path = selection.SelectionPath(
|
||||
points=((1, 2), (8, 2), (4, 9)),
|
||||
invert=True,
|
||||
)
|
||||
value = selection_path.to_json()
|
||||
|
||||
assert set(json.loads(value)) == {"points", "invert"}
|
||||
assert set(json.loads(value)) == {"points"}
|
||||
assert selection.SelectionPath.from_json(value) == selection_path
|
||||
with pytest.raises(ValueError, match="Selection Path data is invalid"):
|
||||
selection.SelectionPath.from_json(
|
||||
json.dumps(
|
||||
{
|
||||
"points": selection_path.points,
|
||||
"invert": selection_path.invert,
|
||||
"fill_rule": "NONZERO",
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_selection_mask_sidecar_round_trip_and_cleanup(tmp_path):
|
||||
original = selection.SelectionMask(
|
||||
np.asarray(((0.0, 0.25), (0.5, 1.0)), dtype=np.float32),
|
||||
(3, 4, 5, 6),
|
||||
)
|
||||
input_path = tmp_path / "input.png"
|
||||
input_path.write_bytes(b"input")
|
||||
|
||||
path = selection.save_selection_mask(input_path, original)
|
||||
loaded = selection.load_selection_mask(path, original.bounds)
|
||||
|
||||
assert path.parent == input_path.parent
|
||||
np.testing.assert_array_equal(loaded.values, original.values)
|
||||
assert loaded.bounds == original.bounds
|
||||
selection.cleanup_selection_mask(path)
|
||||
assert not path.exists()
|
||||
|
||||
|
||||
def test_nonzero_winding_keeps_same_direction_overlap():
|
||||
points = (
|
||||
(1, 1),
|
||||
@@ -144,13 +122,12 @@ def test_scanline_matches_reference_for_edge_cases():
|
||||
((-8, -3), (10, 1), (23, 8), (7, 18), (-4, 10)),
|
||||
)
|
||||
for points in paths:
|
||||
for invert in (False, True):
|
||||
for antialias in (False, True):
|
||||
assert_matches_reference(
|
||||
(18, 14),
|
||||
selection.SelectionPath(points, invert=invert),
|
||||
antialias=antialias,
|
||||
)
|
||||
for antialias in (False, True):
|
||||
assert_matches_reference(
|
||||
(18, 14),
|
||||
selection.SelectionPath(points),
|
||||
antialias=antialias,
|
||||
)
|
||||
|
||||
|
||||
def test_scanline_matches_reference_for_random_paths():
|
||||
@@ -163,13 +140,12 @@ def test_scanline_matches_reference_for_random_paths():
|
||||
random.uniform((-8, -6), (40, 30), size=(point_count, 2)),
|
||||
)
|
||||
)
|
||||
for invert in (False, True):
|
||||
for antialias in (False, True):
|
||||
assert_matches_reference(
|
||||
(32, 24),
|
||||
selection.SelectionPath(points, invert=invert),
|
||||
antialias=antialias,
|
||||
)
|
||||
for antialias in (False, True):
|
||||
assert_matches_reference(
|
||||
(32, 24),
|
||||
selection.SelectionPath(points),
|
||||
antialias=antialias,
|
||||
)
|
||||
|
||||
|
||||
def test_rasterizer_has_no_image_content_parameters():
|
||||
@@ -181,7 +157,7 @@ def test_rasterizer_has_no_image_content_parameters():
|
||||
assert "alpha_threshold" not in parameters
|
||||
|
||||
|
||||
def test_non_inverted_antialias_uses_only_padded_local_canvas(monkeypatch):
|
||||
def test_antialias_uses_only_padded_local_canvas(monkeypatch):
|
||||
selection_path = selection.SelectionPath(
|
||||
((100, 200), (500, 200), (500, 600), (100, 600))
|
||||
)
|
||||
@@ -203,25 +179,6 @@ def test_non_inverted_antialias_uses_only_padded_local_canvas(monkeypatch):
|
||||
assert calls == [(98, 198, 502, 602)]
|
||||
|
||||
|
||||
def test_inverted_selection_uses_full_canvas(monkeypatch):
|
||||
selection_path = selection.SelectionPath(
|
||||
((100, 200), (500, 200), (500, 600), (100, 600)),
|
||||
invert=True,
|
||||
)
|
||||
calls = []
|
||||
rasterize = selection._rasterize_path
|
||||
|
||||
def record(bounds, points):
|
||||
calls.append(bounds)
|
||||
return rasterize(bounds, points)
|
||||
|
||||
monkeypatch.setattr(selection, "_rasterize_path", record)
|
||||
|
||||
selection.rasterize_selection_path((5120, 2880), selection_path)
|
||||
|
||||
assert calls == [(0, 0, 5120, 2880)]
|
||||
|
||||
|
||||
def test_high_resolution_lasso_allocates_one_local_scanline_table(monkeypatch):
|
||||
angles = np.arange(1000, dtype=np.float64) * (2.0 * np.pi / 1000.0)
|
||||
points = tuple(
|
||||
|
||||
Reference in New Issue
Block a user