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

iOS 17/macOS 14 PNG image render wrong by default, only works when disable force decode #3605

Closed
DaoPinWang-git opened this issue Sep 20, 2023 · 30 comments
Labels
apple bug apple's bug cause our framework author's pain ios17 iOS 17 only png PNG image related

Comments

@DaoPinWang-git
Copy link

original image
20230821125431_8522

display image
image_1

@dreampiggy
Copy link
Contributor

dreampiggy commented Sep 20, 2023

At least, you need to provide a sample URL for reproduction and debug...

Also, the issue template should provide the version of SDWebImage and iOS version you used

@DaoPinWang-git
Copy link
Author

@dreampiggy sorry...

    lazy var cImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.sd_setImage(with: URL(string: "https://user-images.githubusercontent.com/18020236/269165495-6a0069f8-582c-4faf-81ae-49879df63af9.png")) { image, _, _, url in

        }
        return imageView
    }()

image url: https://user-images.githubusercontent.com/18020236/269165495-6a0069f8-582c-4faf-81ae-49879df63af9.png

iOS: 17.0; SDWebImage: 5.18.1

@dreampiggy
Copy link
Contributor

dreampiggy commented Sep 21, 2023

Seems not reproducible in our SDWebImage Demo.

I guess it's because your own project's code, for example you use some template image or filter, dark mode (with alpha image) which effect the rendering result.

You can compare the rendering result with MacOS or iPhone native Preview.app to see the differences.

image

@dreampiggy dreampiggy added can not reproduce Need demo to reproduce and removed not enough info labels Sep 21, 2023
@DaoPinWang-git
Copy link
Author

image @dreampiggy You need to use iOS 17 debug

@dreampiggy
Copy link
Contributor

dreampiggy commented Sep 22, 2023

I mean, is this behavior different from Apple's other native App ? Like Photos or Preview, and even on macOS 14 and tvOS 17

If not, it's not SDWebImage's bug, it's Apple's bug, you'd better to fire radar to Apple


Give you a simple demo code, without any use of SDWebImage at all

let data = Data(url: URL(string: url))!
let image = UIImage(data: data)!
imageView.image = image

Is this render issue still not correct ?

@dreampiggy dreampiggy added the apple bug apple's bug cause our framework author's pain label Sep 22, 2023
@dreampiggy
Copy link
Contributor

dreampiggy commented Sep 22, 2023

Or you can choose not to use ImageIO (Apple's Image decoder), use the open-source libpng instead.

https://github.com/glennrp/libpng

@dreampiggy
Copy link
Contributor

dreampiggy commented Sep 22, 2023

image

TestPNGRender.zip

Give you the demo and run by yourself, is this behavior different from SDWebImage ? Note the background view use .black color and your PNG contains alpha channel

@dreampiggy dreampiggy added By Design Something behavior by design currently and removed apple bug apple's bug cause our framework author's pain labels Sep 22, 2023
@dreampiggy
Copy link
Contributor

I guess this is not bug. The PNG is alpha image so it can blend with the background. I don't think these two render result is different, because They are on different background

You should not use that lldb debugger render to blame me, it has another background view which is grey, not the white one

@DaoPinWang-git
Copy link
Author

sorry my fault,i tried to download the image using the iOS API, but got a different result from SDWebImage

    imageView1.frame = CGRect(x: 10, y: 110, width: 295, height: 73)
    view.addSubview(imageView1)
    
    imageView2.frame = CGRect(x: 10, y: 200, width: 295, height: 73)
    view.addSubview(imageView2)
    
    
    imageView1.sd_setImage(with: URL(string: "https://user-images.githubusercontent.com/18020236/269165495-6a0069f8-582c-4faf-81ae-49879df63af9.png")) { image, _, _, url in
    }
    
    
    let url = URL(string: "https://user-images.githubusercontent.com/18020236/269165495-6a0069f8-582c-4faf-81ae-49879df63af9.png")!

    let session = URLSession.shared
    let task = session.dataTask(with: url) { (data, response, error) in
        if let error = error {
            print("Error: \(error)")
            return
        }
        
        guard let data = data,
              let image = UIImage(data: data)
              else {
                print("Invalid image data")
                return
        }
        
        DispatchQueue.main.async {
            self.imageView2.image = image
        }
    }

    task.resume()

in iOS 16.4 simulator
image

in iOS 17.0 simulator
image

@dreampiggy
Copy link
Contributor

dreampiggy commented Sep 22, 2023

Disable the force decode and try again. Use that "avoidDecodeImage" options (or use new API called context[.forceDecodePolicy] = .never)

SDWebImage by default actually just do simple:

  1. Use ImageIO to decode Data into UIImage
  2. Use UIGraphicsImageRenderer to force-decode (because the ImageIO returned back CGImage is lazy, we mostly do not want lazy for Web images)

I guess this maybe something bug of CoreGraphics

I will test again on my demo later. Note: SDWebImage supports file URL as well, so we don't need URLSession or any network, just put that image into App bundle and load via fileURL to compare render result

@dreampiggy dreampiggy changed the title iOS 17 image display error iOS 17 PNG image render wrong by default, only works when disable force decode Sep 22, 2023
@dreampiggy
Copy link
Contributor

dreampiggy commented Sep 22, 2023

Can reproduce on iOS 17 simulator. There are render differences when enable/disable force decode (via avoidDecodeImage or imageForceDecodePolicy)

See:

Enable Force Decode (default)

截屏2023-09-22 14 56 49

Disable Force Decode

截屏2023-09-22 14 57 28

Change Force Decode Solution

image

SDImageCoderHelper.defaultDecodeSolution = .uiKit

You can also use this to force enable the UIKit (UIImage.prepareForDisplay) decode solution, which also works. Only the old CoreGraphics based decode solution does not work.

@dreampiggy dreampiggy added apple bug apple's bug cause our framework author's pain ios17 iOS 17 only and removed By Design Something behavior by design currently can not reproduce Need demo to reproduce labels Sep 22, 2023
@DaoPinWang-git
Copy link
Author

thx!!! 👏👏👏 🎉🎉🎉

@dreampiggy
Copy link
Contributor

Open currently, seems need to fire radar to Apple or find some way for better workaround.

@dreampiggy
Copy link
Contributor

Decide to upload this to Apple for radar:
TestPNGRender.zip

@dreampiggy
Copy link
Contributor

FB13196663

image

@lyandy
Copy link

lyandy commented Oct 9, 2023

It seems like there are some bugs in UIGraphicsImageRenderer
A very simple demo is here: ios_17_image_test
It's not SDWebImage's bug

@dreampiggy
Copy link
Contributor

dreampiggy commented Oct 30, 2023

Update:

It's not bug of UIKit team actually :)

It's bug of ImageIO team

The decoded CGImage contains Wrong BitmapInfo, which store the RGB into pre-multiplied form (which means, each R is actually R * Alpha).

It should use the kCGImageAlphaPremultipliedFirst or kCGImageAlphaPremultipliedFirst to indicate the consumer (We and UIKit team), but however, then return the kCGImageAlphaLast or kCGImageAlphaFirst, which means it's not pre-multiplied.

A stupid and shit code quality.

@dreampiggy
Copy link
Contributor

dreampiggy commented Oct 30, 2023

New Demo code

TestPNGRender.zip

image

Left iOS 16, Right iOS 17

image

The first RGB pixel value is not equal, the iOS 17 one seems Premultiplied the alpha value, which makes each pixel RGB become smaller (or in visible, ligher)

@dreampiggy
Copy link
Contributor

dreampiggy commented Oct 30, 2023

The alphaInfo shows the CGImage use RGBA8888 and non-premultiplied

image

Check the first pixel value

iOS Version 16 17
R 154 30
G 231 45
B 231 45
A 50 50

Compare

Each R in iOS 17 is the premultiply result of R in iOS 16. But CGImage still report non-premultiplied

30 = 154 * (50 / 255)
45 = 231 * (50 / 255)
45 = 231 * (50 / 255)

@dreampiggy
Copy link
Contributor

dreampiggy commented Nov 1, 2023

Apple still don't reply for this issue. And this Bug exits on iOS 17.2 Beta 1🤮
I re-submit with a new radar FB13322401
https://github.com/dreampiggy/iOS17IndexedPNGDecodeBug

@dreampiggy dreampiggy changed the title iOS 17 PNG image render wrong by default, only works when disable force decode iOS 17/macOS 14 PNG image render wrong by default, only works when disable force decode Nov 9, 2023
@dreampiggy dreampiggy pinned this issue Nov 9, 2023
@dreampiggy
Copy link
Contributor

This should be fixed (hacked) by #3634

@dreampiggy
Copy link
Contributor

Finally released 5.18.5

@DaoPinWang-git @lyandy Please have a try. This workaround only make all PNG decoded from SDWebImage works, but not using the hook for system SDK, which need Apple to fix.

@jiangxiaopeng
Copy link

Finally released 5.18.5

@DaoPinWang-git @lyandy Please have a try. This workaround only make all PNG decoded from SDWebImage works, but not using the hook for system SDK, which need Apple to fix.

upgrade 5.18.5, our debug ipa no problem, but the testflihgt ipa not fix

@jiangxiaopeng
Copy link

Finally released 5.18.5
@DaoPinWang-git @lyandy Please have a try. This workaround only make all PNG decoded from SDWebImage works, but not using the hook for system SDK, which need Apple to fix.

upgrade 5.18.5, our debug ipa no problem, but the testflihgt ipa not fix

@dreampiggy

@dreampiggy
Copy link
Contributor

Finally released 5.18.5

@DaoPinWang-git @lyandy Please have a try. This workaround only make all PNG decoded from SDWebImage works, but not using the hook for system SDK, which need Apple to fix.

upgrade 5.18.5, our debug ipa no problem, but the testflihgt ipa not fix

What's the difference between testflight build ? I means maybe about the real device or simulator

Apple may optimize different image format based on Hardware media codec, so make sure you test on the same devices...

@dreampiggy
Copy link
Contributor

@jiangxiaopeng
Or if you believe this is still something not handled by SDWebImage, provide a demo for me to invesitgate using the real device. (Also, with your iPhone model and OS version)

I guess there are something mismatch between simulator and real device

@dreampiggy
Copy link
Contributor

@jiangxiaopeng

You're correct. Use 5.18.9, the final old PR contains typo and only enabled in Debug configuration 😃

@jiangxiaopeng
Copy link

jiangxiaopeng commented Mar 13, 2024

hah, It's not SDWebImage's bug,
Uploading 10d9dbec-69b9-43a6-967d-fe3b2985f90f.png…

@MichaelSSY
Copy link

Can reproduce on iOS 17 simulator. There are render differences when enable/disable force decode (via avoidDecodeImage or imageForceDecodePolicy)

See:

Enable Force Decode (default)

截屏2023-09-22 14 56 49 ## Disable Force Decode 截屏2023-09-22 14 57 28 ## Change Force Decode Solution ![image](https://private-user-images.githubusercontent.com/6919743/269857358-3f77299f-8533-4823-9bce-744c05701f99.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTM5Mjk2MzgsIm5iZiI6MTcxMzkyOTMzOCwicGF0aCI6Ii82OTE5NzQzLzI2OTg1NzM1OC0zZjc3Mjk5Zi04NTMzLTQ4MjMtOWJjZS03NDRjMDU3MDFmOTkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDQyNCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA0MjRUMDMyODU4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTQ5M2MxMTdlNDBkOGY2ZjhiZjU4ZmM4OWUyMGFlNDM0YTM3MGZhNTZmMjgwMDg4NTgwYWEyOWQ4MWZlYzUxYSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.x_ZjXSCNcQk-5a9h7Z-bVPz0oq_MOvYwhxunyw8Loqk)
SDImageCoderHelper.defaultDecodeSolution = .uiKit

You can also use this to force enable the UIKit (UIImage.prepareForDisplay) decode solution, which also works. Only the old CoreGraphics based decode solution does not work.

I have found that if placeholderImage is set, there may still be issues. Could you please help me check the following settings:

let URL=URL (string:“ https://user-images.githubusercontent.com/18020236/269165495-6a0069f8-582c-4faf-81ae-49879df63af9.png )!
let image=SDImageCache. shared. imageFromCache (forKey: URL. absoluteString)
self. imageView1. sd_setImage (with: URL, placeholderImage: image, options: [. avoidDecodeImage])

@MichaelSSY
Copy link

It's strange. The image cached on the disk looks normal, but once it's taken out, there will be a problem displaying it

let url = URL(string: "https://user-images.githubusercontent.com/18020236/269165495-6a0069f8-582c-4faf-81ae-49879df63af9.png")!
let image = SDImageCache.shared.imageFromCache(forKey: url.absoluteString)
self.imageView2.image = image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
apple bug apple's bug cause our framework author's pain ios17 iOS 17 only png PNG image related
Projects
None yet
Development

No branches or pull requests

5 participants