🔄 Batch Convert Guide — Convert Multiple Images Fast

Stop converting images one by one. This guide shows you how to convert hundreds of images in seconds using free tools, command-line scripts, and automated production pipelines.


⚡ Why Batch Conversion?

Without batch conversion:
  100 images × 3 minutes each = 5 hours of manual work 😩

With batch conversion:
  100 images × one command = 30 seconds ✅

🌐 Method 1 — Free Web Tools (Best for Beginners)

ClearAI Tools

Steps:
1. Go to clearaitools.com
2. Select "Batch Convert"
3. Drag and drop your files (up to 50 images)
4. Choose WebP or AVIF as output format
5. Download the ZIP file containing all converted images
Pros:
  ✅ No installation required
  ✅ Free to use
  ✅ Works entirely in your browser
  ✅ Supports JPEG, PNG, GIF → WebP, AVIF

Limitations:
  ⚠️ Files are uploaded to a server (privacy consideration)
  ⚠️ Slower than local tools
  ⚠️ File size limits apply

Free Web Tool Comparison

ToolMax FilesFormatsSpeedFree?
ClearAI Tools50 filesWebP, AVIFMedium
Convertio25 filesManyMedium✅ Partial
Squoosh1 fileManyFast
ILoveIMG30 filesManyMedium✅ Partial
Kraken.io20 MBWebP, JPEG, PNGFast✅ Partial

💻 Method 2 — Command Line (For Power Users)

Setup

# macOS
brew install webp imagemagick

# Ubuntu / Debian
sudo apt-get install webp imagemagick

# Windows (PowerShell with Chocolatey)
choco install webp imagemagick

Core Batch Conversion Commands

# ─── JPEG → WebP ───
# Convert all JPEGs in the current folder
for f in *.jpg *.jpeg; do
  cwebp -q 80 "$f" -o "${f%.*}.webp" && echo "✅ $f"
done

# ─── PNG → WebP (lossless) ───
for f in *.png; do
  cwebp -lossless "$f" -o "${f%.*}.webp" && echo "✅ $f"
done

# ─── All images recursively (including subfolders) ───
find . \( -name "*.jpg" -o -name "*.png" \) | while read f; do
  cwebp -q 80 "$f" -o "${f%.*}.webp"
done

# ─── Convert + resize (max width 1200px) ───
for f in *.jpg; do
  convert "$f" -resize 1200x1200\> \
    -quality 80 \
    "${f%.jpg}.webp"
done

Advanced Script — With Statistics Report

#!/bin/bash
# batch-convert.sh — batch convert with savings report

INPUT_DIR="./images"
OUTPUT_DIR="./images-webp"
QUALITY=80

mkdir -p "$OUTPUT_DIR"

total_before=0
total_after=0
count=0

for f in "$INPUT_DIR"/*.{jpg,jpeg,png,gif}; do
  [ -f "$f" ] || continue

  filename=$(basename "$f")
  name="${filename%.*}"
  output="$OUTPUT_DIR/$name.webp"

  before=$(wc -c < "$f")
  cwebp -q $QUALITY "$f" -o "$output" -quiet
  after=$(wc -c < "$output")

  saving=$(echo "scale=1; (1 - $after / $before) * 100" | bc)
  echo "✅ $filename → $name.webp | Before: ${before}B | After: ${after}B | Saved: ${saving}%"

  total_before=$((total_before + before))
  total_after=$((total_after + after))
  count=$((count + 1))
done

total_saving=$(echo "scale=1; (1 - $total_after / $total_before) * 100" | bc)
echo ""
echo "═══════════════════════════════════════════"
echo "📊 Summary:"
echo "   Images converted: $count"
echo "   Size before:      $((total_before / 1024)) KB"
echo "   Size after:       $((total_after / 1024)) KB"
echo "   Total saved:      ${total_saving}%"
echo "═══════════════════════════════════════════"

🟢 Method 3 — Node.js with Sharp (For Developers)

Sharp is the fastest Node.js image processing library and the go-to choice for production pipelines.

// batch-convert.js
const sharp = require('sharp');
const fs = require('fs');
const path = require('path');
const { promisify } = require('util');
const readdir = promisify(fs.readdir);

const CONFIG = {
  inputDir:  './images',
  outputDir: './images-optimized',
  quality: {
    webp: 80,
    avif: 65,
  },
  maxWidth: 1920,
};

async function convertImage(inputPath, outputDir) {
  const filename = path.basename(inputPath, path.extname(inputPath));
  const stats = fs.statSync(inputPath);

  // WebP for modern browsers
  const webpPath = path.join(outputDir, `${filename}.webp`);
  await sharp(inputPath)
    .resize(CONFIG.maxWidth, null, { withoutEnlargement: true })
    .webp({ quality: CONFIG.quality.webp })
    .toFile(webpPath);

  // AVIF for cutting-edge browsers
  const avifPath = path.join(outputDir, `${filename}.avif`);
  await sharp(inputPath)
    .resize(CONFIG.maxWidth, null, { withoutEnlargement: true })
    .avif({ quality: CONFIG.quality.avif })
    .toFile(avifPath);

  const webpStats = fs.statSync(webpPath);
  const saving = ((1 - webpStats.size / stats.size) * 100).toFixed(1);

  return {
    file: filename,
    before: stats.size,
    after: webpStats.size,
    saving: `${saving}%`,
  };
}

async function batchConvert() {
  if (!fs.existsSync(CONFIG.outputDir)) {
    fs.mkdirSync(CONFIG.outputDir, { recursive: true });
  }

  const files = await readdir(CONFIG.inputDir);
  const imageFiles = files.filter(f => /\.(jpg|jpeg|png|gif)$/i.test(f));

  console.log(`🚀 Converting ${imageFiles.length} images...\n`);

  const results = [];

  for (const file of imageFiles) {
    const inputPath = path.join(CONFIG.inputDir, file);
    try {
      const result = await convertImage(inputPath, CONFIG.outputDir);
      results.push(result);
      console.log(`✅ ${result.file} | Saved: ${result.saving}`);
    } catch (err) {
      console.error(`❌ Error on ${file}: ${err.message}`);
    }
  }

  const totalBefore = results.reduce((s, r) => s + r.before, 0);
  const totalAfter  = results.reduce((s, r) => s + r.after,  0);
  const totalSaving = ((1 - totalAfter / totalBefore) * 100).toFixed(1);

  console.log(`\n${'═'.repeat(50)}`);
  console.log(`📊 Total images: ${results.length}`);
  console.log(`   Size before:  ${(totalBefore / 1024).toFixed(0)} KB`);
  console.log(`   Size after:   ${(totalAfter / 1024).toFixed(0)} KB`);
  console.log(`   Total saved:  ${totalSaving}%`);
}

batchConvert();

Run:

npm install sharp
node batch-convert.js

🐍 Method 4 — Python with Pillow

# batch_convert.py
from PIL import Image
from pathlib import Path

def convert_to_webp(input_dir: str, output_dir: str, quality: int = 80):
    input_path  = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(exist_ok=True)

    extensions = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff'}
    images = [f for f in input_path.iterdir() if f.suffix.lower() in extensions]

    print(f"🚀 Converting {len(images)} images...\n")

    total_before = total_after = 0

    for img_path in images:
        output_file = output_path / (img_path.stem + '.webp')
        before_size = img_path.stat().st_size

        with Image.open(img_path) as img:
            if img.mode in ('RGBA', 'LA', 'P'):
                img = img.convert('RGBA')
            img.save(output_file, 'WEBP', quality=quality, method=6)

        after_size = output_file.stat().st_size
        saving = (1 - after_size / before_size) * 100

        print(f"✅ {img_path.name} → {output_file.name} | -{saving:.1f}%")
        total_before += before_size
        total_after  += after_size

    total_saving = (1 - total_after / total_before) * 100
    print(f"\n{'═' * 50}")
    print(f"📊 Size before: {total_before // 1024} KB")
    print(f"   Size after:  {total_after // 1024} KB")
    print(f"   Saved:       {total_saving:.1f}%")

if __name__ == '__main__':
    convert_to_webp('./images', './images-webp', quality=80)
pip install Pillow
python batch_convert.py

🤖 Method 5 — CI/CD Pipeline (Fully Automated)

# .github/workflows/optimize-images.yml
name: Auto-Optimize Images

on:
  push:
    paths:
      - 'public/images/**'

jobs:
  optimize:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Install WebP tools
        run: sudo apt-get install -y webp

      - name: Convert images to WebP
        run: |
          find public/images \( -name "*.jpg" -o -name "*.png" \) | while read f; do
            cwebp -q 80 "$f" -o "${f%.*}.webp"
          done

      - name: Commit optimized images
        run: |
          git config --global user.email "[email protected]"
          git config --global user.name "Image Bot"
          git add public/images/*.webp
          git commit -m "🖼️ Auto-optimize images to WebP" || echo "Nothing to commit"
          git push

📊 Method Comparison

MethodSpeedFlexibilityEase of UseProduction-Ready
Web tools⭐⭐⭐⭐⭐⭐⭐⭐⭐
Bash + cwebp⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Node.js Sharp⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐✅✅
Python Pillow⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
ImageMagick⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
CI/CD Pipeline⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐✅✅✅

🗂️ Recommended Output Structure

project/
├── images/                    ← Original files (keep as backup)
│   ├── hero.jpg
│   ├── product-01.png
│   └── banner.gif
│
└── images-optimized/          ← Serve these on production
    ├── hero.avif              ← Primary (best compression)
    ├── hero.webp              ← Fallback
    ├── hero.jpg               ← Final fallback
    ├── product-01.webp
    └── banner.webp

HTML to serve them:

<picture>
  <source srcset="/images-optimized/hero.avif" type="image/avif" />
  <source srcset="/images-optimized/hero.webp" type="image/webp" />
  <img
    src="/images-optimized/hero.jpg"
    alt="Hero image"
    width="1200"
    height="630"
    fetchpriority="high"
  />
</picture>

✅ Batch Conversion Checklist

  • [ ] Choose the right method for your project size
  • [ ] Set compression quality to 80% (recommended default)
  • [ ] Back up original images before converting
  • [ ] Visually review a sample of converted images for quality
  • [ ] Update your HTML to reference the new file formats
  • [ ] Measure PageSpeed Insights before and after
  • [ ] Automate the process in your CI/CD or build pipeline
  • [ ] Set up the <picture> element with proper fallbacks

🔗 Related Articles:

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top