Back to skills
SkillHub ClubShip Full StackFull Stack

image-processing

Process images for web development — resize, crop, trim whitespace, convert formats (PNG/WebP/JPG), optimise file size, generate thumbnails, create OG card images. Uses Pillow (Python) — no ImageMagick needed. Trigger with 'resize image', 'convert to webp', 'trim logo', 'optimise images', 'make thumbnail', 'create OG image', 'crop whitespace', 'process image', or 'image too large'.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
624
Hot score
99
Updated
March 20, 2026
Overall rating
C4.6
Composite score
4.6
Best-practice grade
B77.6

Install command

npx @skill-hub/cli install jezweb-claude-skills-image-processing

Repository

jezweb/claude-skills

Skill path: plugins/design-assets/skills/image-processing

Process images for web development — resize, crop, trim whitespace, convert formats (PNG/WebP/JPG), optimise file size, generate thumbnails, create OG card images. Uses Pillow (Python) — no ImageMagick needed. Trigger with 'resize image', 'convert to webp', 'trim logo', 'optimise images', 'make thumbnail', 'create OG image', 'crop whitespace', 'process image', or 'image too large'.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: jezweb.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install image-processing into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/jezweb/claude-skills before adding image-processing to shared team environments
  • Use image-processing for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: image-processing
description: "Process images for web development — resize, crop, trim whitespace, convert formats (PNG/WebP/JPG), optimise file size, generate thumbnails, create OG card images. Uses Pillow (Python) — no ImageMagick needed. Trigger with 'resize image', 'convert to webp', 'trim logo', 'optimise images', 'make thumbnail', 'create OG image', 'crop whitespace', 'process image', or 'image too large'."
compatibility: claude-code-only
---

# Image Processing

Process images for web development. Generate a Pillow script adapted to the user's environment and specific needs.

## Prerequisites

Pillow is usually pre-installed. If not:

```bash
pip install Pillow
```

If Pillow is unavailable, adapt using alternatives:

| Alternative | Platform | Install | Capabilities |
|-------------|----------|---------|-------------|
| `sips` | macOS (built-in) | None | Resize, convert (no trim/OG) |
| `sharp` | Node.js | `npm install sharp` | Full feature set |
| `ffmpeg` | Cross-platform | `brew install ffmpeg` | Resize, convert |

## Capabilities

Generate a Python script using Pillow for any of these operations. See `references/pillow-patterns.md` for implementation patterns, especially RGBA-to-JPG compositing and cross-platform font discovery.

### Resize

Scale to specific dimensions or by width/height (maintain aspect ratio if only one given). Use `Image.LANCZOS` for high-quality downscaling.

### Convert Format

Convert between PNG, JPG, WebP. Handle RGBA-to-JPG by compositing onto white background. Apply format-specific quality settings (WebP: 85, JPG: 90, PNG: optimize).

### Trim Whitespace

Auto-crop surrounding whitespace from logos and icons. Convert to RGBA first, then use `getbbox()` to find content bounds.

### Thumbnail

Fit within max dimensions while maintaining aspect ratio. Use `img.thumbnail((size, size), Image.LANCZOS)`.

### Optimise for Web

Resize + compress in one step. Convert to WebP for best compression. Typical settings: width 1920, quality 85.

### OG Card (1200x630)

Generate Open Graph card with title/subtitle overlay on a background image or solid colour. Apply semi-transparent overlay for text readability. Centre text horizontally.

## Common Workflows

### Logo Cleanup (client-supplied JPG with white background)

1. Trim whitespace
2. Convert to PNG (for transparency)
3. Create favicon-sized version (thumbnail at 512px)

### Prepare Hero Image for Production

Resize to max width 1920, convert to WebP, compress at quality 85.

### Batch Process

For multiple images, generate a single script that loops over all files rather than processing one at a time.

## Pipeline with Gemini Image Gen

Generate images with the gemini-image-gen skill, then process them:

1. Generate with Gemini (raw PNG output)
2. User picks favourite
3. Optimise: resize to target width, convert to WebP, compress

## Output Format Guide

| Use case | Format | Why |
|----------|--------|-----|
| Photos, hero images | WebP | Best compression, wide browser support |
| Logos, icons (need transparency) | PNG | Lossless, supports alpha |
| Fallback for older browsers | JPG | Universal support |
| Thumbnails | WebP or JPG | Small file size priority |
| OG cards | PNG | Social platforms handle PNG best |

## Reference Files

| When | Read |
|------|------|
| Implementing any Pillow operation | [references/pillow-patterns.md](references/pillow-patterns.md) |


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### references/pillow-patterns.md

```markdown
# Pillow Image Processing Patterns

Reference patterns for common web image operations. Claude should adapt these to the user's
specific needs rather than running them as-is.

## RGBA-to-JPG Compositing

JPG does not support transparency. When converting RGBA images to JPG, composite onto a white background first:

```python
from PIL import Image

img = Image.open(input_path)
if output_path.lower().endswith((".jpg", ".jpeg")) and img.mode == "RGBA":
    bg = Image.new("RGB", img.size, (255, 255, 255))
    bg.paste(img, mask=img.split()[3])  # Use alpha channel as mask
    img = bg
```

This also applies inside the save function — always check before saving as JPG.

## Save with Format-Specific Quality

Different formats need different save parameters:

```python
def save_image(img, output_path, quality=None):
    os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True)
    kwargs = {}
    ext = output_path.lower().rsplit(".", 1)[-1]

    if ext == "webp":
        kwargs = {"quality": quality or 85, "method": 6}
    elif ext in ("jpg", "jpeg"):
        kwargs = {"quality": quality or 90, "optimize": True}
        # Handle RGBA → RGB conversion
        if img.mode == "RGBA":
            bg = Image.new("RGB", img.size, (255, 255, 255))
            bg.paste(img, mask=img.split()[3])
            img = bg
    elif ext == "png":
        kwargs = {"optimize": True}

    img.save(output_path, **kwargs)
```

## Resize with Aspect Ratio

When only width or height is given, calculate the other from aspect ratio:

```python
def resize_image(img, width=None, height=None):
    if width and height:
        return img.resize((width, height), Image.LANCZOS)
    elif width:
        ratio = width / img.width
        return img.resize((width, int(img.height * ratio)), Image.LANCZOS)
    elif height:
        ratio = height / img.height
        return img.resize((int(img.width * ratio), height), Image.LANCZOS)
    return img
```

## Trim Whitespace (Auto-Crop)

Remove surrounding whitespace from logos and icons:

```python
img = Image.open(input_path)
if img.mode != "RGBA":
    img = img.convert("RGBA")
bbox = img.getbbox()  # Returns bounding box of non-zero pixels
if bbox:
    img = img.crop(bbox)
```

## OG Card Generation (1200x630)

Composite text on a background image or solid colour:

```python
from PIL import Image, ImageDraw, ImageFont

width, height = 1200, 630

# Background: image or solid colour
if background_path:
    img = Image.open(background_path).resize((width, height), Image.LANCZOS)
else:
    img = Image.new("RGB", (width, height), bg_color or "#1a1a2e")

# Semi-transparent overlay for text readability
overlay = Image.new("RGBA", (width, height), (0, 0, 0, 128))
img = img.convert("RGBA")
img = Image.alpha_composite(img, overlay)

draw = ImageDraw.Draw(img)
font_title = get_font(48)
font_sub = get_font(24)

# Centre title
if title:
    bbox = draw.textbbox((0, 0), title, font=font_title)
    tw = bbox[2] - bbox[0]
    draw.text(((width - tw) // 2, height // 2 - 60), title, fill="white", font=font_title)

img = img.convert("RGB")
```

## Cross-Platform Font Discovery

System font paths differ by OS. Try multiple paths, fall back to Pillow's default:

```python
def get_font(size):
    font_paths = [
        # macOS
        "/System/Library/Fonts/Helvetica.ttc",
        "/System/Library/Fonts/SFNSText.ttf",
        # Linux
        "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
        "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
        # Windows
        "C:/Windows/Fonts/arial.ttf",
    ]
    for path in font_paths:
        if os.path.exists(path):
            try:
                return ImageFont.truetype(path, size)
            except Exception:
                continue
    return ImageFont.load_default()
```

**Tip**: On Linux, `fc-list` shows available fonts. Claude can discover fonts dynamically rather than hardcoding paths.

## Environment Alternatives

If Pillow is not available:

| Alternative | Platform | Install | Best for |
|-------------|----------|---------|----------|
| `sips` | macOS (built-in) | None | Resize, convert (no trim/OG) |
| `sharp` | Node.js | `npm install sharp` | Full feature set, high performance |
| `ffmpeg` | Cross-platform | `brew install ffmpeg` | Resize, convert |

```bash
# macOS sips examples
sips --resampleWidth 1920 input.jpg --out resized.jpg
sips --setProperty format webp input.jpg --out output.webp
```

```