Download src/tools/image/edit.py from Snapkitty/sovereign-engine-v2: direct link, hf CLI and curl.
- Browser
- Download file 7.27 kB
-
https://huggingface.co/Snapkitty/sovereign-engine-v2/resolve/main/src/tools/image/edit.py
- Command line
-
hf download hf://Snapkitty/sovereign-engine-v2/src/tools/image/edit.py
-
curl -L -o edit.py https://huggingface.co/Snapkitty/sovereign-engine-v2/resolve/main/src/tools/image/edit.py
7.27 kB
| """ | |
| Image Editing | |
| Part of SOVEREIGN PYTHON LLM ENGINE | |
| Edit images using PIL/Pillow. | |
| """ | |
| from typing import Any | |
| from pathlib import Path | |
| from dataclasses import dataclass | |
| from io import BytesIO | |
| class EditedImage: | |
| """Edited image result""" | |
| image_bytes: bytes | |
| format: str | |
| size: tuple[int, int] | |
| operations: list[str] | |
| class ImageEditor: | |
| """ | |
| Image editing operations using Pillow. | |
| Supports: | |
| - Resize, crop, rotate | |
| - Format conversion | |
| - Filters and adjustments | |
| - Watermarking | |
| """ | |
| def __init__(self): | |
| try: | |
| from PIL import Image | |
| except ImportError: | |
| raise ImportError("Pillow is required. Install: pip install Pillow") | |
| async def resize( | |
| self, | |
| image_path: Path, | |
| width: int, | |
| height: int, | |
| maintain_aspect: bool = True | |
| ) -> EditedImage: | |
| """ | |
| Resize image. | |
| Args: | |
| image_path: Input image | |
| width: Target width | |
| height: Target height | |
| maintain_aspect: Maintain aspect ratio | |
| Returns: | |
| EditedImage | |
| """ | |
| from PIL import Image | |
| import asyncio | |
| def _sync_resize(): | |
| img = Image.open(image_path) | |
| if maintain_aspect: | |
| img.thumbnail((width, height), Image.Resampling.LANCZOS) | |
| else: | |
| img = img.resize((width, height), Image.Resampling.LANCZOS) | |
| # Save to bytes | |
| buffer = BytesIO() | |
| img.save(buffer, format=img.format or "PNG") | |
| buffer.seek(0) | |
| return EditedImage( | |
| image_bytes=buffer.read(), | |
| format=img.format or "PNG", | |
| size=img.size, | |
| operations=["resize"] | |
| ) | |
| return await asyncio.to_thread(_sync_resize) | |
| async def crop( | |
| self, | |
| image_path: Path, | |
| left: int, | |
| top: int, | |
| right: int, | |
| bottom: int | |
| ) -> EditedImage: | |
| """ | |
| Crop image. | |
| Args: | |
| image_path: Input image | |
| left, top, right, bottom: Crop box | |
| Returns: | |
| EditedImage | |
| """ | |
| from PIL import Image | |
| import asyncio | |
| def _sync_crop(): | |
| img = Image.open(image_path) | |
| img = img.crop((left, top, right, bottom)) | |
| buffer = BytesIO() | |
| img.save(buffer, format=img.format or "PNG") | |
| buffer.seek(0) | |
| return EditedImage( | |
| image_bytes=buffer.read(), | |
| format=img.format or "PNG", | |
| size=img.size, | |
| operations=["crop"] | |
| ) | |
| return await asyncio.to_thread(_sync_crop) | |
| async def rotate( | |
| self, | |
| image_path: Path, | |
| angle: float, | |
| expand: bool = True | |
| ) -> EditedImage: | |
| """ | |
| Rotate image. | |
| Args: | |
| image_path: Input image | |
| angle: Rotation angle in degrees | |
| expand: Expand image to fit rotated content | |
| Returns: | |
| EditedImage | |
| """ | |
| from PIL import Image | |
| import asyncio | |
| def _sync_rotate(): | |
| img = Image.open(image_path) | |
| img = img.rotate(angle, expand=expand) | |
| buffer = BytesIO() | |
| img.save(buffer, format=img.format or "PNG") | |
| buffer.seek(0) | |
| return EditedImage( | |
| image_bytes=buffer.read(), | |
| format=img.format or "PNG", | |
| size=img.size, | |
| operations=["rotate"] | |
| ) | |
| return await asyncio.to_thread(_sync_rotate) | |
| async def convert_format( | |
| self, | |
| image_path: Path, | |
| target_format: str | |
| ) -> EditedImage: | |
| """ | |
| Convert image format. | |
| Args: | |
| image_path: Input image | |
| target_format: Target format ("PNG", "JPEG", "WEBP", etc.) | |
| Returns: | |
| EditedImage | |
| """ | |
| from PIL import Image | |
| import asyncio | |
| def _sync_convert(): | |
| img = Image.open(image_path) | |
| # Convert RGBA to RGB if saving as JPEG | |
| if target_format.upper() == "JPEG" and img.mode == "RGBA": | |
| img = img.convert("RGB") | |
| buffer = BytesIO() | |
| img.save(buffer, format=target_format) | |
| buffer.seek(0) | |
| return EditedImage( | |
| image_bytes=buffer.read(), | |
| format=target_format, | |
| size=img.size, | |
| operations=["convert"] | |
| ) | |
| return await asyncio.to_thread(_sync_convert) | |
| async def apply_filter( | |
| self, | |
| image_path: Path, | |
| filter_name: str | |
| ) -> EditedImage: | |
| """ | |
| Apply filter to image. | |
| Args: | |
| image_path: Input image | |
| filter_name: Filter name ("blur", "sharpen", "contour", etc.) | |
| Returns: | |
| EditedImage | |
| """ | |
| from PIL import Image, ImageFilter | |
| import asyncio | |
| def _sync_filter(): | |
| img = Image.open(image_path) | |
| # Map filter names | |
| filters = { | |
| "blur": ImageFilter.BLUR, | |
| "sharpen": ImageFilter.SHARPEN, | |
| "contour": ImageFilter.CONTOUR, | |
| "detail": ImageFilter.DETAIL, | |
| "edge_enhance": ImageFilter.EDGE_ENHANCE, | |
| "smooth": ImageFilter.SMOOTH, | |
| } | |
| filter_obj = filters.get(filter_name.lower()) | |
| if not filter_obj: | |
| raise ValueError(f"Unknown filter: {filter_name}") | |
| img = img.filter(filter_obj) | |
| buffer = BytesIO() | |
| img.save(buffer, format=img.format or "PNG") | |
| buffer.seek(0) | |
| return EditedImage( | |
| image_bytes=buffer.read(), | |
| format=img.format or "PNG", | |
| size=img.size, | |
| operations=[f"filter:{filter_name}"] | |
| ) | |
| return await asyncio.to_thread(_sync_filter) | |
| # Tool registration helpers | |
| async def resize_image_tool( | |
| image_path: str, | |
| width: int, | |
| height: int, | |
| output_path: str | None = None | |
| ) -> dict: | |
| """Resize image tool""" | |
| editor = ImageEditor() | |
| result = await editor.resize(Path(image_path), width, height) | |
| if output_path: | |
| Path(output_path).write_bytes(result.image_bytes) | |
| return { | |
| "size": result.size, | |
| "format": result.format, | |
| "operations": result.operations | |
| } | |
| async def convert_image_tool( | |
| image_path: str, | |
| target_format: str, | |
| output_path: str | None = None | |
| ) -> dict: | |
| """Convert image format tool""" | |
| editor = ImageEditor() | |
| result = await editor.convert_format(Path(image_path), target_format) | |
| if output_path: | |
| Path(output_path).write_bytes(result.image_bytes) | |
| return { | |
| "format": result.format, | |
| "size": result.size | |
| } | |