SVGAI
SVGAI
ToolsPricingBlogAPI
LoginSign Up
SVGAI

SVG AI helps you create professional vector graphics from text prompts, including logos, icons, illustrations, and text-to-SVG designs.

Product

  • AI SVG Generator
  • AI Icon Generator
  • SVG to MP4 Converter
  • Pricing

Popular Converters

  • PNG to SVG
  • SVG to PNG
  • Image to SVG
  • SVG to JPG
  • SVG to PDF
  • View All →

Resources

  • What is SVG?
  • SVG Gallery
  • SVG Animation
  • Blog
  • Learn Center
  • API & MCP Docs
  • Sitemap

Legal

  • Privacy & Cookies
  • Terms of Service

2026 SVG AI. All rights reserved.

X (Twitter)LinkedInYouTubeInstagram
Back to blog

SVG to PNG in JavaScript: A Complete Browser Example

Published September 20, 2025 · Updated September 27, 2026 · By Ashesh Dhakal, Founder of SVG AI

To export an SVG as PNG in a browser, load the SVG as an image, draw it on a canvas with the required pixel dimensions, then encode the canvas as PNG. The example below includes the conversion function, a preview and a download link.

Use it with static, self-contained SVG that you own or trust. It does not sanitize untrusted markup, fetch external assets or capture a chosen animation frame. If you just need one conversion, open the SVG to PNG converter.

Run the complete example

Open the browser example, choose Convert to PNG, then select Download PNG. The default manual compass drawing exports to 720 × 480 pixels. Change the background to white to compare it with the transparent version.

Manual compass sample: orange needle in a white circle on a navy rounded rectangle
This sample uses a 240 × 160 viewBox. It was drawn in SVG for this tutorial.

Download the example files to run the browser page locally. Unzip the archive and open browser-example.html; its script is included in the file. The archive also includes the standalone JavaScript, the SVG and the Node.js examples used in the SVG string guide.

The conversion function

svgToPng accepts an SVG string and returns a Promise containing a PNG Blob. It checks the XML, requires a viewBox, bounds the input and output size, and revokes its temporary source URL after success or failure. Those checks catch mistakes in this example; they are not a general SVG security filter.

// For trusted, static, self-contained SVG. This does not sanitize SVG.
async function svgToPng(svgSource, { width = 720, height = 480, background = null } = {}) {
  if (typeof svgSource !== 'string' || !svgSource.trim()) {
    throw new Error('Supply a nonempty SVG string.');
  }
  if (new Blob([svgSource]).size > 1024 * 1024) {
    throw new Error('This example limits SVG input to 1 MiB.');
  }
  if (![width, height].every(n => Number.isInteger(n) && n > 0 && n <= 4096)
      || width * height > 16000000) {
    throw new Error('Use integer dimensions from 1 to 4096, with at most 16 million pixels.');
  }
  if (background !== null && !/^#[0-9a-f]{6}$/i.test(background)) {
    throw new Error('Use null or a six-digit hex background such as #ffffff.');
  }

  const doc = new DOMParser().parseFromString(svgSource, 'image/svg+xml');
  const root = doc.documentElement;
  if (doc.doctype || doc.querySelector('parsererror') || root.localName !== 'svg'
      || root.namespaceURI !== 'http://www.w3.org/2000/svg') {
    throw new Error('Expected SVG XML with the SVG namespace and no DTD.');
  }
  const viewBox = (root.getAttribute('viewBox') || '').trim().split(/[\s,]+/).map(Number);
  if (viewBox.length !== 4 || !viewBox.every(Number.isFinite) || viewBox[2] <= 0 || viewBox[3] <= 0) {
    throw new Error('Supply a viewBox with four finite numbers and positive width and height.');
  }
  root.setAttribute('width', String(width));
  root.setAttribute('height', String(height));
  const serialized = new XMLSerializer().serializeToString(root);
  const sourceUrl = URL.createObjectURL(new Blob([serialized], { type: 'image/svg+xml;charset=utf-8' }));
  const img = new Image();
  let timer;

  try {
    await new Promise((resolve, reject) => {
      img.onload = resolve;
      img.onerror = () => reject(new Error('The browser could not load this SVG.'));
      timer = setTimeout(() => reject(new Error('SVG loading exceeded 15 seconds.')), 15000);
      img.src = sourceUrl;
    });
    clearTimeout(timer);
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');
    if (!ctx) throw new Error('A 2D canvas context is unavailable.');
    if (background !== null) {
      ctx.fillStyle = background;
      ctx.fillRect(0, 0, width, height);
    }
    ctx.drawImage(img, 0, 0, width, height);
    return await new Promise((resolve, reject) => {
      canvas.toBlob(blob => blob ? resolve(blob) : reject(new Error('PNG encoding failed.')), 'image/png');
    });
  } finally {
    clearTimeout(timer);
    img.onload = null;
    img.onerror = null;
    img.removeAttribute('src');
    URL.revokeObjectURL(sourceUrl);
  }
}

Download the function if you want to use it in your own browser application. Pass actual output pixels as width and height. The sample call is await svgToPng(svgSource, { width: 720, height: 480 }).

Choose dimensions without stretching the drawing

A canvas has a fixed number of pixels. Displaying that canvas at a smaller CSS size does not add image detail. For a 240 × 160 display at twice that pixel density, export 480 × 320. The default 720 × 480 example is three times the source viewBox dimensions.

The function gives the SVG a viewport matching the output canvas and leaves its viewBox and preserveAspectRatio unchanged. With this sample, a 720 × 720 output keeps the drawing proportional and leaves space above and below it. An input with preserveAspectRatio="none" can stretch to a different ratio; choose that behavior deliberately. The MDN aspect-ratio reference explains the options.

Transparent pixels remain transparent unless you supply a background such as #ffffff. The PNG encoder has no JPEG-style quality slider: choose enough output pixels first. The quality argument to Canvas toBlob applies to formats that support lossy compression.

Keep the output URL alive while the reader uses it

The temporary SVG URL is no longer needed once drawing and encoding finish. The resulting PNG URL has a different lifetime: keep it available while the preview and download link use it, then revoke it when replacing or removing that result. The downloadable page does this on the next conversion and when the page is left. It does not revoke the download URL immediately after a click.

Handle failures at the caller with try/catch and show a message beside the control. The example clears an old result before starting, so an invalid new input cannot leave a stale PNG presented as its output. Use Try invalid XML to exercise that path.

When the exported image differs from the SVG

  • Missing fonts or images: an SVG loaded as an image is a separate document. It cannot rely on the surrounding page's styles or assume that external resources will load. Make the source self-contained and inspect the exported image. See SVG as an image.
  • Wrong colors: resolve inherited values such as currentColor in the source you export. A standalone SVG does not inherit the button color from your application.
  • SecurityError on export: canvas access depends on its origin-clean state. Check the actual image sources and their allowed origins. A public CORS proxy is not a general fix; the MDN canvas and CORS guide describes the restriction.
  • Animation: this function exports a static image. Serializing an animated element is not a reliable way to preserve a selected rendered frame.
  • Very large inputs: process files sequentially and choose smaller output dimensions. The limits here are example limits, not a guarantee that every device can render that much artwork.

If your SVG exists as an element, serialize the complete root with new XMLSerializer().serializeToString(svgElement) before passing it to the function. Add any required styles to the exported source first. For a local Node.js conversion or JPEG/WebP output, continue with convert an SVG string to an image.