Skip to content

Instantly share code, notes, and snippets.

@julientaq
Last active January 31, 2025 21:20
Show Gist options
  • Save julientaq/607076399499191957172dbb1bd55635 to your computer and use it in GitHub Desktop.
Save julientaq/607076399499191957172dbb1bd55635 to your computer and use it in GitHub Desktop.
Pagedjs animated webP to set of images.
// YOU NEED TO USE CSSTREE.JS if you want to define the videos through css => https://www.npmjs.com/package/csstree
// if in the css, an animated webP has a css: "--pagedjs-contact: xx", then it will be transformed into a bunch of images, up to the css to define the grid.
class webp2contact extends Paged.Handler {
constructor(chunker, polisher, caller) {
super(chunker, polisher, caller);
this.toContact = [];
}
// do it here
onDeclaration(declaration, dItem, dList, rule) {
if (declaration.property == "--pagedjs-contact") {
let sel = csstree.generate(rule.ruleNode.prelude);
sel = sel.replace('[data-id="', "#");
sel = sel.replace('"]', "");
this.toContact.push({ selector: sel, value: declaration.value });
}
}
// run when pagedjs is done
afterRendered() {
this.toContact.forEach((obj) => {
document.querySelectorAll(`${obj.selector}`).forEach(async (el) => {
if (!el.tagName == "IMG") return console.log(`${el} is not a img`);
let frames = await extractWebPFramesAtIntervalsBis(el, obj.value.value);
// let contact = document.createElement("div");
let contact = el.closest("figure");
frames.forEach((frameUrl) => {
const img = document.createElement("img");
img.src = frameUrl;
contact.appendChild(img);
});
contact.style.setProperty("--frames", frames.length);
el.closest("figure").classList.add("contact");
el.insertAdjacentElement("beforebegin", contact);
el.remove();
});
});
}
}
Paged.registerHandlers(webp2contact);
async function extractWebPFramesAtIntervalsBis(imgElement, numFrames) {
// for now i’m not using the num frames, but we could get the total amount of frame, divide it by the numframes and only add an image if the frame is in the numFrame
if (!("ImageDecoder" in window)) {
throw new Error("Your browser does not support ImageDecoder.");
}
// Fetch the WebP image as a Blob
const response = await fetch(imgElement.src);
const fileBlob = await response.arrayBuffer();
// Decode WebP animation
const decoder = new ImageDecoder({ data: fileBlob, type: "image/webp" });
await decoder.tracks.ready;
const track = decoder.tracks.selectedTrack;
numFrames = track.frameCount;
let frames = [];
for (let i = 0; i < numFrames; i++) {
try {
const frame = await decoder.decode({ frameIndex: i });
// Draw frame to canvas
const canvas = new OffscreenCanvas(
frame.image.displayWidth,
frame.image.displayHeight,
);
const ctx = canvas.getContext("2d");
ctx.drawImage(frame.image, 0, 0);
// Convert to PNG Blob
const blob = await canvas.convertToBlob({ type: "image/png" });
frames.push(URL.createObjectURL(blob));
console.log(`Frame ${i + 1}`);
frame.image.close(); // Free memory
} catch (error) {
console.error(`Error decoding frame ${i + 1}`, error);
}
}
return frames;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment