Expose the data and format when SDAnimatedImageRep created with APNG/GIF/WebP/HEICS
This can avoid extra decoding (slow) for some cases if you need compressed image data
This commit is contained in:
parent
8dbf8ed97a
commit
1f4292ec82
|
@ -88,6 +88,7 @@
|
|||
|
||||
/**
|
||||
Current animated image format.
|
||||
@note This format is only valid when `animatedImageData` not nil
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) SDImageFormat animatedImageFormat;
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#if SD_MAC
|
||||
|
||||
#import "NSData+ImageContentType.h"
|
||||
|
||||
/**
|
||||
A subclass of `NSBitmapImageRep` to fix that GIF duration issue because `NSBitmapImageRep` will reset `NSImageCurrentFrameDuration` by using `kCGImagePropertyGIFDelayTime` but not `kCGImagePropertyGIFUnclampedDelayTime`.
|
||||
This also fix the GIF loop count issue, which will use the Netscape standard (See http://www6.uniovi.es/gifanim/gifabout.htm) to only place once when the `kCGImagePropertyGIFLoopCount` is nil. This is what modern browser's behavior.
|
||||
|
@ -18,6 +20,14 @@
|
|||
*/
|
||||
@interface SDAnimatedImageRep : NSBitmapImageRep
|
||||
|
||||
/// Current animated image format.
|
||||
/// @note This format is only valid when `animatedImageData` not nil
|
||||
@property (nonatomic, assign, readonly) SDImageFormat animatedImageFormat;
|
||||
|
||||
/// This allows to retrive the compressed data like GIF using `sd_imageData` on parent `NSImage`, without re-encoding (waste CPU and RAM)
|
||||
/// @note This is typically nonnull when you create with `initWithData:`, even it's marked as weak, because ImageIO retain it
|
||||
@property (nonatomic, readonly, nullable, weak) NSData *animatedImageData;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
@interface SDAnimatedImageRep ()
|
||||
/// This wrap the animated image frames for legacy animated image coder API (`encodedDataWithImage:`).
|
||||
@property (nonatomic, readwrite, weak) NSArray<SDImageFrame *> *frames;
|
||||
@property (nonatomic, assign, readwrite) SDImageFormat animatedImageFormat;
|
||||
@end
|
||||
|
||||
@implementation SDAnimatedImageRep {
|
||||
|
@ -33,9 +34,12 @@
|
|||
}
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
SDAnimatedImageRep *imageRep = [super copyWithZone:zone];
|
||||
CFRetain(imageRep->_imageSource);
|
||||
return imageRep;
|
||||
SDAnimatedImageRep *imageRep = [super copyWithZone:zone];
|
||||
// super will copy all ivars
|
||||
if (imageRep->_imageSource) {
|
||||
CFRetain(imageRep->_imageSource);
|
||||
}
|
||||
return imageRep;
|
||||
}
|
||||
|
||||
// `NSBitmapImageRep`'s `imageRepWithData:` is not designed initializer
|
||||
|
@ -63,15 +67,19 @@
|
|||
if (!type) {
|
||||
return self;
|
||||
}
|
||||
_animatedImageData = data; // CGImageSource will retain the data internally, no extra copy
|
||||
SDImageFormat format = SDImageFormatUndefined;
|
||||
if (CFStringCompare(type, kSDUTTypeGIF, 0) == kCFCompareEqualTo) {
|
||||
// GIF
|
||||
// Fix the `NSBitmapImageRep` GIF loop count calculation issue
|
||||
// Which will use 0 when there are no loop count information metadata in GIF data
|
||||
format = SDImageFormatGIF;
|
||||
NSUInteger loopCount = [SDImageGIFCoder imageLoopCountWithSource:imageSource];
|
||||
[self setProperty:NSImageLoopCount withValue:@(loopCount)];
|
||||
} else if (CFStringCompare(type, kSDUTTypePNG, 0) == kCFCompareEqualTo) {
|
||||
// APNG
|
||||
// Do initialize about frame count, current frame/duration and loop count
|
||||
format = SDImageFormatPNG;
|
||||
[self setProperty:NSImageFrameCount withValue:@(frameCount)];
|
||||
[self setProperty:NSImageCurrentFrame withValue:@(0)];
|
||||
NSUInteger loopCount = [SDImageAPNGCoder imageLoopCountWithSource:imageSource];
|
||||
|
@ -79,6 +87,7 @@
|
|||
} else if (CFStringCompare(type, kSDUTTypeHEICS, 0) == kCFCompareEqualTo) {
|
||||
// HEIC
|
||||
// Do initialize about frame count, current frame/duration and loop count
|
||||
format = SDImageFormatHEIC;
|
||||
[self setProperty:NSImageFrameCount withValue:@(frameCount)];
|
||||
[self setProperty:NSImageCurrentFrame withValue:@(0)];
|
||||
NSUInteger loopCount = [SDImageHEICCoder imageLoopCountWithSource:imageSource];
|
||||
|
@ -86,11 +95,15 @@
|
|||
} else if (CFStringCompare(type, kSDUTTypeWebP, 0) == kCFCompareEqualTo) {
|
||||
// WebP
|
||||
// Do initialize about frame count, current frame/duration and loop count
|
||||
format = SDImageFormatWebP;
|
||||
[self setProperty:NSImageFrameCount withValue:@(frameCount)];
|
||||
[self setProperty:NSImageCurrentFrame withValue:@(0)];
|
||||
NSUInteger loopCount = [SDImageAWebPCoder imageLoopCountWithSource:imageSource];
|
||||
[self setProperty:NSImageLoopCount withValue:@(loopCount)];
|
||||
} else {
|
||||
format = [NSData sd_imageFormatForImageData:data];
|
||||
}
|
||||
_animatedImageFormat = format;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
Encode the current image to the data, the image format is unspecified
|
||||
|
||||
@note If the receiver is `SDAnimatedImage`, this will return the animated image data if available. No more extra encoding process.
|
||||
@note For macOS, if the receiver contains only `SDAnimatedImageRep`, this will return the animated image data if available. No more extra encoding process.
|
||||
@return The encoded data. If can't encode, return nil
|
||||
*/
|
||||
- (nullable NSData *)sd_imageData;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#import "UIImage+MultiFormat.h"
|
||||
#import "SDImageCodersManager.h"
|
||||
#import "SDAnimatedImageRep.h"
|
||||
|
||||
@implementation UIImage (MultiFormat)
|
||||
|
||||
|
@ -28,6 +29,18 @@
|
|||
}
|
||||
|
||||
- (nullable NSData *)sd_imageData {
|
||||
#if SD_MAC
|
||||
NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
|
||||
NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil];
|
||||
// Check weak assigned frames firstly
|
||||
if ([imageRep isKindOfClass:[SDAnimatedImageRep class]]) {
|
||||
SDAnimatedImageRep *animatedImageRep = (SDAnimatedImageRep *)imageRep;
|
||||
NSData *imageData = [animatedImageRep animatedImageData];
|
||||
if (imageData) {
|
||||
return imageData;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return [self sd_imageDataAsFormat:SDImageFormatUndefined];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue