Skip to content

Commit

Permalink
refactor: improved image diffing
Browse files Browse the repository at this point in the history
  • Loading branch information
huyenngn committed Oct 4, 2023
1 parent 649c9be commit beab24c
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 57 deletions.
37 changes: 11 additions & 26 deletions capella2polarion/elements/api_helper.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
# Copyright DB Netz AG and contributors
# SPDX-License-Identifier: Apache-2.0
"""Capella2Polarion specific helper functions to use the API."""
import base64
import base64 as b64
import collections.abc as cabc
import io
import logging
import re
import typing as t

import cairosvg
import polarion_rest_api_client as polarion_api
from capellambse.model import common
from PIL import Image, ImageChops

from capella2polarion.elements import serialize

Expand Down Expand Up @@ -82,38 +80,25 @@ def patch_work_item(
logger.error("Updating work item %r failed. %s", wi, error.args[0])


def decode_diagram(dia: str):
"""Decode a diagram from a base64 string."""
encoded = dia.replace("data:image/", "").split(";base64,", 1)

decoded = base64.b64decode(encoded[1])

return encoded[0], decoded
def split_and_decode_diagram(diagram: str) -> tuple[str, bytes]:
"""Split the diagram into type and data and decode the data."""
prefix, encoded = diagram.split(";base64,")
return prefix.replace("data:image/", ""), b64.b64decode(encoded)


def has_visual_changes(old: str, new: str) -> bool:
"""Return True if the images of the diagrams differ."""
type_old, decoded_old = decode_diagram(old)
type_new, decoded_new = decode_diagram(new)
type_old, decoded_old = split_and_decode_diagram(old)
type_new, decoded_new = split_and_decode_diagram(new)

if type_old != type_new:
return True

if type_old == "svg+xml":
d_new = decoded_new.decode("utf-8").splitlines()
for i, d_old in enumerate(decoded_old.decode("utf-8").splitlines()):
if re.sub(r'id=["\'][^"\']*["\']', "", d_old) != re.sub(
r'id=["\'][^"\']*["\']', "", d_new[i]
):
return True
return False

image_old = Image.open(io.BytesIO(decoded_old))
image_new = Image.open(io.BytesIO(decoded_new))

diff = ImageChops.difference(image_old, image_new)
decoded_old = cairosvg.svg2png(bytestring=decoded_old)
decoded_new = cairosvg.svg2png(bytestring=decoded_new)

return bool(diff.getbbox())
return decoded_old != decoded_new


def handle_links(
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dependencies = [
"PyYAML",
"polarion-rest-api-client @ git+https://github.com/DSD-DBS/polarion-rest-api-client.git@feat-add-attachments-workitem-relations",
"requests",
"cairosvg",
]

[project.urls]
Expand Down
32 changes: 1 addition & 31 deletions tests/test_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,36 +80,6 @@ class TestAPIHelper:
pathlib.Path(__file__).parent / "data" / "svg_diff" / "example.svg"
)
SVG_PREFIX = "data:image/svg+xml;base64,"
PNG_PREFIX = "data:image/png;base64,"

def encode_png(self, img: Image.Image) -> str:
image_buffer = io.BytesIO()
img.save(image_buffer, format="PNG")
image_buffer.seek(0)
encoded = base64.b64encode(image_buffer.read()).decode()
image_buffer.close()
return f"{self.PNG_PREFIX}{encoded}"

def test_pixel_diff(self):
img1 = Image.new("RGB", (100, 100))
img2 = Image.new("RGB", (100, 100))
img2.putpixel((0, 0), (255, 0, 0))

assert (
api_helper.has_visual_changes(
self.encode_png(img1),
self.encode_png(img2),
)
is True
)

assert (
api_helper.has_visual_changes(
self.encode_png(img1),
self.encode_png(img1),
)
is False
)

def encode_svg(self, params) -> str:
svg = self.SVG_PATH.read_text()
Expand Down Expand Up @@ -146,7 +116,7 @@ def encode_svg(self, params) -> str:
),
],
)
def test_svg_diff(self, changed_params, expected):
def test_image_diff(self, changed_params, expected):
old_params, new_params = changed_params

assert (
Expand Down

0 comments on commit beab24c

Please sign in to comment.