Image Optimization Workflow
Complete guide for creating, optimizing, and managing images for blog posts.
Table of Contents
- Image Types
- Creating Images
- Optimization Process
- Naming Conventions
- Storage Structure
- Automation Tools
Image Types
1. Featured Images (Social Sharing)
- Purpose: Blog post headers, social media cards
- Dimensions: 1200x630px (2:1 ratio)
- File size: < 200KB
- Format: JPG (or WebP with JPG fallback)
2. Content Images (In-post)
- Purpose: Screenshots, diagrams, illustrations
- Max width: 1200px
- File size: < 150KB per image
- Format: PNG for screenshots, JPG for photos
3. Thumbnails (Optional)
- Purpose: Post listings, archives
- Dimensions: 400x200px
- File size: < 50KB
- Format: JPG or WebP
Creating Images
Featured Images
Canva (Recommended for beginners)
- Use “Blog Banner” template (1200x630)
- Free tier includes many templates
- Export as JPG at 80% quality
Figma (Recommended for designers)
- More control over design
- Reusable components
- Export as PNG or JPG
Photopea (Free alternative)
- Browser-based
- Similar to Photoshop
- No account needed
Design Guidelines
Technical Posts:
1
2
3
4
| [Background: Dark code editor theme]
+ [Post Title: Large, bold, white text]
+ [Tech logos: GitHub, Docker, etc.]
+ [Optional: Code snippet as texture]
|
Startup/Business Posts:
1
2
3
4
| [Background: Professional gradient or photo]
+ [Post Title: Clean, readable font]
+ [Company logo or icon]
+ [Subtle pattern or shape]
|
Personal Posts:
1
2
3
4
| [Background: Warm, inviting photo]
+ [Post Title: Friendly font]
+ [Personal photo or illustration]
+ [Soft overlay for text readability]
|
Content Images
Screenshots
- Take screenshot at 2x resolution
- Crop to relevant area only
- Annotate if needed (arrows, highlights)
- Optimize before adding to post
Tools:
- macOS: Cmd+Shift+4
- Windows: Snipping Tool / Snip & Sketch
- Linux: Flameshot, GNOME Screenshot
Diagrams
- Create in Excalidraw, draw.io, or Mermaid
- Export as PNG or SVG
- Optimize for web
Tools:
- Excalidraw - Hand-drawn style
- draw.io - Professional diagrams
- Mermaid - Code-based diagrams (can embed in markdown)
Optimization Process
Automated Optimization Pipeline
1
2
3
4
5
6
7
8
9
10
11
| # 1. Install optimization tools
npm install -g sharp-cli
# or use online tools like tinypng.com, squoosh.app
# 2. Optimize single image
npx sharp -i input.png -o output.jpg --quality 80 --progressive
# 3. Batch optimize all images in a folder
for img in *.{jpg,png}; do
npx sharp -i "$img" -o "optimized-$img" --quality 85
done
|
Manual Optimization
Using Squoosh (Recommended)
- Visit squoosh.app
- Upload your image
- Choose format:
- JPG for photos (quality: 80-85)
- WebP for modern browsers (quality: 80)
- PNG only for images requiring transparency
- Compare before/after
- Download optimized image
Using TinyPNG
- Visit tinypng.com
- Upload up to 20 images
- Download compressed versions
- Average reduction: 60-70%
Optimization Script
Save as scripts/optimize-images.sh:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| #!/bin/bash
# Image Optimization Script
# Usage: ./optimize-images.sh path/to/images
INPUT_DIR="${1:-.}"
OUTPUT_DIR="${INPUT_DIR}/optimized"
mkdir -p "$OUTPUT_DIR"
echo "Optimizing images in: $INPUT_DIR"
# Optimize JPGs
find "$INPUT_DIR" -maxdepth 1 -type f \( -name "*.jpg" -o -name "*.jpeg" \) | while read img; do
filename=$(basename "$img")
echo "Optimizing: $filename"
convert "$img" -quality 85 -strip "$OUTPUT_DIR/$filename"
done
# Optimize PNGs
find "$INPUT_DIR" -maxdepth 1 -type f -name "*.png" | while read img; do
filename=$(basename "$img")
echo "Optimizing: $filename"
pngquant --quality=80-90 "$img" --output "$OUTPUT_DIR/$filename"
done
echo "Optimization complete! Check: $OUTPUT_DIR"
|
Quality Guidelines
| Image Type | Format | Quality | Max Size |
|---|
| Featured Image | JPG | 80-85 | 200KB |
| Screenshot | PNG | 85-90 | 150KB |
| Photo | JPG | 80 | 150KB |
| Diagram | PNG/SVG | 90 | 100KB |
| Icon | SVG | - | 10KB |
Naming Conventions
Featured Images
1
2
3
| featured.jpg # Default name
featured-dark.jpg # Dark theme variant
featured-social.jpg # Social media specific
|
Content Images
1
2
3
4
| diagram-architecture.png # Descriptive names
screenshot-dashboard.png
photo-team.jpg
icon-github.svg
|
Naming Rules
- Lowercase only
- Use hyphens for spaces
- Be descriptive but concise
- No special characters except hyphens
- Include context (what the image shows)
Good:
cloudflare-r2-upload-diagram.pnggithub-actions-workflow.jpgkwippy-screenshot-homepage.png
Bad:
Screen Shot 2024-11-16 at 3.45.23 PM.pngIMG_1234.jpguntitled-1-copy-final-FINAL.png
Storage Structure
Option 1: Folder Structure (Recommended for posts with multiple images)
1
2
3
4
5
6
| content/post/
└── 2024-10-21-mastering-github-actions-arm/
├── index.md
├── featured.jpg
├── diagram-workflow.png
└── screenshot-results.png
|
Pros:
- All assets organized with post
- Easy to manage
- Clear ownership
Cons:
- Requires folder for each post
- Can’t easily share images across posts
Option 2: Flat Structure with Central Images (Current approach)
1
2
3
4
5
6
7
8
9
10
11
| content/post/
├── 2024-10-21-mastering-github-actions-arm.md
└── ...
static/images/
├── featured/
│ ├── 2024-10-21-github-actions-arm.jpg
│ └── ...
└── content/
├── diagram-workflow.png
└── screenshot-results.png
|
Pros:
- Simple file structure
- Easy to reference across posts
- Centralized image management
Cons:
- Harder to track which images belong to which posts
- Can get crowded
Option 3: Hybrid (Recommended)
1
2
3
4
5
6
7
8
9
10
11
12
| content/post/
├── simple-post.md # Text-only posts
├── post-with-images/ # Posts with images
│ ├── index.md
│ ├── featured.jpg
│ └── diagram.png
└── ...
static/images/shared/ # Shared resources
├── logos/
├── icons/
└── banners/
|
1. Automated Featured Image Generation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| // generate-featured-image.js
// Generates consistent featured images from templates
const { createCanvas, loadImage } = require('canvas');
const fs = require('fs');
async function generateFeaturedImage(title, category, outputPath) {
const width = 1200;
const height = 630;
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');
// Background gradient
const gradient = ctx.createLinearGradient(0, 0, width, height);
gradient.addColorStop(0, '#667eea');
gradient.addColorStop(1, '#764ba2');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
// Title text
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 60px Arial';
ctx.textAlign = 'center';
ctx.fillText(title, width / 2, height / 2);
// Save
const buffer = canvas.toBuffer('image/jpeg', { quality: 0.85 });
fs.writeFileSync(outputPath, buffer);
}
// Usage
generateFeaturedImage(
'Your Post Title',
'Technology',
'content/post/your-post/featured.jpg'
);
|
2. Bulk Image Optimizer
Create scripts/bulk-optimize.sh:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| #!/bin/bash
# Find all images larger than 200KB and optimize them
find content/post -type f \( -name "*.jpg" -o -name "*.png" \) -size +200k | while read img; do
echo "Large image found: $img"
# Backup original
cp "$img" "$img.backup"
# Optimize
if [[ $img == *.jpg ]]; then
convert "$img" -quality 85 -strip "$img.optimized"
else
pngquant --quality=85 "$img" --output "$img.optimized"
fi
# Replace if smaller
if [ -f "$img.optimized" ]; then
mv "$img.optimized" "$img"
echo "Optimized: $img"
fi
done
|
3. WebP Conversion
1
2
3
4
5
6
7
8
| #!/bin/bash
# Convert all JPGs to WebP for modern browsers
find content/post -name "*.jpg" | while read img; do
webp_img="${img%.jpg}.webp"
cwebp -q 85 "$img" -o "$webp_img"
echo "Created: $webp_img"
done
|
4. Pre-commit Hook
Add to .git/hooks/pre-commit:
1
2
3
4
5
6
7
8
9
10
11
12
13
| #!/bin/bash
# Check for large images before commit
large_images=$(find content/post -type f \( -name "*.jpg" -o -name "*.png" \) -size +300k)
if [ ! -z "$large_images" ]; then
echo "Error: Large images detected (>300KB):"
echo "$large_images"
echo ""
echo "Please optimize before committing:"
echo " ./scripts/optimize-images.sh"
exit 1
fi
|
Best Practices Checklist
Before Publishing
Accessibility
Always include alt text:
1
| 
|
Good alt text:
- Descriptive
- Concise
- Mentions important details
- Doesn’t start with “Image of…”
Examples:
- ✅ “GitHub Actions workflow diagram showing build, test, and deploy stages”
- ✅ “Cloudflare R2 dashboard showing uploaded files”
- ❌ “Image”
- ❌ “Screenshot”
Quick Reference
Create Featured Image
- Open Canva/Figma
- Create 1200x630px canvas
- Add title, logo, background
- Export as JPG, 80% quality
- Optimize at squoosh.app if needed
- Save as
featured.jpg
Optimize Existing Image
1
2
3
4
5
6
7
8
| # Using online tool
1. Visit squoosh.app
2. Upload image
3. Set quality to 80-85
4. Download
# Using command line
convert input.jpg -quality 85 -strip output.jpg
|
Add to Post
1
2
3
| 
# or with folder structure

|
Last Updated: 2024-11-16
Tools Required: Canva/Figma, Squoosh/TinyPNG, ImageMagick (optional)
Estimated Time: 10-15 minutes per featured image