Skip to content

Instantly share code, notes, and snippets.

@HackJack-101
Created January 23, 2022 19:56
Show Gist options
  • Save HackJack-101/cd4f38dcdd92ffdc49e7ad240f20bcfe to your computer and use it in GitHub Desktop.
Save HackJack-101/cd4f38dcdd92ffdc49e7ad240f20bcfe to your computer and use it in GitHub Desktop.
A Node.js script to generate a sprite file compatible with mapbox from multiple png files
const { createCanvas, loadImage } = require('canvas');
const path = require('path');
const { readdir } = require('fs').promises;
const { writeFileSync } = require('fs');
const sizeOf = require('image-size');
const spritesFolder = path.join(__dirname, '..', 'src', 'assets', 'sprites');
const outputFolder = path.join(__dirname, '..', 'public', 'assets', 'sprites');
const shapePadding = 5;
const borderPadding = 5;
const pixelRatio = 2;
async function getFiles(dir) {
const dirents = await readdir(dir, { withFileTypes: true });
const files = await Promise.all(
dirents.map((dirent) => {
const res = path.resolve(dir, dirent.name);
return dirent.isDirectory() ? getFiles(res) : res;
}),
);
return Array.prototype.concat(...files);
}
function writeSpriteJSON(images) {
const output = images.reduce((acc, image) => {
acc[image.name] = {
x: image.x,
y: image.y,
height: image.height,
width: image.width,
pixelRatio,
};
return acc;
}, {});
writeFileSync(path.join(outputFolder, 'sprites.json'), JSON.stringify(output, null, 4));
}
getFiles(spritesFolder)
.then(async (files) => {
let incrementalX = borderPadding;
let y = borderPadding + shapePadding;
const images = files
.filter((file) => {
return path.extname(file) === '.png';
})
.map((file) => {
const { height, width } = sizeOf(file);
const img = {
path: file,
name: file.substring(spritesFolder.length + 1),
height,
width,
x: incrementalX + shapePadding,
y,
};
incrementalX += shapePadding * 2 + width;
return img;
});
writeSpriteJSON(images);
const canvasHeight =
images.reduce((maxHeight, file) => {
return file.height > maxHeight ? file.height : maxHeight;
}, 0) +
borderPadding * 2 +
shapePadding * 2;
const canvasWidth =
images.reduce((totalWidth, file) => {
return totalWidth + file.width + shapePadding * 2;
}, 0) +
borderPadding * 2;
const canvas = createCanvas(canvasWidth, canvasHeight);
const ctx = canvas.getContext('2d');
await Promise.all(
images.map((file) => {
return loadImage(file.path).then((image) => {
ctx.drawImage(image, file.x, file.y);
});
}),
);
return canvas;
})
.then((canvas) => {
const dataUrl = canvas.toDataURL();
const buffer = Buffer.from(dataUrl.split(',')[1], 'base64');
writeFileSync(path.join(outputFolder, 'sprites.png'), buffer);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment