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

Append EOI marker to progressive image binary to reduce decoding failures #834

Open
theop-luma opened this issue Mar 6, 2025 · 2 comments

Comments

@theop-luma
Copy link

theop-luma commented Mar 6, 2025

Currently there are intermittent errors when decoding progressive jpegs on iOS:

makeImagePlus:3744: *** ERROR: 'JPEG'-_reader->initImage[0] failed err=-50
createImageAtIndex:2093: *** ERROR: createImageAtIndex[0] - 'JPEG' - failed to create image [-59]
CGImageSourceCreateImageAtIndex:5107: *** ERROR: CGImageSourceCreateImageAtIndex[0] - 'JPEG' - failed to create image [-59]
makeImagePlus:3744: *** ERROR: 'JPEG'-_reader->initImage[0] failed err=-50

I looked at the data being sent to UIImage(data: data, scale: scale) and looks like it's correctly formatted and not malformed, it's just missing the EOI (end-of-image) marker which seems to be tripping up the UIImage decoder.

I was able to validate that the data works correctly if you add [0xFF, 0xD9] at the end of the binary and outputs a functional Jpeg. Interestingly this seems to only happen intermittently, so I'm not sure if UIImage has some fallbacks if EOI is missing but only fails in certain cases.

Nevertheless, here's what fixed it for me:

diff --git a/Sources/Nuke/Decoding/ImageDecoders+Default.swift b/Sources/Nuke/Decoding/ImageDecoders+Default.swift
index 5d6d8ace..ba126104 100644
--- a/Sources/Nuke/Decoding/ImageDecoders+Default.swift
+++ b/Sources/Nuke/Decoding/ImageDecoders+Default.swift
@@ -92,7 +92,12 @@ extension ImageDecoders {
             guard let endOfScan = scanner.scan(data), endOfScan > 0 else {
                 return nil
             }
-            guard let image = ImageDecoders.Default._decode(data[0...endOfScan], scale: scale) else {
+            // To decode data correctly, binary needs to end with an EOI (End Of Image) marker (0xFFD9)
+            var imageData = data[0...endOfScan]
+            if data[endOfScan - 1] != 0xFF || data[endOfScan] != 0xD9 {
+                imageData += [0xFF, 0xD9]
+            }
+            guard let image = ImageDecoders.Default._decode(imageData, scale: scale) else {
                 return nil
             }
@kean
Copy link
Owner

kean commented Mar 6, 2025

Hey, great finding. Would you mind opening a quick PR with a fix?

@theop-luma
Copy link
Author

Yessir! #835

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

No branches or pull requests

2 participants