Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/ffsshhttiikk/opencode-agents-skills --skill image-processing명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | image-processing |
| description | Image processing and manipulation |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":"developers","category":"utilities"} |
When implementing image processing or handling image uploads.
from PIL import Image, ImageFilter, ImageEnhance
from dataclasses import dataclass
from pathlib import Path
from typing import Optional, List, Tuple
import io
@dataclass
class ImageDimensions:
"""Image dimensions."""
width: int
height: int
@property
def aspect_ratio(self) -> float:
return self.width / self.height
def resize(self, max_width: int, max_height: int) -> 'ImageDimensions':
"""Resize while maintaining aspect ratio."""
ratio = min(max_width / self.width, max_height / self.height)
return ImageDimensions(
width=int(self.width * ratio),
height=int(self.height * ratio)
)
@dataclass
class ImageConfig:
"""Image processing configuration."""
format: str = "JPEG"
quality: int = 85
optimize: bool = True
preserve_metadata: bool = False
class ImageProcessor:
"""Image processing operations."""
def __init__(self, config: ImageConfig = None):
self.config = config or ImageConfig()
def open(self, image_path: Path) -> Image:
"""Open an image file."""
return Image.open(image_path)
def resize(
self,
image: Image,
width: int,
height: int,
maintain_aspect: bool = True
) -> Image:
"""Resize image."""
if maintain_aspect:
current_dims = ImageDimensions(image.width, image.height)
new_dims = current_dims.resize(width, height)
width, height = new_dims.width, new_dims.height
return image.resize((width, height), Image.LANCZOS)
def create_thumbnail(
self,
image: Image,
max_size: Tuple[int, int] = (300, 300)
) -> Image:
"""Create thumbnail preserving aspect ratio."""
image.thumbnail(max_size, Image.LANCZOS)
return image
def crop(
self,
image: Image,
left: int,
top: int,
right: int,
bottom: int
) -> Image:
"""Crop image."""
return image.crop((left, top, right, bottom))
def rotate(self, image: Image, degrees: float) -> Image:
"""Rotate image."""
return image.rotate(-degrees, expand=True)
def flip_horizontal(self, image: Image) -> Image:
"""Flip image horizontally."""
return image.transpose(Image.FLIP_LEFT_RIGHT)
def flip_vertical(self, image: Image) -> Image:
"""Flip image vertically."""
return image.transpose(Image.FLIP_TOP_BOTTOM)
class ImageFilterApplier:
"""Apply filters to images."""
@staticmethod
def blur(image: Image, radius: float = 2) -> Image:
"""Apply Gaussian blur."""
return image.filter(ImageFilter.GaussianBlur(radius))
@staticmethod
def sharpen(image: Image) -> Image:
"""Sharpen image."""
return image.filter(ImageFilter.SHARPEN)
@staticmethod
def contour(image: Image) -> Image:
"""Apply contour filter."""
return image.filter(ImageFilter.CONTOUR)
@staticmethod
def edge_enhance(image: Image) -> Image:
"""Edge enhancement."""
return image.filter(ImageFilter.EDGE_ENHANCE)
@staticmethod
def emboss(image: Image) -> Image:
"""Apply emboss effect."""
return image.filter(ImageFilter.EMBOSS)
@staticmethod
def adjust_brightness(image: Image, factor: float) -> Image:
"""Adjust brightness."""
enhancer = ImageEnhance.Brightness(image)
return enhancer.enhance(factor)
@staticmethod
def adjust_contrast(image: Image, factor: float) -> Image:
"""Adjust contrast."""
enhancer = ImageEnhance.Contrast(image)
return enhancer.enhance(factor)
@staticmethod
def adjust_saturation(image: Image, factor: float) -> Image:
"""Adjust saturation."""
enhancer = ImageEnhance.Color(image)
return enhancer.enhance(factor)
class ImageOptimizer:
"""Optimize images for web."""
def __init__(self, config: ImageConfig = None):
self.config = config or ImageConfig()
def optimize(
self,
image: Image,
output_format: str = None
) -> Image:
"""Optimize image."""
format = output_format or self.config.format
if format.upper() == "JPEG":
image = image.convert("RGB")
return image
def save_with_quality(
self,
image: Image,
output_path: Path,
quality: int = None,
format: str = None
) -> None:
"""Save image with specific quality."""
quality = quality or self.config.quality
format = format or self.config.format
save_kwargs = {
"quality": quality,
"optimize": self.config.optimize,
}
if format.upper() == "JPEG":
save_kwargs["subsampling"] = 0
image.save(output_path, format=format, **save_kwargs)
def save_to_bytes(
self,
image: Image,
format: str = None,
quality: int = None
) -> bytes:
"""Save image to bytes."""
format = format or self.config.format
quality = quality or self.config.quality
buffer = io.BytesIO()
save_kwargs = {
"quality": quality,
"optimize": self.config.optimize,
}
image.save(buffer, format=format, **save_kwargs)
return buffer.getvalue()
def create_responsive_set(
self,
image: Image,
sizes: List[Tuple[int, str]],
output_dir: Path,
prefix: str = "image"
) -> List[dict]:
"""Create responsive image set."""
results = []
for width, suffix in sizes:
new_height = int(image.height * (width / image.width))
resized = self.resize(
image,
width,
new_height,
maintain_aspect=True
)
filename = f"{prefix}_{suffix}.jpg"
output_path = output_dir / filename
self.save_with_quality(resized, output_path)
results.append({
"filename": filename,
"width": resized.width,
"height": resized.height,
"url": f"/images/{filename}"
})
return results
from pathlib import Path
from typing import Optional
import magic
import hashlib
class SecureImageUploader:
"""Secure image upload handling."""
ALLOWED_TYPES = {
"image/jpeg": ".jpg",
"image/png": ".png",
"image/gif": ".gif",
"image/webp": ".webp",
}
MAX_SIZE = 10 * 1024 * 1024 # 10MB
def __init__(self, upload_dir: Path, processor: ImageProcessor):
self.upload_dir = upload_dir
self.processor = processor
self.upload_dir.mkdir(parents=True, exist_ok=True)
async def save_upload(
self,
file_content: bytes,
original_filename: str
) -> dict:
"""Save uploaded image securely."""
# Validate file type
mime_type = magic.from_buffer(file_content, mime=True)
if mime_type not in self.ALLOWED_TYPES:
raise InvalidImageError(
f"Invalid file type: "
)
(file_content) > .MAX_SIZE:
InvalidImageError(
)
ext = .ALLOWED_TYPES[mime_type]
safe_filename = ._generate_safe_filename(original_filename, ext)
file_path = .upload_dir / safe_filename
file_path.write_bytes(file_content)
image = .processor.(file_path)
thumbnail = .processor.create_thumbnail(image)
thumbnail_path = .upload_dir /
.processor.save_with_quality(thumbnail, thumbnail_path)
{
: (file_path),
: (thumbnail_path),
: safe_filename,
: image.width,
: image.height,
: (file_content),
: mime_type,
}
() -> :
stem = Path(original_filename).stem
safe_stem = .join(
c c stem
c.isalnum() c
)
safe_stem = safe_stem[:]
hash_suffix = hashlib.md5(
.encode()
).hexdigest()[:]
from PIL import ImageDraw, ImageFont
from collections import Counter
class ImageAnalyzer:
"""Analyze image properties."""
@staticmethod
def get_dimensions(image: Image) -> Tuple[int, int]:
"""Get image dimensions."""
return image.width, image.height
@staticmethod
def get_format(image: Image) -> str:
"""Get image format."""
return image.format or "Unknown"
@staticmethod
def get_mode(image: Image) -> str:
"""Get image mode (RGB, L, etc.)."""
return image.mode
@staticmethod
def get_info(image: Image) -> dict:
"""Get comprehensive image info."""
return {
"format": image.format,
"mode": image.mode,
"width": image.width,
"height": image.height,
"size_bytes": image.size[0] * image.size[1],
: image.mode (, , ),
: image.width / image.height image.height ,
}
() -> :
image.mode != :
image = image.convert()
colors = (image.getdata())
color_counts = Counter(colors)
{
: (color_counts),
: color_counts.most_common(),
}
() -> :
image.height > image.width
() -> :
image.width > image.height
() -> :
image.width == image.height
() -> :
width = image.width
height = image.height
width < height < :
width < height < :
width < height < :
:
:
():
.text = text
.font_size = font_size
() -> Image:
image.mode != :
image = image.convert()
watermark = Image.new(, image.size, (, , , ))
draw = ImageDraw.Draw(watermark)
width, height = image.size
position == :
x = width -
y = height -
position == :
x =
y = height -
position == :
x = width -
y =
position == :
x =
y =
:
x = width // -
y = height //
draw.text(
(x, y),
.text,
fill=(, , , ( * opacity))
)
watermarked = Image.alpha_composite(image, watermark)
watermarked.convert()
Image Processing Best Practices:
1. Validate uploads
Check file type
Check file size
2. Generate unique names
Prevent overwrites
Use hashes
3. Create thumbnails
For previews
Reduce bandwidth
4. Use appropriate formats
JPEG for photos
PNG for graphics
WebP for modern browsers
5. Optimize for web
Compress images
Right-size dimensions
6. Preserve aspect ratio
Don't distort images
Calculate dimensions
7. Handle metadata
Strip sensitive EXIF
Preserve copyright if needed
8. Serve efficiently
CDN for delivery
Responsive images
9. Process asynchronously
Don't block requests
Use queues
10. Clean up old files
Define retention
Delete unused images