TwitterImagePipeline/TIPImageContainer.h (82 lines of code) (raw):
//
// TIPImageContainer.h
// TwitterImagePipeline
//
// Created on 10/8/15.
// Copyright © 2020 Twitter. All rights reserved.
//
#import <ImageIO/CGImageSource.h>
#import <TwitterImagePipeline/TIPImageUtils.h>
#import <UIKit/UIImage.h>
#import <UIKit/UIView.h>
@class TIPImageCodecCatalogue;
NS_ASSUME_NONNULL_BEGIN
/**
`TIPImageContainer` encapsulates a `UIImage` and any relevant meta-data for that image.
For now, animated images (specifically GIF) can have additional info related to animation which
`UIImage` doesn't offer.
*/
@interface TIPImageContainer : NSObject
#pragma mark Properties
/** The `UIImage` being encapsulated by the container */
@property (nonatomic, readonly) UIImage *image;
/**
`YES` if the _image_ is animated.
See `TIPImageContainer(Animated)` for more.
*/
@property (nonatomic, readonly, getter=isAnimated) BOOL animated;
/**
An opaque descriptor object encapsulating info about this `TIPImageContainer` w/o the large `UIImage`.
Can be used to create a new `TIPImageContainer` along with the matching `UIImage` using `[TIPImageContainer imageContainerWithImage:descriptor:]`.
*/
@property (nonatomic, readonly) id descriptor;
#pragma mark Initialization
/**
Initializer to create a `TIPImageContainer` with a specified image.
Can end up being an animated or static image.
@param image the `UIImage` to encapsulate
@return The image container encapsulating the specified _image_.
*/
- (instancetype)initWithImage:(UIImage *)image;
/** `NS_UNAVAILABLE` */
- (instancetype)init NS_UNAVAILABLE;
/** `NS_UNAVAILABLE` */
+ (instancetype)new NS_UNAVAILABLE;
@end
/**
Interface for methods/properties related to animated image containers
*/
@interface TIPImageContainer (Animated)
#pragma mark Properties
/** Number of loops in the animation. `0` indicates _loop forever_. */
@property (nonatomic, readonly) NSUInteger loopCount;
/** Number of frames in the animation. */
@property (nonatomic, readonly) NSUInteger frameCount;
/**
All the frames of the animation (as `UIImage` objects).
This array will have the same count as _frameCount_.
*/
@property (nonatomic, readonly, nullable) NSArray<UIImage *> *frames;
/**
The durations paired to each frame. Durations are `NSNumber` objects wrapping `float` values.
This array will have the same count as _frameCount_.
*/
@property (nonatomic, readonly, nullable) NSArray<NSNumber *> *frameDurations;
#pragma mark Initialization
/**
Initializer to create a `TIPImageContainer` with a specified animated image.
As the name indicates, this initializer expects an animated image with _animation_ arguments,
but the resulting `TIPImageContainer` can still be a static image based on the _image_ passed in.
@param image the `UIImage` to encapsulate
@param loopCount the number of loops for the animation
@param durations the durations for each frame of the animation.
If `nil` or count doesn't match the frames of _image_, `frameDurations` will fall back to being
calculated off of `[UIImage duration]`.
@return The image container encapsulating the specified _image_.
*/
- (instancetype)initWithAnimatedImage:(UIImage *)image
loopCount:(NSUInteger)loopCount
frameDurations:(nullable NSArray<NSNumber *> *)durations;
#pragma mark Methods
/**
Access a specific frame by index.
@param index The index of the frame to grab
@return the `UIImage` of the frame, or `nil` if _index_ is out of bounds
*/
- (nullable UIImage *)frameAtIndex:(NSUInteger)index;
/**
Access a specific frame's duration by index.
@param index The index of the frame's duration to grab
@return the time interval for the frame at _index_ or `0.0` if the _index_ is out of bounds.
*/
- (NSTimeInterval)frameDurationAtIndex:(NSUInteger)index;
@end
/**
`TIPImageContainer(Convenience)` offers additional convenience methods to `TIPImageContainer`.
*/
@interface TIPImageContainer (Convenience)
#pragma mark Constructors
/**
Convenience constructor.
@param image the `UIImage` to encapsulate
@param descriptor the matching descriptor (sourced from a `TIPImageContainer` with the same _image_)
@return image container encapsulating the desired image, or `nil` if the _descriptor_ and _image_ are incompatible
*/
+ (nullable instancetype)imageContainerWithImage:(UIImage *)image descriptor:(id)descriptor;
/**
Convenience constructor.
@param imageSource the `CGImageSourceRef` to read in as a `UIImage` and encapsulate
@param targetDimensions the dimension sizing constraints to decode the image into (`CGSizeZero` for full size)
@param targetContentMode the content mode sizing constraints to decode the image into (any non-scaling mode for full size)
@return image container encapsulating the desired image, or `nil` if the image could not be loaded
@note unlike the other `TIPImageContainer` convenience constructor methods, this method
does NOT load via a `TIPImageCodecCatalogue`.
*/
+ (nullable instancetype)imageContainerWithImageSource:(CGImageSourceRef)imageSource
targetDimensions:(CGSize)targetDimensions
targetContentMode:(UIViewContentMode)targetContentMode;
+ (nullable instancetype)imageContainerWithImageSource:(CGImageSourceRef)imageSource;
/**
Convenience constructor.
@param data the `NSData` to load as a `UIImage` and encapsulate
@param targetDimensions the dimension sizing constraints to decode the image into (`CGSizeZero` for full size)
@param targetContentMode the content mode sizing constraints to decode the image into (any non-scaling mode for full size)
@param decoderConfigMap an optional dictionary of opaque config objects for the decoder to use (config will be matched by the decoder's image type string), passing `nil` is always fine
@param catalogue the catalogue of codecs to load with, pass `nil` to use
`[TIPImageCodecCatalogue sharedInstance]`
@return image container encapsulating the desired image, or `nil` if the image could not be loaded
*/
+ (nullable instancetype)imageContainerWithData:(NSData *)data
targetDimensions:(CGSize)targetDimensions
targetContentMode:(UIViewContentMode)targetContentMode
decoderConfigMap:(nullable NSDictionary<NSString *, id> *)decoderConfigMap
codecCatalogue:(nullable TIPImageCodecCatalogue *)catalogue;
+ (nullable instancetype)imageContainerWithData:(NSData *)data
decoderConfigMap:(nullable NSDictionary<NSString *, id> *)decoderConfigMap
codecCatalogue:(nullable TIPImageCodecCatalogue *)catalogue;
/**
Convenience constructor.
@param filePath the file path to load as a `UIImage` and encpasulate
@param targetDimensions the dimension sizing constraints to decode the image into (`CGSizeZero` for full size)
@param targetContentMode the content mode sizing constraints to decode the image into (any non-scaling mode for full size)
@param decoderConfigMap an optional dictionary of opaque config objects for the decoder to use (config will be matched by the decoder's image type string), passing `nil` is always fine
@param catalogue the catalogue of codecs to load with, pass `nil` to use
`[TIPImageCodecCatalogue sharedInstance]`
@param map `YES` to load the image data via memory map, `NO` (default) to load the image data into memory
@return image container encapsulating the desired image, or `nil` if the image could not be loaded
@warning Loading with memory mapped file is very fragile. Modification/move/deletion and even high velocity reading of the underlying file (at that path) can yield a crash or corruption. Take care to only provide `YES` for _map_ if you are very confident in the approach.
*/
+ (nullable instancetype)imageContainerWithFilePath:(NSString *)filePath
targetDimensions:(CGSize)targetDimensions
targetContentMode:(UIViewContentMode)targetContentMode
decoderConfigMap:(nullable NSDictionary<NSString *, id> *)decoderConfigMap
codecCatalogue:(nullable TIPImageCodecCatalogue *)catalogue
memoryMap:(BOOL)map;
+ (nullable instancetype)imageContainerWithFilePath:(NSString *)filePath
decoderConfigMap:(nullable NSDictionary<NSString *, id> *)decoderConfigMap
codecCatalogue:(nullable TIPImageCodecCatalogue *)catalogue
memoryMap:(BOOL)map;
/**
Convenience constructor.
@param fileURL the file path `NSURL` to load as a `UIImage` and encpasulate
@param targetDimensions the dimension sizing constraints to decode the image into (`CGSizeZero` for full size)
@param targetContentMode the content mode sizing constraints to decode the image into (any non-scaling mode for full size)
@param decoderConfigMap an optional dictionary of opaque config objects for the decoder to use (config will be matched by the decoder's image type string), passing `nil` is always fine
@param catalogue the catalogue of codecs to load with, pass `nil` to use
`[TIPImageCodecCatalogue sharedInstance]`
@param map `YES` to load the image data via memory map, `NO` (default) to load the image data into memory
@return image container encapsulating the desired image, or `nil` if the image could not be loaded
@warning Loading with memory mapped file is very fragile. Modification/move/deletion and even high velocity reading of the underlying file (at that path) can yield a crash or corruption. Take care to only provide `YES` for _map_ if you are very confident in the approach.
*/
+ (nullable instancetype)imageContainerWithFileURL:(NSURL *)fileURL
targetDimensions:(CGSize)targetDimensions
targetContentMode:(UIViewContentMode)targetContentMode
decoderConfigMap:(nullable NSDictionary<NSString *, id> *)decoderConfigMap
codecCatalogue:(nullable TIPImageCodecCatalogue *)catalogue
memoryMap:(BOOL)map;
+ (nullable instancetype)imageContainerWithFileURL:(NSURL *)fileURL
decoderConfigMap:(nullable NSDictionary<NSString *, id> *)decoderConfigMap
codecCatalogue:(nullable TIPImageCodecCatalogue *)catalogue
memoryMap:(BOOL)map;
#pragma mark Inferred Properties
/** the size, in bytes, the encapsulated image takes up in memory */
@property (nonatomic, readonly) NSUInteger sizeInMemory;
/** the dimensions, in pixels (not points), of the encapsulated image */
@property (nonatomic, readonly) CGSize dimensions;
/** the size, in points (not pixels), of the encapsulated image */
@property (nonatomic, readonly) CGSize pointSize;
#pragma mark Methods
/** synchronously decode the encapsulated image */
- (void)decode;
/**
Scale the encapsulated image to a new `TIPImageContainer`
@param dimensions the target dimensions (in pixels) to scale to
@param contentMode the target content mode to scale with
@return the new `TIPImageContainer` encapsulated the scaled image, `nil` in the extreme case that
the scaling failed (super exceptional case).
*/
- (nullable TIPImageContainer *)scaleToTargetDimensions:(CGSize)dimensions
contentMode:(UIViewContentMode)contentMode;
/**
Save the encapsulated image to disk
@param path the file path to save the image to
@param type the _TIPImageType_ to save as
@param catalogue the catalogue of codecs to load with, pass `nil` for the `sharedInstance`
@param options the `TIPImageEncodingOptions` to save with
@param quality the quality (`0.0` to `1.0`) to save lossy images as, if _type_ supports lossy
@param atomic whether or not to atomically write the image to disk
@param error set if an error was encountered
@return `YES` on success, `NO` on failure
*/
- (BOOL)saveToFilePath:(NSString *)path
type:(nullable NSString *)type
codecCatalogue:(nullable TIPImageCodecCatalogue *)catalogue
options:(TIPImageEncodingOptions)options
quality:(float)quality
atomic:(BOOL)atomic
error:(out NSError * __nullable * __nullable)error;
@end
NS_ASSUME_NONNULL_END