Merge pull request #3243 from dreampiggy/convenience_api_frame_count
Added `sd_imageFrameCount` convenient API for UIAinmatedImage/NSBitmapImageRep
This commit is contained in:
commit
1e7f7174b6
|
@ -314,6 +314,10 @@ static CGFloat SDImageScaleFromPath(NSString *string) {
|
|||
return;
|
||||
}
|
||||
|
||||
- (NSUInteger)sd_imageFrameCount {
|
||||
return self.animatedImageFrameCount;
|
||||
}
|
||||
|
||||
- (SDImageFormat)sd_imageFormat {
|
||||
return self.animatedImageFormat;
|
||||
}
|
||||
|
|
|
@ -135,7 +135,6 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
|
|||
avgDuration = 0.1; // if it's a animated image but no duration, set it to default 100ms (this do not have that 10ms limit like GIF or WebP to allow custom coder provide the limit)
|
||||
}
|
||||
|
||||
__block NSUInteger index = 0;
|
||||
__block NSUInteger repeatCount = 1;
|
||||
__block UIImage *previousImage = animatedImages.firstObject;
|
||||
[animatedImages enumerateObjectsUsingBlock:^(UIImage * _Nonnull image, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
|
@ -149,15 +148,12 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
|
|||
SDImageFrame *frame = [SDImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount];
|
||||
[frames addObject:frame];
|
||||
repeatCount = 1;
|
||||
index++;
|
||||
}
|
||||
previousImage = image;
|
||||
// last one
|
||||
if (idx == frameCount - 1) {
|
||||
SDImageFrame *frame = [SDImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount];
|
||||
[frames addObject:frame];
|
||||
}
|
||||
}];
|
||||
// last one
|
||||
SDImageFrame *frame = [SDImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount];
|
||||
[frames addObject:frame];
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDMemoryCacheCostForImage(UIImage *image) {
|
|||
frameCount = 1;
|
||||
#elif SD_UIKIT || SD_WATCH
|
||||
// Filter the same frame in `_UIAnimatedImage`.
|
||||
frameCount = image.images.count > 0 ? [NSSet setWithArray:image.images].count : 1;
|
||||
frameCount = image.images.count > 1 ? [NSSet setWithArray:image.images].count : 1;
|
||||
#endif
|
||||
NSUInteger cost = bytesPerFrame * frameCount;
|
||||
return cost;
|
||||
|
|
|
@ -20,12 +20,23 @@
|
|||
* For animated image format, 0 means infinite looping.
|
||||
* Note that because of the limitations of categories this property can get out of sync if you create another instance with CGImage or other methods.
|
||||
* AppKit:
|
||||
* NSImage currently only support animated via GIF imageRep unlike UIImage.
|
||||
* The getter of this property will get the loop count from GIF imageRep
|
||||
* The setter of this property will set the loop count from GIF imageRep
|
||||
* NSImage currently only support animated via `NSBitmapImageRep`(GIF) or `SDAnimatedImageRep`(APNG/GIF/WebP) unlike UIImage.
|
||||
* The getter of this property will get the loop count from animated imageRep
|
||||
* The setter of this property will set the loop count from animated imageRep
|
||||
*/
|
||||
@property (nonatomic, assign) NSUInteger sd_imageLoopCount;
|
||||
|
||||
/**
|
||||
* UIKit:
|
||||
* Returns the `images`'s count by unapply the patch for the different frame durations. Which matches the real visible frame count when displaying on UIImageView.
|
||||
* See more in `SDImageCoderHelper.animatedImageWithFrames`.
|
||||
* Returns 1 for static image.
|
||||
* AppKit:
|
||||
* Returns the underlaying `NSBitmapImageRep` or `SDAnimatedImageRep` frame count.
|
||||
* Returns 1 for static image.
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) NSUInteger sd_imageFrameCount;
|
||||
|
||||
/**
|
||||
* UIKit:
|
||||
* Check the `images` array property.
|
||||
|
|
|
@ -29,6 +29,32 @@
|
|||
objc_setAssociatedObject(self, @selector(sd_imageLoopCount), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (NSUInteger)sd_imageFrameCount {
|
||||
NSArray<UIImage *> *animatedImages = self.images;
|
||||
if (!animatedImages || animatedImages.count <= 1) {
|
||||
return 1;
|
||||
}
|
||||
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageFrameCount));
|
||||
if ([value isKindOfClass:[NSNumber class]]) {
|
||||
return [value unsignedIntegerValue];
|
||||
}
|
||||
__block NSUInteger frameCount = 1;
|
||||
__block UIImage *previousImage = animatedImages.firstObject;
|
||||
[animatedImages enumerateObjectsUsingBlock:^(UIImage * _Nonnull image, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
// ignore first
|
||||
if (idx == 0) {
|
||||
return;
|
||||
}
|
||||
if (![image isEqual:previousImage]) {
|
||||
frameCount++;
|
||||
}
|
||||
previousImage = image;
|
||||
}];
|
||||
objc_setAssociatedObject(self, @selector(sd_imageFrameCount), @(frameCount), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
|
||||
return frameCount;
|
||||
}
|
||||
|
||||
- (BOOL)sd_isAnimated {
|
||||
return (self.images != nil);
|
||||
}
|
||||
|
@ -87,6 +113,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (NSUInteger)sd_imageFrameCount {
|
||||
NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
|
||||
NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil];
|
||||
NSBitmapImageRep *bitmapImageRep;
|
||||
if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) {
|
||||
bitmapImageRep = (NSBitmapImageRep *)imageRep;
|
||||
}
|
||||
if (bitmapImageRep) {
|
||||
return [[bitmapImageRep valueForProperty:NSImageFrameCount] unsignedIntegerValue];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (BOOL)sd_isAnimated {
|
||||
BOOL isAnimated = NO;
|
||||
NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
|
||||
|
|
|
@ -770,7 +770,10 @@ static BOOL _isCalled;
|
|||
[[SDImageCodersManager sharedManager] addCoder:[SDImageAWebPCoder sharedCoder]];
|
||||
UIImage *image = [UIImage sd_imageWithData:[NSData dataWithContentsOfFile:[self testMemotyCostImagePath]]];
|
||||
NSUInteger cost = [image sd_memoryCost];
|
||||
#if SD_UIKIT
|
||||
expect(image.images.count).equal(5333);
|
||||
#endif
|
||||
expect(image.sd_imageFrameCount).equal(16);
|
||||
expect(image.scale).equal(1);
|
||||
expect(cost).equal(16 * image.size.width * image.size.height * 4);
|
||||
[[SDImageCodersManager sharedManager] removeCoder:[SDImageAWebPCoder sharedCoder]];
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
image = [UIImage sd_imageWithGIFData:data];
|
||||
expect(image).notTo.beNil();
|
||||
expect(image.sd_isAnimated).beTruthy();
|
||||
expect(image.sd_imageFrameCount).equal(5);
|
||||
}
|
||||
|
||||
#pragma mark - Helper
|
||||
|
|
|
@ -410,9 +410,7 @@ withLocalImageURL:(NSURL *)imageUrl
|
|||
UIImage *outputImage = [coder decodedImageWithData:outputImageData options:nil];
|
||||
expect(outputImage.size).to.equal(inputImage.size);
|
||||
expect(outputImage.scale).to.equal(inputImage.scale);
|
||||
#if SD_UIKIT
|
||||
expect(outputImage.images.count).to.equal(inputImage.images.count);
|
||||
#endif
|
||||
expect(outputImage.sd_imageLoopCount).to.equal(inputImage.sd_imageLoopCount);
|
||||
|
||||
// check max pixel size encoding with scratch
|
||||
CGFloat maxWidth = 50;
|
||||
|
@ -429,13 +427,11 @@ withLocalImageURL:(NSURL *)imageUrl
|
|||
// Image/IO's thumbnail API does not always use round to preserve precision, we check ABS <= 1
|
||||
expect(ABS(outputMaxImage.size.width - maxPixelSize.width)).beLessThanOrEqualTo(1);
|
||||
expect(ABS(outputMaxImage.size.height - maxPixelSize.height)).beLessThanOrEqualTo(1);
|
||||
#if SD_UIKIT
|
||||
expect(outputMaxImage.images.count).to.equal(inputImage.images.count);
|
||||
#endif
|
||||
expect(outputMaxImage.sd_imageLoopCount).to.equal(inputImage.sd_imageLoopCount);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)thumbnailImagesFromImageSource:(CGImageSourceRef)source API_AVAILABLE(ios(11.0), tvos(11.0), macos(13.0)) {
|
||||
- (NSArray *)thumbnailImagesFromImageSource:(CGImageSourceRef)source API_AVAILABLE(ios(11.0), tvos(11.0), macos(10.13)) {
|
||||
NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil);
|
||||
NSDictionary *fileProperties = properties[(__bridge NSString *)kCGImagePropertyFileContentsDictionary];
|
||||
NSArray *imagesProperties = fileProperties[(__bridge NSString *)kCGImagePropertyImages];
|
||||
|
|
Loading…
Reference in New Issue