ApeironTsuka / node-webpmux

A mostly 1:1 re-implementation of webpmux as a Node module in pure Javascript. Only thing currently missing is a command-line version.
GNU Lesser General Public License v3.0
21 stars 8 forks source link

Extracting individual frames from Webp animation #13

Closed 2chivi closed 3 years ago

2chivi commented 3 years ago

This isn't great git etiquette, but I wanted to ask someone familiar with webpmux / js.

Basically, what I'm trying to do is convert lossy WEBP animations to html-canvas. That means extracting individual frames from a webp animation. I believe the library has the power to do what I'm looking for... I'm just not sure what steps/commands I should be using.

I'm able to extract individual frames from Lossless webp animations, but not lossy webp animations.

How do I get readable individual frame-data from a lossy webp animation?

ApeironTsuka commented 3 years ago

If you're simply wanting to dump all the frames to files (such as dumping "anim.webp" to "anim_1.webp", "anim_2.webp", etc), then...

let webp = new WebP.Image();
await webp.load('anim.webp');
await webp.demux('path/to/where/you/want/them'); // for 2.0.x
// await webp.demux({ path: 'path/to/where/you/want/them' }); // for 3.x, coming soon-ish

or for dumping them to an array of Buffers instead.. let frames = await webp.demuxToBuffers(); (for 2.0.x, currently in NPM) let frames = await webp.demux({ buffers: true }); (for 3.x, coming soon-ish) Both of these should generate valid, standard WEBP images.

If this approach is working for lossless but not lossy frames, then I'll need to look into that.

Alternatively, if what you're after is the raw pixel data rather than specifically the frames as WEBP images, you can do...

await webp.initLib(); // only needed once for each WebP.Image instance, even across .load() calls
// await Image.initLib(); // for 3.x
for (let i = 0, l = webp.frames.length; i < l; i++) {
  let rawPixels = await webp.getFrameData(i);
  // rawPixels being a Buffer of size webp.width * webp.height * 4, in RGBA order
}
2chivi commented 3 years ago

Hey, Thanks for getting back to me.

Please refer to the following two WEBP animations I'm using as examples.

Example 1.) Lossy https://cdn.7tv.app/emote/609f4f7c326f0aaa85b649f8/2x

Example 2.) Lossless https://cdn.7tv.app/emote/6084b792fcf1f9923f6cf442/2x

I attempted using await webp.demuxToBuffers() on either of these webp files, and was given back a tiny Buffer-Array, that didnt' contain any image data that could be read. They were like 12-bytes long?

I then used await webp.getFrameData(i) and got readable Buffer data that could be read for my Lossless example, but not for my Lossy example. My Lossless images looked fine.. but my lossy images looked corrupted / missing data : https://imgur.com/a/u7ITciO

So, I'm still unable to get image-frame data from lossy animations.

Edit: await webp.demux('path/to/where/you/want/them'); is also not working for the lossy animation. returns corrupted files.

ApeironTsuka commented 3 years ago

Pushed 3.0.0 (minor breaking API changes that affect this, detailed at the bottom of the README).

In my testing, I couldn't reproduce the issue with .getFrameData() nor with .demux({ buffers: true }) giving effectively empty images, so it's possible I inadvertently fixed that already somehow. However, I did fix the corrupt images .demux() was returning.

Give it a test on your end in case it's a "well, it works on my machine.." type of thing.

2chivi commented 3 years ago

I downloaded your latest version from GIT, instead of using NPM, and I think my issues are resolved.

Thanks.

ApeironTsuka commented 3 years ago

Awesome! I'll push 3.0.0 to NPM, then.