Back to Blog

How to compress an image without visible quality loss

To make a photo or screenshot smaller without a visible drop in quality, do three things in order: shrink its pixel dimensions to the size it will actually be shown at, pick a format that suits the content (lossy for photos, lossless for screenshots and text), and then lower the quality setting until you can just start to see a difference, and step back up. The steps below use the free SnapCompress compressor, which runs in your browser, and finish with the same procedure on the command line.

Last updated:

What does compressing an image actually do?

There are two kinds of image compression, and the difference decides how far you can go.

  • Lossy compression discards detail to get a much smaller file. JPEG is always lossy; WebP and AVIF can be lossy. MDN's image format guide notes that photographs usually tolerate this, because the discarded detail is hard to see (MDN).
  • Lossless compression reproduces the original exactly. PNG is lossless, and WebP has a lossless mode. MDN recommends lossless encoding for screenshots, diagrams, logos, and line art, because blur and colored fringes around text and sharp edges are easy to spot.

JPEG's lossy encoder works on blocks of pixels and keeps brightness detail while throwing away much more color detail. Push it too far and the seams between those blocks start to show (web.dev, JPEG). That is the "quality loss" people worry about: blockiness, smeared color, and halos around edges.

"Without losing quality" therefore means one of two things. For a screenshot, it can mean literally lossless. For a photo, it means the loss is there but you cannot see it at the size the image is viewed.

How do I compress a photo or screenshot in SnapCompress?

  1. Open /compress and drop in a JPEG, PNG, WebP, HEIC, or DNG file (up to 100 MB). The file is decoded and re-encoded inside your browser tab; it is not uploaded anywhere.
  2. Leave the Quality slider at its default of 80% for a first pass. The slider runs from 10% to 100%.
  3. If the image is larger than it needs to be, tick Resize Image and enter a maximum width and height (see the next section).
  4. Click Compress, then compare the before and after previews. Zoom in on edges, skin, sky, and any text.
  5. If it looks the same, try a lower quality; if you can see artifacts, go higher. Then download.

What the slider does depends on the file type. This is based on SnapCompress's own code (src/lib/compression.ts) and the browser-image-compression library it uses:

InputOutputWhat the Quality slider controls
JPEGJPEGThe browser's JPEG encoder quality (80% is passed as 0.8)
WebPWebPThe browser's WebP encoder quality
PNGPNGThe maximum number of colors kept (4,096 × quality), so PNG output is reduced to a palette, not lossless
HEIC (iPhone)JPEGJPEG quality of the converted file
DNG (raw)JPEGJPEG quality of the converted file

A few details that follow from the code:

  • SnapCompress keeps your format. A JPEG comes back as a JPEG and a PNG as a PNG; only HEIC and DNG change, to JPEG. To switch format (for example PNG to WebP), use the converter instead.
  • The JPEG and WebP encoders are the browser's own canvas encoders. The canvas toBlob() quality parameter only applies to lossy formats such as JPEG and WebP, so results can differ slightly between Chrome, Safari, and Firefox.
  • PNG compression goes through UPNG.js, where any color count other than zero means lossy palette reduction. For flat screenshots with few colors this is usually invisible; for gradients and photos saved as PNG it can cause banding. If you need a bit-exact PNG, use a lossless tool from the command-line section below.
  • If the first result is bigger than the file you started with, the library re-encodes at a lower quality, up to 10 attempts. If it is still over 10 MB, it also scales the dimensions down in small steps.
  • Re-encoding through a canvas does not copy EXIF metadata (the library's preserveExif option is off by default and SnapCompress does not enable it). Camera details and GPS location are not carried into the compressed file.

Which quality setting should I start with?

There is no universal number. web.dev points out that tools do not interpret a quality value such as 75 the same way, and recommends going just a little lower than the point where you would notice a difference (web.dev, JPEG). A practical routine (SnapCompress recommendation):

  • Photos: start at 80%. Drop in steps of 5 to 10 points, checking at 100% zoom, until you see blockiness or color smearing; then go back one step.
  • Hero images and product photos that people look at closely: stay around 85% to 90%.
  • Screenshots and images with text: keep them as PNG or lossless WebP when you can. If you do use JPEG, stay high, since text edges are where lossy artifacts show first.
  • Photos you will post on social media: platforms commonly re-encode uploads (generation loss), so do not save at a very low quality first; you will stack two rounds of loss.

How many kilobytes each setting saves depends heavily on the image. Rather than quote invented averages here, the measured results for real test files are published with the compressor comparison benchmark.

Should I resize before compressing?

Usually, yes. Pixel dimensions are often the biggest lever. A 4,000-pixel-wide phone photo shown in a 1,200-pixel-wide column is carrying data nobody sees, and web.dev's advice is to resize images to the size they are displayed at (web.dev, correct dimensions). Resizing first also means the quality setting is applied to fewer pixels, so you can often keep it higher.

In the compressor, the Resize Image option takes a maximum width and height. SnapCompress scales the image to fit inside both limits, keeps the aspect ratio, never enlarges, and encodes once at your quality setting. The boxes start filled with the original dimensions.

If you need specific output dimensions rather than a size limit, use the dedicated resize tool, then compress the result. For iPhone HEIC photos, leave Resize off in the compressor (it outputs JPEG), or convert them first with HEIC to JPG and then resize. The resizing guide covers choosing target sizes for different layouts.

Which format should I save to?

Photos: JPEG for maximum compatibility, or WebP for smaller files on the web. Screenshots, logos, and anything with text or sharp edges: PNG or lossless WebP. Compressing an image well in the wrong format still leaves you with a large file or a blurry one.

The full comparison, including AVIF and browser support, is in JPEG vs PNG vs WebP.

Can I compress the same image more than once?

You can, but every lossy save throws away more detail. JPEG is not stable under repeated re-encoding, especially when the quality setting changes between saves, and the damage builds up (Wikipedia, generation loss). Keep the original, finish all edits and crops first, and compress once at the end. If a result is not small enough, go back to the original and try again with a lower setting or smaller dimensions, rather than compressing the compressed copy.

How do I compress images from the command line?

If you process images in bulk or in a build step, the same three moves (resize, choose format, set quality) map onto standard tools. Each example limits the longest side to 1,600 pixels; adjust that to your layout.

cwebp, Google's WebP encoder. Quality runs from 0 to 100 (default 75); a 0 for one -resize dimension keeps the aspect ratio; add -lossless for screenshots. Metadata is dropped by default.

bash
cwebp -q 80 -resize 1600 0 photo.jpg -o photo.webp
cwebp -lossless screenshot.png -o screenshot.webp

ImageMagick. For JPEG, -quality runs from 1 to 100. The > flag in the geometry only shrinks images that are larger than the target (geometry docs), and -strip removes profiles and comments, including EXIF.

bash
magick photo.jpg -resize "1600x1600>" -strip -quality 82 photo-small.jpg

sharp for Node.js, built on libvips. JPEG and WebP default to quality 80, mozjpeg: true trades speed for a smaller JPEG, and metadata is removed unless you ask to keep it. withoutEnlargement stops small images from being upscaled (resize docs). PNG output stays lossless unless you set a quality or palette option.

js
import sharp from 'sharp'

await sharp('photo.jpg')
  .resize({ width: 1600, height: 1600, fit: 'inside', withoutEnlargement: true })
  .jpeg({ quality: 80, mozjpeg: true })
  .toFile('photo-small.jpg')

For a side-by-side look at browser-based and desktop compressors, see the free image compressor comparison. If the goal is a smaller attachment, the email guide covers size limits; for page speed, see images and Core Web Vitals.

Sources

Further reading