Skip to main content
Performance 17 min read

9 Ways to Reduce Image File Size Without Losing Quality

Nine ways to shrink image files and keep them sharp: right-sizing, modern formats, quality tuning, metadata stripping and CDN negotiation.

By ImageGuide Team · Published August 15, 2026 · Updated August 15, 2026

Disclosure: ImageGuide is published by Sirv, an image CDN company. This guide mentions Sirv products. Read how we write these guides.

image compressionfile sizeweb performancewebpavifoptimization

“Without losing quality” needs a definition. No lossy encoder is mathematically lossless, so the honest target is this: no difference a visitor can see at the size the image is displayed. Under that definition a 3 MB photograph routinely becomes a 90 KB file with nothing visible lost.

These nine techniques are ordered by how much they usually save. Apply the first three and most images are already 90% smaller. The rest close the remaining gap.

The Worked Example

Every technique below is measured against the same source file so the savings compound visibly.

Source: terrace.jpg, 4032×3024, straight from a phone, 3,850 KB.

StepTechniqueResultRunning total
0Original3,850 KB—
1Resize to 1600×12001,120 KB−71%
2Encode as AVIF178 KB−95%
3Tune quality to the knee132 KB−96.6%
4Strip metadata128 KB−96.7%
5Chroma subsampling 4:2:0119 KB−96.9%

The final file is 119 KB and looks identical on screen to the 3,850 KB original.

Apply the same loop to a folder: Press audits the biggest images first, lets you set the maximum edge, format, and quality, then compare the result at 100% before writing non-destructive copies. It runs locally on macOS, Windows, and Linux.

1. Resize to the Size You Actually Display

Resolution is the largest single lever, and it is the one people skip. File size scales with the pixel count, so halving both dimensions removes about 75% of the data before any encoder runs.

Find the Right Width

The correct source width is the widest CSS box the image occupies, multiplied by the device pixel ratio you support.

Displayed width1× target2× target (recommended cap)
400 px thumbnail400 px800 px
600 px article image600 px1200 px
800 px product photo800 px1600 px
Full-width hero1440 px2400 px

Going beyond 2× is wasted. The perceptual return above 2× is close to zero, while file size keeps climbing.

Do It

# ImageMagick: cap the long edge at 1600, never upscale
magick terrace.jpg -resize '1600x1600>' -quality 85 terrace-1600.jpg

# Sharp (Node)
sharp('terrace.jpg')
  .resize({ width: 1600, withoutEnlargement: true })
  .toFile('terrace-1600.jpg');
# Sirv: width as a URL parameter, no build step
https://demo.sirv.com/terrace.jpg?w=1600

Use a good resampling filter. Lanczos and Mitchell preserve detail far better than nearest-neighbour, and every tool above defaults to a good one. The image resizing guide covers filter choice and upscaling.

2. Switch to AVIF or WebP

At matched visual quality, modern formats simply need fewer bytes than JPEG and PNG. This is the highest-value change after resizing, and it requires no visual compromise.

Same photo, same visual quality

terrace.jpg resized to 1600×1200, encoded at settings that produce no visible difference.

What Each Format Buys You

FormatVersus JPEGAlphaAnimationBrowser support
WebP25–35% smallerYesYesUniversal since 2021
AVIF40–60% smallerYesYesUniversal since Safari 16 (2022)
JPEG XL30–50% smallerYesYesSafari 17+ only (Chrome and Firefox behind a flag)

Serve Them Safely

<picture>
  <source srcset="terrace.avif" type="image/avif">
  <source srcset="terrace.webp" type="image/webp">
  <img src="terrace.jpg" width="1600" height="1200" alt="Stone terrace at sunset">
</picture>
# AVIF
avifenc --min 0 --max 63 -a end-usage=q -a cq-level=30 -s 4 terrace.jpg terrace.avif

# WebP
cwebp -q 80 -m 6 terrace.jpg -o terrace.webp

An image CDN skips the markup entirely by reading the Accept header and returning the best format each browser supports. Sirv does this by default on every URL.

3. Tune Quality to the Knee, Not to a Habit

Most teams pick one quality number and use it forever. Every image has a knee: the point where file size drops steeply while visual difference stays invisible. Below the knee, artifacts appear fast. Above it, you pay for nothing.

Find Your Knee

#!/usr/bin/env bash
# Sweep quality and print the size ladder
for q in 95 90 85 80 75 70 65 60; do
  cwebp -quiet -q $q input.jpg -o "/tmp/test-$q.webp"
  printf "q%-3s %6s KB\n" "$q" "$(( $(stat -c%s "/tmp/test-$q.webp") / 1024 ))"
done

Open the outputs side by side at display size and pick the lowest quality with no visible change. Do it once per content category, not once per image.

Starting Points by Content

ContentJPEGWebPAVIF
Photograph, busy detail82–8578–8255–63
Photograph, smooth gradients (sky, skin)85–8882–8660–68
Product on white background85–9080–8558–65
Illustration, flat colourUse lossless-lossless--lossless
Screenshot with small textUse lossless-lossless70–80

Quality scales are not comparable between formats. AVIF q58 is roughly JPEG q85. Copying a JPEG number into an AVIF encoder produces either a bloated file or a mushy one.

Automate It With Butteraugli or SSIMULACRA2

For large catalogues, target a perceptual score instead of a fixed quality:

# Encode, then score. Keep lowering quality while the score stays under threshold.
ssimulacra2 original.png candidate.png
# Scores above ~80 are visually indistinguishable at 1:1

The compression fundamentals guide explains what the encoder is actually discarding at each step.

4. Strip Metadata

A phone photo carries EXIF, GPS coordinates, a JPEG thumbnail preview, maker notes, and sometimes an embedded colour profile. That is 20 KB to 100 KB per file that no browser renders.

# ExifTool: strip everything, restore orientation
exiftool -all= -tagsFromFile @ -Orientation -overwrite_original terrace.jpg

# ImageMagick
magick terrace.jpg -strip terrace-clean.jpg

# Sharp keeps nothing unless asked
sharp('terrace.jpg').jpeg({ quality: 82 }).toFile('out.jpg');

Keep Exactly Two Things

  1. Orientation, or portrait photos render sideways in some pipelines. Better still, apply the rotation and then drop the tag.
  2. The ICC profile, but only if the image is not sRGB. Converting to sRGB and dropping the profile is smaller and more predictable.
# Convert to sRGB, then drop the profile
magick wide-gamut.jpg -profile sRGB.icc -strip out.jpg

Stripping metadata also removes GPS coordinates from user uploads, which matters for privacy as much as for bytes. See the metadata and privacy guide.

5. Use Chroma Subsampling Deliberately

Human vision resolves brightness far more finely than colour. Chroma subsampling exploits that by storing colour at half resolution. On photographs it is free bytes. On text and sharp colour edges it causes visible fringing.

ModeColour resolutionSize effectUse for
4:4:4FullBaselineScreenshots, text, logos, sharp red/blue edges
4:2:2Half horizontal−10%Mixed content
4:2:0Half both axes−15–20%Photographs (default)
# JPEG, force 4:4:4 for a screenshot
magick screenshot.png -sampling-factor 1x1 -quality 90 screenshot.jpg

# JPEG, 4:2:0 for a photo (usually the default)
magick photo.jpg -sampling-factor 2x2 -quality 85 photo-out.jpg

# AVIF
avifenc --yuv 420 photo.png photo.avif   # photos
avifenc --yuv 444 diagram.png diagram.avif  # text and diagrams

The classic symptom of the wrong setting is red text on a white background turning into a smeared orange halo. If you see that, switch to 4:4:4.

6. Match the Format to the Content

Compression cannot rescue a bad format choice. A logo saved as a 200 KB PNG becomes a 3 KB SVG that is also infinitely scalable.

ContentBest formatTypical sizeWrong choice costs
Logo, icon, chart, mapSVG2–15 KBPNG at 3 DPRs: 60–300 KB
PhotographAVIF, WebP60–200 KBPNG: 1,500–3,000 KB
Screenshot, UI captureWebP lossless, PNG80–250 KBJPEG: text fringing
Flat illustration, ≤256 coloursSVG or PNG-810–40 KBPNG-24: 2–4×
Photo with transparencyAVIF, WebP70–220 KBPNG-24: 3–8×
Short animationMP4, WebM120–300 KBGIF: 5–20×

SVG Is the Biggest Win Available

If the asset was drawn rather than photographed, it belongs in SVG. Then optimize the SVG itself:

npx svgo --multipass icon.svg -o icon.min.svg

SVGO typically removes 40% to 70% of an exported SVG: editor metadata, redundant precision, empty groups. Serve it gzipped or brotli-compressed and it shrinks again. The SVG best practices guide covers the safe plugin set.

7. Run a Lossless Optimizer as the Last Step

After lossy encoding, lossless optimizers rewrite the file’s internal structure. Nothing changes visually because nothing changes in the decoded pixels. They simply find a better encoding of the same data.

ToolFormatTypical extra saving
jpegtran -optimize -progressiveJPEG3–8%
MozJPEG (cjpeg)JPEG8–15% versus libjpeg
oxipng -o 4 --strip safePNG10–30%
gifsicle -O3GIF10–25%
svgo --multipassSVG40–70%
# JPEG: progressive + optimized Huffman tables, pixel-identical
jpegtran -copy none -optimize -progressive -outfile out.jpg in.jpg

# PNG: try harder, keep the colour profile
oxipng -o 4 --strip safe in.png

# MozJPEG: better encoder, same input
cjpeg -quality 82 -progressive -optimize -outfile out.jpg in.ppm

Progressive JPEG deserves a note of its own. It renders a low-quality full-frame pass first, then refines. The file is usually slightly smaller than baseline and the perceived load is faster. There is no reason not to use it above roughly 10 KB.

The compression tools comparison benchmarks these against each other.

8. Change the Image, Not Just the Encoder

Some of the largest savings come from editing rather than encoding. An encoder must faithfully represent whatever you give it, including the parts nobody needs.

Crop to the Subject

A product photo with 40% empty background is 40% wasted pixels. Cropping to the subject reduces the pixel count and lets the remaining pixels carry more detail at the same file size.

Flatten Unnecessary Transparency

An image with an alpha channel that is fully opaque everywhere still pays for the channel. Flatten it onto a background and drop to a format without alpha.

magick input.png -background white -alpha remove -alpha off output.jpg

Reduce Noise Before Encoding

Sensor noise is high-frequency detail that no encoder can compress well. Light denoising before encoding can cut 15% to 25% off a low-light photograph with no perceived quality loss.

magick noisy.jpg -enhance -quality 85 clean.jpg

Simplify the Palette on Flat Art

# 256-colour PNG-8 for illustrations, often 60% smaller than PNG-24
pngquant --quality 65-90 --speed 1 illustration.png

For product catalogues, background removal does both jobs at once: it isolates the subject and it makes the background a single flat colour that compresses to almost nothing. Sirv AI Studio does this in batch, and the Sirv Studio API exposes it programmatically for automated pipelines.

9. Let a CDN Negotiate Per Request

Every technique above produces one file. A visitor on a 375-pixel phone in Safari and a visitor on a 27-inch monitor in Chrome need different files. Deciding at build time means guessing.

An image CDN decides at request time using the Accept header, the requested width, and the device pixel ratio.

https://demo.sirv.com/terrace.jpg?w=800            → 800px, AVIF to Chrome, WebP to older clients
https://demo.sirv.com/terrace.jpg?w=1600&q=80      → explicit quality
https://demo.sirv.com/terrace.jpg?w=400&format=webp → explicit format when you need it

What This Removes From Your Build

TaskBuild-time pipelineImage CDN
Generate 4 widths × 3 formats12 files per image0 files
Add a new breakpointRebuild everythingChange a URL
Support a new formatUpdate the pipelineAutomatic
Storage12× originals1× original

Create a Sirv account if you want this without maintaining a build step. The image CDN comparison covers the alternatives and their pricing models.

Putting It Together

A complete Sharp pipeline that applies techniques 1, 2, 3, 4, and 5 in one pass:

import sharp from 'sharp';

const WIDTHS = [400, 800, 1200, 1600];

async function processImage(input, basename) {
  const outputs = [];

  for (const width of WIDTHS) {
    const base = sharp(input)
      .rotate()                                   // apply EXIF orientation, then drop it
      .resize({ width, withoutEnlargement: true }); // technique 1

    outputs.push(
      base.clone()
        .avif({ quality: 58, chromaSubsampling: '4:2:0' })  // techniques 2, 3, 5
        .toFile(`${basename}-${width}.avif`),
      base.clone()
        .webp({ quality: 80, effort: 6 })
        .toFile(`${basename}-${width}.webp`),
      base.clone()
        .jpeg({ quality: 82, progressive: true, mozjpeg: true })
        .toFile(`${basename}-${width}.jpg`)
    );
  }

  return Promise.all(outputs);   // metadata is dropped by default: technique 4
}

Summary

Savings by Technique

#TechniqueTypical savingEffort
1Resize to displayed size50–90%Low
2AVIF or WebP25–60%Low
3Tune quality to the knee15–40%Medium
4Strip metadata20–100 KB per fileLow
5Chroma subsampling10–20%Low
6Right format for the content2–50× on the wrong onesLow
7Lossless optimizer pass3–30%Low
8Crop, flatten, denoise15–40%Medium
9CDN negotiation per requestRemoves the guessworkLow

Checklist

  1. ✅ No image exceeds 2× its largest displayed width
  2. ✅ AVIF and WebP are offered, with JPEG or PNG as fallback
  3. ✅ Quality is tuned per content category, not set once globally
  4. ✅ Metadata is stripped, orientation is applied first
  5. ✅ 4:2:0 on photographs, 4:4:4 on text and diagrams
  6. ✅ Drawn assets are SVG, not PNG
  7. ✅ A lossless pass runs last in the pipeline
  8. ✅ Images are cropped to the subject before encoding
  9. ✅ Delivery negotiates format and width per request

Techniques 1 through 3 do most of the work. Everything after that is the difference between a good result and a fully optimized one.

Sources

Related Resources

Resize and deliver images with Sirv

Upload your images to Sirv, then request the sizes and formats your pages need.

Get started