/web-files-image-handling
Client-side image handling - preview generation, Canvas API resizing, compression, EXIF orientation, format conversion, memory management with object URL cleanup
$ npx -y skills add agents-inc/skills --skill web-files-image-handling --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/web-files-image-handling
Context preview
The summary Claude sees to decide when to auto-load this skill.
Client-side image handling - preview generation, Canvas API resizing, compression, EXIF orientation, format conversion, memory management with object URL cleanup
SKILL.md
web-files-image-handling.SKILL.mdname: web-files-image-handling
description: Client-side image handling - preview generation, Canvas API resizing, compression, EXIF orientation, format conversion, memory management with object URL cleanup
Image Handling Patterns
> **Quick Guide:** Use `URL.createObjectURL()` for image previews (most efficient). Resize/compress with Canvas API before upload. Always cleanup object URLs with `URL.revokeObjectURL()` to prevent memory leaks. Handle EXIF orientation for mobile photos only when processing for upload (modern browsers auto-rotate for display). Use step-down scaling for quality preservation on large reductions.
---
<critical_requirements>
CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST cleanup object URLs with `URL.revokeObjectURL()` in useEffect cleanup or when replacing URLs)**
**(You MUST check browser context before applying EXIF orientation - modern browsers auto-rotate, manual handling causes double rotation)**
**(You MUST use step-down scaling when reducing images by more than 50% - single-pass resize loses quality)**
**(You MUST limit canvas dimensions to browser maximums (typically 4096px) - larger canvases crash browsers)**
</critical_requirements>
---
**Auto-detection:** image preview, URL.createObjectURL, revokeObjectURL, canvas resize, image compression, EXIF orientation, toBlob, toDataURL, FileReader image, image thumbnail, client-side resize, image crop, canvas drawImage, createImageBitmap, image quality
**When to use:**
- Creating image previews before upload
- Resizing or compressing images client-side
- Handling EXIF orientation from mobile photos
- Converting between image formats (JPEG/PNG/WebP)
- Generating thumbnails from user-selected images
- Implementing image cropping interfaces
**When NOT to use:**
- Server-side image processing (not client-side scope)
- Image CDN/optimization services (infrastructure concern)
- Complex image editing (consider dedicated libraries like Fabric.js or Konva)
---
<philosophy>
Philosophy
Client-side image handling improves UX by providing instant previews and reducing upload sizes before they hit your server. The key insight is that **preview and processing have different optimal approaches** - `URL.createObjectURL()` for previews (fast, memory-efficient), Canvas API for processing (resize, compress, convert).
**Core Principles:**
1. **Object URLs for preview** - No file reading, instant display, must cleanup 2. **Canvas for processing** - Resize, compress, convert formats 3. **Memory management is critical** - Leaked object URLs accumulate indefinitely 4. **EXIF awareness** - Modern browsers auto-rotate for display; manual handling only for upload processing 5. **Progressive quality** - Step-down scaling preserves sharpness on large reductions
**Preview Method Comparison:**
| Method | Speed | Memory | Use Case | | ---------------------------- | ------- | ------------------ | -------------------- | | `URL.createObjectURL()` | Instant | Low (reference) | Display previews | | `FileReader.readAsDataURL()` | Slow | High (full Base64) | Need data URL string | | Canvas `toDataURL()` | Medium | Medium | After processing |
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: Object URL Preview with Cleanup
Use `URL.createObjectURL()` for instant image previews. **Always cleanup** to prevent memory leaks. The critical pattern is revoking the previous URL before creating a new one, and revoking in the useEffect cleanup.
// The essential cleanup pattern
useEffect(() => {
const url = URL.createObjectURL(file);
setPreviewUrl(url);
return () => URL.revokeObjectURL(url); // MUST cleanup
}, [file]);**Why good:** Instant preview without reading file into memory, cleanup prevents memory leaks
// BAD: No cleanup - memory leak
const [preview] = useState(() => URL.createObjectURL(file));
// URL never revoked - memory accumulates indefinitely!
**Why bad:** Object URL never revoked, browser holds blob reference indefinitely, compounds with each file selection
See [examples/core.md](examples/core.md) Pattern 1-2 for complete hook and component implementations.
---
Pattern 2: Canvas Resize with Quality Preservation
Resize images using Canvas API. Key concerns: clamp dimensions to browser limits (4096px safe max), enable `imageSmoothingQuality: "high"`, fill white background for JPEG (transparency becomes black otherwise).
const MAX_CANVAS_DIMENSION = 4096;
// Clamp to browser limits, maintain aspect ratio
const ratio = Math.min(maxWidth / img.width, maxHeight / img.height);
const width = Math.round(img.width * Math.min(ratio, 1));
const height = Math.round(img.height * Math.min(ratio, 1));
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
if (mimeType === "image/jpeg") {
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, width, height); // White bg for JPEG
}
ctx.drawImage(img, 0, 0, width, height);See [examples/core.md](examples/core.md) Pattern 3 for dimension validation, [examples/canvas.md](examples/canvas.md) for complete resize pipeline.
---
Pattern 3: Step-Down Scaling
For reductions >50%, scale in multiple passes to preserve sharpness. A 4000px to 100px single-pass resize produces blurry results; two intermediate steps maintain quality.
const STEP_DOWN_THRESHOLD = 0.5;
const reductionRatio = targetWidth / img.width;
if (reductionRatio < STEP_DOWN_THRESHOLD) {
// Multi-pass: 4000 -> 400 -> 100 (two steps)
const factor = Math.pow(targetWidth / img.width, 1 / steps);
for (let i = 0; i < steps; i++) {
/* scale by factor each step */
}
} else {
// Single-pass is fine for small reductions
}See [examples/canvas.md](examples/canvas.md) Patt
Read more
name: web-files-image-handling description: Client-side image handling - preview generation, Canvas API resizing, compression, EXIF orientation, format conversion, memory management with object URL cleanup
Image Handling Patterns
> **Quick Guide:** Use `URL.createObjectURL()` for image previews (most efficient). Resize/compress with Canvas API before upload. Always cleanup object URLs with `URL.revokeObjectURL()` to prevent memory leaks. Handle EXIF orientation for mobile photos only when processing for upload (modern browsers auto-rotate for display). Use step-down scaling for quality preservation on large reductions.
---
<critical_requirements>
CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST cleanup object URLs with `URL.revokeObjectURL()` in useEffect cleanup or when replacing URLs)**
**(You MUST check browser context before applying EXIF orientation - modern browsers auto-rotate, manual handling causes double rotation)**
**(You MUST use step-down scaling when reducing images by more than 50% - single-pass resize loses quality)**
**(You MUST limit canvas dimensions to browser maximums (typically 4096px) - larger canvases crash browsers)**
</critical_requirements>
---
**Auto-detection:** image preview, URL.createObjectURL, revokeObjectURL, canvas resize, image compression, EXIF orientation, toBlob, toDataURL, FileReader image, image thumbnail, client-side resize, image crop, canvas drawImage, createImageBitmap, image quality
**When to use:**
- Creating image previews before upload
- Resizing or compressing images client-side
- Handling EXIF orientation from mobile photos
- Converting between image formats (JPEG/PNG/WebP)
- Generating thumbnails from user-selected images
- Implementing image cropping interfaces
**When NOT to use:**
- Server-side image processing (not client-side scope)
- Image CDN/optimization services (infrastructure concern)
- Complex image editing (consider dedicated libraries like Fabric.js or Konva)
---
<philosophy>
Philosophy
Client-side image handling improves UX by providing instant previews and reducing upload sizes before they hit your server. The key insight is that **preview and processing have different optimal approaches** - `URL.createObjectURL()` for previews (fast, memory-efficient), Canvas API for processing (resize, compress, convert).
**Core Principles:**
1. **Object URLs for preview** - No file reading, instant display, must cleanup 2. **Canvas for processing** - Resize, compress, convert formats 3. **Memory management is critical** - Leaked object URLs accumulate indefinitely 4. **EXIF awareness** - Modern browsers auto-rotate for display; manual handling only for upload processing 5. **Progressive quality** - Step-down scaling preserves sharpness on large reductions
**Preview Method Comparison:**
| Method | Speed | Memory | Use Case | | ---------------------------- | ------- | ------------------ | -------------------- | | `URL.createObjectURL()` | Instant | Low (reference) | Display previews | | `FileReader.readAsDataURL()` | Slow | High (full Base64) | Need data URL string | | Canvas `toDataURL()` | Medium | Medium | After processing |
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: Object URL Preview with Cleanup
Use `URL.createObjectURL()` for instant image previews. **Always cleanup** to prevent memory leaks. The critical pattern is revoking the previous URL before creating a new one, and revoking in the useEffect cleanup.
// The essential cleanup pattern
useEffect(() => {
const url = URL.createObjectURL(file);
setPreviewUrl(url);
return () => URL.revokeObjectURL(url); // MUST cleanup
}, [file]);**Why good:** Instant preview without reading file into memory, cleanup prevents memory leaks
// BAD: No cleanup - memory leak const [preview] = useState(() => URL.createObjectURL(file)); // URL never revoked - memory accumulates indefinitely!
**Why bad:** Object URL never revoked, browser holds blob reference indefinitely, compounds with each file selection
See [examples/core.md](examples/core.md) Pattern 1-2 for complete hook and component implementations.
---
Pattern 2: Canvas Resize with Quality Preservation
Resize images using Canvas API. Key concerns: clamp dimensions to browser limits (4096px safe max), enable `imageSmoothingQuality: "high"`, fill white background for JPEG (transparency becomes black otherwise).
const MAX_CANVAS_DIMENSION = 4096;
// Clamp to browser limits, maintain aspect ratio
const ratio = Math.min(maxWidth / img.width, maxHeight / img.height);
const width = Math.round(img.width * Math.min(ratio, 1));
const height = Math.round(img.height * Math.min(ratio, 1));
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
if (mimeType === "image/jpeg") {
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, width, height); // White bg for JPEG
}
ctx.drawImage(img, 0, 0, width, height);See [examples/core.md](examples/core.md) Pattern 3 for dimension validation, [examples/canvas.md](examples/canvas.md) for complete resize pipeline.
---
Pattern 3: Step-Down Scaling
For reductions >50%, scale in multiple passes to preserve sharpness. A 4000px to 100px single-pass resize produces blurry results; two intermediate steps maintain quality.
const STEP_DOWN_THRESHOLD = 0.5;
const reductionRatio = targetWidth / img.width;
if (reductionRatio < STEP_DOWN_THRESHOLD) {
// Multi-pass: 4000 -> 400 -> 100 (two steps)
const factor = Math.pow(targetWidth / img.width, 1 / steps);
for (let i = 0; i < steps; i++) {
/* scale by factor each step */
}
} else {
// Single-pass is fine for small reductions
}See [examples/canvas.md](examples/canvas.md) Patt
Showing the first part of this file.
The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?
Repo: agents-inc/skills
Other skills on agents-inc-skills.
- /ai-infrastructure-huggingface-inference
Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints
Open skill - /ai-infrastructure-litellm
LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment
Open skill - /ai-infrastructure-modal
Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns
Open skill - /ai-infrastructure-ollama
Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint
Open skill - /ai-infrastructure-replicate
Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training
Open skill - /ai-infrastructure-together-ai
Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints
Open skill

