Add support for built-in ImageIO WebP codec for iOS 14/tvOS 14/macOS 11/watchOS 7

This commit is contained in:
DreamPiggy 2020-07-03 12:40:47 +08:00
parent f876da5031
commit 6eacb15067
10 changed files with 204 additions and 54 deletions

View File

@ -14,9 +14,8 @@
#import <MobileCoreServices/MobileCoreServices.h>
#endif
#import "SDImageHEICCoderInternal.h"
#import "SDImageAWebPCoderInternal.h"
// Currently Image/IO does not support WebP
#define kSDUTTypeWebP ((__bridge CFStringRef)@"public.webp")
#define kSVGTagEnd @"</svg>"
@implementation NSData (ImageContentType)

View File

@ -15,6 +15,7 @@
#import "SDImageAPNGCoder.h"
#import "SDImageHEICCoder.h"
#import "SDImageHEICCoderInternal.h"
#import "SDImageAWebPCoderInternal.h"
@implementation SDAnimatedImageRep {
CGImageSourceRef _imageSource;
@ -70,6 +71,13 @@
[self setProperty:NSImageCurrentFrame withValue:@(0)];
NSUInteger loopCount = [SDImageHEICCoder imageLoopCountWithSource:imageSource];
[self setProperty:NSImageLoopCount withValue:@(loopCount)];
} else if (CFStringCompare(type, kSDUTTypeWebP, 0) == kCFCompareEqualTo) {
// WebP
// Do initialize about frame count, current frame/duration and loop count
[self setProperty:NSImageFrameCount withValue:@(frameCount)];
[self setProperty:NSImageCurrentFrame withValue:@(0)];
NSUInteger loopCount = [SDImageAWebPCoder imageLoopCountWithSource:imageSource];
[self setProperty:NSImageLoopCount withValue:@(loopCount)];
}
}
return self;
@ -100,6 +108,9 @@
} else if (CFStringCompare(type, kSDUTTypeHEICS, 0) == kCFCompareEqualTo) {
// HEIC
frameDuration = [SDImageHEICCoder frameDurationAtIndex:index source:imageSource];
} else if (CFStringCompare(type, kSDUTTypeWebP, 0) == kCFCompareEqualTo) {
// WebP
frameDuration = [SDImageAWebPCoder frameDurationAtIndex:index source:imageSource];
}
if (!frameDuration) {
return;

View File

@ -0,0 +1,21 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDImageIOAnimatedCoder.h"
/**
This coder is used for Google WebP and Animated WebP(AWebP) image format.
Image/IO provide the WebP support in iOS 14/macOS 11/tvOS 14/watchOS 7+.
@note If you need to support lower firmware version for WebP, you can have a try at https://github.com/SDWebImage/SDWebImageWebPCoder
*/
@interface SDImageAWebPCoder : SDImageIOAnimatedCoder <SDProgressiveImageCoder, SDAnimatedImageCoder>
@property (nonatomic, class, readonly, nonnull) SDImageAWebPCoder *sharedCoder;
@end

View File

@ -0,0 +1,119 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDImageAWebPCoder.h"
#import "SDImageAWebPCoderInternal.h"
#import "SDImageIOAnimatedCoderInternal.h"
// These constants are available from iOS 14+ and Xcode 12. This raw value is used for toolchain and firmware compatibility
static NSString * kSDCGImagePropertyWebPDictionary = @"{WebP}";
static NSString * kSDCGImagePropertyWebPLoopCount = @"LoopCount";
static NSString * kSDCGImagePropertyWebPDelayTime = @"DelayTime";
static NSString * kSDCGImagePropertyWebPUnclampedDelayTime = @"UnclampedDelayTime";
@implementation SDImageAWebPCoder
+ (void)initialize {
#if __IPHONE_14_0 || __TVOS_14_0 || __MAC_11_0 || __WATCHOS_7_0
// Xcode 12
if (@available(iOS 14, tvOS 14, macOS 11, watchOS 7, *)) {
// Use SDK instead of raw value
kSDCGImagePropertyWebPDictionary = (__bridge NSString *)kCGImagePropertyWebPDictionary;
kSDCGImagePropertyWebPLoopCount = (__bridge NSString *)kCGImagePropertyWebPLoopCount;
kSDCGImagePropertyWebPDelayTime = (__bridge NSString *)kCGImagePropertyWebPDelayTime;
kSDCGImagePropertyWebPUnclampedDelayTime = (__bridge NSString *)kCGImagePropertyWebPUnclampedDelayTime;
}
#endif
}
+ (instancetype)sharedCoder {
static SDImageAWebPCoder *coder;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
coder = [[SDImageAWebPCoder alloc] init];
});
return coder;
}
#pragma mark - SDImageCoder
- (BOOL)canDecodeFromData:(nullable NSData *)data {
switch ([NSData sd_imageFormatForImageData:data]) {
case SDImageFormatWebP:
// Check WebP decoding compatibility
return [self.class canDecodeFromWebPFormat];
default:
return NO;
}
}
- (BOOL)canIncrementalDecodeFromData:(NSData *)data {
return [self canDecodeFromData:data];
}
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
switch (format) {
case SDImageFormatWebP:
// Check WebP encoding compatibility
return [self.class canEncodeToWebPFormat];
default:
return NO;
}
}
#pragma mark - WebP Format
+ (BOOL)canDecodeFromWebPFormat {
static BOOL canDecode = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
canDecode = [self canDecodeFromFormat:SDImageFormatWebP];
});
return canDecode;
}
+ (BOOL)canEncodeToWebPFormat {
static BOOL canEncode = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
canEncode = [self canEncodeToFormat:SDImageFormatWebP];
});
return canEncode;
}
#pragma mark - Subclass Override
+ (SDImageFormat)imageFormat {
return SDImageFormatWebP;
}
+ (NSString *)imageUTType {
return (__bridge NSString *)kSDUTTypeWebP;
}
+ (NSString *)dictionaryProperty {
return kSDCGImagePropertyWebPDictionary;
}
+ (NSString *)unclampedDelayTimeProperty {
return kSDCGImagePropertyWebPUnclampedDelayTime;
}
+ (NSString *)delayTimeProperty {
return kSDCGImagePropertyWebPDelayTime;
}
+ (NSString *)loopCountProperty {
return kSDCGImagePropertyWebPLoopCount;
}
+ (NSUInteger)defaultLoopCount {
return 0;
}
@end

View File

@ -8,6 +8,7 @@
#import "SDImageHEICCoder.h"
#import "SDImageHEICCoderInternal.h"
#import "SDImageIOAnimatedCoderInternal.h"
// These constants are available from iOS 13+ and Xcode 11. This raw value is used for toolchain and firmware compatibility
static NSString * kSDCGImagePropertyHEICSDictionary = @"{HEICS}";
@ -73,15 +74,6 @@ static NSString * kSDCGImagePropertyHEICSUnclampedDelayTime = @"UnclampedDelayTi
#pragma mark - HEIF Format
+ (BOOL)canDecodeFromFormat:(SDImageFormat)format {
CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:format];
NSArray *imageUTTypes = (__bridge_transfer NSArray *)CGImageSourceCopyTypeIdentifiers();
if ([imageUTTypes containsObject:(__bridge NSString *)(imageUTType)]) {
return YES;
}
return NO;
}
+ (BOOL)canDecodeFromHEICFormat {
static BOOL canDecode = NO;
static dispatch_once_t onceToken;
@ -100,22 +92,6 @@ static NSString * kSDCGImagePropertyHEICSUnclampedDelayTime = @"UnclampedDelayTi
return canDecode;
}
+ (BOOL)canEncodeToFormat:(SDImageFormat)format {
NSMutableData *imageData = [NSMutableData data];
CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:format];
// Create an image destination.
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL);
if (!imageDestination) {
// Can't encode to HEIC
return NO;
} else {
// Can encode to HEIC
CFRelease(imageDestination);
return YES;
}
}
+ (BOOL)canEncodeToHEICFormat {
static BOOL canEncode = NO;
static dispatch_once_t onceToken;

View File

@ -108,6 +108,32 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
#pragma mark - Utils
+ (BOOL)canDecodeFromFormat:(SDImageFormat)format {
CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:format];
NSArray *imageUTTypes = (__bridge_transfer NSArray *)CGImageSourceCopyTypeIdentifiers();
if ([imageUTTypes containsObject:(__bridge NSString *)(imageUTType)]) {
// Can decode from target format
return YES;
}
return NO;
}
+ (BOOL)canEncodeToFormat:(SDImageFormat)format {
NSMutableData *imageData = [NSMutableData data];
CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:format];
// Create an image destination.
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL);
if (!imageDestination) {
// Can't encode to target format
return NO;
} else {
// Can encode to target format
CFRelease(imageDestination);
return YES;
}
}
+ (NSUInteger)imageLoopCountWithSource:(CGImageSourceRef)source {
NSUInteger loopCount = self.defaultLoopCount;
NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil);

View File

@ -11,7 +11,6 @@
#import "NSImage+Compatibility.h"
#import <ImageIO/ImageIO.h>
#import "UIImage+Metadata.h"
#import "SDImageHEICCoderInternal.h"
#import "SDImageIOAnimatedCoderInternal.h"
// Specify File Size for lossy format encoding, like JPEG
@ -55,19 +54,7 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
#pragma mark - Decode
- (BOOL)canDecodeFromData:(nullable NSData *)data {
switch ([NSData sd_imageFormatForImageData:data]) {
case SDImageFormatWebP:
// Do not support WebP decoding
return NO;
case SDImageFormatHEIC:
// Check HEIC decoding compatibility
return [SDImageHEICCoder canDecodeFromHEICFormat];
case SDImageFormatHEIF:
// Check HEIF decoding compatibility
return [SDImageHEICCoder canDecodeFromHEIFFormat];
default:
return YES;
}
return YES;
}
- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderOptions *)options {
@ -205,19 +192,7 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
#pragma mark - Encode
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
switch (format) {
case SDImageFormatWebP:
// Do not support WebP encoding
return NO;
case SDImageFormatHEIC:
// Check HEIC encoding compatibility
return [SDImageHEICCoder canEncodeToHEICFormat];
case SDImageFormatHEIF:
// Check HEIF encoding compatibility
return [SDImageHEICCoder canEncodeToHEIFFormat];
default:
return YES;
}
return YES;
}
- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDImageCoderOptions *)options {

View File

@ -0,0 +1,20 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDImageAWebPCoder.h"
// kUTTypeWebP seems not defined in public UTI framework, Apple use the hardcode string, we define them :)
#define kSDUTTypeWebP ((__bridge CFStringRef)@"org.webmproject.webp")
@interface SDImageAWebPCoder ()
+ (BOOL)canDecodeFromWebPFormat;
+ (BOOL)canEncodeToWebPFormat;
@end

View File

@ -14,5 +14,7 @@
+ (NSTimeInterval)frameDurationAtIndex:(NSUInteger)index source:(nonnull CGImageSourceRef)source;
+ (NSUInteger)imageLoopCountWithSource:(nonnull CGImageSourceRef)source;
+ (nullable UIImage *)createFrameAtIndex:(NSUInteger)index source:(nonnull CGImageSourceRef)source scale:(CGFloat)scale preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize options:(nullable NSDictionary *)options;
+ (BOOL)canEncodeToFormat:(SDImageFormat)format;
+ (BOOL)canDecodeFromFormat:(SDImageFormat)format;
@end

View File

@ -70,6 +70,7 @@ FOUNDATION_EXPORT const unsigned char SDWebImageVersionString[];
#import <SDWebImage/SDWebImageOptionsProcessor.h>
#import <SDWebImage/SDImageIOAnimatedCoder.h>
#import <SDWebImage/SDImageHEICCoder.h>
#import <SDWebImage/SDImageAWebPCoder.h>
// Mac
#if __has_include(<SDWebImage/NSImage+Compatibility.h>)