Quantcast
Viewing all articles
Browse latest Browse all 17

Answer by Teocci for Convert SVG to image (JPEG, PNG, etc.) in the browser

This is an old question, in 2022 we have ES6 and we don't need 3rd party libraries.

Here is a very basic way to convert svg images into other formats.

The trick is to load the svg element as an img element, then use a canvas element to convert the image into the desired format. So, four steps are needed:

  1. Extract svg as xml data string.
  2. Load the xml data string into a img element
  3. Convert the img element to a dataURL using a canvas element
  4. Load the converted dataURL into a new img element

Step 1

Extracting a svg as xml data string is simple, we don't need to convert it as a base64 string. We just serialize it as XML then we encode the string as a URI:

// Data header for a svg image: const dataHeader = 'data:image/svg+xml;charset=utf-8'// Serialize it as xml string:const serializeAsXML = $e => (new XMLSerializer()).serializeToString($e)// Encode URI data as UTF8 data:const encodeAsUTF8 = s => `${dataHeader},${encodeURIComponent(s)}`// Select the element:const $svg = document.getElementById('svg-container').querySelector('svg')// Encode it as a data string:const svgData = encodeAsUTF8(serializeAsXML($svg))

Note:

If you need a base64 data you can use this option:

...// Encode URI data as base64 data:const encodeAsB64 = s => `${dataHeader};base64,${btoa(s)}`...// Encode it as a data string:const svgData = encodeAsB64(serializeAsXML($svg))

Step 2

Loading the xml data string into a img element:

// This function returns a Promise whenever the $img is loadedconst loadImage = async url => {    const $img = document.createElement('img')    $img.src = url    return new Promise((resolve, reject) => {        $img.onload = () => resolve($img)        $img.onerror = reject        $img.src = url    })}

Step 3

Converting the img element to a dataURL using a canvas element:

const $canvas = document.createElement('canvas')$canvas.width = $svg.clientWidth$canvas.height = $svg.clientHeight$canvas.getContext('2d').drawImage(img, 0, 0, $svg.clientWidth, $svg.clientHeight)return $canvas.toDataURL(`image/${format}`, 1.0)

Step 4

Loading the converted dataURL into a new img element:

const $img = document.createElement('img')$img.src = dataURL$holder.appendChild($img)

Here you have a working snippet:

const dataHeader = 'data:image/svg+xml;charset=utf-8'const $svg = document.getElementById('svg-container').querySelector('svg')const $holder = document.getElementById('img-container')const $label = document.getElementById('img-format')const destroyChildren = $element => {  while ($element.firstChild) {    const $lastChild = $element.lastChild ?? false    if ($lastChild) $element.removeChild($lastChild)  }}const loadImage = async url => {  const $img = document.createElement('img')  $img.src = url  return new Promise((resolve, reject) => {    $img.onload = () => resolve($img)    $img.onerror = reject  })}const serializeAsXML = $e => (new XMLSerializer()).serializeToString($e)const encodeAsUTF8 = s => `${dataHeader},${encodeURIComponent(s)}`const encodeAsB64 = s => `${dataHeader};base64,${btoa(s)}`const convertSVGtoImg = async e => {  const $btn = e.target  const format = $btn.dataset.format ?? 'png'  $label.textContent = format  destroyChildren($holder)  const svgData = encodeAsUTF8(serializeAsXML($svg))  const img = await loadImage(svgData)  const $canvas = document.createElement('canvas')  $canvas.width = $svg.clientWidth  $canvas.height = $svg.clientHeight  $canvas.getContext('2d').drawImage(img, 0, 0, $svg.clientWidth, $svg.clientHeight)  const dataURL = await $canvas.toDataURL(`image/${format}`, 1.0)  console.log(dataURL)  const $img = document.createElement('img')  $img.src = dataURL  $holder.appendChild($img)}const buttons = [...document.querySelectorAll('[data-format]')]for (const $btn of buttons) {  $btn.onclick = convertSVGtoImg}
.wrapper {  display: flex;  flex-flow: row nowrap;  width: 100vw;}.images {  display: flex;  flex-flow: row nowrap;  width: 70%;}.image {  width: 50%;  display: flex;  flex-flow: row wrap;  justify-content: center;}.label {  width: 100%;  text-align: center;}
<div class="wrapper"><div class="item images"><div class="image left"><div class="label">svg</div><div id="svg-container"><svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="200" height="200" viewBox="0 0 248 204"><path fill="#1d9bf0" d="M221.95 51.29c.15 2.17.15 4.34.15 6.53 0 66.73-50.8 143.69-143.69 143.69v-.04c-27.44.04-54.31-7.82-77.41-22.64 3.99.48 8 .72 12.02.73 22.74.02 44.83-7.61 62.72-21.66-21.61-.41-40.56-14.5-47.18-35.07 7.57 1.46 15.37 1.16 22.8-.87-23.56-4.76-40.51-25.46-40.51-49.5v-.64c7.02 3.91 14.88 6.08 22.92 6.32C11.58 63.31 4.74 33.79 18.14 10.71c25.64 31.55 63.47 50.73 104.08 52.76-4.07-17.54 1.49-35.92 14.61-48.25 20.34-19.12 52.33-18.14 71.45 2.19 11.31-2.23 22.15-6.38 32.07-12.26-3.77 11.69-11.66 21.62-22.2 27.93 10.01-1.18 19.79-3.86 29-7.95-6.78 10.16-15.32 19.01-25.2 26.16z"/></svg></div></div><div class="image right"><div id="img-format" class="label"></div><div id="img-container"></div></div></div><div class="item buttons"><button id="btn-png" data-format="png">PNG</button><button id="btn-jpg" data-format="jpeg">JPG</button><button id="btn-webp" data-format="webp">WEBP</button></div></div>

Viewing all articles
Browse latest Browse all 17

Trending Articles