From 76e2f4e0eb1c990f84ce87cf58bd134ea20e029e Mon Sep 17 00:00:00 2001 From: Antoine Beyeler <49431240+abey79@users.noreply.github.com> Date: Sun, 27 Mar 2022 14:49:26 +0200 Subject: [PATCH] Fixed how `write` handles opacity in SVG output (#429) Inkscape does not support alpha in `stroke` attribute (e.g. `stroke="#ff00007f"`). The attribute `stroke-opacity` must be used instead. Fixes #422 --- CHANGELOG.md | 2 +- tests/test_files.py | 12 ++++++++++++ vpype/io.py | 11 +++++++---- vpype/metadata.py | 4 ++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea21256b..d11ada14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ Release date: UNRELEASED ### Bug fixes -* ... +* Fixed issue with `write` where layer opacity was included in the `stroke` attribute instead of using `stroke-opacity`, which, although compliant, was not compatible with Inkscape (#429) ### Other changes diff --git a/tests/test_files.py b/tests/test_files.py index 4568f3e2..03f317b6 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -428,6 +428,18 @@ def test_write_svg_svg_props_unknown_namespace(capsys): assert 'unknown:version="1.1.0"' not in capsys.readouterr().out +def test_write_opacity_100pct(capsys): + vpype_cli.execute("line 0 0 10 10 color red write -f svg -") + assert 'stroke="#ff0000"' in capsys.readouterr().out + + +def test_write_opacity_50pct(capsys): + vpype_cli.execute("line 0 0 10 10 color '#ff00007f' write -f svg -") + output = capsys.readouterr().out + assert 'stroke="#ff0000"' in output + assert 'stroke-opacity="0.498"' in output + + def test_read_no_fail(): with pytest.raises(click.BadParameter): vpype_cli.execute("read doesnotexist.svg") diff --git a/vpype/io.py b/vpype/io.py index d5e1688d..c7be4945 100644 --- a/vpype/io.py +++ b/vpype/io.py @@ -748,21 +748,24 @@ def write_svg( group = inkscape.layer(label=label) group.attribs["fill"] = "none" + color = Color("black") if color_mode == "layer" or ( color_mode == "default" and not layer.property_exists(METADATA_FIELD_COLOR) ): - group.attribs["stroke"] = METADATA_DEFAULT_COLOR_SCHEME[ + color = METADATA_DEFAULT_COLOR_SCHEME[ color_idx % len(METADATA_DEFAULT_COLOR_SCHEME) ] color_idx += 1 elif color_mode == "default": - group.attribs["stroke"] = str(layer.property(METADATA_FIELD_COLOR)) + color = Color(layer.property(METADATA_FIELD_COLOR)) # we want to avoid a subsequent layer whose color is undefined to have its color # affected by whether or not previous layer have their color defined color_idx += 1 - elif color_mode == "none": - group.attribs["stroke"] = "black" + + group.attribs["stroke"] = color.as_rgb_hes() + if color.alpha < 255: + group.attribs["stroke-opacity"] = f"{color.alpha/255:.3f}" group.attribs["style"] = "display:inline" group.attribs["id"] = f"layer{layer_id}" if layer.property_exists(METADATA_FIELD_PEN_WIDTH): diff --git a/vpype/metadata.py b/vpype/metadata.py index 37684a7a..ea885d80 100644 --- a/vpype/metadata.py +++ b/vpype/metadata.py @@ -60,6 +60,10 @@ def as_hex(self) -> str: """Return a standard, hexadecimal representation of the instance.""" return svgelements.Color(self.red, self.green, self.blue, self.alpha).hex + def as_rgb_hes(self) -> str: + """Return a standard, hexadecimal representation of the instance, ignoring alpha.""" + return svgelements.Color(self.red, self.green, self.blue).hexrgb + def __str__(self) -> str: return self.as_hex()