Skip to content

Instantly share code, notes, and snippets.

@iamnotacoder-djs
Created December 21, 2022 08:32
Show Gist options
  • Save iamnotacoder-djs/5663a5ac2e501fdcb540fdf19a73e768 to your computer and use it in GitHub Desktop.
Save iamnotacoder-djs/5663a5ac2e501fdcb540fdf19a73e768 to your computer and use it in GitHub Desktop.
Add overlay to GIF file
const gifFrames = require('gif-frames'); // @1.0.1
const { createCanvas, loadImage } = require('canvas'); // @2.10.2
const GifEncoder = require('gif-encoder'); // 0.4.3
const fs = require("fs");
convertBanner();
async function convertBanner() {
const originalFrames = await gifFrames({ url: 'source.gif', frames: "all" }).catch(console.error);
if (!originalFrames) return;
// console.log(originalFrames[0]); // { getImage: [Function: getImage], frameIndex: 0, frameInfo: { x: 0, y: 0, width: 900, height: 540, has_local_palette: false, palette_offset: 13, palette_size: 256, data_offset: 890, data_length: 287127, transparent_index: null, interlaced: false, delay: 1, disposal: 0 } }
// return;
const canvasOverlay = createCanvas(originalFrames[0].frameInfo.width, originalFrames[0].frameInfo.height);
const contextOverlay = canvasOverlay.getContext('2d');
const date = new Date();
const targetDate = new Date(date.getFullYear(), 11, 31);
const remainingDays = Math.ceil( (targetDate.getTime() - date.getTime()) / (1000 * 60 * 60 * 24) );
const message = `До Нового Года ${remainingDays} ${dayPlural(remainingDays)}`;
contextOverlay.textAlign = 'left';
contextOverlay.font = `bold ${originalFrames[0].frameInfo.height * 0.1}px serif`;
contextOverlay.fillStyle = '#000';
contextOverlay.fillText(message, 52, originalFrames[0].frameInfo.height * 0.9+2);
contextOverlay.fillStyle = '#fff';
contextOverlay.fillText(message, 50, originalFrames[0].frameInfo.height * 0.9);
let frames = [];
for(let frame of originalFrames) {
const canvas = createCanvas(frame.frameInfo.width, frame.frameInfo.height);
const context = canvas.getContext('2d');
const frameImage = await loadImage(frame.getImage()._obj).catch(console.error);
if (frameImage) {
context.drawImage(frameImage, 0, 0, frame.frameInfo.width, frame.frameInfo.height);
context.drawImage(canvasOverlay, 0, 0, frame.frameInfo.width, frame.frameInfo.height);
frames.push(context.getImageData(0, 0, frame.frameInfo.width, frame.frameInfo.height).data);
}
}
const gif = new GifEncoder(originalFrames[0].frameInfo.width, originalFrames[0].frameInfo.height, { highWaterMark: 50 * 1024 * 1024 }); // highWaterMark устанавливает лимит нашего внутреннего буфера для нашего потока GIFEncoder. Также есть метод read() — это один из способов вывода содержимого из внутреннего буфера, что освобождает место для большего количества кадров.
const buffers = [];
gif.on('data', data => buffers.push(data));
gif.on('end', () => {
let file = Buffer.concat(buffers);
fs.writeFileSync('destination.gif', file);
// <Guild>.setBanner('./destination.gif').catch(console.error);
})
gif.writeHeader();
gif.setRepeat(0);
for(let frame of frames) {
gif.read(1024 * 1024 * 5);
gif.addFrame(frame);
}
gif.finish();
}
function dayPlural(number) {
if (number > 10 && [11, 12, 13, 14].includes(number%100)) return 'дней';
last_num = number%10;
if (last_num == 1) return 'день';
if ([2,3,4].includes(last_num)) return 'дня';
if ([5,6,7,8,9, 0].includes(last_num)) return 'дней';
}
@iamnotacoder-djs
Copy link
Author

source

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment