diff --git a/.gitignore b/.gitignore index 1eae968..a17c89e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /data /pyrightconfig.json /pyrightconfig.toml +/uv.lock # 缓存文件 __pycache__ diff --git a/konabot/plugins/fx_process/fx_handle.py b/konabot/plugins/fx_process/fx_handle.py index f2a2048..248a89c 100644 --- a/konabot/plugins/fx_process/fx_handle.py +++ b/konabot/plugins/fx_process/fx_handle.py @@ -194,23 +194,27 @@ class ImageFilterImplement: # 缩放 @staticmethod def apply_resize(image: Image.Image, scale: float = 1.5, scale_y = None) -> Image.Image: - # scale 可以为负 - # 如果 scale 为负,则代表翻转 - if scale_y is not None: - if float(scale_y) < 0: + scale_x = float(scale) + scale_y_value = float(scale_y) if scale_y is not None else None + + if scale_y_value is not None: + if scale_y_value < 0: image = ImageOps.flip(image) - scale_y = abs(float(scale_y)) - if scale < 0: + scale_y_value = abs(scale_y_value) + if scale_x < 0: image = ImageOps.mirror(image) - scale = abs(scale) - new_size = (int(image.width * scale), int(image.height * float(scale_y))) - return image.resize(new_size, Image.Resampling.LANCZOS) - if scale < 0: - image = ImageOps.mirror(image) - image = ImageOps.flip(image) - scale = abs(scale) - new_size = (int(image.width * scale), int(image.height * scale)) - return image.resize(new_size, Image.Resampling.LANCZOS) + scale_x = abs(scale_x) + target_scale_y = scale_y_value + else: + if scale_x < 0: + image = ImageOps.mirror(image) + image = ImageOps.flip(image) + scale_x = abs(scale_x) + target_scale_y = scale_x + + new_width = max(1, round(image.width * scale_x)) + new_height = max(1, round(image.height * target_scale_y)) + return image.resize((new_width, new_height), Image.Resampling.LANCZOS) # 波纹 @staticmethod diff --git a/tests/test_fx_process.py b/tests/test_fx_process.py index 98171f7..206c6ef 100644 --- a/tests/test_fx_process.py +++ b/tests/test_fx_process.py @@ -35,3 +35,39 @@ def test_apply_jpeg_damage_clamps_quality_range(): assert high.size == image.size assert low.mode == "RGBA" assert high.mode == "RGBA" + + +def test_apply_resize_clamps_small_result_to_at_least_one_pixel(): + image = Image.new("RGBA", (10, 10), (255, 0, 0, 255)) + + result = ImageFilterImplement.apply_resize(image, 0.01) + + assert result.size == (1, 1) + + +def test_apply_resize_negative_x_with_positive_y_only_mirrors_horizontally(): + image = Image.new("RGBA", (2, 1)) + image.putpixel((0, 0), (255, 0, 0, 255)) + image.putpixel((1, 0), (0, 0, 255, 255)) + + result = ImageFilterImplement.apply_resize(image, -1, 1) + + assert result.size == (2, 1) + assert result.getpixel((0, 0)) == (0, 0, 255, 255) + assert result.getpixel((1, 0)) == (255, 0, 0, 255) + + +def test_apply_resize_negative_scale_without_y_flips_both_axes(): + image = Image.new("RGBA", (2, 2)) + image.putpixel((0, 0), (255, 0, 0, 255)) + image.putpixel((1, 0), (0, 255, 0, 255)) + image.putpixel((0, 1), (0, 0, 255, 255)) + image.putpixel((1, 1), (255, 255, 0, 255)) + + result = ImageFilterImplement.apply_resize(image, -1) + + assert result.size == (2, 2) + assert result.getpixel((0, 0)) == (255, 255, 0, 255) + assert result.getpixel((1, 0)) == (0, 0, 255, 255) + assert result.getpixel((0, 1)) == (0, 255, 0, 255) + assert result.getpixel((1, 1)) == (255, 0, 0, 255)