File & PDF Tools

SVG to Image

Render SVG files as PNG, JPEG, or WebP images.

SVG to image
Safely render SVG as PNG, JPEG, or WebP.
Local processing

SVG to Image

Render SVG into PNG, JPEG, or WebP with configurable dimensions, quality, and JPEG background.

Safety and Compatibility

  • Scripts, event attributes, and remote references are removed
  • External fonts and images are not fetched
  • Output is limited to 40 megapixels

Renders one sanitized SVG into a PNG, JPEG or WebP raster on a browser canvas, at whatever output size you type up to 12,000 pixels per side. It suits exporting logos, icons and flat illustrations for places that reject vector files: app icons, social cards, email templates, or a CMS upload field that only accepts bitmaps.

The sanitizer deletes more than you expect

Before anything is painted, the text is re-parsed by DOMParser in image/svg+xml mode; a <parsererror> element or a root whose local name is not svg aborts the load. Then every <script> and <foreignObject> element is removed outright, attributes whose name starts with on are dropped, and href or xlink:href values beginning with http:, https: or // are stripped. What survives is worth knowing: data: URIs are left alone, so inlined bitmaps and fonts still render, and internal references such as url(#gradient) or href="#clip" are untouched. The visible casualty is foreignObject: charts that put HTML labels inside it export with those labels gone, and getting them back means rewriting them as native <text> first.

Why a 24-pixel icon exports at 24 pixels

The starting width and height are not read from CSS. The parseLength helper matches only ^(\d+(?:\.\d+)?)(?:px)?$, so width="512" and width="512px" resolve while 100%, 24pt, 1in, 2em and auto all resolve to zero. On a zero the tool falls back to the third and fourth numbers of viewBox, and if those are missing too it assumes 512. An icon declaring viewBox="0 0 24 24" with no width therefore opens with 24 and 24 in the fields: the honest intrinsic size, but a thumbnail once the file reaches a page. With Lock aspect ratio on, editing one field recomputes the other as round(value × counterpart ÷ source), which is how 1200 wide turns a 96×32 mark into 1200×400.

Quality stops at 20%, and only JPEG gets a background

canvas.toBlob(callback, type, quality) receives the slider for JPEG and WebP only; for PNG the spec lets the encoder ignore it, so the slider is hidden and 0.2 produces the same bytes as 1.0. The slider spans 0.2 to 1.0 in steps of 0.01 with a default of 0.9, so neither 0 nor 100 is reachable here, and the float is an encoder-defined knob rather than a percentage of anything. Transparency separates the three formats: the component floods the canvas with the background colour, default #ffffff, only on the JPEG branch, because JPEG has no alpha channel, while PNG and WebP keep whatever pixels the SVG left unpainted. The colour picker is hidden for those two by design, so flattening a transparent PNG onto white is not something this page can do.

Worked example

Exporting a viewBox-only icon at 1200 px wide

Input
brand-mark.svg containing <svg viewBox="0 0 96 32"> with no width or height attributes; Width typed as 1200 with Lock aspect ratio on; format PNG
Output
brand-mark.png, image/png, 1200×400 pixels, 8-bit RGBA

With no width or height the natural size falls back to the viewBox, so both fields start at 96 and 32. Changing Width to 1200 runs the aspect handler, which computes round(1200 × 32 ÷ 96) = 400, and the canvas is created at 1200×400 — 480,000 pixels, inside both the 12,000 per-side and 40-megapixel checks. PNG keeps the alpha channel, so any area the SVG never painted stays transparent instead of becoming white.

Limits and pitfalls

  • The SVG itself is capped at 10 MB (10 × 1024 × 1024 bytes) and is read as text, so the budget is eaten by long path data or inline Base64 payloads rather than by anything visual.
  • The background colour input appears only for JPEG. PNG and WebP output preserve transparent pixels, so a white backdrop has to be added inside the SVG as a filled <rect> before converting.
  • Width and height must be integers from 1 to 12,000 and their product at most 40,000,000 pixels: 6324×6324 = 39,992,976 is accepted, 12000×12000 = 144,000,000 is rejected outright.
  • Text set in a font that is not installed falls back silently; fonts referenced by name are never converted to outlines, and external font or image URLs are stripped, so glyphs must travel as paths or the font must be embedded.
  • One file per run: the output name is the source basename with .png, .jpg or .webp appended, so a batch of icons means repeating the whole select, resize and convert sequence.

Related tools

When it goes wrong

The saved file is logo.webp, but the CMS rejects it as "not a WebP" and a hex viewer shows it starting with 89 50 4E 47.

CauseThe suffix is assembled from the format select and never from blob.type. canvas.toBlob(callback, "image/webp", quality) is permitted to hand back a PNG when the browser has no WebP encoder, so genuinely PNG bytes keep the .webp name.

FixRead the first bytes: RIFF at the front is WebP, 89 50 4E 47 is PNG. If it is the latter, export as PNG on purpose (or JPEG, accepting the background fill) rather than trusting the extension, or rerun the same conversion in a browser that encodes WebP.

The first icon exported at 1024 px as intended; the next file dropped in came back at 24 px without any field being touched.

CauseEvery selection rewrites both fields from the new file — the parseLength value, else the viewBox width and height, else 512 — while format, quality and background colour are left as they were. Leftovers from a viewBox-only icon therefore look like ignored input.

FixAfter each drop, retype the width and let the locked height follow, then compare the two fields with the source size shown in the preview header before pressing Convert.

After unticking Lock aspect ratio, a 96 × 32 wordmark entered as 512 wide and 512 high exported with the letters squeezed into squares.

CauseThe canvas is created at exactly the two numbers and drawImage stretches the raster across it on each axis separately, with no letterboxing step. Clearing the lock only stops the Math.round(value × counterpart ÷ source) recompute; it does not make the drawing keep its proportions.

FixRetick the box and edit one field only, or type 1536 wide with the lock on to land on exactly 1536 × 512 for a 3:1 asset. If a square frame is mandatory, pad the SVG with a surrounding <rect> and a square viewBox before converting.

The same file draws fine in a browser tab, yet here it only reports that the SVG content is invalid.

CauseThe bytes go through File.text() into DOMParser under image/svg+xml, which demands well-formed XML with a single <svg> root. A gzipped .svgz arrives as mojibake, an "SVG" saved from a web page has an <html> root, and a bare ampersand or an unclosed tag in a text node is a parse error — none of which stop a browser from drawing it.

FixGunzip the .svgz first (the GZIP tool runs locally), trim the file to the block starting at <svg, escape stray ampersands as &amp;, and re-export from the editor as plain SVG instead of an HTML-wrapped variant.

Width 12000 and height 4000 are both inside the min and max shown on the inputs, yet Convert refuses with the "1 to 12,000 … 40 megapixels" message.

CauseOne check emits one string for three rules: both values must be integers, each from 1 to 12,000, and their product at most 40,000,000. 12000 × 4000 = 48,000,000 trips only the product rule, while a typed 512.5 passes through v-model.number as a float and trips only the integer rule.

FixMultiply first: 8000 × 5000 = 40,000,000 is accepted, 8000 × 5001 = 40,008,000 is not. Round any decimal, then shorten the wider side until the product clears the limit.

One concrete scenario

A 4:5 cover for print, and exactly where the pixel budget cuts off

The press wants an 8 × 10 inch cover at 700 dpi, which is 5600 × 7000. The source cover.svg declares width 1080 and height 1350, so both fields open at those numbers; typing 5600 into Width with Lock aspect ratio on recomputes the height as Math.round(5600 × 1350 ÷ 1080) = 7000, giving 39,200,000 pixels and leaving 800,000 to spare under the 40-megapixel check. Pushing to 8.1 × 10.1 inches, 5670 × 7070, multiplies out to 40,086,900 and is refused although neither side is close to 12,000. Stay at 5600 × 7000 and export PNG for the transparent artwork: that branch hides the quality slider, so a smaller file means fewer pixels, not lower quality.

Frequently Asked Questions

When does SVG → PNG come out blurry?
Never, as long as output size ≥ design size: SVG is vector and renders sharp at any scale. Blur means the output resolution was set below the display size — export at 2–3× the display dimensions for Retina-crisp results.
Do external images and fonts inside the SVG convert?
For security, external references (web fonts, linked images) are not fetched — those parts drop or fall back. Embed fonts as outlines or Base64 and images as Data URIs first, then convert.
The PNG has a transparent background — how do I make it white?
SVG defaults to transparency; use the tool’s background option to fill it. JPEG output is opaque by nature and fills white automatically. For icons, keeping a transparent PNG is usually more useful for layering.

Content reviewed: