Convert an SVG String to an Image: Browser or Node.js
Published September 29, 2025 · Updated · By Ashesh Dhakal, Founder of SVG AI
An SVG string is already an image description. If you want to show it in an HTML image element, give the browser an SVG Blob URL. If the destination requires PNG, JPEG or WebP, render the SVG into pixels first. Changing a filename extension does not perform that conversion.
This guide uses one manually drawn compass, with no external fonts or images, to show both choices. Use trusted, self-contained input for these examples. They are local utilities, not a service for processing arbitrary uploads.
Choose the output your destination needs
| Task | Approach | Result |
|---|---|---|
| Show a string in an HTML image element | SVG Blob URL | Still SVG; no raster export |
| Let a visitor download a PNG | Browser image → canvas → PNG Blob | A PNG with chosen pixel dimensions |
| Write PNG, JPEG or WebP from a local script | Node.js with Sharp | A file encoded in the chosen format |
Choose between these by where the conversion needs to run, which format is required and how the actual file renders. There is no timing ranking here: renderer, input, output size and machine all affect a conversion.
A complete SVG string to try
Download the SVG or copy this complete source. The title includes Unicode text, so the examples keep the string as UTF-8 rather than applying btoa directly to it.
<svg xmlns="http://www.w3.org/2000/svg" width="240" height="160" viewBox="0 0 240 160">
<title>Café compass — a manually drawn conversion sample</title>
<rect x="30" y="20" width="180" height="120" rx="20" fill="#18345f"/>
<circle cx="120" cy="80" r="42" fill="#ffffff"/>
<path d="M137 47 128 88 103 113 112 72Z" fill="#f97316"/>
</svg>
Display the string without rasterizing it
In a browser, call the following function with your SVG string, an existing container element and suitable alternative text. The returned cleanup function removes the image and releases its URL when your interface no longer needs it.
async function displaySvg(svgSource, container, alt) {
const url = URL.createObjectURL(new Blob([svgSource], {
type: 'image/svg+xml;charset=utf-8'
}));
const image = new Image();
image.alt = alt;
image.src = url;
try {
await image.decode();
container.appendChild(image);
return () => {
image.remove();
URL.revokeObjectURL(url);
};
} catch (error) {
URL.revokeObjectURL(url);
throw error;
}
}For example, call const dispose = await displaySvg(svgSource, document.querySelector('#preview'), 'Compass') after that container exists, inside an async function or module. Later, call dispose() when removing the preview. Handle a rejected Promise with try/catch. The image decode method waits for the image data or rejects if it cannot be decoded.
Open the complete browser example and select Preview SVG to use this function. Then select Convert to PNG to render the same string into a PNG. The browser PNG guide explains that conversion function, pixel dimensions and URL cleanup in detail.
Render the string with Node.js and Sharp
For a script that writes actual image files, download render-string.cjs and sample.svg into a new folder. Install a supported Node.js release, then run these commands there. On Windows PowerShell, use npm.cmd if the npm wrapper is blocked.
npm init -y
npm install sharp@0.34.5
node render-string.cjs sample.svg sample-720.png png 720
node render-string.cjs sample.svg sample-720.jpg jpeg 720
node render-string.cjs sample.svg sample-720.webp webp 720The complete script is below. It reads the file as a UTF-8 string, converts that string to a Buffer and gives it to Sharp. The function can also be called with a string already held by your application. The command refuses to overwrite an existing output file.
// Trusted, self-contained SVG only. Not an upload-processing service.
const fs = require('node:fs/promises');
const sharp = require('sharp');
async function renderSvgString(svgSource, { width = 720, format = 'png' } = {}) {
if (typeof svgSource !== 'string' || !svgSource.trim()) throw new Error('Supply an SVG string.');
const input = Buffer.from(svgSource, 'utf8');
if (input.length > 1024 * 1024) throw new Error('Input exceeds the 1 MiB example limit.');
if (!Number.isInteger(width) || width < 1 || width > 4096) throw new Error('Width must be an integer from 1 to 4096.');
if (!['png', 'jpeg', 'webp'].includes(format)) throw new Error('Choose png, jpeg or webp.');
const metadata = await sharp(input).metadata();
if (metadata.format !== 'svg' || !metadata.width || !metadata.height) throw new Error('Expected an SVG with usable dimensions.');
const maxHeight = Math.min(4096, Math.floor(16000000 / width));
const density = Math.max(72, Math.ceil(72 * width / metadata.width));
if (density > 100000) throw new Error('Required input density is too high.');
let image = sharp(input, { density, limitInputPixels: 64000000 })
.resize({ width, height: maxHeight, fit: 'inside' });
if (format === 'jpeg') image = image.flatten({ background: '#ffffff' }).jpeg({ quality: 90 });
else if (format === 'webp') image = image.webp({ quality: 90 });
else image = image.png();
const { data, info } = await image.toBuffer({ resolveWithObject: true });
if (info.width !== width || info.height > maxHeight || info.width * info.height > 16000000) {
throw new Error('The requested width cannot fit within the output limits. Choose a smaller width.');
}
return data;
}
async function main() {
const [input, output, format = 'png', rawWidth = '720'] = process.argv.slice(2);
if (!input || !output) throw new Error('Usage: node render-string.cjs input.svg output.png png 720');
const stat = await fs.stat(input);
if (stat.size > 1024 * 1024) throw new Error('Input exceeds the 1 MiB example limit.');
const svgSource = await fs.readFile(input, 'utf8');
const buffer = await renderSvgString(svgSource, { width: Number(rawWidth), format });
await fs.writeFile(output, buffer, { flag: 'wx' });
const info = await sharp(buffer).metadata();
console.log(`${info.format}: ${info.width} × ${info.height}; ${buffer.length} bytes saved to ${output}`);
}
module.exports = { renderSvgString };
if (require.main === module) main().catch(error => {
console.error(error.message);
process.exitCode = 1;
});
The script passes SVG rendering density into the Sharp constructor, then resizes to the requested width while preserving the input ratio. Density is an input option, not a chainable .density() operation. The resize box allows at most 4,096 pixels per side and 16 million output pixels. If the requested width cannot fit while preserving the ratio, the script rejects the conversion and asks for a smaller width. It checks the actual encoded dimensions too. These limits do not make untrusted SVG safe to process.
Inspect the supplied outputs
The linked files were rendered from this exact manual sample using Node.js 22.9.0 and Sharp 0.34.5 on Windows. All three are 720 × 480 pixels. This demonstrates this sample; it is not a benchmark or a claim that every renderer produces identical pixels.

- PNG output: retains transparency outside the rounded rectangle.
- JPEG output: the script deliberately fills transparent space with white before encoding.
- WebP output: this example retains transparency and uses quality 90.
JPEG and WebP quality values are encoder options, not a measured percentage of visual fidelity. Check the Sharp output documentation when choosing compression settings. Inspect thin edges, text and the background in the actual destination before deciding that a file is suitable.
Fix the source when the output is wrong
An SVG image does not automatically inherit CSS from the page that created the string. Give the file its own colors, dimensions and viewBox. If it relies on a remote image or font, make the source self-contained and confirm that you have permission to include that resource. Browser SVG-image restrictions are documented in SVG as an image.
For invalid XML, correct the input rather than stripping tags with regular expressions and calling the result sanitized. For unsupported artwork, simplify a copy and compare it with the original. Keep your editable SVG alongside the raster exports; a PNG cannot preserve editable paths.
Download all examples and sample outputs, or follow the Windows folder conversion walkthrough for a sequential batch. If you only need to inspect the XML, use the SVG file-format guide.