const fs = require("fs"); const path = require('path'); const { PNG } = require("pngjs"); // Constants const IMAGES_ROOT = path.join(...[ '.', 'assets', 'characters', 'penny', 'Sample sets', 'Mouth' ]); const FILE_OUT = path.join(...[ '.', 'assets', 'characters', 'penny', 'textures', 'mouth.png' ]) // Code const imageLoad = (image) => new Promise(resolve => { fs.createReadStream(image) .pipe(new PNG({ filterType: 4 })) .on("parsed", function () { // Normalize const pixels = []; for(let y = 0; y < this.height; y++) { for(let x = 0; x < this.width; x++) { const idx = (this.width * y + x) << 2; const r = this.data[idx]; const g = this.data[idx + 1]; const b = this.data[idx + 2]; const a = this.data[idx + 3]; pixels.push({ r, g, b, a }); } } resolve({ pixels, width: this.width, height: this.height }); }) ; }); const imageWrite = (image, file) => new Promise(resolve => { const png = new PNG({ width: image.width, height: image.height }); png.width = image.width; png.height = image.height; for(let y = 0; y < image.height; y++) { for(let x = 0; x < image.width; x++) { const i = (image.width * y + x); const idx = i << 2; const pixel = image.pixels[i]; png.data[idx] = pixel.r; png.data[idx + 1] = pixel.g; png.data[idx + 2] = pixel.b; png.data[idx + 3] = pixel.a; } } png.pack().pipe(fs.createWriteStream(file)) .on('close', () => resolve(true)) ; }); (async () => { const files = fs.readdirSync(IMAGES_ROOT); let stitched = null; let k = 0; for(let i = 0; i < files.length; i++) { const filePath = path.join(IMAGES_ROOT, files[i]); const image = await imageLoad(filePath); if(!stitched) { stitched = { width: image.width, height: image.height * files.length, pixels: Array(image.width*image.height*files.length) } } for(let j = 0; j < image.pixels.length; j++) { stitched.pixels[j + (i * image.width * image.height)] = { ...image.pixels[j] }; } }; console.log('Writing'); await imageWrite(stitched, FILE_OUT); })().catch(console.error);