image-rs / image

Encoding and decoding images in Rust
Apache License 2.0
4.89k stars 605 forks source link

Any way to create a GIF with infinte repeat only with this crate? #1041

Closed 38 closed 5 years ago

38 commented 5 years ago

Hi there, I am currently trying to create a GIF that repeats infinitely. But I get confused when I look at APIs under image::gif::Encoder. It seems it would only generate a GIF that repeat exact one time.

I know there's another gif crate which we can use and image crate actually use gif crate provides these functionalities. But what is the best way to make infinite repeat GIFs , ideally I would like having only image dependency for my crate ?

Thanks a lot!

HeroicKatora commented 5 years ago

Most browsers will loop a gif by default if no other control is given. All that is required is that the last frame also specifies a delay and then for many purposes that will be used as the delay to loop into the first frame again.

Actual loop control in gif is an application extension (still, widely supported). The very basics are implemented in the gif crate directly: https://docs.rs/gif/0.10.3/gif/enum.ExtensionData.html#variant.Repetitions Here is a web resource I found for the extension type that is use to achieve the exact loop control if you want to read more: http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension

There is also no large cost (in terms of binary size and compile time) associated with depending on gif if you depend on image already. Since the goal of image is to provide a common interface please use gif for the specialized purposes.

38 commented 5 years ago

Thanks for answering the question.

Most browsers will loop a gif by default if no other control is given.

Here's what I generated using image crate. It doesn't loop on my browser (P.S. I am using firefox 69.0)

test

However, these GIFs is able to repeat again and again. (This is from a screen recorder) plotters-piston

There is also no large cost (in terms of binary size and compile time) associated with depending on gif if you depend on image already. Since the goal of image is to provide a common interface please use gif for the specialized purposes.

Of course, that is the case. But I am concerning about depending on several different versions of gif crate, cause I am working hard to reduce the binary size as well. Although this is not the case for now, my explicitly dependency would be likely different from the image crate one in the future.

I am working hard to reduce the binary artifact size. So it would be ideal if I can handle this completely with image crate. Or at least, re-export the gif crate from image crate.

HeroicKatora commented 5 years ago

Most browsers will loop a gif by default if no other control is given.

Sorry but you are right, it doesn't. I overlooked the loop control extension in the sample that I used to make that claim.

38 commented 5 years ago

So any instruction on how I could use image crate to do this ?

read more: http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension

This gives me a change to do a dirty hack that modifying the file after the GIF encoder is dropped. But I think it would be helpful if we can control the loop extension directly from image crate because of the versioning issue I mentioned.

Especially most of the crate author using

crate-name = "^version"

to include dependency. And that is what I am concerning.

Thanks again!

HeroicKatora commented 5 years ago
image = "0.22"
gif = "*"

makes cargo select the same version of gif that's also used in image during version resolution. Not sure if that is a guarantee but almost certain. Re-exporting gif extends that the public API (and thus SemVer compatibility) of image to the whole of gif, making upgrades to gif without a major breaking release of image also impossible, instead of having a more stable, common interface.

38 commented 5 years ago

Hmm, avoid breaking by a breaking change is the full point of using exact version instead of a wildcard.

So the problem remains to who would be break if gif is making breaking change, either image crate or image crate itself plus all image's downstream using features provided by gif crate that isn't exposed by image.

The solution using gif = "*" sounds good for me so far. I am still prefer to have API that controls the loop (and maybe other tweaks) within image::gif, as long as image::gif provides GIF functionalities.

And if you guys think it's good to expose some of the gif tweak to image::gif, I am more than happy to make a PR for that.

38 commented 5 years ago

Now I come up with a solution which disable gif support for image and directly depends gif from my crate. It just works fine.

But I think another problem is, if I use gif directly, there's no need to use image::gif anyway. Plus image::gif::Encoder isn't the same type as gif::Encoder, thus once people adopt their own dependency to gif crate. It seems there's no reason to use image::gif anymore.

So I am still thinking it would be better to support those tweaks directly to image::gif. Since once people need to use gif crate, there's no reason to use image::gif anyway. This makes image::gif module meaningless once people need some tweak.

fintelia commented 5 years ago

@38 I'm personally in favor of having image::gif just re-export the gif crate. The reason that it doesn't right now is that there are some types and traits from the image crate that it wouldn't have access to. That may be changing though once we have a separate image-core crate.

38 commented 5 years ago

Thanks @fintelia, it seems the best approach for me is to disable the image gif feature and manipulate gif with the gif crate.