SVG is vector; PNG is raster. The hard part isn't the conversion itself — it's deciding what resolution to render at, how to handle transparent backgrounds, and what to do with unusual SVG features (filters, embedded fonts, external references). cairosvg handles 90% of cases cleanly.

Method 1: cairosvg (Cairo-based, highest quality)

cairosvg uses the Cairo graphics library — the same engine GTK and Inkscape use for SVG rendering. Output is crisp at any resolution.

pip install cairosvg
# On macOS: brew install cairo pango
# On Ubuntu: apt install libcairo2 libpango-1.0-0
import cairosvg

def svg_to_png(in_path: str, out_path: str, width: int = 2048, dpi: int = 96) -> None:
    cairosvg.svg2png(
        url=in_path,
        write_to=out_path,
        output_width=width,
        dpi=dpi,
    )

svg_to_png("logo.svg", "logo.png", width=2048)

# Or render at a specific output size:
svg_to_png("diagram.svg", "diagram.png", width=4096)  # 4K wide

The width parameter is what determines image quality, not DPI. SVG has no inherent size — it's vector — so you choose the output resolution. Common defaults:

  • width=512 — for retina app icons (256 logical, 2x for HiDPI).
  • width=2048 — for high-quality web hero images.
  • width=4096 — for print or 4K display.

For SVG with transparent backgrounds, the PNG inherits the transparency. To force a solid background:

cairosvg.svg2png(url="logo.svg", write_to="logo.png", background_color="white", output_width=2048)

Method 2: svglib + reportlab (pure Python, no native deps)

If you can't install Cairo (locked-down environments, certain CI runners), svglib is pure Python.

pip install svglib reportlab Pillow
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM

def svg_to_png(in_path: str, out_path: str, dpi: int = 200) -> None:
    drawing = svg2rlg(in_path)
    renderPM.drawToFile(drawing, out_path, fmt="PNG", dpi=dpi)

svg_to_png("logo.svg", "logo.png", dpi=200)

svglib's renderer is less complete than Cairo — it handles basic SVG well (paths, text, gradients) but struggles with complex filters, masks, and certain CSS features. Use it only when you can't install Cairo.

Method 3: ChangeThisFile API (no deps, handles unusual SVGs)

For SVGs from users — different generators, custom filters, embedded fonts — the API uses the same Cairo engine but handles edge cases like font fallbacks. Get a free API key.

import requests

API_KEY = "ctf_sk_your_key_here"

def svg_to_png(in_path: str, out_path: str) -> None:
    with open(in_path, "rb") as f:
        response = requests.post(
            "https://changethisfile.com/v1/convert",
            headers={"Authorization": f"Bearer {API_KEY}"},
            files={"file": f},
            data={"source": "svg", "target": "png"},
            timeout=30,
        )
    response.raise_for_status()
    with open(out_path, "wb") as out:
        out.write(response.content)

svg_to_png("user_logo.svg", "user_logo.png")

The API auto-detects sensible output dimensions from the SVG's viewBox and ratio. To override, pass width parameter in the form data.

When to use each

ApproachBest forTradeoff
cairosvgDefault for production work, full SVG spec coverageNative Cairo dep on every machine
svglib + reportlabPure-Python environments, locked-down CILimited SVG feature support
ChangeThisFile APIUser-uploaded SVGs, no install hassle, edge runtimesPer-call cost, network call

CLI alternative: rsvg-convert or Inkscape

For one-off conversions or shell scripts:

# rsvg-convert (lightweight, ships with Cairo)
apt install librsvg2-bin
rsvg-convert -w 2048 logo.svg -o logo.png

# Inkscape (full-featured, slower startup)
inkscape -w 2048 logo.svg -o logo.png

rsvg-convert is the same engine as cairosvg's underlying library — same output quality, much faster startup than spawning Python. Use it for shell scripts; use cairosvg when conversion is part of a larger Python pipeline.

Common pitfalls

  • SVG without a viewBox renders at the wrong size. If the SVG only has width/height in inches/cm, conversion can produce a tiny PNG. Add a viewBox or pass output_width explicitly.
  • External fonts won't render correctly. If the SVG references a Google Font or a system font that's not installed, cairosvg falls back to a default font. Convert text to paths before exporting if you need pixel-perfect output.
  • Filter effects can be slow. Gaussian blur, drop shadows, and complex masks can take seconds to render at 4K resolution. If you're batch-converting, profile a few representative SVGs first.
  • The DPI parameter is misleading. SVG is resolution-independent. The DPI parameter only affects unit conversion (e.g., for fonts measured in pt). Use output_width to control actual pixel dimensions.

For production: cairosvg with width=2048 (or 4096 for print). For locked-down environments: svglib. For user uploads with unpredictable SVGs: the API. Free tier is 100 conversions/month.