BrainCoder
All guides

How to Convert HTML to an Image (PNG, JPEG, WebP) in Your Browser

BrainCoder5 min read

Render HTML to a PNG, JPEG or WebP at an exact 1x-4x device-pixel scale: a measured capture-box preview, a disclosed pixel budget, a 200 KB cap, and an honest account of what a canvas 2D re-draw does not reproduce.

What this converter actually does

You paste markup, choose a capture width, a scale and a format, and the tool re-draws that markup into an image and saves it. The capture width (240 to 1200 px) fixes the width of the box your content is laid out in, exactly as a container element would. The scale is the device-pixel multiplier, and it is the part most tools describe vaguely: at 2x, every CSS pixel is painted as two image pixels, so a 480 px wide box becomes a 960 px wide file. That is the same relationship between CSS pixels and device pixels that a retina display has, which is why 2x is the useful default for mockups, docs and anything with small text.

Because that arithmetic is exact, the tool can show it to you before you commit. The projection under the scale control prints the output size in pixels, and it is calculated the way the renderer calculates it - floor(css size x scale) - so the number you read is the number the canvas is allocated. There is no separate vague quality slider and no hidden resampling step that quietly produces a different size from the one you asked for.

The pixel budget, and why the scale moves on its own

There is a ceiling on the canvas the browser will allocate, and this tool fixes it at 16 megapixels total and 8192 pixels on any single side. Those two numbers handle different failures: the pixel budget is what the browser refuses to allocate, and the side limit is what some canvas implementations cap independently. When your requested scale would break either one, the tool does not refuse the capture and it does not pretend. It lowers the scale to the largest value that fits, tells you the scale you asked for and the scale actually used, and still writes the file.

Two things it will not do. It will never go below 1x, because rendering under 1x softens text to fake a size you did not request, and a smaller image quietly presented as the one you asked for is worse than an honest reduction. And if the content cannot fit the budget even at 1x, the capture is refused with the limit named, because at that point there is no honest scale left to offer. There is also a hard refusal for content wider than the capture box: the image is cropped to the box rather than reflowed, so the tool tells you the width you need instead of cropping a card in half.

Format, files, and the copy you get

PNG is lossless and the largest file, which makes it the right choice for UI, code, diagrams and flat colour. JPEG is lossy at quality 0.92 and has no transparency channel, so it suits photographs and gradients. WebP is lossy at the same quality, usually smaller than JPEG, and keeps transparency - but not every browser can encode it. If yours cannot, the canvas returns PNG instead; the tool says so, and the file is named after the bytes you actually received rather than the format you clicked, so the extension never lies about the contents.

The file is saved automatically when the capture finishes, and the result panel then offers the same bytes two more ways: copy to clipboard, and download again. Re-downloading is not a second render - it writes the identical buffer under the identical name, so the file you attach to an issue is provably the file in the panel. The name comes from the file you opened, so invoice.html becomes invoice-2x.png; pasted markup has no source name and is called capture-2x.png. Anything a filename cannot contain is replaced rather than passed through.

What a re-draw reproduces, and what it does not

This is a re-draw, not a photograph of your screen. The renderer copies the page into an offscreen iframe, reads each element's computed style and repaints it with the canvas 2D API. That is why the layout is right: flexbox and grid are painted the way your browser already resolved them, inline styles and class rules apply, a <style> block is honoured, borders, box-shadow, text-shadow, linear and radial gradients, tables, list markers and ::before/::after all come through, along with any web font the page has already loaded.

The same mechanism has real gaps, and they are listed on the tool itself rather than discovered afterwards. filter, backdrop-filter, mix-blend-mode, conic-gradient, the repeating gradients and object-fit are not painted. It does not use an SVG foreignObject, so content that depends on one will not survive. The output is composited on white, so a transparent PNG source still lands on white. An image served without CORS headers is left out of the capture rather than drawn blank, and a remote <img src> or CSS url() is fetched by your browser exactly as any page would fetch it. Finally, vw, vh and position: fixed resolve against the browser window rather than the capture width, so a layout that looks right in a full viewport can be cropped differently here.

What is removed before anything is drawn

Pasted markup is rebuilt from an allowlist before it is displayed or painted. Scripts, iframes, objects, embedded SVG, MathML, form controls and <canvas> elements are removed with their contents, every on* handler is stripped, and javascript: and vbscript: URLs are rejected in any URL attribute - including entity-encoded and whitespace-obfuscated spellings of the same thing. A <style> block is deliberately kept, because a class-based mockup is most of what people want to capture, and so are data: and aria- attributes. The id attribute is removed: it could collide with this page's own ids and hijack a label or a :target rule. Executable CSS constructs - expression(), -moz-binding, behavior: and @import - are scrubbed from both inline styles and kept style blocks.

The important part is that there is only one markup string. The preview and the capture both render the exact same sanitized output, so what you see on screen is what ends up in the file, and the one-line disclosure under the editor reports the real counts of what was removed. Input is capped at 200 KB.

Privacy, and when to reach for something else

Nothing is uploaded. Your markup is read in this tab, laid out in this tab, repainted in this tab and written to your downloads from this tab, and no request is made for your HTML. The one network traffic that can happen is whatever your own markup points at - a remote image or stylesheet - which your browser fetches as it would on any page.

If you need a full scrolling page, or a capture of something that is not currently in the DOM, or a renderer that reproduces filter and blend modes, use a headless browser screenshot or the browser's own capture instead: this tool is built for a bounded, self-contained box, and it is honest about that boundary rather than pretending otherwise.

Try it free — HTML to Image

Re-draw pasted HTML into a PNG, JPEG or WebP at an exact 1x–4x device-pixel scale, inside the 16 MP budget. Composited on white and cropped to the capture box — it is a re-draw, not a screen grab, and runs locally with nothing uploaded.

Open HTML to Image