import { createCanvas, loadImage } from 'canvas'; import fs from 'fs'; import { exec } from 'child_process'; async function overlayImage(time_string, index, total) { let imageHeight = 479; let imageWidth = 853; let ctx = createCanvas(imageWidth, imageHeight).getContext('2d'); let bg = await loadImage('bg.png') ctx.globalAlpha = 1; ctx.drawImage(bg, 0, 0, imageWidth, imageHeight) let overlay = await loadImage('images/raw/' + time_string + '.png') ctx.globalAlpha = 0.6; ctx.drawImage(overlay, 0, 0, imageWidth, imageHeight) let text = time_string.substring(8, 10) + ':' + time_string.substring(10, 12); ctx.font = 'bold 70px sans-serif'; ctx.fillStyle = 'rgba(0,0,0,0.7)'; ctx.globalAlpha = 0.9; ctx.fillText(text, imageWidth - 250, imageHeight - 40); ctx.fillStyle = 'rgba(56, 64, 219, 0.7)'; console.log(index, total); ctx.fillRect(0, imageHeight - 20, imageWidth * (index / total) , 20); return ctx.canvas.toBuffer("image/png"); } async function generateFinalImages() { //Clear out the final images directory let final_files = fs.readdirSync('images/final'); for (let file of final_files) { fs.unlinkSync(`images/final/${file}`); } let files = fs.readdirSync('images/raw'); let i = 0; for (let file of files) { let time_string = file.split('.')[0]; let final_image = await overlayImage(time_string, i, files.length - 1); fs.writeFileSync(`images/final/${i}.png`, final_image); i++; } } export async function createVideo() { await generateFinalImages(); //remove video try { fs.unlinkSync('out/output.gif'); } catch (error) { console.log('No video to delete'); } //run the command ffmpeg -framerate 5 -i %d.png -c:v libx264 -r 30 output.mp4 return new Promise((resolve, reject) => { exec('ffmpeg -framerate 5 -i images/final/%d.png -vf "fps=5,tpad=stop_mode=clone:stop_duration=2,scale=853:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 out/output.gif', (err, stdout, stderr) => { if (err) { reject(err); return; } resolve(stdout); }); }); }