CLOUD
Guides

Image Optimization for Web: Size, Quality, and Speed

CLOUD|February 22, 2026|4 min read|474 views
Image Optimization for Web: Size, Quality, and Speed

WebP, lazy loading, responsive images — images are the biggest cause of slow websites. We explain how to reduce size without losing quality.

Images and Performance — A Relationship You Cannot Ignore

Images represent on average 50-70% of a webpage's total size. Optimizing them is the easiest and fastest way to improve site performance. A site loading in 2 seconds is completely different from one loading in 5 seconds — and the difference is often the images.

Image Formats — Which to Choose?

WebP — The Optimal Choice for Web

# Convert JPEG/PNG to WebP
apt install webp -y

# Convert a single image
cwebp -q 80 image.jpg -o image.webp

# Bulk convert all JPEGs in a directory
find . -name "*.jpg" -exec sh -c 'cwebp -q 80 "$1" -o "${1%.jpg}.webp"' _ {} \;

# Size vs JPEG: 25-35% smaller
# Size vs PNG: 25-35% smaller as well

AVIF — The Next Generation

# 30-50% smaller than WebP but slower to encode
# Browser support: Chrome 85+, Firefox 113+, Safari 16+

# Convert using ImageMagick
apt install imagemagick -y
convert image.jpg -quality 60 image.avif

SVG — For Icons and Graphics

# Minify SVG using svgo
npm install -g svgo
svgo icon.svg -o icon.min.svg

# Bulk minification
svgo --folder ./images/icons/

When to Use What?

Use Case Best Choice Alternative
Content images WebP JPEG
Transparent images WebP PNG
Icons SVG WebP
Photographic quality AVIF WebP
Legacy browser support JPEG/PNG -

Correct Image Dimensions

Never Display a 3000px Image at 300px Width

<!-- Wrong: image far too large for its actual display size -->
<img src="hero-3000px.jpg" style="width: 600px">

<!-- Correct: use srcset for different sizes -->
<img
 src="hero-600.webp"
 srcset="
 hero-400.webp 400w,
 hero-800.webp 800w,
 hero-1200.webp 1200w
 "
 sizes="(max-width: 400px) 400px, (max-width: 800px) 800px, 1200px"
 alt="Hero image"
 loading="lazy"
>

Generate Multiple Sizes with ImageMagick

#!/bin/bash
# resize-images.sh
INPUT=$1
FILENAME=$(basename "${INPUT%.*}")

for width in 400 800 1200 1920; do
 convert "$INPUT" -resize "${width}x>" -quality 85 "${FILENAME}-${width}.jpg"
 cwebp -q 80 "${FILENAME}-${width}.jpg" -o "${FILENAME}-${width}.webp"
done

echo "Generated 4 sizes for $INPUT"

Lazy Loading

<!-- Defer loading of off-screen images -->
<img src="product.webp" loading="lazy" decoding="async" alt="...">

<!-- For first image on page (above the fold): eager -->
<img src="hero.webp" loading="eager" fetchpriority="high" alt="...">
// Intersection Observer for full control
const images = document.querySelectorAll('img[data-src]');
const observer = new IntersectionObserver((entries) => {
 entries.forEach(entry => {
 if (entry.isIntersecting) {
 const img = entry.target;
 img.src = img.dataset.src;
 img.removeAttribute('data-src');
 observer.unobserve(img);
 }
 });
}, { rootMargin: '50px' });

images.forEach(img => observer.observe(img));

Server-Side Image Processing

Intervention Image for Laravel

composer require intervention/image
use Intervention\Image\Facades\Image;

// Process on upload
public function store(Request $request): JsonResponse
{
 $image = $request->file('image');

 // Full-resolution original
 Image::read($image)
 ->resize(1200, null, fn($c) => $c->aspectRatio)
 ->toWebp(85)
 ->save(storage_path("app/public/products/{$filename}-1200.webp"));

 // Thumbnail version
 Image::read($image)
 ->resize(400, 400)
 ->cover(400, 400)
 ->toWebp(80)
 ->save(storage_path("app/public/products/{$filename}-thumb.webp"));

 return response->json(['success' => true]);
}

Automatic Thumbnail Generation

// Background job for image processing
class ProcessProductImage implements ShouldQueue
{
 public function handle: void
 {
 $sizes = [
 'thumb' => [400, 400],
 'medium' => [800, 600],
 'large' => [1200, 900],
 ];

 foreach ($sizes as $name => [$w, $h]) {
 Image::read($this->imagePath)
 ->resize($w, $h, fn($c) => $c->aspectRatio->upsize)
 ->toWebp(82)
 ->save(storage_path("app/public/{$this->folder}/{$name}.webp"));
 }
 }
}

nginx WebP Delivery

# Serve WebP if browser supports it
map $http_accept $webp_suffix {
 default "";
 "~*webp" ".webp";
}

server {
 location ~* ^(/.*)\.(png|jpg)$ {
 set $image_path $1;
 if (-f "$document_root${image_path}${webp_suffix}") {
 rewrite ^(.*)$ ${image_path}${webp_suffix} last;
 }
 }
}

Measuring Image Optimization

# File size before and after
ls -lh image.jpg image.webp

# Calculate savings percentage
original=$(stat -c%s image.jpg)
optimized=$(stat -c%s image.webp)
saving=$(( (original - optimized) * 100 / original ))
echo "Saving: ${saving}%"

Impact on Google PageSpeed

Optimization PageSpeed Impact Implementation Difficulty
WebP instead of JPEG +5-15 points Easy
Lazy Loading +5-10 points Easy
Proper resizing +5-10 points Medium
AVIF +5-10 points Medium
CDN for images +5-20 points Easy

On cloud.net.sa Servers

cloud.net.sa servers with NVMe SSDs make image processing very fast. When installing ImageMagick and enabling background image processing via Queue, you can process thousands of images without affecting site performance. The 1TB+ bandwidth is sufficient to serve images directly from the server without needing a CDN initially.

Summary

Image optimization is the low-hanging fruit of performance improvement. Converting images to WebP with lazy loading visibly improves user experience without any changes to the core code.

Share