Processing Images with Pillow
Processing Images with Pillow
Deterministic pixel-level image operations: resize, crop, composite, convert formats, watermark, and optimize. No AI/generative work — for that (text-to-image, background removal, inpainting, upscaling), use a generative image skill like bria-ai instead.
Pythonfrom image_utils import ImageUtils image = ImageUtils.load_from_url("https://example.com/image.jpg") resized = ImageUtils.resize(image, width=800, height=600) ImageUtils.save(resized, "output.webp", quality=90)
Requires: pip install Pillow requests
For a typical post-processing task:
Progress:
- [ ] Load image (from URL, path, bytes, or base64)
- [ ] Inspect with get_info() if dimensions/format unknown
- [ ] Apply transforms (crop/resize/composite/adjust) in logical order
- [ ] Add watermark/border/padding last, after sizing
- [ ] Save/export in target format with appropriate quality
Order matters: crop before resize (avoid scaling then losing detail to crop), adjust colors before watermarking (don't fade the watermark), resize before adding fixed-size watermarks/borders.
| Category | Method | Description |
|---|---|---|
| Load | load(source) | From URL, path, bytes, or base64 |
| Load | load_from_url(url) | Download from URL |
| Save | save(image, path) | Auto-detects format from extension |
| Save | to_bytes(image, format) | Convert to bytes |
| Save | to_base64(image, format) | Convert to base64 / data URL |
| Resize | resize(image, width, height) | Exact or aspect-preserving |
| Resize | scale(image, factor) | Scale by factor |
| Resize | thumbnail(image, size) | Fit within bounds |
| Crop | crop(image, l, t, r, b) | Crop to region |
| Crop | crop_center(image, w, h) | Crop from center |
| Crop | crop_to_aspect(image, ratio, anchor) | Crop to aspect ratio |
| Composite | paste(bg, fg, position) | Overlay at coordinates |
| Composite | composite(bg, fg, mask) | Alpha composite |
| Composite | fit_to_canvas(image, w, h) | Letterbox onto canvas |
| Border | add_border(image, width, color) | Solid border |
| Border | add_padding(image, padding) | Whitespace padding |
| Transform | rotate/flip_horizontal/flip_vertical | Basic transforms |
| Watermark | add_text_watermark(image, text, position) | Text overlay |
| Watermark | add_image_watermark(image, logo, opacity, scale) | Logo overlay |
| Adjust | adjust_brightness/contrast/saturation/sharpness(image, factor) | 1.0 = original |
| Adjust | blur(image, radius) | Gaussian blur |
| Web | optimize_for_web(image, max_dimension, format, quality) | Web-ready bytes |
| Info | get_info(image) | Dimensions, format, mode |
Example 1: Responsive image set Input: One 4000×3000 source image, need large/medium/thumb WebP variants.
Pythonimage = ImageUtils.load("source.jpg") sizes = { "large": ImageUtils.resize(image, width=1200), "medium": ImageUtils.resize(image, width=600), "thumb": ImageUtils.thumbnail(image, (150, 150)), } for name, img in sizes.items(): ImageUtils.save(img, f"product_{name}.webp", quality=85)
Output: product_large.webp, product_medium.webp, product_thumb.webp.
Example 2: Social media crop Input: Landscape product photo, need Instagram square and Story vertical.
Pythonsquare = ImageUtils.crop_to_aspect(image, "1:1") story = ImageUtils.crop_to_aspect(image, "9:16", anchor="top")
Output: Two cropped images ready for platform-specific posting.
Example 3: Batch watermark + optimize Input: Directory of raw catalog images.
Pythonfrom pathlib import Path for f in Path("./raw_images").glob("*.jpg"): img = ImageUtils.load(f) img = ImageUtils.crop_to_aspect(img, "1:1") img = ImageUtils.resize(img, width=800, height=800) img = ImageUtils.add_text_watermark(img, "© My Brand", position="bottom-right") ImageUtils.save(img, f"./processed/{f.stem}.webp", quality=85)
Output: Uniform 800×800 watermarked WebP files in ./processed/.
- Default to WEBP at quality 85 for web delivery — good compression/quality tradeoff.
- Preserve alpha channel (RGBA) when source has transparency; flatten to RGB only when exporting JPEG.
- Use
maintain_aspect=Trueon resize unless exact dimensions are explicitly required (avoids distortion). - For watermarks, use semi-transparent alpha (e.g., 128/255) so they don't overpower the image.
- When chaining AI generation with this skill: download/load the generated image first, then apply post-processing — never re-request generation for a pixel-level tweak.
- Use
crop_to_aspectwith explicitanchorfor subject-aware cropping instead of always defaulting to center.
- Don't use this skill for anything requiring image understanding or new content generation (background removal, inpainting, style transfer, upscaling) — route to
bria-aiinstead. - Don't resize before cropping when detail matters — crop first to avoid compounding quality loss.
- Don't save JPEG with an image that has an alpha channel without flattening first — it will error or produce unexpected results.
- Don't apply watermarks before final resize — fixed-size text/logos will scale incorrectly.
- Don't forget quality parameter on lossy formats (JPEG/WEBP) — omitting it uses library defaults that may be too aggressive or too large.