ibireme 9 жил өмнө
parent
commit
d82174cc79

+ 8 - 4
Demo/YYTextDemo/YYImage/YYAnimatedImageView.h

@@ -11,6 +11,8 @@
 
 #import <UIKit/UIKit.h>
 
+NS_ASSUME_NONNULL_BEGIN
+
 /**
  An image view for displaying animated image.
  
@@ -38,7 +40,7 @@
  
  The default value is `YES`.
  */
-@property (nonatomic, assign) BOOL autoPlayAnimatedImage;
+@property (nonatomic) BOOL autoPlayAnimatedImage;
 
 /**
  Index of the currently displayed frame (index from 0).
@@ -48,7 +50,7 @@
  
  You can add an observer to this property to observe the playing status.
  */
-@property (nonatomic, assign) NSUInteger currentAnimatedImageIndex;
+@property (nonatomic) NSUInteger currentAnimatedImageIndex;
 
 /**
  Whether the image view is playing animation currently.
@@ -76,7 +78,7 @@
  When receive memory warning or app enter background, the buffer will be released 
  immediately, and may grow back at the right time.
  */
-@property (nonatomic, assign) NSUInteger maxBufferSize;
+@property (nonatomic) NSUInteger maxBufferSize;
 
 @end
 
@@ -107,7 +109,7 @@
 /// Returns the frame image from a specified index.
 /// This method may be called on background thread.
 /// @param index  Frame index (zero based).
-- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index;
+- (nullable UIImage *)animatedImageFrameAtIndex:(NSUInteger)index;
 
 /// Returns the frames's duration from a specified index.
 /// @param index  Frame index (zero based).
@@ -119,3 +121,5 @@
 /// It may used to display sprite animation with a single image (sprite sheet).
 - (CGRect)animatedImageContentsRectAtIndex:(NSUInteger)index;
 @end
+
+NS_ASSUME_NONNULL_END

+ 16 - 7
Demo/YYTextDemo/YYImage/YYAnimatedImageView.m

@@ -135,7 +135,7 @@ typedef NS_ENUM(NSUInteger, YYAnimatedImageType) {
     NSUInteger _curIndex; ///< current frame index (from 0)
     NSUInteger _totalFrameCount; ///< total frame count
     
-    BOOL _loopEnd; ///< weather the loop is end.
+    BOOL _loopEnd; ///< whether the loop is end.
     NSUInteger _curLoop; ///< current loop count (from 0)
     NSUInteger _totalLoop; ///< total loop count, 0 means infinity
     
@@ -165,22 +165,28 @@ typedef NS_ENUM(NSUInteger, YYAnimatedImageType) {
     if ([self isCancelled]) return;
     view->_incrBufferCount++;
     if (view->_incrBufferCount == 0) [view calcMaxBufferCount];
-    if ((int)view->_incrBufferCount > (int)view->_maxBufferCount) {
+    if (view->_incrBufferCount > (NSInteger)view->_maxBufferCount) {
         view->_incrBufferCount = view->_maxBufferCount;
     }
     NSUInteger idx = _nextIndex;
     NSUInteger max = view->_incrBufferCount < 1 ? 1 : view->_incrBufferCount;
     NSUInteger total = view->_totalFrameCount;
+    view = nil;
+    
     for (int i = 0; i < max; i++, idx++) {
         @autoreleasepool {
             if (idx >= total) idx = 0;
             if ([self isCancelled]) break;
+            __strong YYAnimatedImageView *view = _view;
+            if (!view) break;
             LOCK_VIEW(BOOL miss = (view->_buffer[@(idx)] == nil));
+            
             if (miss) {
                 UIImage *img = [_curImage animatedImageFrameAtIndex:idx];
-                img = [img yy_imageByDecoded];
+                img = img.yy_imageByDecoded;
                 if ([self isCancelled]) break;
                 LOCK_VIEW(view->_buffer[@(idx)] = img ? img : [NSNull null]);
+                view = nil;
             }
         }
     }
@@ -373,16 +379,18 @@ typedef NS_ENUM(NSUInteger, YYAnimatedImageType) {
 
 // dynamically adjust buffer size for current memory.
 - (void)calcMaxBufferCount {
-    NSUInteger bytes = _curAnimatedImage.animatedImageBytesPerFrame;
-    if (bytes == 0) bytes = 1;
+    int64_t bytes = (int64_t)_curAnimatedImage.animatedImageBytesPerFrame;
+    if (bytes == 0) bytes = 1024;
     
     int64_t total = _YYDeviceMemoryTotal();
     int64_t free = _YYDeviceMemoryFree();
     int64_t max = MIN(total * 0.2, free * 0.6);
     max = MAX(max, BUFFER_SIZE);
     if (_maxBufferSize) max = max > _maxBufferSize ? _maxBufferSize : max;
-    _maxBufferCount = (float)max / (float)bytes;
-    if (_maxBufferCount == 0) _maxBufferCount = 1;
+    double maxBufferCount = (double)max / (double)bytes;
+    if (maxBufferCount < 1) maxBufferCount = 1;
+    else if (maxBufferCount > 512) maxBufferCount = 512;
+    _maxBufferCount = maxBufferCount;
 }
 
 - (void)dealloc {
@@ -398,6 +406,7 @@ typedef NS_ENUM(NSUInteger, YYAnimatedImageType) {
 
 - (void)stopAnimating {
     [super stopAnimating];
+    [_requestQueue cancelAllOperations];
     _link.paused = YES;
     self.currentIsPlayingAnimation = NO;
 }

+ 16 - 4
Demo/YYTextDemo/YYImage/YYFrameImage.h

@@ -19,6 +19,8 @@
 #import "YYAnimatedImageView.h"
 #endif
 
+NS_ASSUME_NONNULL_BEGIN
+
 /**
  An image to display frame-based animation.
  
@@ -49,7 +51,9 @@
  
  @return An initialized YYFrameImage object, or nil when an error occurs.
  */
-- (instancetype)initWithImagePaths:(NSArray *)paths oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount;
+- (nullable instancetype)initWithImagePaths:(NSArray<NSString *> *)paths
+                           oneFrameDuration:(NSTimeInterval)oneFrameDuration
+                                  loopCount:(NSUInteger)loopCount;
 
 /**
  Create a frame animated image from files.
@@ -65,7 +69,9 @@
  
  @return An initialized YYFrameImage object, or nil when an error occurs.
  */
-- (instancetype)initWithImagePaths:(NSArray *)paths frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount;
+- (nullable instancetype)initWithImagePaths:(NSArray<NSString *> *)paths
+                             frameDurations:(NSArray<NSNumber *> *)frameDurations
+                                  loopCount:(NSUInteger)loopCount;
 
 /**
  Create a frame animated image from an array of data.
@@ -78,7 +84,9 @@
  
  @return An initialized YYFrameImage object, or nil when an error occurs.
  */
-- (instancetype)initWithImageDataArray:(NSArray *)dataArray oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount;
+- (nullable instancetype)initWithImageDataArray:(NSArray<NSData *> *)dataArray
+                               oneFrameDuration:(NSTimeInterval)oneFrameDuration
+                                      loopCount:(NSUInteger)loopCount;
 
 /**
  Create a frame animated image from an array of data.
@@ -92,6 +100,10 @@
  
  @return An initialized YYFrameImage object, or nil when an error occurs.
  */
-- (instancetype)initWithImageDataArray:(NSArray *)dataArray frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount;
+- (nullable instancetype)initWithImageDataArray:(NSArray<NSData *> *)dataArray
+                                 frameDurations:(NSArray *)frameDurations
+                                      loopCount:(NSUInteger)loopCount;
 
 @end
+
+NS_ASSUME_NONNULL_END

+ 9 - 7
Demo/YYTextDemo/YYImage/YYImage.h

@@ -30,7 +30,7 @@ FOUNDATION_EXPORT const unsigned char YYImageVersionString[];
 #import "YYAnimatedImageView.h"
 #endif
 
-
+NS_ASSUME_NONNULL_BEGIN
 
 
 /**
@@ -53,10 +53,10 @@ FOUNDATION_EXPORT const unsigned char YYImageVersionString[];
  */
 @interface YYImage : UIImage <YYAnimatedImage>
 
-+ (YYImage *)imageNamed:(NSString *)name; // no cache!
-+ (YYImage *)imageWithContentsOfFile:(NSString *)path;
-+ (YYImage *)imageWithData:(NSData *)data;
-+ (YYImage *)imageWithData:(NSData *)data scale:(CGFloat)scale;
++ (nullable YYImage *)imageNamed:(NSString *)name; // no cache!
++ (nullable YYImage *)imageWithContentsOfFile:(NSString *)path;
++ (nullable YYImage *)imageWithData:(NSData *)data;
++ (nullable YYImage *)imageWithData:(NSData *)data scale:(CGFloat)scale;
 
 /**
  If the image is created from data or file, then the value indicates the data type.
@@ -67,7 +67,7 @@ FOUNDATION_EXPORT const unsigned char YYImageVersionString[];
  If the image is created from animated image data (multi-frame GIF/APNG/WebP),
  this property stores the original image data.
  */
-@property (nonatomic, readonly) NSData *animatedImageData;
+@property (nullable, nonatomic, readonly) NSData *animatedImageData;
 
 /**
  The total memory usage (in bytes) if all frame images was loaded into memory.
@@ -85,6 +85,8 @@ FOUNDATION_EXPORT const unsigned char YYImageVersionString[];
  
  See `animatedImageMemorySize` for memory cost.
  */
-@property (nonatomic, assign) BOOL preloadAllAnimatedImageFrames;
+@property (nonatomic) BOOL preloadAllAnimatedImageFrames;
 
 @end
+
+NS_ASSUME_NONNULL_END

+ 53 - 50
Demo/YYTextDemo/YYImage/YYImageCoder.h

@@ -11,6 +11,8 @@
 
 #import <UIKit/UIKit.h>
 
+NS_ASSUME_NONNULL_BEGIN
+
 /**
  Image file type.
  */
@@ -76,15 +78,15 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  An image frame object.
  */
 @interface YYImageFrame : NSObject <NSCopying>
-@property (nonatomic, assign) NSUInteger index;    ///< Frame index (zero based)
-@property (nonatomic, assign) NSUInteger width;    ///< Frame width
-@property (nonatomic, assign) NSUInteger height;   ///< Frame height
-@property (nonatomic, assign) NSUInteger offsetX;  ///< Frame origin.x in canvas (left-bottom based)
-@property (nonatomic, assign) NSUInteger offsetY;  ///< Frame origin.y in canvas (left-bottom based)
-@property (nonatomic, assign) NSTimeInterval duration;      ///< Frame duration in seconds
-@property (nonatomic, assign) YYImageDisposeMethod dispose; ///< Frame dispose method.
-@property (nonatomic, assign) YYImageBlendOperation blend;  ///< Frame blend operation.
-@property (nonatomic, strong) UIImage *image; ///< The image.
+@property (nonatomic) NSUInteger index;    ///< Frame index (zero based)
+@property (nonatomic) NSUInteger width;    ///< Frame width
+@property (nonatomic) NSUInteger height;   ///< Frame height
+@property (nonatomic) NSUInteger offsetX;  ///< Frame origin.x in canvas (left-bottom based)
+@property (nonatomic) NSUInteger offsetY;  ///< Frame origin.y in canvas (left-bottom based)
+@property (nonatomic) NSTimeInterval duration;          ///< Frame duration in seconds
+@property (nonatomic) YYImageDisposeMethod dispose;     ///< Frame dispose method.
+@property (nonatomic) YYImageBlendOperation blend;      ///< Frame blend operation.
+@property (nullable, nonatomic, strong) UIImage *image; ///< The image.
 + (instancetype)frameWithImage:(UIImage *)image;
 @end
 
@@ -124,9 +126,9 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  */
 @interface YYImageDecoder : NSObject
 
-@property (nonatomic, readonly) NSData *data;       ///< Image data.
-@property (nonatomic, readonly) YYImageType type;   ///< Image data type.
-@property (nonatomic, readonly) CGFloat scale;      ///< Image scale.
+@property (nullable, nonatomic, readonly) NSData *data;    ///< Image data.
+@property (nonatomic, readonly) YYImageType type;          ///< Image data type.
+@property (nonatomic, readonly) CGFloat scale;             ///< Image scale.
 @property (nonatomic, readonly) NSUInteger frameCount;     ///< Image frame count.
 @property (nonatomic, readonly) NSUInteger loopCount;      ///< Image loop count, 0 means infinite.
 @property (nonatomic, readonly) NSUInteger width;          ///< Image canvas width.
@@ -158,7 +160,7 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  
  @return Whether succeed.
  */
-- (BOOL)updateData:(NSData *)data final:(BOOL)final;
+- (BOOL)updateData:(nullable NSData *)data final:(BOOL)final;
 
 /**
  Convenience method to create a decoder with specified data.
@@ -166,7 +168,7 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  @param scale Image's scale.
  @return A new decoder, or nil if an error occurs.
  */
-+ (instancetype)decoderWithData:(NSData *)data scale:(CGFloat)scale;
++ (nullable instancetype)decoderWithData:(NSData *)data scale:(CGFloat)scale;
 
 /**
  Decodes and returns a frame from a specified index.
@@ -175,7 +177,7 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
     If NO, it will try to returns the original frame data without blend.
  @return A new frame with image, or nil if an error occurs.
  */
-- (YYImageFrame *)frameAtIndex:(NSUInteger)index decodeForDisplay:(BOOL)decodeForDisplay;
+- (nullable YYImageFrame *)frameAtIndex:(NSUInteger)index decodeForDisplay:(BOOL)decodeForDisplay;
 
 /**
  Returns the frame duration from a specified index.
@@ -191,13 +193,13 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  @param index  Frame image index (zero-based).
  @return The ImageIO frame property.
  */
-- (NSDictionary *)framePropertiesAtIndex:(NSUInteger)index;
+- (nullable NSDictionary *)framePropertiesAtIndex:(NSUInteger)index;
 
 /**
  Returns the image's properties. See "CGImageProperties.h" in ImageIO.framework
  for more information.
  */
-- (NSDictionary *)imageProperties;
+- (nullable NSDictionary *)imageProperties;
 
 @end
 
@@ -231,10 +233,10 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  */
 @interface YYImageEncoder : NSObject
 
-@property (nonatomic, readonly) YYImageType type;   ///< Image type.
-@property (nonatomic, assign) NSUInteger loopCount; ///< Loop count, 0 means infinit, only available for GIF/APNG/WebP.
-@property (nonatomic, assign) BOOL lossless;        ///< Lossless, only available for WebP.
-@property (nonatomic, assign) CGFloat quality;      ///< Compress quality, 0.0~1.0, only available for JPG/JP2/WebP.
+@property (nonatomic, readonly) YYImageType type; ///< Image type.
+@property (nonatomic) NSUInteger loopCount;       ///< Loop count, 0 means infinit, only available for GIF/APNG/WebP.
+@property (nonatomic) BOOL lossless;              ///< Lossless, only available for WebP.
+@property (nonatomic) CGFloat quality;            ///< Compress quality, 0.0~1.0, only available for JPG/JP2/WebP.
 
 - (instancetype)init UNAVAILABLE_ATTRIBUTE;
 + (instancetype)new UNAVAILABLE_ATTRIBUTE;
@@ -244,7 +246,7 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  @param type Image type.
  @return A new encoder, or nil if an error occurs.
  */
-- (instancetype)initWithType:(YYImageType)type NS_DESIGNATED_INITIALIZER;
+- (nullable instancetype)initWithType:(YYImageType)type NS_DESIGNATED_INITIALIZER;
 
 /**
  Add an image to encoder.
@@ -271,7 +273,7 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  Encodes the image and returns the image data.
  @return The image data, or nil if an error occurs.
  */
-- (NSData *)encode;
+- (nullable NSData *)encode;
 
 /**
  Encodes the image to a file.
@@ -287,7 +289,7 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  @param quality Image quality, 0.0~1.0.
  @return The image data, or nil if an error occurs.
  */
-+ (NSData *)encodeImage:(UIImage *)image type:(YYImageType)type quality:(CGFloat)quality;
++ (nullable NSData *)encodeImage:(UIImage *)image type:(YYImageType)type quality:(CGFloat)quality;
 
 /**
  Convenience method to encode image from a decoder.
@@ -296,7 +298,7 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  @param quality Image quality, 0.0~1.0.
  @return The image data, or nil if an error occurs.
  */
-+ (NSData *)encodeImageWithDecoder:(YYImageDecoder *)decoder type:(YYImageType)type quality:(CGFloat)quality;
++ (nullable NSData *)encodeImageWithDecoder:(YYImageDecoder *)decoder type:(YYImageType)type quality:(CGFloat)quality;
 
 @end
 
@@ -319,7 +321,7 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  Wherher the image can be display on screen without additional decoding.
  @warning It just a hint for your code, change it has no other effect.
  */
-@property (nonatomic, assign) BOOL yy_isDecodedForDisplay;
+@property (nonatomic) BOOL yy_isDecodedForDisplay;
 
 /**
  Saves this image to iOS Photos Album. 
@@ -332,7 +334,7 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
     assetURL: An URL that identifies the saved image file. If the image is not saved, assetURL is nil.
     error: If the image is not saved, an error object that describes the reason for failure, otherwise nil.
  */
-- (void)yy_saveToAlbumWithCompletionBlock:(void(^)(NSURL *assetURL, NSError *error))completionBlock;
+- (void)yy_saveToAlbumWithCompletionBlock:(nullable void(^)(NSURL * _Nullable assetURL, NSError * _Nullable error))completionBlock;
 
 /**
  Return a 'best' data representation for this image.
@@ -343,7 +345,7 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
  
  @return Image data, or nil if an error occurs.
  */
-- (NSData *)yy_imageDataRepresentation;
+- (nullable NSData *)yy_imageDataRepresentation;
 
 @end
 
@@ -355,13 +357,13 @@ typedef NS_ENUM(NSUInteger, YYImageBlendOperation) {
 CG_EXTERN YYImageType YYImageDetectType(CFDataRef data);
 
 /// Convert YYImageType to UTI (such as kUTTypeJPEG).
-CG_EXTERN CFStringRef YYImageTypeToUTType(YYImageType type);
+CG_EXTERN CFStringRef _Nullable YYImageTypeToUTType(YYImageType type);
 
 /// Convert UTI (such as kUTTypeJPEG) to YYImageType.
 CG_EXTERN YYImageType YYImageTypeFromUTType(CFStringRef uti);
 
 /// Get image type's file extension (such as @"jpg").
-CG_EXTERN NSString *YYImageTypeGetExtension(YYImageType type);
+CG_EXTERN NSString *_Nullable YYImageTypeGetExtension(YYImageType type);
 
 
 
@@ -402,7 +404,7 @@ CG_EXTERN NSInteger YYUIImageOrientationToEXIFValue(UIImageOrientation orientati
  
  @return A decoded image, or NULL if an error occurs.
  */
-CG_EXTERN CGImageRef YYCGImageCreateDecodedCopy(CGImageRef imageRef, BOOL decodeForDisplay);
+CG_EXTERN CGImageRef _Nullable YYCGImageCreateDecodedCopy(CGImageRef imageRef, BOOL decodeForDisplay);
 
 /**
  Create an image copy with an orientation.
@@ -412,9 +414,9 @@ CG_EXTERN CGImageRef YYCGImageCreateDecodedCopy(CGImageRef imageRef, BOOL decode
  @param destBitmapInfo Destimation image bitmap, only support 32bit format (such as ARGB8888).
  @return A new image, or NULL if an error occurs.
  */
-CG_EXTERN CGImageRef YYCGImageCreateCopyWithOrientation(CGImageRef imageRef,
-                                              UIImageOrientation orientation,
-                                              CGBitmapInfo destBitmapInfo);
+CG_EXTERN CGImageRef _Nullable YYCGImageCreateCopyWithOrientation(CGImageRef imageRef,
+                                                                  UIImageOrientation orientation,
+                                                                  CGBitmapInfo destBitmapInfo);
 
 /**
  Create an image copy with CGAffineTransform.
@@ -425,10 +427,10 @@ CG_EXTERN CGImageRef YYCGImageCreateCopyWithOrientation(CGImageRef imageRef,
  @param destBitmapInfo Destimation image bitmap, only support 32bit format (such as ARGB8888).
  @return A new image, or NULL if an error occurs.
  */
-CG_EXTERN CGImageRef YYCGImageCreateAffineTransformCopy(CGImageRef imageRef,
-                                              CGAffineTransform transform,
-                                              CGSize destSize,
-                                              CGBitmapInfo destBitmapInfo);
+CG_EXTERN CGImageRef _Nullable YYCGImageCreateAffineTransformCopy(CGImageRef imageRef,
+                                                                  CGAffineTransform transform,
+                                                                  CGSize destSize,
+                                                                  CGBitmapInfo destBitmapInfo);
 
 /**
  Encode an image to data with CGImageDestination.
@@ -438,7 +440,7 @@ CG_EXTERN CGImageRef YYCGImageCreateAffineTransformCopy(CGImageRef imageRef,
  @param quality   The quality (0.0~1.0)
  @return A new image data, or nil if an error occurs.
  */
-CG_EXTERN CFDataRef YYCGImageCreateEncodedData(CGImageRef imageRef, YYImageType type, CGFloat quality);
+CG_EXTERN CFDataRef _Nullable YYCGImageCreateEncodedData(CGImageRef imageRef, YYImageType type, CGFloat quality);
 
 
 /**
@@ -468,12 +470,11 @@ CG_EXTERN NSUInteger YYImageGetWebPFrameCount(CFDataRef webpData);
                             (speed down, and may lose some details).
  @return The decoded image, or NULL if an error occurs.
  */
-CG_EXTERN CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
-                                       BOOL decodeForDisplay,
-                                       BOOL useThreads,
-                                       BOOL bypassFiltering,
-                                       BOOL noFancyUpsampling);
-
+CG_EXTERN CGImageRef _Nullable YYCGImageCreateWithWebPData(CFDataRef webpData,
+                                                           BOOL decodeForDisplay,
+                                                           BOOL useThreads,
+                                                           BOOL bypassFiltering,
+                                                           BOOL noFancyUpsampling);
 
 typedef NS_ENUM(NSUInteger, YYImagePreset) {
     YYImagePresetDefault = 0,  ///< default preset.
@@ -495,8 +496,10 @@ typedef NS_ENUM(NSUInteger, YYImagePreset) {
  @param preset        Preset for different image type, default is YYImagePresetDefault.
  @return WebP data, or nil if an error occurs.
  */
-CG_EXTERN CFDataRef YYCGImageCreateEncodedWebPData(CGImageRef imageRef,
-                                         BOOL lossless,
-                                         CGFloat quality,
-                                         int compressLevel,
-                                         YYImagePreset preset);
+CG_EXTERN CFDataRef _Nullable YYCGImageCreateEncodedWebPData(CGImageRef imageRef,
+                                                             BOOL lossless,
+                                                             CGFloat quality,
+                                                             int compressLevel,
+                                                             YYImagePreset preset);
+
+NS_ASSUME_NONNULL_END

+ 36 - 23
Demo/YYTextDemo/YYImage/YYImageCoder.m

@@ -1399,7 +1399,8 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     config.output.u.RGBA.stride = (int)bytesPerRow;
     config.output.u.RGBA.size = destLength;
     
-    if (WebPDecode(payload, payloadSize, &config) != VP8_STATUS_OK) goto fail;
+    VP8StatusCode result = WebPDecode(payload, payloadSize, &config);
+    if ((result != VP8_STATUS_OK) && (result != VP8_STATUS_NOT_ENOUGH_DATA)) goto fail;
     
     if (iter.x_offset != 0 || iter.y_offset != 0) {
         void *tmp = calloc(1, destLength);
@@ -2150,7 +2151,8 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
         config.output.u.RGBA.rgba = pixels;
         config.output.u.RGBA.stride = (int)bytesPerRow;
         config.output.u.RGBA.size = length;
-        if (WebPDecode(payload, payloadSize, &config) != VP8_STATUS_OK) { // decode
+        VP8StatusCode result = WebPDecode(payload, payloadSize, &config); // decode
+        if ((result != VP8_STATUS_OK) && (result != VP8_STATUS_NOT_ENOUGH_DATA)) {
             WebPDemuxReleaseIterator(&iter);
             free(pixels);
             return NULL;
@@ -2415,27 +2417,38 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     }
     
     for (int i = 0; i < count; i++) {
-        id imageSrc = _images[i];
-        NSDictionary *frameProperty = NULL;
-        if (_type == YYImageTypeGIF && count > 1) {
-            frameProperty = @{(NSString *)kCGImagePropertyGIFDictionary : @{(NSString *) kCGImagePropertyGIFDelayTime:_durations[i]}};
-        } else {
-            frameProperty = @{(id)kCGImageDestinationLossyCompressionQuality : @(_quality)};
-        }
-        
-        if ([imageSrc isKindOfClass:[UIImage class]]) {
-            CGImageDestinationAddImage(destination, ((UIImage *)imageSrc).CGImage, (CFDictionaryRef)frameProperty);
-        } else if ([imageSrc isKindOfClass:[NSURL class]]) {
-            CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)imageSrc, NULL);
-            if (source) {
-                CGImageDestinationAddImageFromSource(destination, source, i, (CFDictionaryRef)frameProperty);
-                CFRelease(source);
+        @autoreleasepool {
+            id imageSrc = _images[i];
+            NSDictionary *frameProperty = NULL;
+            if (_type == YYImageTypeGIF && count > 1) {
+                frameProperty = @{(NSString *)kCGImagePropertyGIFDictionary : @{(NSString *) kCGImagePropertyGIFDelayTime:_durations[i]}};
+            } else {
+                frameProperty = @{(id)kCGImageDestinationLossyCompressionQuality : @(_quality)};
             }
-        } else if ([imageSrc isKindOfClass:[NSData class]]) {
-            CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)imageSrc, NULL);
-            if (source) {
-                CGImageDestinationAddImageFromSource(destination, source, i, (CFDictionaryRef)frameProperty);
-                CFRelease(source);
+            
+            if ([imageSrc isKindOfClass:[UIImage class]]) {
+                UIImage *image = imageSrc;
+                if (image.imageOrientation != UIImageOrientationUp && image.CGImage) {
+                    CGBitmapInfo info = CGImageGetBitmapInfo(image.CGImage) | CGImageGetAlphaInfo(image.CGImage);
+                    CGImageRef rotated = YYCGImageCreateCopyWithOrientation(image.CGImage, image.imageOrientation, info);
+                    if (rotated) {
+                        image = [UIImage imageWithCGImage:rotated];
+                        CFRelease(rotated);
+                    }
+                }
+                if (image.CGImage) CGImageDestinationAddImage(destination, ((UIImage *)imageSrc).CGImage, (CFDictionaryRef)frameProperty);
+            } else if ([imageSrc isKindOfClass:[NSURL class]]) {
+                CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)imageSrc, NULL);
+                if (source) {
+                    CGImageDestinationAddImageFromSource(destination, source, i, (CFDictionaryRef)frameProperty);
+                    CFRelease(source);
+                }
+            } else if ([imageSrc isKindOfClass:[NSData class]]) {
+                CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)imageSrc, NULL);
+                if (source) {
+                    CGImageDestinationAddImageFromSource(destination, source, i, (CFDictionaryRef)frameProperty);
+                    CFRelease(source);
+                }
             }
         }
     }
@@ -2724,7 +2737,7 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
 }
 
 + (NSData *)encodeImageWithDecoder:(YYImageDecoder *)decoder type:(YYImageType)type quality:(CGFloat)quality {
-    if (!decoder || !decoder.frameCount == 0) return nil;
+    if (!decoder || decoder.frameCount == 0) return nil;
     YYImageEncoder *encoder = [[YYImageEncoder alloc] initWithType:type];
     encoder.quality = quality;
     for (int i = 0; i < decoder.frameCount; i++) {

+ 10 - 6
Demo/YYTextDemo/YYImage/YYSpriteSheetImage.h

@@ -19,6 +19,8 @@
 #import "YYAnimatedImageView.h"
 #endif
 
+NS_ASSUME_NONNULL_BEGIN
+
 /**
  An image to display sprite sheet animation.
  
@@ -79,13 +81,13 @@
  
  @return An image object, or nil if an error occurs.
  */
-- (instancetype)initWithSpriteSheetImage:(UIImage *)image
-                            contentRects:(NSArray *)contentRects
-                          frameDurations:(NSArray *)frameDurations
-                               loopCount:(NSUInteger)loopCount;
+- (nullable instancetype)initWithSpriteSheetImage:(UIImage *)image
+                                     contentRects:(NSArray<NSValue *> *)contentRects
+                                   frameDurations:(NSArray<NSNumber *> *)frameDurations
+                                        loopCount:(NSUInteger)loopCount;
 
-@property (nonatomic, readonly) NSArray *contentRects;
-@property (nonatomic, readonly) NSArray *frameDurations;
+@property (nonatomic, readonly) NSArray<NSValue *> *contentRects;
+@property (nonatomic, readonly) NSArray<NSValue *> *frameDurations;
 @property (nonatomic, readonly) NSUInteger loopCount;
 
 /**
@@ -98,3 +100,5 @@
 - (CGRect)contentsRectForCALayerAtIndex:(NSUInteger)index;
 
 @end
+
+NS_ASSUME_NONNULL_END