Closed Katreque closed 1 year ago
Judging purely on those thumbnails, the striped/noisy ones are likely from putting, for instance, 10x10 image data inside of a 20x20 image. setImageData takes your word for it on if the data provided matches the width/height provided. The thing with WebP animations is that every frame can have its own width/height and x/y offset within the overall animation size. As for the white squares... that's likely an artifact from an optimizing algorithm since the frames are generally (but not always) drawn on top of previous frame, and those squares are probably transparent. Saves some on the file size.
This library isn't really for extracting rendered frames, only raw ones in this context. You could use ImageMagick or node-canvas to construct rendered frames from them relatively easily. With node-canvas, something like below could work.
const { createImageData, createCanvas } = require('canvas'), { Image } = require('node-webpmux');
let canvas = createCanvas(anim.width, anim.height), ctx = canvas.getContext('2d');
let anim = new Image(), output;
/* ..... */
await Image.initLib();
await anim.load(path);
output = await Image.getEmptyImage();
canvas.fillStyle = `rgba(${anim.bgColor.join(',')})`;
for (let i = 0, { frameCount, frames } = anim; i < frameCount; i++) {
let frame = frames[i], data = createImageData(await anim.getFrameData(i), frame.width, frame.height);
// clear the frame back to anim.bgColor if needed
if (frame.dispose) { ctx.clearRect(0, 0, anim.width, anim.height); ctx.fillRect(0, 0, anim.width, anim.height); }
// blend with alpha or draw directly over
if (frame.blend) { ctx.globalAlpha = 1.0; } else { ctx.globalAlpha = 0.0; }
// draw the frame at the frame's offset
ctx.putImageData(data, frame.x, frame.y);
data = ctx.getImageData(0, 0, anim.width, anim.height);
await output.setImageData(data, { width: anim.width; height: anim.height }); // set other options as desired
await output.save(framePath);
}
This is only an example, though - I can't guarantee the above code works (I didn't test it) but it gets the idea across if you have a better/easier library for image drawing.
Thanks for the insight. Helped me a lot!
I used Sharp to get the frames as it can return a buffer. I did what a needed to the buffers then I saved to a array after running generateFrame. Then I a recreate the animations from scratch using Webp.Image.save and the array of frames.
All good! Thanks again.
@ApeironTsuka I am trying to extract a frame from an animated webp this way:
const fs = require('fs');
const WebP = require('node-webpmux');
async function extractFrame() {
const img = new WebP.Image();
const filePath = 'anim12.webp';
const frame1Path = 'frame1.webp';
await img.load(filePath);
await img.demux(frame1Path, { frame: 3 });
}
extractFrame().catch(console.error);
But it doesn't save anything in that folder. What am I doing wrong?
@DanielZanchi
The syntax to demux() is incorrect here for this usage, you'll want img.demux({ path: '.', frame: 3 })
and the output will be named 'anim12_3.webp'. demux() is mainly for extract frames into predictable names. You can, though I don't recommend it[1], directly use await img._demuxFrame(frame1Path, img.frames[3])
to have more direct control over what the filename is.
[1]. I may break it in the future, but I currently don't plan to. Functions starting with _ are considered private, rather than using the more modern private syntax in order to keep support with older Node versions that don't have support for private member functions.
@DanielZanchi The syntax to demux() is incorrect here for this usage, you'll want
img.demux({ path: '.', frame: 3 })
and the output will be named 'anim12_3.webp'. demux() is mainly for extract frames into predictable names. You can, though I don't recommend it[1], directly useawait img._demuxFrame(frame1Path, img.frames[3])
to have more direct control over what the filename is.[1]. I may break it in the future, but I currently don't plan to. Functions starting with _ are considered private, rather than using the more modern private syntax in order to keep support with older Node versions that don't have support for private member functions.
Thanks, that works. In the readme the syntax is different.
Hello!
I'm trying to extract the frames from a animation using this:
I get the frames, but mostly all of them are buggy:
I tried to use the demux. The noisy frames were fixed but the ones with white squares were not. However, I still want to use the setImageData because of the options its offers.
Am I doing something wrong?
I'm using the 3.1.3 version and node 16.18.0. (Using node 18.12.1 and 19.0.0, the initLib doesn't work. Looks like a problem with node's builtin fetch)