A border is a quantity, not a style
The space around a photograph is a measurement before it is anything else. It has a width on each of four edges, those widths are expressed in some unit, and that unit has to resolve to whole pixels before a single byte can be written. Most tools that add a margin conceal all three of those facts behind a slider marked thin to thick. This one puts them in a rail and prints the result above the canvas.
Two intents arrive at this page and they want different things from it. One is presentation: a photographer or a printer wants a defined margin of a known size, usually white, usually even, sometimes weighted at the bottom the way a mounted print is. The other is fitting: a picture is the wrong shape for where it is going, and bars have to be added so that nothing gets cut off. The second is the larger job by a distance, and it is the one most competitors treat as an afterthought.
| Resolution | Margin in pixels | A 4000 px edge becomes |
|---|---|---|
| 72 DPI | 14 px | 4028 px |
| 150 DPI | 30 px | 4060 px |
| 300 DPI | 59 px | 4118 px |
Working the rail from the top down
The first control is the compositing mode, and it is first because it decides what the other numbers mean. Grow adds the border outside the picture: the photograph keeps every pixel it arrived with and the output file is larger by the sum of the two widths on each axis. Inset draws the border within the original dimensions, so the output matches the input and the picture scales down to fit the space that is left. Fit ratio ignores the question of thickness and asks a different one: what proportion should the finished frame be, and what should fill the difference.
Below that sit the unit and the resolution, in that order, because a width in millimetres is meaningless until the second field has a number in it. The tool reads the JFIF density block of a JPEG, the resolution tags in its Exif block, and the pHYs chunk of a PNG, and it shows which one it found. When a file declares nothing, the field reads unset and the millimetre entry stays inactive — an assumed 72 or an assumed 300 would be a guess presented as a measurement.
The four edge fields come next, linked by default. Linked, one number drives all four and a weighting control lets the lower edge run between 1.1 and 1.3 times the sides, which is the convention a framer uses so that a mounted picture does not appear to be sliding down its own mat. Unlinked, each side is independent. Arrow keys move the focused field by one unit and Shift-arrows by ten; L toggles the link; holding Space takes the border away so you can see what it was doing.
Containers this page will decode
JPG, PNG, WebP, AVIF, GIF, BMP, TIFF and ICO all decode through the browser’s own image pipeline. HEIC — what a recent iPhone writes by default — needs a WebAssembly decoder that is fetched the first time one of them is opened and is absent from the page until then, so nobody who never opens a HEIC ever downloads it.
Four container details change what the tool says rather than what it does. A JPEG with four colour components is CMYK or YCCK; it is converted to sRGB on decode and the rail names the conversion. An animated GIF or WebP contributes its first frame, stated before you export rather than discovered afterwards. A source with an alpha channel keeps it, and the border is drawn in the colour you chose or left empty — it is never quietly flattened onto white. And the orientation flag is resolved before anything is measured, because a rotated frame changes which edge is the long one and therefore what a percentage means.
Guardrails are evaluated against the output, not the input, which matters here more than on most tools: a 24-megapixel photograph with a 60 mm margin at 300 DPI composites to well over 30 megapixels, and the ceiling that matters is the one the finished canvas has to clear. Past roughly 32 megapixels (16 on iOS) a lighter working copy is offered as a choice; past 100 (40 on iOS) the file is declined with the measured figure named.
Two things this tool will not do
Both are limits of the operation itself, not of this implementation.
- Padding a photograph into another proportion adds no information to it. The bars are inert: they carry no detail, and enlarging the result later enlarges empty colour along with the picture. The alternative — filling the frame instead — means cropping or enlarging, and both cost something. One loses the edges of the composition, the other softens the whole picture. This tool chooses the loss you can see and measure.
- The composite is redrawn and re-encoded, so an embedded colour profile does not survive it. Output is sRGB and a wide-gamut original is converted on the way in. Capture data and location tags do not survive either; the saved file holds pixels and the dimensions of those pixels, and nothing else. If either matters to the destination, keep the original alongside the bordered copy.
Questions the measurements raise
- I asked for a 5 mm border and the readout said 59 pixels. Where does that number come from?
- From the resolution the file declares. A millimetre is a distance on paper and a pixel is a cell in a grid, and the only thing that converts one into the other is a figure for how many cells occupy an inch. At 300 DPI, 5 mm is 5 ÷ 25.4 × 300, which is 59.06 and rounds to 59. Change the resolution field to 150 and the same 5 mm becomes 30 pixels. Neither figure is more correct than the other; they describe different sheets of paper.
- One percentage gave me a thick top edge and a thin side edge. Is the setting broken?
- No, and the readout is showing you why. A percentage here resolves against the long edge of the photograph, so on a 4000 by 1000 panorama a 3% border is 120 pixels on every side — which is a twelfth of the height and a thirty-third of the width. It looks unequal because it is equal in absolute terms and unequal in relative ones. If you want the four margins to look matched on a long frame, switch to pixels or unlink the sides.
- Does padding a photograph out to a square change the photograph?
- Not one pixel of it. Fit-to-ratio mode computes the smallest frame of the target proportion that contains the picture at its own size, then centres the picture in it and fills the remainder. The original grid is copied across untouched; what changes is the number of rows and columns around it. This is the opposite operation to cropping, which reaches the same proportion by removing pixels instead.
- The resolution field says the file claims 72 DPI. Should I believe it?
- Treat it as a statement of intent by whatever wrote the file, not as a measurement of the picture. Many cameras and most screenshot utilities write 72 because it was once a screen convention and nothing has cleared it since. The pixels are unaffected either way. If the print is going out at 300, put 300 in the field and the millimetre widths recompute against that.
- Grow or inset — which one does a print shop want?
- Grow, nearly always. It leaves the photograph at full size and adds paper around it, so a 4000 by 3000 file with a 60-pixel margin goes to the lab as 4120 by 3120 and the image area is unchanged. Inset keeps the file's original dimensions and shrinks the picture to make room, which is what you want when a layout has already fixed the dimensions and the border has to come out of the existing frame.
- Can the bars be empty rather than white?
- Yes, with the transparent fill and a PNG export. The border region is left with an alpha of zero and whatever the file is placed on shows through. A JPG cannot hold that — the format has no alpha channel at all — so choosing JPG with a transparent fill writes the bars as white, and the rail says so before you export rather than after.
What the two output formats cost
The export row offers PNG and JPG and nothing else, and the choice is not cosmetic: it decides whether the bars can be empty and whether the photograph is compressed a second time on its way out. WebP is absent deliberately — several browsers accept the request and hand back a PNG wearing the wrong name, and a saved file that lies about its own container is worse than one fewer option.
| Part of the export | PNG | JPG at quality 92 |
|---|---|---|
| A border of flat colour | Costs almost nothing | Costs almost nothing |
| A border left empty | Held as alpha | Written as white |
| The photograph itself | Re-encoded without loss | Re-encoded with loss |
| The whole file | Order of 10 MB | Order of 2 MB |
A flat region compresses to near nothing in either format, so the border is never what makes the file heavy — the photograph is. That is why PNG is the default here and the wrong default almost everywhere else: a bordered picture is usually on its way to a printer or a frame shop, where one generation of loss is one too many. When the destination is a web page and the original was a JPG already, JPG out costs a second generation that nobody will see and takes most of the weight off.
The same instrument, opened differently
Two routes open this workbench in a different starting state, because the first thing a visitor sees ought to match what they came for. One begins on a target proportion with the width fields standing down; the other begins in millimetres with the resolution the file declares already on screen.
- Square fitBars added until a photograph is square, with nothing cut away.
- Print marginMillimetres first, with the resolution they are measured against on show.
The written notes go further into the arithmetic than a rail can. They are indexed on one page, and each of them answers a question the readout raises but has no room to settle.
Decode, composite and encode all execute in the page process, so no request made by this site carries your photograph.


