@someaspy/pet-pet-gif
Version:
Given an avatar, generate a petting gif (known as "petpet" or "pet the").
37 lines (36 loc) • 1.77 kB
JavaScript
import { resolve } from "node:path";
import { buffer } from "node:stream/consumers";
import { createCanvas, loadImage, } from "@napi-rs/canvas";
import { GifEncoder } from "@skyra/gifenc";
const FRAMES = 10;
const petGifCache = [];
export default async function petPetGif(avatarURL, options = { resolution: 128, delay: 20, backgroundColor: null }) {
const encoder = new GifEncoder(options.resolution, options.resolution);
const outputStream = encoder.createReadStream();
encoder.start();
encoder.setRepeat(0);
encoder.setDelay(options.delay);
encoder.setTransparent(0);
const canvas = createCanvas(options.resolution, options.resolution);
const ctx = canvas.getContext("2d");
const avatar = await loadImage(avatarURL);
for (let i = 0; i < FRAMES; i++) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (options.backgroundColor) {
ctx.fillStyle = options.backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
const j = i < FRAMES / 2 ? i : FRAMES - i;
const width = 0.8 + j * 0.02;
const height = 0.8 - j * 0.05;
const offsetX = (1 - width) * 0.5 + 0.1;
const offsetY = 1 - height - 0.08;
if (i === petGifCache.length)
petGifCache.push(await loadImage(resolve(import.meta.dirname, `../img/pet${i.toString()}.gif`)));
ctx.drawImage(avatar, options.resolution * offsetX, options.resolution * offsetY, options.resolution * width, options.resolution * height);
ctx.drawImage(petGifCache[i], 0, 0, options.resolution, options.resolution);
encoder.addFrame(ctx.getImageData(0, 0, canvas.width, canvas.height).data);
}
encoder.finish();
return await buffer(outputStream);
}