Skip to content

Commit

Permalink
Add ability to download icons as PNG files
Browse files Browse the repository at this point in the history
  • Loading branch information
quentin-st committed Oct 25, 2022
1 parent 58a6e43 commit ea0ca88
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 11 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"canvg": "^4.0.1",
"core-js": "^3.6.5",
"material-scss-colors": "^1.1.2",
"vue": "^3.0.0",
Expand Down
57 changes: 47 additions & 10 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,34 @@
</template>
</overflow-menu>

<button @click="downloadSvg" type="button" :disabled="!activeIconSvg">
<i class="mdi mdi-download"></i>
{{ actionLabels['download-svg'] }}
</button>
<overflow-menu
ref="overflow-download"
:on-open="() => this.openOverflowMenu = this.$refs['overflow-download']"
:on-close="() => this.openOverflowMenu = null"
x="right"
y="bottom"
>
<div @click="download('png')">
<i class="mdi mdi-file-png-box"></i>
<div>
{{ actionLabels['download-png'] }}<br />
<small>{{ activeIcon && activeIcon.name }}.png</small>
</div>
</div>
<div @click="download('svg')">
<i class="mdi mdi-file-xml-box"></i>
<div>
{{ actionLabels['download-svg'] }}<br />
<small>{{ activeIcon && activeIcon.name }}.png</small>
</div>
</div>
<template v-slot:button="slotProps">
<button type="button" @click="slotProps.setOpen()">
<i class="mdi mdi-download"></i>
Download&hellip;
</button>
</template>
</overflow-menu>
</div>
</footer>
</transition>
Expand Down Expand Up @@ -262,6 +286,7 @@ import {objectChunk} from '@/helpers/array';
import {getWeight} from '@/helpers/search';
import Toast from '@/components/Toast.vue';
import {prefersDarkColorScheme} from '@/helpers/theme';
import {svgToPng} from '@/helpers/img';
const SETTINGS = {
ACCENT_COLOR: 'color-accent',
Expand All @@ -287,6 +312,7 @@ const ACTIONS_LABELS = {
'svg-path': 'Copy SVG path',
'markdown-preview': 'Copy markdown preview',
'download-svg': 'Download SVG',
'download-png': 'Download PNG',
} as Record<Action, string>;
const searchReplaceRegex = new RegExp('-', 'g');
Expand Down Expand Up @@ -440,9 +466,11 @@ export default defineComponent({
},
doAction(action: Action): void {
if (action === 'download-svg') {
this.downloadSvg();
} else {
this.copy(action);
this.download('svg');
} else if (action === 'download-png') {
this.download('png')
} {
this.copy(action as Copy);
}
},
copy(what: Copy): void {
Expand Down Expand Up @@ -486,7 +514,7 @@ export default defineComponent({
this.toast('Copied to clipboard');
},
downloadSvg(): void {
async download(format: 'svg'|'png'): Promise<void> {
if (this.activeIcon === null) {
return;
}
Expand All @@ -503,8 +531,15 @@ export default defineComponent({
}
const blob = new Blob([svg], {type: "image/svg+xml"});
const url = URL.createObjectURL(blob);
const filename = this.activeIcon.name+'.svg';
let url;
if (format === 'png') {
url = await svgToPng(svg);
} else {
url = URL.createObjectURL(blob);
}
const filename = `${this.activeIcon.name}.${format}`;
const browserApi = getBrowserInstance();
browserApi && browserApi.downloads.download({
Expand All @@ -513,6 +548,8 @@ export default defineComponent({
});
this.toast(`Downloaded ${filename}`);
// Close overflow menu once done
this.openOverflowMenu && this.openOverflowMenu.close();
},
selectText(e: Event): void {
// Find .icon-usage
Expand Down
2 changes: 1 addition & 1 deletion src/enums.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@

export type Copy = 'svg'|'svg-path'|'name'|'markdown-preview'|'desktop-font-icon'|'codepoint';
export type Action = Copy|'download-svg';
export type Action = Copy|'download-svg'|'download-png';
17 changes: 17 additions & 0 deletions src/helpers/img.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Img helper
*/

import {Canvg} from 'canvg';

export const svgToPng = async (svg: string, size = 512): Promise<string> => {
const canvas = document.createElement('canvas');
canvas.width = canvas.height = size;
const ctx = canvas.getContext('2d');
if (ctx === null) {
throw new Error();
}
const v = await Canvg.fromString(ctx, svg);
await v.render();
return canvas.toDataURL("image/png");
};
44 changes: 44 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,11 @@
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==

"@types/offscreencanvas@^2019.6.4":
version "2019.7.0"
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz#e4a932069db47bb3eabeb0b305502d01586fa90d"
integrity sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==

"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
Expand All @@ -1147,6 +1152,11 @@
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==

"@types/raf@^3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@types/raf/-/raf-3.4.0.tgz#2b72cbd55405e071f1c4d29992638e022b20acc2"
integrity sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==

"@types/range-parser@*":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
Expand Down Expand Up @@ -2576,6 +2586,18 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001254:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001256.tgz#182410b5f024e0ab99c72ec648f234a9986bd548"
integrity sha512-QirrvMLmB4txNnxiaG/xbm6FSzv9LqOZ3Jp9VtCYb3oPIfCHpr/oGn38pFq0udwlkctvXQgPthaXqJ76DaYGnA==

canvg@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/canvg/-/canvg-4.0.1.tgz#122532dffeff6fc36074582af2cd37c454ae9ffa"
integrity sha512-5gD/d6SiCCT7baLnVr0hokYe93DfcHW2rSqdKOuOQD84YMlyfttnZ8iQsThTdX6koYam+PROz/FuQTo500zqGw==
dependencies:
"@types/offscreencanvas" "^2019.6.4"
"@types/raf" "^3.4.0"
raf "^3.4.1"
rgbcolor "^1.0.1"
stackblur-canvas "^2.0.0"
svg-pathdata "^6.0.3"

case-sensitive-paths-webpack-plugin@^2.3.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
Expand Down Expand Up @@ -7374,6 +7396,13 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==

raf@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
dependencies:
performance-now "^2.1.0"

randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
Expand Down Expand Up @@ -7669,6 +7698,11 @@ rgba-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=

rgbcolor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/rgbcolor/-/rgbcolor-1.0.1.tgz#d6505ecdb304a6595da26fa4b43307306775945d"
integrity sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==

rimraf@2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
Expand Down Expand Up @@ -8210,6 +8244,11 @@ stable@^0.1.8:
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==

stackblur-canvas@^2.0.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz#aa87bbed1560fdcd3138fff344fc6a1c413ebac4"
integrity sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==

stackframe@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.0.tgz#52429492d63c62eb989804c11552e3d22e779303"
Expand Down Expand Up @@ -8418,6 +8457,11 @@ svg-inline-loader@^0.8.2:
object-assign "^4.0.1"
simple-html-tokenizer "^0.1.1"

svg-pathdata@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/svg-pathdata/-/svg-pathdata-6.0.3.tgz#80b0e0283b652ccbafb69ad4f8f73e8d3fbf2cac"
integrity sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==

svg-tags@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
Expand Down

0 comments on commit ea0ca88

Please sign in to comment.