Skip to content

Instantly share code, notes, and snippets.

@luveti
Last active June 10, 2021 22:37
Show Gist options
  • Save luveti/c92e2e533bf392d1d42166cff0a4e573 to your computer and use it in GitHub Desktop.
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.
#!/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