Last active
July 20, 2020 11:34
-
-
Save isair/aabe5ac37ea4ee92a900157acda7d4a3 to your computer and use it in GitHub Desktop.
ts-node script for converting all SVG files in a directory to @1x @2x @3x PNG files, files are processed in parallel for optimal performance
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
import path from 'path'; | |
import { exec } from 'child_process'; | |
import fse from 'fs-extra'; | |
import glob from 'glob-promise'; | |
import pLimit from 'p-limit'; | |
const imagesPath = path.resolve('./assets/svg'); | |
const outputPath = path.resolve('./assets/images'); | |
const concurrency = 2; // File count only. Actual parallelism is three times this. | |
function execAsync(command: string): Promise<string> { | |
return new Promise((resolve, reject) => { | |
exec(command, (error, stdout, stderr) => { | |
if (error) { | |
reject(error.message); | |
} else if (stderr) { | |
reject(stderr); | |
} else { | |
resolve(stdout); | |
} | |
}); | |
}); | |
} | |
async function convertSvgToPng(svgPath: string, scale: number) { | |
const svgBuffer = await fse.readFile(svgPath); | |
const svgString = svgBuffer.toString(); | |
const widthMatches = svgString.match(/ width="(\d+)(px)*"/); | |
const heightMatches = svgString.match(/ height="(\d+)(px)*"/); | |
const newWidth = | |
widthMatches && widthMatches.length > 1 | |
? Number(widthMatches[1]) * scale | |
: 300; | |
const newHeight = | |
heightMatches && heightMatches.length > 1 | |
? Number(heightMatches[1]) * scale | |
: 300; | |
const svgPathWithoutExtension = svgPath.slice(0, -4); | |
const svgName = svgPathWithoutExtension.substr( | |
svgPathWithoutExtension.lastIndexOf('/') + 1 | |
); | |
const scaleAnnotation = scale !== 1 ? `@${scale}x` : ''; | |
const pngPath = `${outputPath}/${svgName}${scaleAnnotation}.png`; | |
await execAsync( | |
`inkscape ${svgPath} -w ${newWidth} -h ${newHeight} --export-file ${pngPath}` | |
); | |
process.stdout.write('.'); | |
} | |
const convertSvgToPngBundle = async (svgPath: string) => | |
Promise.all([1, 2, 3].map((scale) => convertSvgToPng(svgPath, scale))); | |
async function run() { | |
await fse.ensureDir(imagesPath); | |
const svgPaths = await glob.promise(path.join(imagesPath, '**/*.svg')); | |
console.log( | |
`Converting ${svgPaths.length} SVG files in parallel, please wait` | |
); | |
const limit = pLimit(concurrency); | |
await Promise.all( | |
svgPaths.map((svgPath) => limit(() => convertSvgToPngBundle(svgPath))) | |
); | |
console.log('\nSuccessfully converted SVGs to PNGs'); | |
} | |
run().catch((error) => | |
console.error(`Failed to transform: ${error.toString()}`) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Assuming you are already in a TypeScript project with ts-node, install the following development dependencies:
Add the following script to your
package.json
after placing this script underscripts
:I'm using Inkscape as no NPM package I have tried has given as good results as the Inkscape CLI does.