ififfy / flipflip

Random slideshow of local images. Electron app for Mac/Windows/Linux
MIT License
159 stars 43 forks source link

Enhancement - Applying Scene "GIF Options" to Animated WEBP images #267

Open prof-m opened 3 years ago

prof-m commented 3 years ago

Background .webp is a relatively new image format, but one that many websites are switching over to using (where possible) due to it's noticeably smaller file size while still retaining the same quality as other image formats. In particular, because .webp images can be both stills and animated images, it is often being used as a replacement for .gif images.

Issue In the current iteration of FlipFlip, .webp images are displayed in scenes without issue. However, from a scene logic perspective, they're always treated the same as other still images, regardless of whether they're animated or still. The "GIF Options" logic (that allows GIF images to have different logic for display length than the base scene) does not apply to animated WEBP images.

How We Currently Apply Timing Logic to GIFs It looks like the way that we're able to have GIF-specific options in FlipFlip is largely due to the gif-info library. That library lets us derive two important bits of metadata from a GIF file (without having to first render the gif):

  1. The total number of frames in the GIF
  2. The delay between each frame of the GIF

With those two pieces of information, we're able to quickly calculate the total duration of a GIF in milliseconds, and apply whatever Scene logic is specified to affect how long a given GIF is displayed.

Solution Brainstorming Getting the same two pieces of information about a webp image in Javascript seems to be, well, difficult at the moment. But after a lot of googling and stack overflow spelunking, I did come across this nodeJS package - a javascript implementation of Google's C++ webpmux library.

I'm unsure how well the async loadBuffer() function would work here, but, if we could integrate it into FlipFlip (probably somewhere in the processInfo() function in ImagePlayer?), it looks like the Image object in this library should be able to tell us whether or not the WEBP image is animated, and, if it is, the number of frames and delay time!

The only two potential issues I can currently see are whether the async stuff will mess with FlipFlip's current synchronous processing, and whether calling this function on WEBP images would present a significant processing or memory increase. In the meantime, though, I figured I'd write down the results of the research I did here in case it's helpful!

StarrHelixx commented 3 years ago

I can't seem to get this nodeJS library to work with FlipFlip (seems to be an issue with the webpack, but I can't seem to figure out why or a solution). I've submitted an issue to their repo, so we'll see if they're able to help https://github.com/ApeironTsuka/node-webpmux/issues/8

prof-m commented 3 years ago

@StarrHelixx I could repro that same error you posted about there, just for confirmation. After the dev responded, though, I pulled down the latest code from their repo and it does seem to have addressed the issue we saw!

That said, in the classic programmer definition of "progress", we're now onto the next error:

    ERROR in ./node_modules/node-webpmux/webp.js 424:36
    Module parse failed: Unexpected character '#' (424:36)
    You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
    |   get iccp() { return this.data.extended ? this.data.extended.hasICCP ? this.data.iccp.raw : undefined : undefined; }
    |   set iccp(raw) {
    >     if (!this.data.extended) { this.#convertToExtended(); }
    |     if (raw === undefined) { this.data.extended.hasICCP = false; delete this.data.iccp; }
    |     else { this.data.iccp = { raw }; this.data.extended.hasICCP = true; }
     @ ./src/renderer/components/player/ImagePlayer.tsx 6:0-32 677:46-50
     @ ./src/renderer/components/player/SourceScraper.tsx
     @ ./src/renderer/components/player/Player.tsx
     @ ./src/renderer/components/Meta.tsx
     @ ./src/renderer/renderer.tsx

So basically, webpack doesn't like the # character - which is an issue, cause there are a bunch of methods and fields in that class that use it. With the caveat I'm definitely still new to TypeScript and am just kind of hacking away here without actually learning the basics, I did do a little looking into this. Apparently the # character in Javascript is slated to be/probably kind of already is the new way to make a method or field "private" in JS! (wild, absolutely wild)

From what I can tell from this issue on webpack's github, it seems to be "new" enough that support for it was only fairly recently included in the newer versions of webpack. There seem to be some ways to use babel for transpilation as an alternative? This is definitely a bit over my head at this point, but I figured I'd give you the info to see if you had any ideas for how you might wanna proceed!