Last active
June 10, 2021 22:37
-
-
Save luveti/c92e2e533bf392d1d42166cff0a4e573 to your computer and use it in GitHub Desktop.
Generate iOS icons and splashscreen images from an svg, using nodejs and phantomjs.
This file contains hidden or 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
#!/usr/bin/env node | |
const path = require("path") | |
const fs = require("fs") | |
// https://gist.github.com/luveti/67a1c93be3d58b085f6c76ae876c556c | |
function installDeps(deps, quiet, cb) { | |
const hash = require('crypto').createHash('md5').update(__filename).digest('hex') | |
const dir = require('os').tmpdir() + require('path').sep + hash | |
try { | |
require('fs').mkdirSync(dir) | |
if (!quiet) console.log(`Created temp folder at "${dir}"`) | |
} catch (e) {} | |
try { | |
require('fs').writeFileSync(dir + require('path').sep + 'package.json', JSON.stringify({ | |
name: hash, description: hash, author: hash, repository: hash, license: "ISC", | |
dependencies: deps.reduce((p, c) => { p[c]='latest'; return p; }, {}) | |
})) | |
if (!quiet) console.log("Created package.json") | |
} catch (e) {} | |
if (!quiet) console.log("Ensuring dependencies are installed") | |
require('child_process').execSync(`cd ${dir} && npm install`) | |
cb.apply(undefined, deps.map(d => require(`${dir}/node_modules/${d}`.replace(/\\/g,'/')))) | |
} | |
if (process.argv.length == 2) | |
return console.log("Usage: node ios_img_gen.js <path to svg> <output directory> <prefix> <percentage> <background> <\"icons\"|\"splashscreens\">") | |
let argIndex = 2 | |
const inputSvgPath = process.argv[argIndex++] | |
const outputDirectory = process.argv[argIndex++] | |
const prefix = process.argv[argIndex++] | |
const percentage = process.argv[argIndex++] | |
const background = process.argv[argIndex++] | |
const task = process.argv[argIndex++] | |
if (inputSvgPath === undefined) | |
return console.error("Please provide an input svg") | |
if (prefix === undefined) | |
return console.error("Please provide a output file prefix") | |
if (percentage === undefined) | |
return console.error("Please provide a what percentage of the screen you want the icon to take up") | |
if (isNaN(parseInt(percentage))) | |
return console.error("Please provide a valid number for the percentage") | |
if (outputDirectory === undefined) | |
return console.error("Please provide an output directory") | |
if (background === undefined) | |
return console.error("Please provide a background, this is a css value like \"#00FF00\"") | |
if (task === undefined) | |
return console.error("Please provide a task, either \"icons\" or \"splashscreens\"") | |
if (task != "icons" && task != "splashscreens") | |
return console.error("Task must be either \"icons\" or \"splashscreens\"") | |
installDeps(["phantom"], false, (phantom) => { | |
const sourceBuffer = fs.readFileSync(path.resolve(inputSvgPath)) | |
const iconNameAndSizes = [ | |
["-60@3x", 180], | |
["-60", 60], | |
["-60@2x", 120], | |
["-76", 76], | |
["-76@2x", 152], | |
["-40", 40], | |
["-40@2x", 80], | |
["", 57], | |
["@2x", 114], | |
["-72", 72], | |
["-72@2x", 144], | |
["-167", 167], | |
["-small", 29], | |
["-small@2x", 58], | |
["-50", 50], | |
["-50@2x", 100], | |
["-83.5@2x", 167], | |
] | |
const splashNameWidthAndHeights = [ | |
["~iphone", 320, 480], | |
["@2x~iphone", 640, 960], | |
["-Portrait~ipad", 768, 1024], | |
["-Portrait@2x~ipad", 1536, 2048], | |
["-Landscape~ipad", 1024, 768], | |
["-Landscape@2x~ipad", 2048, 1536], | |
["-568h@2x~iphone", 640, 1136], | |
["-667h", 750, 1334], | |
["-736h", 1242, 2208], | |
] | |
function renderImage(width, height, fileName) { | |
return new Promise((resolve, reject) => { | |
const html = ` | |
<html> | |
<head> | |
<style> | |
body { | |
margin: 0; | |
width: 100%; | |
height: 100%; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
display: -webkit-flex; | |
-webkit-align-items: center; | |
-webkit-justify-content: center; | |
background: ${background}; | |
} | |
svg { | |
width: ${percentage}%; | |
height: ${percentage}%; | |
} | |
</style> | |
</head> | |
<body>${sourceBuffer.toString().replace(/<\?(.*)\?>\n/g, '').replace(/<\?(.*)\?>/g, '')}</body> | |
</html> | |
` | |
let ph, page | |
phantom.create().then(i => ph = i) | |
.then(() => ph.createPage()).then(i => page = i) | |
.then(() => page.property("viewportSize", { width, height })) | |
.then(() => page.property("content", html)) | |
.then(() => new Promise((resolve, reject) => setTimeout(resolve, 2500))) | |
.then(() => page.render(path.resolve(outputDirectory, fileName))) | |
.then(() => ph.exit()) | |
.then(() => resolve()) | |
.catch((err) => reject(err)) | |
}) | |
} | |
if (task == "icons") { | |
function renderNextIcon() { | |
if (iconNameAndSizes.length == 0) return | |
let [name, size] = iconNameAndSizes.pop() | |
let fileName = `${prefix}${name}.png` | |
console.log(`Rendering "${fileName}" icon image`) | |
renderImage(size, size, fileName) | |
.then(() => renderNextIcon()) | |
.catch((err) => console.error(err)) | |
} | |
renderNextIcon() | |
} | |
else if (task == "splashscreens") { | |
function renderNextSplash() { | |
if (splashNameWidthAndHeights.length == 0) return | |
let [name, width, height] = splashNameWidthAndHeights.pop() | |
let fileName = `${[prefix]}${name}.png` | |
console.log(`Rendering "${fileName}" splashscreen image`) | |
renderImage(width, height, fileName) | |
.then(() => renderNextSplash()) | |
.catch((err) => console.error(err)) | |
} | |
renderNextSplash() | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment