From 9a71726aec807a6f17867305edf4214bb020e16d Mon Sep 17 00:00:00 2001 From: Frankie Dintino Date: Wed, 3 Jul 2024 12:22:42 -0400 Subject: [PATCH 1/3] fix: compatibility with thumbor.filters.fill fixes #12 --- src/thumbor_video_engine/engines/video.py | 7 + tests/data/hotdog-transparent.png | Bin 0 -> 34936 bytes tests/engines/test_video_engine.py | 24 ++- tests/utils.py | 173 ++++++++++++++++++++++ 4 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 tests/data/hotdog-transparent.png create mode 100644 tests/utils.py diff --git a/src/thumbor_video_engine/engines/video.py b/src/thumbor_video_engine/engines/video.py index 944efdc..113c874 100644 --- a/src/thumbor_video_engine/engines/video.py +++ b/src/thumbor_video_engine/engines/video.py @@ -120,6 +120,13 @@ def is_multiple(self): def cleanup(self): pass + def __getattribute__(self, attr): + # For compatibility with some thumbor filters, return the image_engine + # or video_engine class, when appropriate, for self.__class__ + if attr == "__class__" and self.__dict__.get("engine"): + return self.__dict__["engine"].__class__ + return super().__getattribute__(attr) + def __getattr__(self, attr): if not self.__dict__.get('engine'): raise AttributeError("'Engine' object has no attribute '%s'" % attr) diff --git a/tests/data/hotdog-transparent.png b/tests/data/hotdog-transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..1f4bc8083d8fd884eeac663e4ff1d8472b2ea10b GIT binary patch literal 34936 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 i6u;h8tJTE+7hnL1$jRDCKvuK>0000 0.5: + codes += (38, 2, 0, 0, 0) + else: + codes += (38, 2, 255, 255, 255) + + return "%(codes)s%(hex)s%(reset)s" % { + "codes": esc_code(codes), + "hex": hex_color, + "reset": reset, + } + + +def rgb_to_lab(input_color): + RGB = [0, 0, 0] + + for i, value in enumerate(input_color): + value = float(value) / 255 + + if value > 0.04045: + value = ((value + 0.055) / 1.055) ** 2.4 + else: + value = value / 12.92 + + RGB[i] = value * 100 + + XYZ = [0, 0, 0] + + X = RGB[0] * 0.4124 + RGB[1] * 0.3576 + RGB[2] * 0.1805 + Y = RGB[0] * 0.2126 + RGB[1] * 0.7152 + RGB[2] * 0.0722 + Z = RGB[0] * 0.0193 + RGB[1] * 0.1192 + RGB[2] * 0.9504 + XYZ = [round(n, 4) for n in [X, Y, Z]] + + # Observer= 2°, Illuminant= D65 + XYZ[0] = float(XYZ[0]) / 95.047 # ref_X = 95.047 + XYZ[1] = float(XYZ[1]) / 100.0 # ref_Y = 100.000 + XYZ[2] = float(XYZ[2]) / 108.883 # ref_Z = 108.883 + + for i, value in enumerate(XYZ): + if value > 0.008856: + value = value ** (0.3333333333333333) + else: + value = (7.787 * value) + (16 / 116) + + XYZ[i] = value + + Lab = [0, 0, 0] + + L = (116 * XYZ[1]) - 16 + a = 500 * (XYZ[0] - XYZ[1]) + b = 200 * (XYZ[1] - XYZ[2]) + + Lab = [round(n, 4) for n in [L, a, b]] + + return Lab + + +def avg(*args): + return float(sum(args)) / len(args) + + +def delta_e_cie2000(lab1, lab2, k_L=1.0, k_C=1.0, k_H=1.0): + L1, a1, b1 = lab1 + L2, a2, b2 = lab2 + pow25_7 = math.pow(25, 7) + C1 = math.sqrt(math.pow(a1, 2) + math.pow(b1, 2)) + C2 = math.sqrt(math.pow(a2, 2) + math.pow(b2, 2)) + C_avg = avg(C1, C2) + G = 0.5 * (1 - math.sqrt(math.pow(C_avg, 7) / (math.pow(C_avg, 7) + pow25_7))) + L1_ = L1 + a1_ = (1 + G) * a1 + b1_ = b1 + L2_ = L2 + a2_ = (1 + G) * a2 + b2_ = b2 + C1_ = math.sqrt(math.pow(a1_, 2) + math.pow(b1_, 2)) + C2_ = math.sqrt(math.pow(a2_, 2) + math.pow(b2_, 2)) + h1_ = ( + 0 + if a1_ == 0 and b1_ == 0 + else math.degrees(math.atan2(b1_, a1_)) + (0 if b1_ >= 0 else 360.0) + ) + h2_ = ( + 0 + if a2_ == 0 and b2_ == 0 + else math.degrees(math.atan2(b2_, a2_)) + (0 if b2_ >= 0 else 360.0) + ) + dh_cond = 1.0 if h2_ - h1_ > 180 else (2.0 if h2_ - h1_ < -180 else 0) + dh_ = ( + h2_ - h1_ + if dh_cond == 0 + else (h2_ - h1_ - 360.0 if dh_cond == 1 else h2_ + 360.0 - h1_) + ) + dL_ = L2_ - L1_ + dC_ = C2_ - C1_ + dH_ = 2 * math.sqrt(C1_ * C2_) * math.sin(math.radians(dh_ / 2.0)) + L__avg = avg(L1_, L2_) + C__avg = avg(C1_, C2_) + h__avg_cond = ( + 3.0 + if C1_ * C2_ == 0 + else (0 if abs(h2_ - h1_) <= 180 else (1.0 if h2_ + h1_ < 360 else 2.0)) + ) + h__avg = ( + h1_ + h2_ + if h__avg_cond == 3 + else ( + avg(h1_, h2_) + if h__avg_cond == 0 + else (avg(h1_, h2_) + 180.0 if h__avg_cond == 1 else avg(h1_, h2_) - 180.0) + ) + ) + AB = math.pow(L__avg - 50.0, 2) # (L'_ave-50)^2 + S_L = 1 + 0.015 * AB / math.sqrt(20.0 + AB) + S_C = 1 + 0.045 * C__avg + T = ( + 1 + - 0.17 * math.cos(math.radians(h__avg - 30.0)) + + 0.24 * math.cos(math.radians(2.0 * h__avg)) + + 0.32 * math.cos(math.radians(3.0 * h__avg + 6.0)) + - 0.2 * math.cos(math.radians(4 * h__avg - 63.0)) + ) + S_H = 1 + 0.015 * C__avg * T + dTheta = 30.0 * math.exp(-1 * math.pow((h__avg - 275.0) / 25.0, 2)) + R_C = 2.0 * math.sqrt(math.pow(C__avg, 7) / (math.pow(C__avg, 7) + pow25_7)) + R_T = -math.sin(math.radians(2.0 * dTheta)) * R_C + AJ = dL_ / S_L / k_L # dL' / k_L / S_L + AK = dC_ / S_C / k_C # dC' / k_C / S_C + AL = dH_ / S_H / k_H # dH' / k_H / S_H + dE = math.sqrt(math.pow(AJ, 2) + math.pow(AK, 2) + math.pow(AL, 2) + R_T * AK * AL) + + dE_norm = dE / 100.0 + if dE_norm > 1: + return 1 + elif dE_norm < 0: + return 0 + else: + return dE_norm + + +def color_diff(rgb_a, rgb_b): + lab_a = rgb_to_lab(rgb_a) + lab_b = rgb_to_lab(rgb_b) + return delta_e_cie2000(lab_a, lab_b) From a75bdf04196ee7e5e8b5da72597ad88843ae2778 Mon Sep 17 00:00:00 2001 From: Frankie Dintino Date: Wed, 3 Jul 2024 12:39:22 -0400 Subject: [PATCH 2/3] python 2 compatibility --- src/thumbor_video_engine/engines/video.py | 2 +- tests/engines/test_video_engine.py | 2 +- tests/result_storages/test_file_storage.py | 14 +++++++------- tests/result_storages/test_s3_storage.py | 6 +++--- tests/utils.py | 1 + 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/thumbor_video_engine/engines/video.py b/src/thumbor_video_engine/engines/video.py index 113c874..8fb51a5 100644 --- a/src/thumbor_video_engine/engines/video.py +++ b/src/thumbor_video_engine/engines/video.py @@ -125,7 +125,7 @@ def __getattribute__(self, attr): # or video_engine class, when appropriate, for self.__class__ if attr == "__class__" and self.__dict__.get("engine"): return self.__dict__["engine"].__class__ - return super().__getattribute__(attr) + return object.__getattribute__(self, attr) def __getattr__(self, attr): if not self.__dict__.get('engine'): diff --git a/tests/engines/test_video_engine.py b/tests/engines/test_video_engine.py index 5b91da7..2cc961d 100644 --- a/tests/engines/test_video_engine.py +++ b/tests/engines/test_video_engine.py @@ -15,7 +15,7 @@ def assert_colors_similar(rgb1, rgb2, message): delta_e = color_diff(rgb1, rgb2) - assert delta_e < 0.05, f"{message}: {repr_rgb(rgb1)} != {repr_rgb(rgb2)}" + assert delta_e < 0.05, "%s: %s != %s" % (message, repr_rgb(rgb1), repr_rgb(rgb2)) @pytest.fixture diff --git a/tests/result_storages/test_file_storage.py b/tests/result_storages/test_file_storage.py index aab1992..82177e3 100644 --- a/tests/result_storages/test_file_storage.py +++ b/tests/result_storages/test_file_storage.py @@ -3,7 +3,7 @@ import pytest -from thumbor_video_engine.engines.video import Engine as VideoEngine +from thumbor_video_engine.engines.ffmpeg import Engine as FFMpegEngine @pytest.fixture @@ -55,12 +55,12 @@ def test_file_result_storage_retrieve(config, mocker, http_client, base_url, tmp src_file, "%s/%s/ba/68/88258f0b20357d15380b611a7b31da32f19b" % (tmp_path, subdir)) - mocker.spy(VideoEngine, "load") + mocker.spy(FFMpegEngine, "load") response = yield http_client.fetch("%s/unsafe/hotdog.gif" % base_url, headers={'Accept': mime_type}) assert response.code == 200 - assert VideoEngine.load.call_count == 0 + assert FFMpegEngine.load.call_count == 0 assert response.headers.get('content-type') == mime_type if auto_gif: assert response.headers.get('vary') == 'Accept' @@ -71,7 +71,7 @@ def test_file_result_storage_retrieve(config, mocker, http_client, base_url, tmp "%s/unsafe/pbj-time.gif" % base_url, headers={'Accept': mime_type}) assert response.code == 200 - assert VideoEngine.load.call_count == 1 + assert FFMpegEngine.load.call_count == 1 @pytest.mark.gen_test @@ -92,15 +92,15 @@ def test_file_result_storage_legacy_retrieve( src_file, "%s/v2%s/un/sa/unsafe/hotdog.gif" % (tmp_path, subdir)) - mocker.spy(VideoEngine, "load") + mocker.spy(FFMpegEngine, "load") response = yield http_client.fetch("%s/unsafe/hotdog.gif" % base_url, headers={'Accept': accept}) assert response.code == 200 - assert VideoEngine.load.call_count == 0 + assert FFMpegEngine.load.call_count == 0 response = yield http_client.fetch( "%s/unsafe/pbj-time.gif" % base_url, headers={'Accept': accept}) assert response.code == 200 - assert VideoEngine.load.call_count == 1 + assert FFMpegEngine.load.call_count == 1 diff --git a/tests/result_storages/test_s3_storage.py b/tests/result_storages/test_s3_storage.py index a010092..981cb3e 100644 --- a/tests/result_storages/test_s3_storage.py +++ b/tests/result_storages/test_s3_storage.py @@ -14,7 +14,7 @@ asyncio = None from thumbor.engines import BaseEngine -from thumbor_video_engine.engines.video import Engine as VideoEngine +from thumbor_video_engine.engines.ffmpeg import Engine as FFMpegEngine # Subclassed Popen that gets around mirakuru not capturing stderr @@ -106,7 +106,7 @@ def test_s3_result_storage_load(mocker, config, http_client, base_url, auto_gif, if mime_type == 'image/gif': config.FFMPEG_GIF_AUTO_H264 = False - mocker.spy(VideoEngine, "load") + mocker.spy(FFMpegEngine, "load") if not auto_gif and mime_type != 'image/png': bucket_key = 'unsafe/hotdog.gif' @@ -134,7 +134,7 @@ def test_s3_result_storage_load(mocker, config, http_client, base_url, auto_gif, assert response.headers.get("vary") == "Accept" else: assert response.headers.get("vary") is None - assert VideoEngine.load.call_count == 0 + assert FFMpegEngine.load.call_count == 0 @pytest.mark.skipif(Bucket is None, reason="tc_aws unavailable") diff --git a/tests/utils.py b/tests/utils.py index 7dcb23b..4c1fbdf 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import math From 37d8972cc37ef46b22e90d4810b30ffa9b05fade Mon Sep 17 00:00:00 2001 From: Frankie Dintino Date: Wed, 3 Jul 2024 12:36:08 -0400 Subject: [PATCH 3/3] fix(ci): pin to moto v4 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 117e675..8f3d869 100644 --- a/tox.ini +++ b/tox.ini @@ -42,7 +42,7 @@ deps = py27: PyYAML==5.3.1 py27: moto[server] <= 2.1.0 py27: flask-cors<4 - !py27: moto[server] + !py27: moto[server]<5 py37: boto3==1.21.21 py37: botocore==1.24.21