Resizing images without visible quality loss

Shrinking an image sounds like the one operation that cannot go wrong: fewer pixels, smaller file, done. In practice careless resizing produces soft, aliased or jagged results, halos around edges, dark fringes on transparent logos and photos that arrive rotated on their side. None of this is inevitable. A few facts about how resampling works, plus a handful of habits, keep downscaled images looking like the original, only smaller.
What actually happens when pixels are resampled
A resized image has a different pixel grid, so every output pixel must be computed from some neighbourhood of input pixels. The rule for combining that neighbourhood is the resampling filter. Nearest-neighbour just copies the closest pixel, which is fast and keeps pixel art crisp but produces jagged edges and shimmering on photographs. Bilinear averages the four nearest pixels and is soft. Bicubic looks at sixteen and is the usual default in editors.
Lanczos, a windowed sinc filter, produces the sharpest downscales with a slight risk of ringing next to hard edges; it is what ImageMagick, sharp and most serious tools use for photos. Browsers do not expose a filter choice on the canvas, but setting imageSmoothingQuality to "high" asks the engine for its best available filter, which in Chromium and Firefox is a high-quality multi-tap resampler rather than plain bilinear.
Big reductions: step down, then finish
Every filter samples a limited neighbourhood. Shrink a 6000-pixel-wide photo to 600 pixels in one pass and each output pixel should represent a hundred input pixels, but a bicubic filter only looks at a few of them; the rest are skipped, which shows up as aliasing, moiré on fabric and roof tiles, and sparkling noise. The remedy is to reduce in stages: halve the image repeatedly while it is still more than twice the target, then make one final pass to the exact size.
Each halving step is effectively a box average of 2×2 pixels, so no input pixel is ignored, and the final pass does the fractional adjustment with the best filter. This is exactly how PixelShrinkr resizes inside its Web Workers: repeated halves, then a last high-quality draw to the requested dimensions. The cost is a few extra milliseconds per image and the payoff is a clean result at any reduction ratio.
A touch of sharpening brings back the edge
Downscaling averages neighbouring pixels, so it always softens slightly, and the effect is most visible on hair, foliage and text. Print and web workflows have compensated for decades with a light unsharp mask after resizing: a small radius (0.5–1 pixel at the output size) and a modest amount (50–100%) restore the perceived crispness without creating halos. Editors call this "output sharpening" and apply it as the last step.
Command-line tools expose it directly (ImageMagick's -unsharp 0x0.75, sharp's .sharpen()). Browsers have no built-in sharpening on the canvas, so a browser-based batch tool will give you a faithfully averaged result; if a set of images needs that final bite, run it through an editor afterwards, sharpening the resized files rather than the originals.
DPI does not mean what you think on screen
DPI (or PPI) is a number stored in the file's metadata that tells a printer how many pixels to place per inch of paper. It does not change a single pixel. A 3000×2000 image tagged 72 dpi and the same image tagged 300 dpi are identical on any screen and identical in size on disk; the only difference is that a printer would output the first at 41 inches wide and the second at 10. Browsers ignore the tag entirely.
So "reduce the DPI to make the file smaller" achieves nothing, and "increase it to 300 for print" only matters if the pixel count is already there. For the web, think in pixels: the width of the slot times the device pixel ratio. For print, divide the pixel width by the desired dpi to get the maximum size in inches. Re-encoding through a canvas, as PixelShrinkr does, drops the DPI tag along with the rest of the metadata, which changes nothing about how the image displays.
Upscaling: the honest limit
Enlarging an image cannot add information; a filter can only spread the existing pixels smoothly, so bicubic upscaling beyond about 1.5–2× looks soft and any JPEG artefacts in the source are magnified along with the picture. Machine-learning upscalers do better by inventing plausible texture, which is fine for a wallpaper and wrong for a product photo, a medical scan or evidence. When the original exists at a larger size, fetching it always beats upscaling a copy.
This is why a good batch resizer never scales up. PixelShrinkr treats "max width and height" as a ceiling: images larger than it are reduced, images already smaller keep their native dimensions and are only re-encoded. If you truly need a bigger version, keep the master file and use a dedicated upscaler on purpose, not a resize step by accident.
Transparent edges and sideways photos
Two mistakes account for most "the resize ruined it" complaints. The first is dark fringing on transparent images: fully transparent pixels usually hold black colour values, and a resampler that averages colour without weighting by alpha bleeds that black into the edge of a logo. Correct pipelines work in premultiplied alpha, which is what the browser canvas does; the visible symptom to watch for is a thin grey or dark outline that was not in the original. When converting to JPEG, which has no alpha, choose the flattening colour deliberately rather than letting it default to black.
The second is orientation. Phones and cameras rarely rotate the pixels when you shoot in portrait; they store the sensor's landscape frame and write an EXIF Orientation tag (values 1 to 8) telling viewers how to turn it. A resizer that reads pixels but ignores the tag outputs a sideways image, and one that keeps the tag while also rotating the pixels produces a photo that some viewers rotate twice. The right procedure is to apply the rotation to the pixels and then either strip the tag or reset it to 1. Browsers have honoured the tag for img elements since 2020, and createImageBitmap applies it during decoding, which is how PixelShrinkr gets it right before the resize even starts.
The takeaway
Resize from the original with a high-quality filter, stepping down by halves for large reductions and finishing with one exact pass; sharpen lightly afterwards if the images need it; think in pixels, not DPI; never scale up by accident; and make sure transparency is handled premultiplied and the EXIF orientation is baked into the pixels before the tag is dropped.
Drop your images and see how much smaller they get
More guides

JPEG vs WebP vs AVIF: which format when
Three lossy formats with different ideas about what detail to discard. Where each is supported, how fast it encodes, and when JPEG still wins.

Image compression for web performance
Images decide most LCP scores. How to size them, which quality to pick, when to lazy-load, and whether you need an image CDN at all.