Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Introduce global and per-image-request policy control about whether to use UIKit animated image or SDAnimatedImage, based on frame count and bytes size #3669

Open
dreampiggy opened this issue Jan 26, 2024 · 6 comments

Comments

@dreampiggy
Copy link
Contributor

dreampiggy commented Jan 26, 2024

Proposa,

Some people in #3668 #3667 seems talk about this old issue. When:

A large Application which contains both UIImageView and SDAnimatedImageView, but wants only SDAnimatedImageView shows animation, ignore _UIAnimatedImage at all.

Note _UIAnimatedImage will load all frames into memory and may cause OOM for huge GIF/AWebP

Here I have an idea:

Provide custom control SDAnimatedImageDecodingPolicy class

It can setted into global one SDImageCoderHelper.DefaultAnimatedImageDecodingPolicy, or can be passed as context value, per image-request

The policy can be controlled like:

  1. Only frame count > N (animated image, like GIF, or AWebP), use SDAnimatedImage class and supports animating.
  2. All image use SDAnimatedImage (UIImageView will not show animating)
  3. All image use _UIAnimatedImage, note this cause all frames loaded into RAM (like preloadAllFrames), which may cause OOM (for example, a 1024x1024 100 frame GIF occupy 381MB)
  4. Only when current image bytes (calculated by image.sd_memoryCost, can be overrided by setter) > M, use SDAnimatedImage, else use _UIAnimatedImage
  5. Default policy (which is suggested value from most common Apps, controled by us)

Then, this can be customized and solve many App's issue.

For example, if you always load small GIF for icons, you can use frame count > 10 as a policy, this means it's suitable for this case.

For example, if you have a high ratio of OOM, you can use bytes > 1MB to avoid huge GIF accidentlly passed into _UIAnimatedImage

For example, if you don't want UIImageView to play animation at all, you just use All use SDAnimatedImage

This can be really flexible for customization

@dreampiggy
Copy link
Contributor Author

@simonmcl
@pepsikirk

Any idea ? Can this solve your problem from the scratch ?

@dreampiggy dreampiggy changed the title Proposal: Introduce global and per-image-request policy control about whether to use UIKit animated image or SDAnimatedImage Proposal: Introduce global and per-image-request policy control about whether to use UIKit animated image or SDAnimatedImage, based on frame count and bytes size Jan 26, 2024
@simonmcl
Copy link

@dreampiggy Yes this would be great. In my case, I don't know ahead of time whether urls will be animated or not. So i'm just using SDAnimatedImageView everywhere I want them to be able to animate. Having a global setting to say use SDAnimatedImage everywhere would be ideal

@pepsikirk
Copy link

@simonmcl @pepsikirk

Any idea ? Can this solve your problem from the scratch ?

This feature doesn't solve my problem. What I actually need is for both UIImageView and SDAnimatedImageView to be able to play the same animated image URL. However, it's still a good solution for #3668.

@dreampiggy
Copy link
Contributor Author

dreampiggy commented Jan 30, 2024

What I actually need is for both UIImageView and SDAnimatedImageView to be able to play the same animated image UR

@pepsikirk Seems not really easy. Possible but need more way to do so.

Note: If you want this, you'll facing more RAM occpuy.

As a example, a 1024 x 1024, 100 frame GIF, will occupy 381MB for _UIAnimatedImage (which used for UIImageView animation)
And also another SDAnimatedImage, which need at least 3.81MB * 3 (The poster + current frame + next frame, 3 individual CGImage) in the memory.

So this cause 392.43 MB in memory...Is this really want you want ?


Anyway, this sounds another feature request, but I don't have a clever and clear implementation for now.

Store multiple different image instance into the same cache key is a challenge for our SDWebImage API design. A stupid way is to use associated type or a wrapper SDWrapperImage which hold both SDAnimatedImage and _UIAnimatedImage

@pepsikirk
Copy link

What I actually need is for both UIImageView and SDAnimatedImageView to be able to play the same animated image UR

@pepsikirk Seems not really easy. Possible but need more way to do so.

Note: If you want this, you'll facing more RAM occpuy.

As a example, a 1024 x 1024, 100 frame GIF, will occupy 381MB for _UIAnimatedImage (which used for UIImageView animation) And also another SDAnimatedImage, which need at least 3.81MB * 3 (The poster + current frame + next frame, 3 individual CGImage) in the memory.

So this cause 392.43 MB in memory...Is this really want you want ?

Anyway, this sounds another feature request, but I don't have a clever and clear implementation for now.

Store multiple different image instance into the same cache key is a challenge for our SDWebImage API design. A stupid way is to use associated type or a wrapper SDWrapperImage which hold both SDAnimatedImage and _UIAnimatedImage

The situations where we encounter this are primarily with relatively small animated images, so the memory consumption is still acceptable.
Indeed, my case is a special one, and it seems unnecessary to implement a dedicated solution. I can handle it by implementing it myself.

@LeoTheCatMeow
Copy link

Having this very configurable class seems nice. But @simonmcl, I also have a very similar use case as you. We don't know if the image is animated or not before hand, so we use the animated image class everywhere. What I am currently doing is set a custom processor:
SDWebImageManager.shared.optionsProcessor = <yourCustomProcessor>
And then with this processor, we pass
context[.animatedImageClass] = SDAnimatedImage.self
This will request all images loaded to use SDAnimatedImage. So if the intention is simply having a global setting, then this approach works just fine, without the need of an advanced class to configure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants