Skip to content
This repository has been archived by the owner on Feb 2, 2023. It is now read-only.

[ASImageNode] An ASImageNode debug feature showing pixel scaling amount #1336

Merged
28 changes: 28 additions & 0 deletions AsyncDisplayKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@
69F10C861C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; };
69F10C871C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; };
6BDC61F61979037800E50D21 /* AsyncDisplayKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
764D83D51C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h in Headers */ = {isa = PBXBuildFile; fileRef = 764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */; settings = {ATTRIBUTES = (Public, ); }; };
764D83D61C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m in Sources */ = {isa = PBXBuildFile; fileRef = 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */; };
767E7F8D1C9019130066C000 /* AsyncDisplayKit+Debug.h in Headers */ = {isa = PBXBuildFile; fileRef = 764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */; settings = {ATTRIBUTES = (Public, ); }; };
767E7F8E1C90191D0066C000 /* AsyncDisplayKit+Debug.m in Sources */ = {isa = PBXBuildFile; fileRef = 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */; };
81EE384F1C8E94F000456208 /* ASRunLoopQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
81EE38501C8E94F000456208 /* ASRunLoopQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */; };
92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -726,6 +730,8 @@
68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMainSerialQueue.mm; sourceTree = "<group>"; };
69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASRangeControllerUpdateRangeProtocol+Beta.h"; sourceTree = "<group>"; };
6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; path = AsyncDisplayKit.h; sourceTree = "<group>"; };
764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AsyncDisplayKit+Debug.h"; sourceTree = "<group>"; };
764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AsyncDisplayKit+Debug.m"; sourceTree = "<group>"; };
81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRunLoopQueue.h; path = ../ASRunLoopQueue.h; sourceTree = "<group>"; };
81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRunLoopQueue.mm; path = ../ASRunLoopQueue.mm; sourceTree = "<group>"; };
92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMapNode.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1010,6 +1016,8 @@
ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */,
ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */,
6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */,
764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */,
764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */,
DB55C2651C641AE4004EDCF5 /* ASContextTransitioning.h */,
058D09E1195D050800B7D73C /* Details */,
058D0A01195D050800B7D73C /* Private */,
Expand Down Expand Up @@ -1404,6 +1412,7 @@
AC7A2C171BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */,
058D0A4D195D05CB00B7D73C /* ASDisplayNodeExtras.h in Headers */,
68B0277A1C1A79CC0041016B /* ASDisplayNode+Beta.h in Headers */,
767E7F8D1C9019130066C000 /* AsyncDisplayKit+Debug.h in Headers */,
257754B11BEE44CD00737CA5 /* ASTextKitShadower.h in Headers */,
058D0A7B195D05F900B7D73C /* ASDisplayNodeInternal.h in Headers */,
0587F9BD1A7309ED00AFF0BA /* ASEditableTextNode.h in Headers */,
Expand Down Expand Up @@ -1592,6 +1601,7 @@
9C49C3701B853961000B0DD5 /* ASStackLayoutable.h in Headers */,
DE040EF91C2B40AC004692FF /* ASCollectionViewFlowLayoutInspector.h in Headers */,
34EFC7701B701CFA00AD841F /* ASStackLayoutDefines.h in Headers */,
764D83D51C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h in Headers */,
E5711A2C1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */,
254C6B7B1BF94DF4003EC431 /* ASTextKitRenderer+Positioning.h in Headers */,
CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */,
Expand Down Expand Up @@ -1665,6 +1675,7 @@
058D09B9195D04C000B7D73C /* Frameworks */,
058D09BA195D04C000B7D73C /* Resources */,
3B9D88CDF51B429C8409E4B6 /* Copy Pods Resources */,
BD5CC779F736EBA28F5313FB /* Embed Pods Frameworks */,
);
buildRules = (
);
Expand Down Expand Up @@ -1794,6 +1805,21 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
BD5CC779F736EBA28F5313FB /* Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
Expand Down Expand Up @@ -1842,6 +1868,7 @@
ACF6ED211B17843500DA7C62 /* ASDimension.mm in Sources */,
058D0A28195D050800B7D73C /* ASDisplayNode+AsyncDisplay.mm in Sources */,
058D0A29195D050800B7D73C /* ASDisplayNode+DebugTiming.mm in Sources */,
764D83D61C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m in Sources */,
058D0A2A195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm in Sources */,
25E327581C16819500A2170C /* ASPagerNode.m in Sources */,
058D0A14195D050800B7D73C /* ASDisplayNode.mm in Sources */,
Expand Down Expand Up @@ -1986,6 +2013,7 @@
B35061F91B010EFD0018CF92 /* ASControlNode.mm in Sources */,
B35062181B010EFD0018CF92 /* ASDataController.mm in Sources */,
B350621A1B010EFD0018CF92 /* ASDealloc2MainObject.m in Sources */,
767E7F8E1C90191D0066C000 /* AsyncDisplayKit+Debug.m in Sources */,
34EFC75C1B701BD200AD841F /* ASDimension.mm in Sources */,
B350624E1B010EFD0018CF92 /* ASDisplayNode+AsyncDisplay.mm in Sources */,
25E327591C16819500A2170C /* ASPagerNode.m in Sources */,
Expand Down
45 changes: 42 additions & 3 deletions AsyncDisplayKit/ASImageNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
#import <AsyncDisplayKit/ASDisplayNodeInternal.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
#import <AsyncDisplayKit/ASDisplayNode+Beta.h>
#import <AsyncDisplayKit/ASTextNode.h>

#import "ASImageNode+CGExtras.h"
#import "AsyncDisplayKit+Debug.h"

#import "ASInternalHelpers.h"
#import "ASEqualityHelpers.h"
Expand Down Expand Up @@ -55,7 +57,6 @@ - (NSString *)description

@end


@implementation ASImageNode
{
@private
Expand All @@ -69,6 +70,8 @@ @implementation ASImageNode
BOOL _forceUpscaling; //Defaults to NO.
CGRect _cropRect; // Defaults to CGRectMake(0.5, 0.5, 0, 0)
CGRect _cropDisplayBounds;

ASTextNode *_debugLabelNode;
}

@synthesize image = _image;
Expand All @@ -89,6 +92,12 @@ - (id)init
_cropRect = CGRectMake(0.5, 0.5, 0, 0);
_cropDisplayBounds = CGRectNull;
_placeholderColor = ASDisplayNodeDefaultPlaceholderColor();

if ([ASImageNode shouldShowImageScalingOverlay]) {
_debugLabelNode = [[ASTextNode alloc] init];
_debugLabelNode.layerBacked = YES;
[self addSubnode:_debugLabelNode];
}

return self;
}
Expand Down Expand Up @@ -152,6 +161,12 @@ - (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
contentMode:self.contentMode];
}

- (NSDictionary *)debugLabelAttributes
{
return @{ NSFontAttributeName: [UIFont systemFontOfSize:15.0],
NSForegroundColorAttributeName: [UIColor redColor] };
}

- (UIImage *)displayWithParameters:(_ASImageNodeDrawParameters *)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled
{
UIImage *image;
Expand Down Expand Up @@ -202,6 +217,19 @@ - (UIImage *)displayWithParameters:(_ASImageNodeDrawParameters *)parameters isCa
CGSize imageSizeInPixels = CGSizeMake(imageSize.width * image.scale, imageSize.height * image.scale);
CGSize boundsSizeInPixels = CGSizeMake(floorf(bounds.size.width * contentsScale), floorf(bounds.size.height * contentsScale));

if (_debugLabelNode) {
CGFloat pixelCountRatio = (imageSizeInPixels.width * imageSizeInPixels.height) / (boundsSizeInPixels.width * boundsSizeInPixels.height);
if (pixelCountRatio != 1.0) {
NSString *scaleString = [NSString stringWithFormat:@"%.2fx", pixelCountRatio];
_debugLabelNode.attributedString = [[NSAttributedString alloc] initWithString:scaleString attributes:[self debugLabelAttributes]];
_debugLabelNode.hidden = NO;
[self setNeedsLayout];
} else {
_debugLabelNode.hidden = YES;
_debugLabelNode.attributedString = nil;
}
}

BOOL contentModeSupported = contentMode == UIViewContentModeScaleAspectFill
|| contentMode == UIViewContentModeScaleAspectFit
|| contentMode == UIViewContentModeCenter;
Expand Down Expand Up @@ -410,9 +438,21 @@ - (void)setImageModificationBlock:(asimagenode_modification_block_t)imageModific
_imageModificationBlock = imageModificationBlock;
}

#pragma mark - Debug
- (void)layout
{
[super layout];

if (_debugLabelNode) {
CGSize boundsSize = self.bounds.size;
CGSize debugLabelSize = [_debugLabelNode measure:boundsSize];
CGPoint debugLabelOrigin = CGPointMake(boundsSize.width - debugLabelSize.width,
boundsSize.height - debugLabelSize.height);
_debugLabelNode.frame = (CGRect) {debugLabelOrigin, debugLabelSize};
}
}
@end


#pragma mark - Extras
extern asimagenode_modification_block_t ASImageNodeRoundBorderModificationBlock(CGFloat borderWidth, UIColor *borderColor)
{
Expand Down Expand Up @@ -460,4 +500,3 @@ extern asimagenode_modification_block_t ASImageNodeTintColorModificationBlock(UI
return modifiedImage;
};
}

23 changes: 23 additions & 0 deletions AsyncDisplayKit/AsyncDisplayKit+Debug.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// AsyncDisplayKit+Debug.h
// AsyncDisplayKit
//
// Created by Hannah Troisi on 3/7/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "ASImageNode.h"

@interface ASImageNode (Debugging)

/**
* Enables an ASImageNode debug label that shows the ratio of pixels in the source image to those in
* the displayed bounds (including cropRect). This helps detect excessive image fetching / downscaling,
* as well as upscaling (such as providing a URL not suitable for a Retina device). For dev purposes only.
* @param enabled Specify YES to show the label on all ASImageNodes with non-1.0x source-to-bounds pixel ratio.
*/
+ (void)setShouldShowImageScalingOverlay:(BOOL)show;
+ (BOOL)shouldShowImageScalingOverlay;

@end
26 changes: 26 additions & 0 deletions AsyncDisplayKit/AsyncDisplayKit+Debug.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// AsyncDisplayKit+Debug.m
// AsyncDisplayKit
//
// Created by Hannah Troisi on 3/7/16.
// Copyright © 2016 Facebook. All rights reserved.
//

#import "AsyncDisplayKit+Debug.h"
#import "ASDisplayNode+Subclasses.h"

static BOOL __shouldShowImageScalingOverlay = NO;

@implementation ASImageNode (Debugging)

+ (void)setShouldShowImageScalingOverlay:(BOOL)show;
{
__shouldShowImageScalingOverlay = show;
}

+ (BOOL)shouldShowImageScalingOverlay
{
return __shouldShowImageScalingOverlay;
}

@end
2 changes: 2 additions & 0 deletions AsyncDisplayKit/AsyncDisplayKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,5 @@
#import <AsyncDisplayKit/NSMutableAttributedString+TextKitAdditions.h>
#import <AsyncDisplayKit/UICollectionViewLayout+ASConvenience.h>
#import <AsyncDisplayKit/UIView+ASConvenience.h>

#import <AsyncDisplayKit/AsyncDisplayKit+Debug.h>