Resizing math
Every resize on this site is decided before a pixel moves. The Image Resizer hands a pure planning function the decoded image's width and height and the request you typed, and gets back the exact output dimensions, the source rectangle to draw from, an enlargement flag, the output pixel count and any cautions. Only then does the browser's canvas resample, and the finished file is decoded again to confirm its dimensions match the plan. This guide walks through that arithmetic mode by mode. Every result in it is computed at build time by the module the tool runs, from illustrative inputs, so the examples cannot disagree with it; the other guides cover the steps around it.
What the planner receives and returns
The inputs are the source width and height, as positive whole pixels, and a request in one of four modes. The dimensions are those of the decoded bitmap, after the orientation tag has been applied, so a sideways phone photo enters the planner upright. Zero, negative or fractional source dimensions are rejected rather than repaired — a width of 0 or of 100.5 both answer "Source dimensions must be positive whole pixels." — because a decoder never produces half a pixel. The plan that comes back has five parts: the target width and height; the source crop, the whole image in every mode but fill; an upscaling flag, true when either target dimension exceeds its source counterpart; the output pixel count; and warnings that never block the resize. The main illustrative source is the methodology page's own 4032×3024 photo of 12,192,768 pixels; the other sizes in this guide are invented to exercise one rule each.
Fit: the smaller of two ratios
Fit scales the image to sit within a box while keeping its shape. The scale factor is
min(boxWidth / w, boxHeight / h): both ratios are computed and the smaller wins,
because it is the one that brings the longer side inside the box. For the 4032×3024 photo into a
1200×1200 box, the width ratio is 1200/4032 = 0.2976 and the height ratio is 1200/3024 = 0.3968; the smaller is
applied to both sides and the plan is 1200×900. Turn the photo portrait — 3024×4032
into the same box — and the height ratio binds instead: 900×1200. An invented
1600×900 frame into 800×800 is bounded by its width and lands at 800×450; an invented
2048×2048 square into a 512×100 letterbox is bounded by the box's short side and becomes
100×100.
Two consequences follow. Fit never crops: the source rectangle is always the full image, 4032×3024 at offset 0, 0 for the photo above. And fit fills the box on one axis only, which is why a 1200×1200 box produced 1200×900 rather than 1200×1200.
Exact mode and the aspect lock
Exact mode is the plainest arithmetic here: the output is whatever you typed, rounded to whole pixels, and the image is stretched to meet it. The 4032×3024 photo to exact 640×640 produces 640×640, drawn from the full source, so a 4:3 frame becomes a square. The planner does not prevent this; distortion is the documented cost of asking for a shape the source does not have. Fractional requests are rounded: 33.4×66.6 on an invented 100×100 source becomes 33×67.
The aspect lock removes the distortion by deriving one dimension from the other. The engine's
lockedDimension function takes the source size and the one number you know and returns
the other in the source's ratio: a width of 1200 on the 4032×3024 photo gives a height of
900, and a height of 900 gives back 1200. The resizer wires the lock as "height
follows width" and enables it only in exact mode, since fit and percent preserve the ratio by
construction. Rounding applies here too — a width of 500 on an invented 1000×333 source works
out to 166.5 and is returned as 167 — and so does the floor: a width of 3 on an
invented 10000×10 strip computes to 0.003 and is returned as 1.
Percent: one factor, both sides
Percent mode multiplies both sides by the same factor and rounds each to a whole pixel. 25% of the 4032×3024 photo is 1008×756; 50% is 2016×1512. The percentage is of each dimension, not of the pixel count and not of the file size: halving both sides leaves 25% of the pixels (3,048,192 of 12,192,768), and what that does to bytes depends on the encoder and the image, which is why no byte figure appears here. Asking for 0 is refused with "Enter a scale percentage greater than zero." Asking for 1001 is refused with "Scaling beyond 1000% is not supported." A tiny percentage still yields a real image: 0.1% of an invented 100×100 source is 1×1, because of the floor.
Whole pixels and the 1-pixel floor
Every dimension the planner emits passes through one clamp: round to the nearest whole pixel, then take at least 1. Halves round up, and each side is rounded independently, so a fit result can differ by a pixel from the ratio computed by hand. The floor exists for extreme aspect ratios. An invented 10000×10 strip fit into 100×100 has a scale of 0.01, so the height becomes 10 × 0.01 = 0.1 of a pixel, which would round to zero and leave an image with no rows; the floor makes the plan 100×1 instead, a one-pixel line. It is the one place the planner knowingly departs from the aspect ratio, and the tests pin it along with the 0.1% case and the lock's floor.
Fill: cover and crop, in the engine
The planning module also defines fill, exercised by the same tests: the output takes the box's
exact dimensions, the scale is max(boxWidth / w, boxHeight / h) so the image covers the
box, and the overflow is removed by a centred crop. The 4032×3024 photo into a 1000×1000 fill yields 1000×1000, drawn from a 3024×3024 square starting 504 pixels in from the left edge and
0 from the top, the crop clamped to the source. The Image Resizer page offers
fit, exact and percent.
The caps and the warning threshold
After the dimensions are fixed, the planner applies two hard limits and one soft one, in that order — each this engine's rule, not a property of images in general. The per-side cap is 16,384 pixels: a request for 16,385 on one side is refused with "Output dimensions are limited to 16384 pixels per side (browser canvas limit)." while 16,384 exactly is accepted — 16,384×10 from an invented 100×100 source, enlargement flagged. The total cap is 80 megapixels of output: 10,000×9,000 is 90 megapixels and is refused with "Outputs are limited to 80 megapixels to keep the browser responsive." Both are errors rather than warnings — no plan is made and nothing is drawn. The refusals carry their own reasons in the engine's words: the per-side message names the browser canvas limit, the pixel message says the cap keeps the browser responsive, and the module's note on that cap is that it avoids exhausting a browser tab's memory — and a clear refusal beats a blank download.
The soft limit is a warning above 50 megapixels. An invented 8000×8000 image kept at 100% is 64 megapixels: under the hard cap, so the plan succeeds, but it carries the note "Very large output (over 50 megapixels) — encoding may be slow or fail on low-memory devices." An invented 6000×4000 image at 100% is 24 megapixels and carries no warning. These figures govern outputs; inputs are limited separately by the client, as the methodology page states — 50 megapixels, 100 MB per file, and 40 files or 300 MB per selection — so reaching the warning or the cap takes enlargement.
Enlargement: permitted, flagged every time
Upscaling is true when either target dimension exceeds its source counterpart. An invented 400×300 image fit into 800×800 becomes 800×600 with the flag set and the row note "Enlarging beyond the original size cannot add detail — the result will be softer than the source." The either-dimension rule matters in exact mode: an invented 1000×1000 source to 500×2000 halves the width and doubles the height, and the plan still reports upscaling, because the stretched axis has been interpolated. Percent above 100 flags as well: an invented 800×600 at 200% is 1600×1200. The wording is flat because the arithmetic is — interpolation spreads the same information over more pixels and adds no detail, and the methodology page commits the site to saying so rather than advertising enhancement.
What happens after the plan
The plan fixes geometry; the client does the rest. The decoded bitmap is drawn onto a canvas of
exactly the planned size from the plan's source rectangle, and the canvas is encoded in the
input's own format where the browser can encode it. For the formats the page's picker lists —
PNG, JPEG, WebP, GIF and BMP — that means PNG stays PNG, JPEG stays JPEG and WebP stays WebP, at
the engine's default quality parameter for the lossy pair, 0.92 for JPEG and 0.85 for WebP on the canvas 0–1 scale, while GIF and BMP
come back as PNG because browsers cannot encode them. A HEIC file, which the picker does not
list but the client still handles, also comes back as PNG: the site never encodes HEIC — it is
decoded by the self-hosted libheif module, decode only. The row says so in each case. An
animated GIF or WebP is recognised before decoding and only its first frame is resized, with the
caveat on the row; how image formats are detected covers the animation check. AVIF is the exception, and the client's behaviour on it is worth stating
plainly. The resizer accepts it because it accepts every format the engine decodes —
PNG, JPEG, WebP, GIF, BMP, HEIC, AVIF — and the engine's plan for an AVIF source sets the first-frame flag to
yes, so an image sequence carries the same note as an
animated GIF: a constructed ftyp box with major brand avis is detected as
AVIF and its animation check answers yes. But the resizer re-encodes
only through the browser canvas, as PNG, JPEG or WebP, while still expecting
AVIF back, so the verification step sniffs the canvas's bytes where it expected
AVIF and the row ends in a verification error rather than a resized AVIF. Convert
first with the AVIF to PNG or
AVIF to JPG converter, then resize the result. The output name swaps the
extension for the target's and, when that would leave the name unchanged, inserts a suffix so the
download cannot shadow the original:
holiday.jpg becomes holiday-resized.jpg, while banner.gif, which
changes format, becomes banner.png with no suffix needed.
Then the output is verified: the bytes are sniffed by the same signature detector that identified the input, and the blob is decoded again to confirm its dimensions equal the plan's, before a download button appears. The row's first note is the arithmetic itself — "Resized from 4032×3024 to 1200×900." for the fit example — with the plan's warnings after it. Metadata does not survive: canvas re-encoding strips EXIF including GPS location, colour-profile tags and text chunks; orientation was applied during decoding, before anything was discarded, so the image stays upright. The metadata guide covers that in full, and the conversion pipeline covers the decode, draw and verify steps every converter on the site shares.
What the planner cannot know
The planner sees two integers and a request; it does not see the image. It cannot know whether a photo will survive enlargement or whether a downscale will blur a fine pattern, and this guide makes no such judgement: the resampling is the browser canvas's own, and the engine fixes only where the pixels land. Output size is measured after encoding and reported as a true byte count, never predicted — the site publishes no blanket percentages for what resizing saves — and when a byte target matters more than a pixel target, the Image Compressor searches for it by measurement. Placing an image on a page of a given physical size is a separate arithmetic, covered in image-to-PDF page math.
Frequently asked questions
Why did fit give me 1200×900 instead of filling the 1200×1200 box?
Fit keeps the aspect ratio and fills the box on one axis only. The scale is the smaller of two ratios — 1200/4032 = 0.2976 against 1200/3024 = 0.3968 for a 4032×3024 photo — applied to both sides, which gives 1200×900. Exact mode stretches to both numbers; the engine's fill mode crops to them.
What does the aspect lock do, and when is it active?
It derives the height from the width in the source's own ratio, using the engine's lockedDimension function: a width of 1200 on a 4032×3024 source gives 900. It is active only in exact mode, because fit and percent preserve the ratio by construction.
Can a resize ever produce a zero-pixel dimension?
No. Every dimension is rounded to a whole pixel and then floored at 1. An invented 10000×10 strip fit into 100×100 would compute to 0.1 of a pixel tall and is planned as 100×1; 0.1% of an invented 100×100 image is planned as 1×1.
What are the output limits, and are they warnings or errors?
Two errors and one warning, all this engine's rules. Outputs above 16,384 pixels on a side or above 80 megapixels in total are refused before anything is drawn; outputs above 50 megapixels are allowed but carry a performance warning. Inputs have separate limits, the client's own, stated on the methodology page: 50 megapixels, 100 MB per file, and 40 files or 300 MB per selection.
Is enlarging an image blocked?
No — it is permitted and flagged. The plan sets upscaling whenever either output dimension exceeds its source counterpart, and the row carries the engine's own wording: "Enlarging beyond the original size cannot add detail — the result will be softer than the source." Interpolation adds no detail, so the warning says that rather than promising enhancement.
Does resizing change my file’s format or metadata?
PNG, JPEG and WebP come back as themselves. GIF and BMP come back as PNG because browsers cannot encode them, and HEIC comes back as PNG because the site never encodes HEIC — it is decoded by the self-hosted libheif module, decode only; the row says so in each case. An animated GIF or WebP is detected before decoding and only its first frame is resized, with the caveat on the row. AVIF is accepted — the client takes every format the engine decodes, PNG, JPEG, WebP, GIF, BMP, HEIC, AVIF — and an avis image sequence carries the same first-frame note, but the resizer encodes only through the browser canvas as PNG, JPEG or WebP while expecting AVIF back, so the row ends in a verification error instead of a resized AVIF; convert it with the AVIF to PNG or AVIF to JPG converter first, then resize the result. Metadata does not pass through: canvas re-encoding strips EXIF (including GPS location), colour-profile tags and text chunks. Orientation is applied during decoding, before anything is discarded, so the resized image is upright.
Local processing: the arithmetic described here runs in your own browser tab when you use the Image Resizer — files are decoded, converted, and verified entirely in your browser and never transmitted. See the methodology page for how to verify that yourself.