You can convert SVG(Online, Font-awesome, exists SVG) to PNG with the script and save it.
Last active
July 19, 2021 12:23
-
-
Save CarsonSlovoka/81195ea3c04edbaa02b35b0678aa7038 to your computer and use it in GitHub Desktop.
You can convert SVG(Online, Font-awesome, exists SVG) to PNG with the script and save it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SVG2IMG { | |
/** | |
* @param {HTMLCanvasElement} canvas | |
* @param {string} src "http://.../xxx.svg" or "data:image/svg+xml;base64,${base64}" | |
* */ | |
constructor(canvas, src) { | |
this.canvas = canvas; | |
this.context = this.canvas.getContext("2d") | |
this.src = src | |
this.addTextList = [] | |
} | |
/** | |
* @param {HTMLElement} node | |
* @param {string} mediaType: https://en.wikipedia.org/wiki/Media_type#Common_examples_%5B10%5D | |
* @see https://en.wikipedia.org/wiki/List_of_URI_schemes | |
* */ | |
static Convert2URIData(node, mediaType = 'data:image/svg+xml') { | |
const base64 = btoa(node.outerHTML) | |
return `${mediaType};base64,${base64}` | |
} | |
/** | |
* @param {string} text | |
* @param {int} x | |
* @param {int} y | |
* @param {"stroke"|"fill"} mode | |
* @param {string} size, "30px" | |
* @param {string} font, example: "Arial" | |
* @param {string} color, example: "#3ae016" or "yellow" | |
* @param {int} alpha, 0.0 (fully transparent) to 1.0 (fully opaque) // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors#transparency | |
* */ | |
AddText(text, x, y, {mode = "fill", size = "32px", font = "Arial", color = "black", alpha = 1.0}) { | |
const drawFunc = (text, x, y, mode, font) => { | |
return () => { | |
// https://www.w3schools.com/graphics/canvas_text.asp | |
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillText | |
const context = this.context | |
const originAlpha = context.globalAlpha | |
context.globalAlpha = alpha | |
context.font = `${size} ${font}` | |
switch (mode) { | |
case "fill": | |
context.fillStyle = color | |
context.fillText(text, x, y) | |
break | |
case "stroke": | |
context.strokeStyle = color | |
context.strokeText(text, x, y) | |
break | |
default: | |
throw Error(`Unknown mode:${mode}`) | |
} | |
context.globalAlpha = originAlpha | |
} | |
} | |
this.addTextList.push(drawFunc(text, x, y, mode, font)) | |
} | |
/** | |
* @description When the build is finished, you can click the filename to download the PNG or mouse enters to copy PNG to the clipboard. | |
* */ | |
Build(filename = "download.png") { | |
const img = new Image(/*this.canvas.width, this.canvas.height*/) | |
img.src = this.src | |
img.crossOrigin = "anonymous" // Fixes: Tainted canvases may not be exported | |
img.onload = (event) => { | |
this.context.drawImage(event.target, 0, 0) | |
for (const drawTextFunc of this.addTextList) { | |
drawTextFunc() | |
} | |
// create a "a" node for download | |
const a = document.createElement('a') | |
document.querySelector('body').append(a) | |
a.innerText = filename | |
a.download = filename | |
const quality = 1.0 | |
// a.target = "_blank" | |
a.href = this.canvas.toDataURL("image/png", quality) | |
a.append(this.canvas) | |
} | |
this.canvas.onmouseenter = (event) => { | |
document.featurePolicy.allowedFeatures() // Fixes: DOMException: The Clipboard API has been blocked because of a permissions policy applied to the current document | |
// set background to white. Otherwise, background-color is black. | |
this.context.globalCompositeOperation = "destination-over" // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation // https://www.w3schools.com/tags/canvas_globalcompositeoperation.asp | |
this.context.fillStyle = "rgb(255,255,255)" | |
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height) | |
this.canvas.toBlob(blob => navigator.clipboard.write([new ClipboardItem({'image/png': blob})])) // copy to clipboard // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/clipboard | |
/* It will open a new window, and you can drag the picture to your desktop to save it. | |
const quality = 1.0 | |
const iframe = `<iframe width="66%" height="50%" src=${this.canvas.toDataURL("image/png", quality)}></iframe>` // Error: Tainted canvases may not be exported // img.crossOrigin="anonymous" | |
document.open() | |
document.write(iframe) | |
document.close() | |
*/ | |
} | |
} | |
} | |
class Canvas { | |
/** | |
* @description for do something like that: ``<canvas width="" height=""></>canvas>`` | |
**/ | |
constructor(w, h) { | |
const canvas = document.createElement("canvas") | |
document.querySelector(`body`).append(canvas) | |
this.canvas = canvas; | |
[this.canvas.width, this.canvas.height] = [w, h] | |
} | |
/** | |
* @description If your SVG is large, you may want to know which part is what you wanted. | |
* */ | |
DrawGrid(step = 100) { | |
const ctx = this.canvas.getContext('2d') | |
const w = this.canvas.width | |
const h = this.canvas.height | |
// Draw the vertical line. | |
ctx.beginPath(); | |
for (let x = 0; x <= w; x += step) { | |
ctx.moveTo(x, 0); | |
ctx.lineTo(x, h); | |
} | |
// set the color of the line | |
ctx.strokeStyle = 'rgba(255,0,0, 0.5)' | |
ctx.lineWidth = 1 | |
ctx.stroke(); | |
// Draw the horizontal line. | |
ctx.beginPath(); | |
for (let y = 0; y <= h; y += step) { | |
ctx.moveTo(0, y) | |
ctx.lineTo(w, y) | |
} | |
ctx.strokeStyle = 'rgba(128, 128, 128, 0.5)' | |
ctx.lineWidth = 5 | |
ctx.stroke() | |
} | |
} | |
function ImportFontAwesome() { | |
const range = document.createRange() | |
const frag = range.createContextualFragment(` | |
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" integrity="sha512-HK5fgLBL+xu6dm/Ii3z4xhlSUyZgTT9tuc/hSrtw6uzJOvgRr2a9jyxxT1ely+B+xFAmJKVSTbpM/CuL7qxO8w==" crossorigin="anonymous" /> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/js/all.min.js" integrity="sha512-UwcC/iaz5ziHX7V6LjSKaXgCuRRqbTp1QHpbOJ4l1nw2/boCfZ2KlFIqBUA/uRVF0onbREnY9do8rM/uT/ilqw==" crossorigin="anonymous"/> | |
`) | |
document.querySelector("head").append(frag) | |
} | |
// 👇 Below is a Test to teach you how to use it. | |
(() => { | |
window.onload = () => { | |
// Test 1: SVG from Online | |
const canvas = new Canvas(650, 500) | |
// canvas.DrawGrid() // If you want to show grid, you can use it. | |
const svg2img = new SVG2IMG(canvas.canvas, "https://upload.wikimedia.org/wikipedia/commons/b/bd/Test.svg") | |
svg2img.AddText("Hello", 100, 250, {mode: "fill", color: "yellow", alpha: 0.8}) | |
svg2img.AddText("world", 200, 250, {mode: "stroke", color: "red"}) | |
svg2img.AddText("!", 280, 250, {color: "#f700ff", size: "72px"}) | |
svg2img.Build("Test.png") | |
// Test 2: URI.data | |
const canvas2 = new Canvas(180, 180) | |
const uriData = "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc21pbGUtd2luayBmYS13LTE2IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgZGF0YS1wcmVmaXg9ImZhciIgZGF0YS1pY29uPSJzbWlsZS13aW5rIiByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDQ5NiA1MTIiIGRhdGEtZmEtaTJzdmc9IiI+PHBhdGggZmlsbD0iY3VycmVudENvbG9yIiBkPSJNMjQ4IDhDMTExIDggMCAxMTkgMCAyNTZzMTExIDI0OCAyNDggMjQ4IDI0OC0xMTEgMjQ4LTI0OFMzODUgOCAyNDggOHptMCA0NDhjLTExMC4zIDAtMjAwLTg5LjctMjAwLTIwMFMxMzcuNyA1NiAyNDggNTZzMjAwIDg5LjcgMjAwIDIwMC04OS43IDIwMC0yMDAgMjAwem0xMTcuOC0xNDYuNGMtMTAuMi04LjUtMjUuMy03LjEtMzMuOCAzLjEtMjAuOCAyNS01MS41IDM5LjQtODQgMzkuNHMtNjMuMi0xNC4zLTg0LTM5LjRjLTguNS0xMC4yLTIzLjctMTEuNS0zMy44LTMuMS0xMC4yIDguNS0xMS41IDIzLjYtMy4xIDMzLjggMzAgMzYgNzQuMSA1Ni42IDEyMC45IDU2LjZzOTAuOS0yMC42IDEyMC45LTU2LjZjOC41LTEwLjIgNy4xLTI1LjMtMy4xLTMzLjh6TTE2OCAyNDBjMTcuNyAwIDMyLTE0LjMgMzItMzJzLTE0LjMtMzItMzItMzItMzIgMTQuMy0zMiAzMiAxNC4zIDMyIDMyIDMyem0xNjAtNjBjLTI1LjcgMC01NS45IDE2LjktNTkuOSA0Mi4xLTEuNyAxMS4yIDExLjUgMTguMiAxOS44IDEwLjhsOS41LTguNWMxNC44LTEzLjIgNDYuMi0xMy4yIDYxIDBsOS41IDguNWM4LjUgNy40IDIxLjYuMyAxOS44LTEwLjgtMy44LTI1LjItMzQtNDIuMS01OS43LTQyLjF6Ij48L3BhdGg+PC9zdmc+" | |
const svg2img2 = new SVG2IMG(canvas2.canvas, uriData) | |
svg2img2.Build("SmileWink.png") | |
// Test 3: Exists SVG | |
ImportFontAwesome() | |
const range = document.createRange() | |
const fragSmile = range.createContextualFragment(`<i class="far fa-smile" style="background-color:black;color:yellow"></i>`) | |
document.querySelector(`body`).append(fragSmile) | |
// use MutationObserver wait the fontawesome convert ``<i class="far fa-smile"></i>`` to SVG. If you write the element in the HTML, then you can skip this hassle way. | |
const observer = new MutationObserver((mutationRecordList, observer) => { | |
for (const mutation of mutationRecordList) { | |
switch (mutation.type) { | |
case "childList": | |
const targetSVG = mutation.target.querySelector(`svg`) | |
if (targetSVG !== null) { | |
const canvas3 = new Canvas(64, 64) // 👈 Focus here. The part of the observer is not important. | |
const svg2img3 = new SVG2IMG(canvas3.canvas, SVG2IMG.Convert2URIData(targetSVG)) | |
svg2img3.Build("Smile.png") | |
targetSVG.remove() // This SVG is created by font-awesome, and it's an extra element. I don't want to see it. | |
observer.disconnect() | |
return | |
} | |
} | |
} | |
}) | |
observer.observe(document.querySelector(`body`), {childList: true}) | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment