Support use url.path or custom UTI hint passed to ImageIO, solve the TIFF/NEF/SRW raw image decoding with wrong size

This is because file extension will cause ImageIO use different codec, which does not support all of them without context
This commit is contained in:
DreamPiggy 2022-10-27 11:09:29 +08:00
parent 9248fe561a
commit b1b16a17b3
10 changed files with 84 additions and 5 deletions

View File

@ -73,6 +73,7 @@
@"https://s2.ax1x.com/2019/11/01/KHYIgJ.gif",
@"https://raw.githubusercontent.com/icons8/flat-color-icons/master/pdf/stack_of_photos.pdf",
@"https://nr-platform.s3.amazonaws.com/uploads/platform/published_extension/branding_icon/275/AmazonS3.png",
@"https://res.cloudinary.com/dwpjzbyux/raw/upload/v1666474070/RawDemo/raw_vebed5.NEF",
@"http://via.placeholder.com/200x200.jpg",
nil];

View File

@ -28,12 +28,16 @@ SDImageCoderOptions * _Nonnull SDGetDecodeOptionsFromContext(SDWebImageContext *
if (context[SDWebImageContextImageThumbnailPixelSize]) {
thumbnailSizeValue = context[SDWebImageContextImageThumbnailPixelSize];
}
NSString *typeIdentifierHint = context[SDWebImageContextImageTypeIdentifierHint];
NSString *fileExtensionHint = cacheKey.pathExtension; // without dot
SDImageCoderMutableOptions *mutableCoderOptions = [NSMutableDictionary dictionaryWithCapacity:2];
SDImageCoderMutableOptions *mutableCoderOptions = [NSMutableDictionary dictionaryWithCapacity:6];
mutableCoderOptions[SDImageCoderDecodeFirstFrameOnly] = @(decodeFirstFrame);
mutableCoderOptions[SDImageCoderDecodeScaleFactor] = @(scale);
mutableCoderOptions[SDImageCoderDecodePreserveAspectRatio] = preserveAspectRatioValue;
mutableCoderOptions[SDImageCoderDecodeThumbnailPixelSize] = thumbnailSizeValue;
mutableCoderOptions[SDImageCoderDecodeTypeIdentifierHint] = typeIdentifierHint;
mutableCoderOptions[SDImageCoderDecodeFileExtensionHint] = fileExtensionHint;
mutableCoderOptions[SDImageCoderWebImageContext] = context;
SDImageCoderOptions *coderOptions = [mutableCoderOptions copy];

View File

@ -44,6 +44,22 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderDecodePreserveAs
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderDecodeThumbnailPixelSize;
/**
A NSString value indicating the source image's file extension. Example: "jpg", "nef", "tif", don't prefix the dot
Some image file format share the same data structure but has different tag explanation, like TIFF and NEF/SRW, see https://en.wikipedia.org/wiki/TIFF
Changing the file extension cause the different image result. The coder (like ImageIO) may use file extension to choose the correct parser
@note However, different UTType may share the same file extension, like `public.jpeg` and `public.jpeg-2000` both use `.jpg`. If you want detail control, use `TypeIdentifierHint` below
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderDecodeFileExtensionHint;
/**
A NSString value (UTI) indicating the source image's file extension. Example: "public.jpeg-2000", "com.nikon.raw-image", "public.tiff"
Some image file format share the same data structure but has different tag explanation, like TIFF and NEF/SRW, see https://en.wikipedia.org/wiki/TIFF
Changing the file extension cause the different image result. The coder (like ImageIO) may use file extension to choose the correct parser
@note If you provide `TypeIdentifierHint`, the `FileExtensionHint` option above will be ignored (because UTType has high priority)
@note If you really don't want any hint which effect the image result, pass `NSNull.null` instead
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderDecodeTypeIdentifierHint;
// These options are for image encoding
/**

View File

@ -12,6 +12,8 @@ SDImageCoderOption const SDImageCoderDecodeFirstFrameOnly = @"decodeFirstFrameOn
SDImageCoderOption const SDImageCoderDecodeScaleFactor = @"decodeScaleFactor";
SDImageCoderOption const SDImageCoderDecodePreserveAspectRatio = @"decodePreserveAspectRatio";
SDImageCoderOption const SDImageCoderDecodeThumbnailPixelSize = @"decodeThumbnailPixelSize";
SDImageCoderOption const SDImageCoderDecodeFileExtensionHint = @"decodeFileExtensionHint";
SDImageCoderOption const SDImageCoderDecodeTypeIdentifierHint = @"decodeTypeIdentifierHint";
SDImageCoderOption const SDImageCoderEncodeFirstFrameOnly = @"encodeFirstFrameOnly";
SDImageCoderOption const SDImageCoderEncodeCompressionQuality = @"encodeCompressionQuality";

View File

@ -7,7 +7,6 @@
*/
#import <Foundation/Foundation.h>
#import <ImageIO/ImageIO.h>
#import "SDImageCoder.h"
/**

View File

@ -15,6 +15,9 @@
#import "UIImage+ForceDecode.h"
#import "SDInternalMacros.h"
#import <ImageIO/ImageIO.h>
#import <CoreServices/CoreServices.h>
// Specify DPI for vector format in CGImageSource, like PDF
static NSString * kSDCGImageSourceRasterizationDPI = @"kCGImageSourceRasterizationDPI";
// Specify File Size for lossy format encoding, like JPEG
@ -320,10 +323,31 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
}
#endif
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
NSString *typeIdentifierHint = options[SDImageCoderDecodeTypeIdentifierHint];
if (!typeIdentifierHint) {
// Check file extension and convert to UTI, from: https://stackoverflow.com/questions/1506251/getting-an-uniform-type-identifier-for-a-given-extension
NSString *fileExtensionHint = options[SDImageCoderDecodeFileExtensionHint];
if (fileExtensionHint) {
typeIdentifierHint = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtensionHint, NULL);
}
} else if ([typeIdentifierHint isEqual:NSNull.null]) {
// Hack if user don't want to imply file extension
typeIdentifierHint = nil;
}
NSDictionary *creatingOptions = nil;
if (typeIdentifierHint) {
creatingOptions = @{(__bridge NSString *)kCGImageSourceTypeIdentifierHint : typeIdentifierHint};
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)creatingOptions);
if (!source) {
// Try again without UTType hint, the call site from user may provide the wrong UTType
source = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)creatingOptions);
}
if (!source) {
return nil;
}
size_t count = CGImageSourceGetCount(source);
UIImage *animatedImage;

View File

@ -9,10 +9,12 @@
#import "SDImageIOCoder.h"
#import "SDImageCoderHelper.h"
#import "NSImage+Compatibility.h"
#import <ImageIO/ImageIO.h>
#import "UIImage+Metadata.h"
#import "SDImageIOAnimatedCoderInternal.h"
#import <ImageIO/ImageIO.h>
#import <CoreServices/CoreServices.h>
// Specify DPI for vector format in CGImageSource, like PDF
static NSString * kSDCGImageSourceRasterizationDPI = @"kCGImageSourceRasterizationDPI";
// Specify File Size for lossy format encoding, like JPEG
@ -110,7 +112,27 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
preserveAspectRatio = preserveAspectRatioValue.boolValue;
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
NSString *typeIdentifierHint = options[SDImageCoderDecodeTypeIdentifierHint];
if (!typeIdentifierHint) {
// Check file extension and convert to UTI, from: https://stackoverflow.com/questions/1506251/getting-an-uniform-type-identifier-for-a-given-extension
NSString *fileExtensionHint = options[SDImageCoderDecodeFileExtensionHint];
if (fileExtensionHint) {
typeIdentifierHint = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtensionHint, NULL);
}
} else if ([typeIdentifierHint isEqual:NSNull.null]) {
// Hack if user don't want to imply file extension
typeIdentifierHint = nil;
}
NSDictionary *creatingOptions = nil;
if (typeIdentifierHint) {
creatingOptions = @{(__bridge NSString *)kCGImageSourceTypeIdentifierHint : typeIdentifierHint};
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)creatingOptions);
if (!source) {
// Try again without UTType hint, the call site from user may provide the wrong UTType
source = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)creatingOptions);
}
if (!source) {
return nil;
}

View File

@ -262,6 +262,15 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageP
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageThumbnailPixelSize;
/**
A NSString value (UTI) indicating the source image's file extension. Example: "public.jpeg-2000", "com.nikon.raw-image", "public.tiff"
Some image file format share the same data structure but has different tag explanation, like TIFF and NEF/SRW, see https://en.wikipedia.org/wiki/TIFF
Changing the file extension cause the different image result. The coder (like ImageIO) may use file extension to choose the correct parser
@note If you don't provide this option, we will use the `URL.path` as file extension to calculate the UTI hint
@note If you really don't want any hint which effect the image result, pass `NSNull.null` instead
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageTypeIdentifierHint;
/**
A SDImageCacheType raw value which specify the source of cache to query. Specify `SDImageCacheTypeDisk` to query from disk cache only; `SDImageCacheTypeMemory` to query from memory only. And `SDImageCacheTypeAll` to query from both memory cache and disk cache. Specify `SDImageCacheTypeNone` is invalid and totally ignore the cache query.
If not provide or the value is invalid, we will use `SDImageCacheTypeAll`. (NSNumber)

View File

@ -134,6 +134,7 @@ SDWebImageContextOption const SDWebImageContextImageTransformer = @"imageTransfo
SDWebImageContextOption const SDWebImageContextImageScaleFactor = @"imageScaleFactor";
SDWebImageContextOption const SDWebImageContextImagePreserveAspectRatio = @"imagePreserveAspectRatio";
SDWebImageContextOption const SDWebImageContextImageThumbnailPixelSize = @"imageThumbnailPixelSize";
SDWebImageContextOption const SDWebImageContextImageTypeIdentifierHint = @"imageTypeIdentifierHint";
SDWebImageContextOption const SDWebImageContextQueryCacheType = @"queryCacheType";
SDWebImageContextOption const SDWebImageContextStoreCacheType = @"storeCacheType";
SDWebImageContextOption const SDWebImageContextOriginalQueryCacheType = @"originalQueryCacheType";

View File

@ -7,6 +7,7 @@
*/
#import <Foundation/Foundation.h>
#import <ImageIO/ImageIO.h>
#import "SDImageIOAnimatedCoder.h"
// AVFileTypeHEIC/AVFileTypeHEIF is defined in AVFoundation via iOS 11, we use this without import AVFoundation