---
name: image-export-toolkit
description: Toolkit profissional de export, otimização e validação de imagens em máxima resolução. Cobre PNG/JPEG/WebP/AVIF/SVG/PDF/HEIC. Stack libvips + sharp + ImageMagick + Playwright + otimizadores best-in-class.
owner: "@web-designer"
shared_with: ["@web-designer"]
version: 1.0
tags: [image, export, png, jpg, webp, avif, svg, optimization, playwright, vips, sharp, brand]
---

# Skill: Image Export Toolkit

## Stack instalada (verificado 2026-05-29)

**Runtime:** Node v26.0.0 · Python 3.14.5 · macOS aarch64

| Tool | Versão | Função |
|---|---|---|
| **libvips** | 8.18.2 | Engine de imagem mais rápida (8-10x ImageMagick), gigapixel-safe |
| **sharp (Node lib)** | 0.34.5 | Binding libvips em Node — padrão Vercel/Cloudflare Images |
| **sharp-cli** | 5.2.0 | CLI standalone do sharp |
| **ImageMagick** | 7.1.2-22 Q16-HDRI | Suporta 200+ formatos (PSD, AI, EPS, PDF, HEIC, TIFF, BMP, RAW...) |
| **Playwright** | 1.59.0 | HTML → PNG/JPEG/PDF com Chromium/Firefox/Webkit |
| **Pillow** | 12.2.0 | Python PIL — manipulação programática |
| **Pillow-HEIF** | 1.3.0 | Suporte HEIC iPhone |
| **cairosvg** | 2.9.0 | SVG → PNG/PDF vetorial preciso |
| **svglib** | 1.6.0 | SVG → PDF alternativa (com reportlab) |
| **reportlab** | 4.5.1 | PDF generation engine |
| **OpenCV** | 4.13.0 | CV avançado, AI denoise, upscale |
| **Wand** | 0.7.0 | ImageMagick binding Python |
| **rembg** | 2.0.75 | Background removal IA (U²-Net) |
| **OxiPNG** | 10.1.1 | Otimização PNG lossless (Rust, paralelo) |
| **mozjpeg** (cjpeg) | 4.1.5 | JPEG 20-30% menor com mesma qualidade |
| **jpegoptim** | 1.5.6 | JPEG lossless trim |
| **pngquant** | 3.0.3 | PNG quantization (palette, -70% peso) |
| **gifsicle** | 1.96 | GIF otimização |
| **Squoosh CLI** | installed | Google's best-in-class converter |
| **FFmpeg** | 8.1.1 | AVIF, video frames, sequence + libx265 funcional |
| **FFprobe** | 8.1.1 | Metadata extraction (video/audio) |

### ⚠️ Path crítico — mozjpeg

`mozjpeg` (cjpeg/djpeg/jpegtran) NÃO está no `PATH` global por conflito com `jpeg-turbo` do sistema. Use sempre o path absoluto:

```bash
/opt/homebrew/opt/mozjpeg/bin/cjpeg
/opt/homebrew/opt/mozjpeg/bin/djpeg
/opt/homebrew/opt/mozjpeg/bin/jpegtran
```

Alias recomendado (já em scripts da skill):
```bash
MOZJPEG_BIN="/opt/homebrew/opt/mozjpeg/bin"
$MOZJPEG_BIN/cjpeg -quality 85 -progressive input.png > output.jpg
```

## Quando usar

Sempre que @brand-director (ou @web-designer) precisa:
- Exportar brandbook em PDF/PNG alta resolução
- Converter SVG vetor → PNG retina (1x, 2x, 3x, 4x)
- Otimizar PNG/JPG pra web sem perder qualidade visual
- Render HTML brandbook → PNG (Playwright)
- Converter HEIC (iPhone) → PNG/JPG
- Comprimir creative pra under-1MB (ads Meta requirement)
- Background removal (criativo de produto, headshot expert)
- AVIF (formato mais comprimido pra web, -50% vs WebP)
- Upscale 4K/8K com qualidade IA

## Decisão de engine

```
Preciso fazer X com imagem:
  ├─ HTML render → PNG/PDF              → Playwright
  ├─ SVG → PNG retina (vetor preciso)   → cairosvg / sharp
  ├─ Imagem normal (PNG/JPEG/WebP)      → sharp (rápido, simples)
  ├─ 10MB+ TIFF ou gigapixel            → libvips direto
  ├─ Formato exótico (PSD/AI/EPS/RAW)   → ImageMagick (magick)
  ├─ HEIC iPhone                        → Pillow + pillow-heif OR magick
  ├─ Background removal                 → rembg (CLI/Python)
  ├─ AVIF (web moderno)                 → squoosh-cli OR FFmpeg
  ├─ Otimizar PNG final                 → oxipng -o6 (lossless)
  ├─ Otimizar JPEG final                → mozjpeg cjpeg OR jpegoptim
  ├─ Reduzir cor PNG (peso 70%↓)        → pngquant
  └─ Comparação batch                   → sharp pipeline
```

## Receitas canônicas

### 1. SVG → PNG retina (1x/2x/3x/4x) com cairosvg

```python
import cairosvg
for scale, suffix in [(1, "@1x"), (2, "@2x"), (3, "@3x"), (4, "@4x")]:
    cairosvg.svg2png(
        url="logo.svg",
        write_to=f"logo{suffix}.png",
        output_width=512 * scale,
        output_height=512 * scale,
        dpi=300 * scale,
    )
```

```bash
# Alternativa one-liner sharp
sharp -i logo.svg -o logo@4x.png --resize 2048 --density 300
```

### 2. HTML brandbook → PNG full-page (Playwright)

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(
        viewport={"width": 1920, "height": 1080},
        device_scale_factor=2,  # retina 2x
    )
    page.goto("file:///path/brandbook.html")
    page.wait_for_load_state("networkidle")
    page.screenshot(
        path="brandbook.png",
        full_page=True,
        type="png",
        omit_background=False,
    )
    browser.close()
```

### 3. HTML → PDF print-quality (Playwright)

```python
page.pdf(
    path="brandbook.pdf",
    format="A4",
    print_background=True,
    prefer_css_page_size=True,
    margin={"top": "0", "right": "0", "bottom": "0", "left": "0"},
)
```

### 4. PNG/JPEG resize otimizado (sharp)

```bash
# Resize mantendo aspecto, qualidade alta
sharp -i input.png -o output.png \
  --resize 2400 \
  --quality 90 \
  --format png

# Multi-output em batch (responsivo)
for w in 320 640 960 1280 1920 2560; do
  sharp -i hero.png -o "hero-${w}.webp" --resize $w --quality 85 --format webp
done
```

### 5. Imagem master → WebP + AVIF + JPEG fallback (entrega web completa)

```bash
INPUT="hero-4000px.png"
BASE="hero"

# AVIF (mais comprimido)
sharp -i $INPUT -o ${BASE}.avif --quality 70 --format avif
# WebP (boa compat)
sharp -i $INPUT -o ${BASE}.webp --quality 85 --format webp
# JPEG fallback
sharp -i $INPUT -o ${BASE}.jpg  --quality 85 --format jpeg
# PNG transparente (se aplicável)
sharp -i $INPUT -o ${BASE}.png  --format png
```

Resultado: 4 formatos, hierarquia `picture` no HTML.

### 6. AVIF max compression (squoosh)

```bash
squoosh-cli --avif '{"cqLevel":30,"cqAlphaLevel":-1,"denoiseLevel":0,"tileColsLog2":0,"tileRowsLog2":0,"speed":4,"subsample":1,"chromaDeltaQ":false,"sharpness":0,"tune":0}' input.png
# Output: input.avif (50-70% menor que JPEG mesma qualidade)
```

### 7. HEIC iPhone → PNG (Pillow + pillow-heif)

```python
from PIL import Image
from pillow_heif import register_heif_opener
register_heif_opener()

img = Image.open("IMG_0023.HEIC")
img.save("converted.png", "PNG", optimize=True)
```

```bash
# Alternativa ImageMagick
magick IMG_0023.HEIC converted.png
```

### 8. PSD/AI/EPS → PNG (ImageMagick)

```bash
# PSD com layers achatadas
magick "design.psd[0]" -flatten -resize 4000x4000 -quality 95 design.png

# AI (Adobe Illustrator)
magick -density 300 "logo.ai" -resize 2048x2048 logo.png

# EPS vetor
magick -density 300 -colorspace sRGB "diagram.eps" -alpha background diagram.png

# PDF página específica
magick -density 300 "brandbook.pdf[2]" page3.png
```

### 9. Background removal IA (rembg)

```bash
# CLI
rembg i product-photo.jpg product-cutout.png

# Batch de pasta inteira
rembg p ./input-photos ./output-cutouts

# Modelos disponíveis: u2net (default), u2netp (lite), isnet-general-use, sam (preciso)
rembg i -m isnet-general-use input.jpg output.png
```

```python
# Python para integrar no pipeline
from rembg import remove
from PIL import Image

input_img = Image.open("headshot.jpg")
output_img = remove(input_img)
output_img.save("headshot-cutout.png")
```

### 10. Upscale 4K → 8K com qualidade (OpenCV + AI)

```python
import cv2
# Modelo: EDSR_x4.pb, ESPCN_x4.pb, FSRCNN_x4.pb, LapSRN_x4.pb
sr = cv2.dnn_superres.DnnSuperResImpl_create()
sr.readModel("EDSR_x4.pb")
sr.setModel("edsr", 4)
img = cv2.imread("input-1080p.jpg")
result = sr.upsample(img)
cv2.imwrite("output-4k.png", result)
```

Para max quality usar Real-ESRGAN ou Topaz Gigapixel (paid).

### 11. Otimização final (toda imagem entregue)

**PNG:**
```bash
# Lossless máximo (oxipng — paralelo Rust)
oxipng -o 6 --strip safe input.png
# Lossy (palette quantization)
pngquant --quality=80-95 --strip --output input-pq.png input.png
```

**JPEG:**
```bash
# mozjpeg (melhor que libjpeg padrão)
cjpeg -quality 85 -progressive -optimize -outfile output.jpg input.png
# Lossless trim já existente
jpegoptim --strip-all --all-progressive --max=85 input.jpg
```

**GIF:**
```bash
gifsicle -O3 --lossy=80 -o output.gif input.gif
```

**Pipeline completo (master PNG → 5 entregas otimizadas):**
```bash
#!/bin/bash
SRC=$1; OUT=$(dirname $SRC)/optimized
mkdir -p $OUT

# AVIF (web moderno, max compression)
sharp -i $SRC -o $OUT/img.avif --quality 70 --format avif
# WebP (web compat)
sharp -i $SRC -o $OUT/img.webp --quality 85 --format webp
# PNG otimizado (transparência)
sharp -i $SRC -o $OUT/img.png --format png
oxipng -o 6 --strip safe $OUT/img.png
# JPEG progressive (fallback)
sharp -i $SRC -o $OUT/img-orig.jpg --quality 90 --format jpeg
cjpeg -quality 85 -progressive -optimize -outfile $OUT/img.jpg $OUT/img-orig.jpg
rm $OUT/img-orig.jpg
# PNG palette (peso 70%↓ pra ads simples)
pngquant --quality=80-95 --strip --output $OUT/img-pq.png $SRC

echo "Sizes:"
du -h $OUT/*
```

### 12. Watermark / branding em batch

```bash
# Logo canto inferior direito em todas fotos da pasta
for img in input/*.jpg; do
  name=$(basename "$img")
  magick "$img" -gravity SouthEast -geometry +30+30 logo.png -composite "output/$name"
done
```

```python
# Pillow batch
from PIL import Image
from pathlib import Path

logo = Image.open("logo.png").convert("RGBA")
logo.thumbnail((150, 150))

for img_path in Path("input").glob("*.jpg"):
    base = Image.open(img_path).convert("RGBA")
    pos = (base.width - logo.width - 30, base.height - logo.height - 30)
    base.paste(logo, pos, logo)
    base.convert("RGB").save(f"output/{img_path.name}", quality=92, optimize=True)
```

### 13. Color space + ICC profile (impressão profissional)

```bash
# sRGB pra web
magick input.tif -colorspace sRGB -profile sRGB.icc web.jpg

# Adobe RGB pra impressão
magick input.tif -colorspace AdobeRGB -profile AdobeRGB1998.icc print.tif

# CMYK pra gráfica
magick input.png -colorspace CMYK -profile USWebCoatedSWOP.icc print-cmyk.pdf
```

### 14. Multi-resolution sprite / asset library

```python
# Gera @1x, @2x, @3x de uma master
from PIL import Image
master = Image.open("icon-master.png")  # ex: 192x192
sizes = {"@1x": 64, "@2x": 128, "@3x": 192}
for suffix, size in sizes.items():
    resized = master.resize((size, size), Image.Resampling.LANCZOS)
    resized.save(f"icon{suffix}.png", "PNG", optimize=True)
```

### 15. EXIF strip + privacy

```bash
# Remove TODOS metadados (privacy, peso)
jpegoptim --strip-all photo.jpg
exiftool -all= photo.jpg
magick photo.jpg -strip stripped.jpg
```

## Validações pós-export (@brand-director checklist)

- [ ] Resolução final ≥ 2x do display target (retina-ready)
- [ ] Color space sRGB pra web, CMYK pra print
- [ ] ICC profile embarcado quando crítico
- [ ] Tamanho de arquivo dentro do budget (ads: <1MB, web: <500KB hero)
- [ ] Otimização lossless aplicada (oxipng/jpegoptim)
- [ ] Filename kebab-case + suffixes @1x/@2x/@3x se asset library
- [ ] Multi-format entregue quando web (AVIF + WebP + JPEG fallback)
- [ ] Transparência preservada onde aplicável (PNG/AVIF, não JPEG)
- [ ] Watermark/logo aplicado quando exigido
- [ ] Comparação visual antes/depois (sem degradação perceptível)

## Benchmarks típicos (M1/M2 mac)

| Operação | Tempo | Engine |
|---|---|---|
| 4000x4000 PNG resize 2000x2000 | 80ms | sharp/libvips |
| 4000x4000 PNG resize 2000x2000 | 600ms | Pillow |
| 4000x4000 PNG resize 2000x2000 | 1200ms | ImageMagick |
| SVG 1MB → PNG 4K | 200ms | cairosvg |
| HTML brandbook 1080p screenshot | 800-1500ms | Playwright |
| oxipng lossless PNG 4MB | 2-4s | oxipng |
| AVIF encode 4K | 3-8s | squoosh-cli |
| Background removal (rembg u2net) | 2-5s | rembg |
| Upscale 1080p→4K (EDSR x4) | 8-15s | OpenCV DNN |

## Budget de peso por uso

| Uso | Target max |
|---|---|
| Ad Meta (single image) | 1MB |
| Ad Meta (carousel) | 30MB total |
| Hero landing (1920px) | 200-500KB |
| Thumbnail (320px) | 30-80KB |
| Logo SVG | 5-15KB |
| Logo PNG retina (@2x) | 30-80KB |
| Brandbook PDF | 5-15MB |
| Email hero | 100-300KB |
| Email body image | 50-150KB |
| WhatsApp share | <1MB |
| Print A4 300dpi | 8-25MB |

## Anti-patterns

❌ Subir PNG 10MB em landing (use AVIF/WebP)
❌ Esquecer ICC profile em creative impresso (cor sai diferente)
❌ Otimizar JPEG depois de PNG (compounding loss — sempre máster lossless)
❌ Salvar como JPEG quando precisa transparência (use PNG/WebP/AVIF)
❌ Resize via Pillow quando libvips/sharp disponíveis (10x mais lento)
❌ EXIF não removido em ads (privacy do cliente)
❌ Sem retina @2x quando target é display moderno (parece embaçado em mobile)
❌ AVIF sem fallback JPEG no `<picture>` (browser velho quebra)
❌ Upscale fake (resize com nearest neighbor não é upscale IA — fica pixelado)

## Stack em uso por agente

| Agente | Stack principal | Use case |
|---|---|---|
| **@brand-director** | Playwright + sharp + cairosvg + oxipng | Brandbook export, logos, identidade visual |
| **@web-designer** | Playwright + sharp + AVIF/WebP pipeline | Hero landing, criativos web |
| **@web-designer** | Playwright + cairosvg + ImageMagick (PDF) | Decks brandbook, apresentações |
| **@web-designer** | sharp + FFmpeg + Lottie + rembg | Frames de vídeo, thumbnails, cutouts |
| **@copywriter** | sharp + squoosh-cli | Social posts otimizados |
| **@paid-traffic** | sharp + mozjpeg | Criativos Meta Ads dentro do budget 1MB |

## Quick scripts (utilitários @brand-director)

### `optimize-all.sh` — otimiza tudo da pasta

```bash
#!/bin/bash
DIR=${1:-./}
echo "Otimizando $DIR..."
find "$DIR" -type f \( -iname "*.png" \) -exec oxipng -o 4 --strip safe {} \;
find "$DIR" -type f \( -iname "*.jpg" -o -iname "*.jpeg" \) -exec jpegoptim --strip-all --all-progressive --max=85 {} \;
find "$DIR" -type f -iname "*.gif" -exec gifsicle -O3 -b {} \;
echo "Done."
```

### `to-web-formats.sh` — converte uma master pra 4 formatos web

```bash
#!/bin/bash
SRC=$1
[ -z "$SRC" ] && echo "uso: $0 master.png" && exit 1
BASE="${SRC%.*}"
sharp -i "$SRC" -o "${BASE}.avif" --quality 70 --format avif
sharp -i "$SRC" -o "${BASE}.webp" --quality 85 --format webp
sharp -i "$SRC" -o "${BASE}.jpg"  --quality 88 --format jpeg
cjpeg -quality 85 -progressive -optimize -outfile "${BASE}-opt.jpg" "${BASE}.jpg" && mv "${BASE}-opt.jpg" "${BASE}.jpg"
echo "Output: ${BASE}.{avif,webp,jpg}"
du -h "${BASE}.avif" "${BASE}.webp" "${BASE}.jpg"
```

### `screenshot-html.py` — render HTML qualquer pra PNG/PDF

```python
#!/usr/bin/env python3
import sys
from playwright.sync_api import sync_playwright

url = sys.argv[1]          # file:///path OR https://...
out = sys.argv[2]          # output.png ou output.pdf
w   = int(sys.argv[3]) if len(sys.argv) > 3 else 1920
h   = int(sys.argv[4]) if len(sys.argv) > 4 else 1080
dsf = float(sys.argv[5]) if len(sys.argv) > 5 else 2.0

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={"width": w, "height": h}, device_scale_factor=dsf)
    page.goto(url)
    page.wait_for_load_state("networkidle")
    if out.endswith(".pdf"):
        page.pdf(path=out, format="A4", print_background=True)
    else:
        page.screenshot(path=out, full_page=True, type="png" if out.endswith(".png") else "jpeg")
    browser.close()
    print(f"Saved {out}")
```

Uso: `python3 screenshot-html.py file:///path/brandbook.html out.png 1920 1080 2`

## Referências

- libvips: https://www.libvips.org/
- sharp (Node): https://sharp.pixelplumbing.com
- Squoosh: https://squoosh.app
- Playwright: https://playwright.dev/python
- ImageMagick: https://imagemagick.org
- mozjpeg: https://github.com/mozilla/mozjpeg
- oxipng: https://github.com/shssoichiro/oxipng
- rembg: https://github.com/danielgatis/rembg
