Generate PWA assets and splash screens from Logo image

Handy script to generate all mobile assets and favicon related to Progressive Web Applications based on a logo image

NOTE: works best if the logo is square shaped.

// Shortcut: command option p
// Menu: P.I.G
// version: 1.0.0
// Description: 🌆 Generate favicons, assets and splash screens for Progressive Web Apps
// Author: Pramod Jingade
// Twitter: @avj2352
import "@johnlindquist/kit";
const Jimp = await npm("jimp");
// allowed file extensions
const allowImageExtensions: string[] = [".png", ".jpg"];
// Read source icon
let imagePath: string = await getSelectedFile();
if (!imagePath || imagePath === "")
imagePath = await selectFile(`Choose icon to generate PWA assets:`);
// Check if extension is .PNG or .JPG
let extension: string = path.extname(imagePath);
// guard check - extension
while (!allowImageExtensions.includes(extension)) {
let fileName: string = path.basename(imagePath);
imagePath = await selectFile(`${fileName} wasn't an image:`);
if (!imagePath) {
exit();
}
// get file extension
extension = path.extname(imagePath);
}
// Create image list - android
const createAndroidImageList: Promise<string>[] = [
createImage(imagePath, 16, "android"),
createImage(imagePath, 32, "android"),
createImage(imagePath, 72, "android"),
createImage(imagePath, 96, "android"),
createImage(imagePath, 128, "android"),
createImage(imagePath, 144, "android"),
createImage(imagePath, 152, "android"),
createImage(imagePath, 192, "android"),
createImage(imagePath, 384, "android"),
createImage(imagePath, 512, "android"),
];
// Create image list - windows
const creaeMicrosoftImageList: Promise<string>[] = [
createImage(imagePath, 70, "ms-icon"),
createImage(imagePath, 150, "ms-icon"),
createImage(imagePath, 310, "ms-icon"),
];
// Create image list - iOS
const createiOSImageList: Promise<string>[] = [
createImage(imagePath, 120, "ios"),
createImage(imagePath, 152, "ios"),
createImage(imagePath, 167, "ios"),
createImage(imagePath, 180, "ios"),
createImage(imagePath, 192, "ios"),
createImage(imagePath, 512, "ios"),
];
// Create splash screens
const createSplashScreenList: Promise<string>[] = [
createSplashScreenWithLogo(imagePath, 1536, 2048),
createSplashScreenWithLogo(imagePath, 2436, 1125),
createSplashScreenWithLogo(imagePath, 1620, 2160),
createSplashScreenWithLogo(imagePath, 2532, 1170),
createSplashScreenWithLogo(imagePath, 1668, 2224),
createSplashScreenWithLogo(imagePath, 1668, 2388),
createSplashScreenWithLogo(imagePath, 2688, 1242),
createSplashScreenWithLogo(imagePath, 2732, 2048),
createSplashScreenWithLogo(imagePath, 1125, 2436),
createSplashScreenWithLogo(imagePath, 1792, 828),
createSplashScreenWithLogo(imagePath, 2778, 1284),
createSplashScreenWithLogo(imagePath, 1136, 640),
createSplashScreenWithLogo(imagePath, 2046, 1536),
createSplashScreenWithLogo(imagePath, 1170, 2532),
createSplashScreenWithLogo(imagePath, 2048, 2732),
createSplashScreenWithLogo(imagePath, 750, 1334),
createSplashScreenWithLogo(imagePath, 1242, 2208),
createSplashScreenWithLogo(imagePath, 2160, 1620),
createSplashScreenWithLogo(imagePath, 828, 1792),
createSplashScreenWithLogo(imagePath, 1242, 2688),
createSplashScreenWithLogo(imagePath, 2208, 1242),
createSplashScreenWithLogo(imagePath, 1284, 2778),
createSplashScreenWithLogo(imagePath, 2224, 1668),
createSplashScreenWithLogo(imagePath, 1334, 750),
createSplashScreenWithLogo(imagePath, 2388, 1668),
];
// Create favicon
createFavicon(imagePath);
// Create assets
Promise.all(createAndroidImageList);
Promise.all(creaeMicrosoftImageList);
Promise.all(createiOSImageList);
Promise.all(createSplashScreenList);
/**
* Reusable function to create image
* @param {string} imagePath - complete file path
* @param {number} width - width of image
*/
async function createImage(
imagePath: string,
width: number,
folder: string = "android"
): Promise<string> {
let image = await Jimp.read(imagePath);
const dirName: string = path.parse(imagePath).dir;
const newHeight = Math.floor(
image.bitmap.height * (width / image.bitmap.width)
);
const resizedImageName = `${folder}-icon-${width}x${width}${extension}`;
await image
.resize(width, newHeight)
.write(`${dirName}/${folder}/${resizedImageName}`);
return `Created image: ${imagePath}-${width}${extension}`;
}
/**
* Create splash screen with logo in center
* @param {string} imagePath - complete file path
* @param {number} canvasWidth - width of splash screen
* @param {number} canvasHeight - height of splash screen
*/
async function createSplashScreenWithLogo(
imagePath: string,
canvasWidth: number,
canvasHeight: number,
color = "#FFFFFF",
folder = "ios"
): Promise<string> {
const dirName: string = path.parse(imagePath).dir;
const resizedImageName = `${folder}-splash-${canvasWidth}x${canvasHeight}${extension}`;
let image = await Jimp.read(imagePath);
const imageCanvas = new Jimp(canvasWidth, canvasHeight, color);
// composite
imageCanvas
.composite(
image,
alignImageCenter(canvasWidth, image.bitmap.width),
alignImageCenter(canvasHeight, image.bitmap.height)
)
.write(`${dirName}/${folder}/${resizedImageName}`);
return `Created splash screen!`;
}
/**
* util function to offset image to the center of canvas
* @param {number} canvasSize
* @param {number} imageSize
* @returns {number} offset size
*/
function alignImageCenter(canvasSize: number, imageSize: number): number {
return (canvasSize - imageSize) / 2;
}
/**
* Create favicon.ico file at the root of the folder
* @param {string} imagePath
*/
async function createFavicon(imagePath: string) {
const dirName: string = path.parse(imagePath).dir;
let image = await Jimp.read(imagePath);
const resizedImageName = `favicon.ico`;
await image.resize(16, 16).write(`${dirName}/${resizedImageName}`);
return `Created Favicon!`;
}