Merge pull request #3743 from dreampiggy/bugfix/fix_jfif_orientation_new_solution

Fix the thumbnail decoding on JPEG which contains EXIF orientation, use the new way to workaround JFIF bug
This commit is contained in:
DreamPiggy 2024-08-22 15:28:01 +08:00 committed by GitHub
commit 0a4f92c59a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 16 additions and 9 deletions

View File

@ -27,8 +27,6 @@ static CGImageSourceRef (*SDCGImageGetImageSource)(CGImageRef);
// Specify File Size for lossy format encoding, like JPEG // Specify File Size for lossy format encoding, like JPEG
static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestinationRequestedFileSize"; static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestinationRequestedFileSize";
// Avoid ImageIO translate JFIF orientation to EXIF orientation which cause bug because returned CGImage already apply the orientation transform
static NSString * kSDCGImageSourceSkipMetadata = @"kCGImageSourceSkipMetadata";
// This strip the un-wanted CGImageProperty, like the internal CGImageSourceRef in iOS 15+ // This strip the un-wanted CGImageProperty, like the internal CGImageSourceRef in iOS 15+
// However, CGImageCreateCopy still keep those CGImageProperty, not suit for our use case // However, CGImageCreateCopy still keep those CGImageProperty, not suit for our use case
@ -440,12 +438,13 @@ static BOOL SDImageIOPNGPluginBuggyNeedWorkaround(void) {
} }
} }
// Parse the image properties // Parse the image properties
NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(source, index, (__bridge CFDictionaryRef)@{kSDCGImageSourceSkipMetadata : @(YES)}); NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(source, index, NULL);
CGFloat pixelWidth = [properties[(__bridge NSString *)kCGImagePropertyPixelWidth] doubleValue]; CGFloat pixelWidth = [properties[(__bridge NSString *)kCGImagePropertyPixelWidth] doubleValue];
CGFloat pixelHeight = [properties[(__bridge NSString *)kCGImagePropertyPixelHeight] doubleValue]; CGFloat pixelHeight = [properties[(__bridge NSString *)kCGImagePropertyPixelHeight] doubleValue];
CGImagePropertyOrientation exifOrientation = (CGImagePropertyOrientation)[properties[(__bridge NSString *)kCGImagePropertyOrientation] unsignedIntegerValue]; CGImagePropertyOrientation exifOrientation = kCGImagePropertyOrientationUp;
if (!exifOrientation) { NSNumber *exifOrientationValue = properties[(__bridge NSString *)kCGImagePropertyOrientation];
exifOrientation = kCGImagePropertyOrientationUp; if (exifOrientationValue != NULL) {
exifOrientation = [exifOrientationValue unsignedIntValue];
} }
NSMutableDictionary *decodingOptions; NSMutableDictionary *decodingOptions;

View File

@ -547,15 +547,23 @@
} }
- (void)test29ThatJFIFDecodeOrientationShouldNotApplyTwice { - (void)test29ThatJFIFDecodeOrientationShouldNotApplyTwice {
// I don't think this is SDWebImage's issue, it's Apple's ImgeIO Bug, but user complain about this: #3594
// In W3C standard, JFIF should always be orientation up, and should not contains EXIF orientation
// But some bad image editing tool will generate this kind of image :(
NSURL *url = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestJFIF" withExtension:@"jpg"]; NSURL *url = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestJFIF" withExtension:@"jpg"];
NSData *data = [NSData dataWithContentsOfURL:url]; NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [SDImageIOCoder.sharedCoder decodedImageWithData:data options:nil]; UIImage *image = [SDImageIOCoder.sharedCoder decodedImageWithData:data options:nil];
expect(image.sd_imageFormat).equal(SDImageFormatJPEG);
#if SD_UIKIT #if SD_UIKIT
UIImageOrientation orientation = image.imageOrientation; UIImageOrientation orientation = image.imageOrientation;
expect(orientation).equal(UIImageOrientationUp); expect(orientation).equal(UIImageOrientationDown);
#else #endif
expect(image.sd_imageFormat).equal(SDImageFormatJPEG);
UIImage *systemImage = [[UIImage alloc] initWithData:data];
#if SD_UIKIT
orientation = image.imageOrientation;
expect(orientation).equal(UIImageOrientationDown);
#endif #endif
// Manual test again for Apple's API // Manual test again for Apple's API