kirby icon indicating copy to clipboard operation
kirby copied to clipboard

Add frame option to ImageMagick Thumb Driver

Open tobimori opened this issue 3 years ago โ€ข 3 comments

This PR โ€ฆ

Adds a frame option to the ImageMagick Thumb/Darkroom Driver, that allows one to select a single frame from an animated or multi-layered image. This should be useful when e.g. generating inline thumbs that shouldn't be animated, with e.g. kirby-blurry-placeholder - see also.

Ready?

  • [ ] Unit tests for fixed bug/feature
  • [x] In-code documentation (wherever needed)
  • [x] Tests and checks all pass

For review team

tobimori avatar Apr 16 '22 11:04 tobimori

Unsure about how detailed the unit test should be, but selecting the first frame should also work on single-layer/single-frame images - so we could extend the current testProcess test with the frame option, or add a new one that specifically transforms a GIF.

tobimori avatar Apr 16 '22 11:04 tobimori

@tobimori would you be able to add unit tests for this? honest answer, no grudges if not. only then someone from us would need to pick it up at some point.

distantnative avatar May 25 '22 07:05 distantnative

I'm moving atm and don't have capacities for that, so I'd appreciate your help :)

tobimori avatar May 25 '22 07:05 tobimori

@tobimori Sorry that we kept this dormant so long. Are you still interested in this feature? Then we can try to finish it together.

lukasbestle avatar Dec 10 '22 21:12 lukasbestle

I would be, and think it's a general issue that needs to be tackled at some point (especially for use cases like the placeholder plugin), but it's not a priority for me, as the client project I needed this for is done, and I disabled placeholders for all (or they stayed huge, dunno, wasn't a big deal in the end)

If you need any help in finishing this, I'll gladly help, although it's christmas season, and I'm on holidays from the end of next week until new years.

tobimori avatar Dec 10 '22 21:12 tobimori

I have to admit I gave unit tests a try once but failed and abandoned it quickly ๐Ÿ˜…๐Ÿ™ˆ

distantnative avatar Dec 10 '22 21:12 distantnative

Thanks for your quick reply. I think before we can tackle unit tests, we need to answer this open question:

What happens if a subsequent frame is selected for a static image? I.e. if I tried to get the third frame of a JPG? Would be great to have a fallback for that unless ImageMagick already handles this case internally.

lukasbestle avatar Dec 10 '22 21:12 lukasbestle

Thanks for your quick reply. I think before we can tackle unit tests, we need to answer this open question:

What happens if a subsequent frame is selected for a static image? I.e. if I tried to get the third frame of a JPG? Would be great to have a fallback for that unless ImageMagick already handles this case internally.

Still returns the first frame: CleanShot 2022-12-10 at 22 42 10@2x -> both same output

tobimori avatar Dec 10 '22 21:12 tobimori

@tobimori I've rebased the PR against our develop branch and made minor updates to the code. I think the change itself is good, we "just" need a good unit test for it that actually tests the behavior. Could you prepare a test case? We can help to integrate it.

lukasbestle avatar Dec 30 '22 14:12 lukasbestle

CleanShot 2023-01-02 at 13 24 17@2x

Just stumbled upon this while working on a test case. It only happened with a file that has a limited number of frames, not e.g. a .png file that only has one.

The result of this command is two images with the frame attached as suffix. CleanShot 2023-01-02 at 13 25 45@2x

It's the same as when converting a .gif to a single-level format like .png anyway, this shouldn't be a problem, right?

Edit: Throws error if out of bounds. CleanShot 2023-01-02 at 13 46 05@2x

tobimori avatar Jan 02 '23 12:01 tobimori

I've added a unit test. It checks a sample GIF with a reference file generated by the same snippet.

tobimori avatar Jan 02 '23 13:01 tobimori

Summarizing my previous comments:

Currrent behavior when transforming a .gif with multiple frames to a .png without selecting a frame: CleanShot 2023-01-02 at 14 11 40@2x Multiple files generated with frame index as suffix.

When transforming a .gif with multiple frames to a .png with an not existing frame: CleanShot 2023-01-02 at 14 13 11@2x Generates the same files as above, but shows that the command execution failed.

When transforming a .gif with multiple frames to a .png with an existing frame: A .png with the same file name as the .gif is generated as expected with the selected frame.

When transforming a .jpeg/.png without multiple frames to an image with an not existing frame selected: The first frame will always be output.

tobimori avatar Jan 02 '23 13:01 tobimori

Thanks for adding the tests and for checking the edge cases. I think it would be good to have those covered as well, in the order of importance:

  • Is it possible to stop ImageMagick from writing the frames in the "non-existing frame is selected" case? It's good that the error is generated, but an error case shouldn't generate files.
  • I think it would be good to have special handling for the case when an animated image is converted to a non-animated image (like GIF to PNG) but no frame is passed. This should either trigger an error or use the first frame (whichever is easiest to implement; the main problem probably being that it's hard to detect whether an image is animated). AFAICT, the current behavior leads to broken thumbs anyway because of the automatically inserted suffix that won't be detected by Kirby. So this change would fix a bug and make the behavior consistent.
    • Possible solution from the top of my head: The default for the frame prop could be 0 when the target format does not have frame support. This would implement the "use the first frame" idea but still with compatibility for non-animated source images. However it's again difficult to detect whether the target format has animation support. We could hard-code ['jpg', 'png'] (with APNG, WebP and AVIF not listed as they support frames), but maybe there's a better option.

Could you please add unit tests for the edge cases as well?

lukasbestle avatar Jan 02 '23 19:01 lukasbestle

I've looked through the ImageMagick docs and haven't found anything that stops IM from creating files in an error case. :/

tobimori avatar Jan 05 '23 17:01 tobimori

I've implemented a new method that checks the frame count using the ImageMagick identify CLI. This is unfortunately the only method I found that works, besides using the Imagick extension. This requires a new config option, identifyBin, which works similar to the current bin option when using the ImageMagick driver.

Each image generation now checks using such method whether a frame is in bounds or not, and automatically fallbacks if not converting to a supported format (Currently avif, webp, gif listed as supported).

Unit tests are added covering the following cases:

  • Exception gets thrown when a frame out of bounds is requested
  • Output image by fallback is the same as when requesting frame 0 manually
  • Frame count method works as expected, returning 2 for a sample GIF and 1 for a PNG.

I think this is a fair trade-off, given this fixes a significant bug that happens when trying to transform a GIF to any other unsupported format, if included in a major release of course. It'd also open the possibility to add APNG support in the future, as such must be specified with the APNG: prefix manually, which we could probably detect using identify.

tobimori avatar Jan 05 '23 19:01 tobimori

Any updates?

tobimori avatar Feb 15 '23 20:02 tobimori

Thanks for your research and sorry for the delay. We haven't yet found the time to look into this again. Especially because the edge cases make it all a lot more complex. To the point where I feel like the current implementation could be a downgrade for 99% of users who don't need to access frames.

lukasbestle avatar Feb 23 '23 21:02 lukasbestle

To the point where I feel like the current implementation could be a downgrade for 99% of users who don't need to access frames.

The way I look at this PR now is not an enhancement or feature, but rather a critical bug fix for everyone working with GIFs as those currently do not get generated/converted properly. If there is an alternative driver, such as the ImageMagick one, which most important difference to GD is to provide support for animated files, it should support them properly IMHO. (AVIF support is added to SimpleImage as we speak as it's in GDlib by now, so it'll probably be in the next Kirby release too)

If you are completely sure that this is not interesting to you, I'd also be up for moving this in a plugin. Although I heavily think this should be in core.

tobimori avatar Feb 23 '23 21:02 tobimori

I moved this into a plugin: https://github.com/tobimori/kirby-magick-extended

tobimori avatar Feb 23 '23 22:02 tobimori

I'm not sure yet. As I said, we haven't found the time to look at this again in detail due to other projects.

lukasbestle avatar Feb 24 '23 08:02 lukasbestle

Revisiting this after a few months, I think:

  • The default behavior should be limiting to frame 0, when the target format does not support frames (e.g. not avif, webp, gif, etc.), otherwise do not pass frame options.
  • This would solely fix the bugs described when e.g. converting a GIF to a JPEG and the current unexpected behavior where all frames will be converted separately as JPEG with suffixes.
  • The frame counting behavior and its related options: a. should stay in a plugin, and not become part of Kirby core b. should always fall back to the first frame, if identifyBin is unavailable c. should be togglable by either having identifyBin undefined by default, or having a separate option to toggle the behavior
  • If b or c, this would also allow for APNG support in core.

@distantnative

tobimori avatar Apr 16 '23 17:04 tobimori

@tobimori Yep, agreed on the first two. The third, I'd go for (c) - having it undefined by default already adds the option for users to define it and activate those functionalities. Could also be a plugin, but it doesn't seem like much of a burden to have that in the core as well then.

distantnative avatar Apr 16 '23 17:04 distantnative

Perfect. I'll get back to this PR in the next few weeks.

tobimori avatar Apr 16 '23 17:04 tobimori

This PR has been marked as stale because it requires further changes but has not seen activity in the past months. This is for us to prioritize PRs that can be reviewed and merged. It will be closed if no further activity occurs within the next 15 days. If you still have interest in this PR, please help us finalizing it. Please let us know in case you are stuck on the required changes.

github-actions[bot] avatar Jun 16 '23 00:06 github-actions[bot]

Still planned, will wait for v4.

tobimori avatar Jun 16 '23 00:06 tobimori

@tobimori if you want, we'd be up to integrate this during the alpha phase already. That way we can also test better if anything breaks.

distantnative avatar Jun 19 '23 17:06 distantnative

I don't have the time right now, sorry.

tobimori avatar Jun 19 '23 17:06 tobimori

This PR has been marked as stale because it requires further changes but has not seen activity in the past months. This is for us to prioritize PRs that can be reviewed and merged. It will be closed if no further activity occurs within the next 15 days. If you still have interest in this PR, please help us finalizing it. Please let us know in case you are stuck on the required changes.

github-actions[bot] avatar Aug 19 '23 00:08 github-actions[bot]

This PR has been marked as stale because it requires further changes but has not seen activity in the past months. This is for us to prioritize PRs that can be reviewed and merged. It will be closed if no further activity occurs within the next 15 days. If you still have interest in this PR, please help us finalizing it. Please let us know in case you are stuck on the required changes.

github-actions[bot] avatar Nov 03 '23 00:11 github-actions[bot]

This PR has been marked as stale because it requires further changes but has not seen activity in the past months. This is for us to prioritize PRs that can be reviewed and merged. It will be closed if no further activity occurs within the next 15 days. If you still have interest in this PR, please help us finalizing it. Please let us know in case you are stuck on the required changes.

github-actions[bot] avatar Jan 29 '24 00:01 github-actions[bot]