diff --git a/AsyncDisplayKit/ASImageNode.h b/AsyncDisplayKit/ASImageNode.h index 5ebc0113b8..0012350331 100644 --- a/AsyncDisplayKit/ASImageNode.h +++ b/AsyncDisplayKit/ASImageNode.h @@ -48,6 +48,14 @@ typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image); */ @property (nonatomic, assign, getter=isCropEnabled) BOOL cropEnabled; +/** + * @abstract Indicates that efficient downsizing of backing store should *not* be enabled. + * + * @discussion Defaults to NO. @see ASCroppedImageBackingSizeAndDrawRectInBounds for more + * information. + */ +@property (nonatomic, assign) BOOL forceUpscaling; + /** * @abstract Enables or disables efficient cropping. * diff --git a/AsyncDisplayKit/ASImageNode.mm b/AsyncDisplayKit/ASImageNode.mm index c3d5d330a5..2824a2e81f 100644 --- a/AsyncDisplayKit/ASImageNode.mm +++ b/AsyncDisplayKit/ASImageNode.mm @@ -66,6 +66,7 @@ // Cropping. BOOL _cropEnabled; // Defaults to YES. + BOOL _forceUpscaling; //Defaults to NO. CGRect _cropRect; // Defaults to CGRectMake(0.5, 0.5, 0, 0) CGRect _cropDisplayBounds; } @@ -84,6 +85,7 @@ self.opaque = NO; _cropEnabled = YES; + _forceUpscaling = NO; _cropRect = CGRectMake(0.5, 0.5, 0, 0); _cropDisplayBounds = CGRectNull; _placeholderColor = ASDisplayNodeDefaultPlaceholderColor(); @@ -156,6 +158,7 @@ { UIImage *image; BOOL cropEnabled; + BOOL forceUpscaling; CGFloat contentsScale; CGRect cropDisplayBounds; CGRect cropRect; @@ -169,6 +172,7 @@ } cropEnabled = _cropEnabled; + forceUpscaling = _forceUpscaling; contentsScale = _contentsScaleForDisplay; cropDisplayBounds = _cropDisplayBounds; cropRect = _cropRect; @@ -223,6 +227,7 @@ boundsSizeInPixels, contentMode, cropRect, + forceUpscaling, &backingSize, &imageDrawRect); } @@ -385,6 +390,18 @@ }); } +- (BOOL)forceUpscaling +{ + ASDN::MutexLocker l(_imageLock); + return _forceUpscaling; +} + +- (void)setForceUpscaling:(BOOL)forceUpscaling +{ + ASDN::MutexLocker l(_imageLock); + _forceUpscaling = forceUpscaling; +} + - (asimagenode_modification_block_t)imageModificationBlock { ASDN::MutexLocker l(_imageLock); diff --git a/AsyncDisplayKit/Private/ASImageNode+CGExtras.h b/AsyncDisplayKit/Private/ASImageNode+CGExtras.h index e549313c8a..0c4803c206 100644 --- a/AsyncDisplayKit/Private/ASImageNode+CGExtras.h +++ b/AsyncDisplayKit/Private/ASImageNode+CGExtras.h @@ -19,12 +19,14 @@ ASDISPLAYNODE_EXTERN_C_BEGIN @param boundsSize The bounds in which the image will be displayed. @param contentMode The mode that defines how image will be scaled and cropped to fit. Supported values are UIViewContentModeScaleToAspectFill and UIViewContentModeScaleToAspectFit. @param cropRect A rectangle that is to be featured by the cropped image. The rectangle is specified as a "unit rectangle," using percentages of the source image's width and height, e.g. CGRectMake(0.5, 0, 0.5, 1.0) will feature the full right half a photo. If the cropRect is empty, the contentMode will be used to determine the drawRect's size, and only the cropRect's origin will be used for positioning. + @param forceUpscaling A boolean that indicates you would *not* like the backing size to be downscaled if the image is smaller than the destination size. Setting this to YES will result in higher memory usage when images are smaller than their destination. @discussion If the image is smaller than the size and UIViewContentModeScaleToAspectFill is specified, we suggest the input size so it will be efficiently upscaled on the GPU by the displaying layer at composite time. */ extern void ASCroppedImageBackingSizeAndDrawRectInBounds(CGSize sourceImageSize, CGSize boundsSize, UIViewContentMode contentMode, CGRect cropRect, + BOOL forceUpscaling, CGSize *outBackingSize, CGRect *outDrawRect ); diff --git a/AsyncDisplayKit/Private/ASImageNode+CGExtras.m b/AsyncDisplayKit/Private/ASImageNode+CGExtras.m index a3d862700b..1467bc0e14 100644 --- a/AsyncDisplayKit/Private/ASImageNode+CGExtras.m +++ b/AsyncDisplayKit/Private/ASImageNode+CGExtras.m @@ -36,6 +36,7 @@ void ASCroppedImageBackingSizeAndDrawRectInBounds(CGSize sourceImageSize, CGSize boundsSize, UIViewContentMode contentMode, CGRect cropRect, + BOOL forceUpscaling, CGSize *outBackingSize, CGRect *outDrawRect ) @@ -62,7 +63,7 @@ void ASCroppedImageBackingSizeAndDrawRectInBounds(CGSize sourceImageSize, // If fitting the desired aspect ratio to the image size actually results in a larger buffer, use the input values. // However, if there is a pixel savings (e.g. we would have to upscale the image), overwrite the function arguments. - if ((scaledSizeForImage.width * scaledSizeForImage.height) < (destinationWidth * destinationHeight)) { + if (forceUpscaling == NO && (scaledSizeForImage.width * scaledSizeForImage.height) < (destinationWidth * destinationHeight)) { destinationWidth = (size_t)roundf(scaledSizeForImage.width); destinationHeight = (size_t)roundf(scaledSizeForImage.height); if (destinationWidth == 0 || destinationHeight == 0) {