Last active
January 31, 2025 21:20
-
-
Save julientaq/607076399499191957172dbb1bd55635 to your computer and use it in GitHub Desktop.
Pagedjs animated webP to set of images.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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