Fixed image clipping / resizing logic
This commit is contained in:
parent
672b77f355
commit
7232b1bbc7
|
@ -25,7 +25,7 @@
|
||||||
13DF61B61B67A45000EDB188 /* RCTMethodArgumentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13DF61B51B67A45000EDB188 /* RCTMethodArgumentTests.m */; };
|
13DF61B61B67A45000EDB188 /* RCTMethodArgumentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13DF61B51B67A45000EDB188 /* RCTMethodArgumentTests.m */; };
|
||||||
141FC1211B222EBB004D5FFB /* IntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 141FC1201B222EBB004D5FFB /* IntegrationTests.m */; };
|
141FC1211B222EBB004D5FFB /* IntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 141FC1201B222EBB004D5FFB /* IntegrationTests.m */; };
|
||||||
143BC5A11B21E45C00462512 /* UIExplorerSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 143BC5A01B21E45C00462512 /* UIExplorerSnapshotTests.m */; };
|
143BC5A11B21E45C00462512 /* UIExplorerSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 143BC5A01B21E45C00462512 /* UIExplorerSnapshotTests.m */; };
|
||||||
144D21241B2204C5006DB32B /* RCTClipRectTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 144D21231B2204C5006DB32B /* RCTClipRectTests.m */; };
|
144D21241B2204C5006DB32B /* RCTImageUtilTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 144D21231B2204C5006DB32B /* RCTImageUtilTests.m */; };
|
||||||
147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 147CED4B1AB34F8C00DA3E4C /* libRCTActionSheet.a */; };
|
147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 147CED4B1AB34F8C00DA3E4C /* libRCTActionSheet.a */; };
|
||||||
1497CFAC1B21F5E400C1F8F2 /* RCTAllocationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */; };
|
1497CFAC1B21F5E400C1F8F2 /* RCTAllocationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */; };
|
||||||
1497CFAD1B21F5E400C1F8F2 /* RCTBridgeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */; };
|
1497CFAD1B21F5E400C1F8F2 /* RCTBridgeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */; };
|
||||||
|
@ -191,7 +191,7 @@
|
||||||
143BC5951B21E3E100462512 /* UIExplorerIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIExplorerIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
143BC5951B21E3E100462512 /* UIExplorerIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIExplorerIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
143BC5981B21E3E100462512 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
143BC5981B21E3E100462512 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
143BC5A01B21E45C00462512 /* UIExplorerSnapshotTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIExplorerSnapshotTests.m; sourceTree = "<group>"; };
|
143BC5A01B21E45C00462512 /* UIExplorerSnapshotTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIExplorerSnapshotTests.m; sourceTree = "<group>"; };
|
||||||
144D21231B2204C5006DB32B /* RCTClipRectTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTClipRectTests.m; sourceTree = "<group>"; };
|
144D21231B2204C5006DB32B /* RCTImageUtilTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageUtilTests.m; sourceTree = "<group>"; };
|
||||||
1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAllocationTests.m; sourceTree = "<group>"; };
|
1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAllocationTests.m; sourceTree = "<group>"; };
|
||||||
1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBridgeTests.m; sourceTree = "<group>"; };
|
1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBridgeTests.m; sourceTree = "<group>"; };
|
||||||
1497CFA61B21F5E400C1F8F2 /* RCTContextExecutorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTContextExecutorTests.m; sourceTree = "<group>"; };
|
1497CFA61B21F5E400C1F8F2 /* RCTContextExecutorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTContextExecutorTests.m; sourceTree = "<group>"; };
|
||||||
|
@ -357,12 +357,12 @@
|
||||||
1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */,
|
1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */,
|
||||||
1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */,
|
1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */,
|
||||||
138D6A151B53CD440074A87E /* RCTCacheTests.m */,
|
138D6A151B53CD440074A87E /* RCTCacheTests.m */,
|
||||||
144D21231B2204C5006DB32B /* RCTClipRectTests.m */,
|
|
||||||
1497CFA61B21F5E400C1F8F2 /* RCTContextExecutorTests.m */,
|
1497CFA61B21F5E400C1F8F2 /* RCTContextExecutorTests.m */,
|
||||||
1497CFA71B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m */,
|
1497CFA71B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m */,
|
||||||
1497CFA81B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m */,
|
1497CFA81B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m */,
|
||||||
1497CFA91B21F5E400C1F8F2 /* RCTEventDispatcherTests.m */,
|
1497CFA91B21F5E400C1F8F2 /* RCTEventDispatcherTests.m */,
|
||||||
1300627E1B59179B0043FE5A /* RCTGzipTests.m */,
|
1300627E1B59179B0043FE5A /* RCTGzipTests.m */,
|
||||||
|
144D21231B2204C5006DB32B /* RCTImageUtilTests.m */,
|
||||||
13DB03471B5D2ED500C27245 /* RCTJSONTests.m */,
|
13DB03471B5D2ED500C27245 /* RCTJSONTests.m */,
|
||||||
13DF61B51B67A45000EDB188 /* RCTMethodArgumentTests.m */,
|
13DF61B51B67A45000EDB188 /* RCTMethodArgumentTests.m */,
|
||||||
1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.m */,
|
1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.m */,
|
||||||
|
@ -793,7 +793,7 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
1497CFB01B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m in Sources */,
|
1497CFB01B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m in Sources */,
|
||||||
144D21241B2204C5006DB32B /* RCTClipRectTests.m in Sources */,
|
144D21241B2204C5006DB32B /* RCTImageUtilTests.m in Sources */,
|
||||||
1393D0381B68CD1300E1B601 /* RCTModuleMethodTests.m in Sources */,
|
1393D0381B68CD1300E1B601 /* RCTModuleMethodTests.m in Sources */,
|
||||||
1497CFB21B21F5E400C1F8F2 /* RCTSparseArrayTests.m in Sources */,
|
1497CFB21B21F5E400C1F8F2 /* RCTSparseArrayTests.m in Sources */,
|
||||||
1300627F1B59179B0043FE5A /* RCTGzipTests.m in Sources */,
|
1300627F1B59179B0043FE5A /* RCTGzipTests.m in Sources */,
|
||||||
|
|
|
@ -33,11 +33,11 @@ RCTAssertEqualPoints(a.origin, b.origin); \
|
||||||
RCTAssertEqualSizes(a.size, b.size); \
|
RCTAssertEqualSizes(a.size, b.size); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface RCTClipRectTests : XCTestCase
|
@interface RCTImageUtilTests : XCTestCase
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation RCTClipRectTests
|
@implementation RCTImageUtilTests
|
||||||
|
|
||||||
- (void)testLandscapeSourceLandscapeTarget
|
- (void)testLandscapeSourceLandscapeTarget
|
||||||
{
|
{
|
||||||
|
@ -46,19 +46,19 @@ RCTAssertEqualSizes(a.size, b.size); \
|
||||||
|
|
||||||
{
|
{
|
||||||
CGRect expected = {CGPointZero, {100, 20}};
|
CGRect expected = {CGPointZero, {100, 20}};
|
||||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleToFill);
|
CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleToFill);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CGRect expected = {CGPointZero, {100, 10}};
|
CGRect expected = {CGPointZero, {100, 10}};
|
||||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFit);
|
CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFit);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CGRect expected = {{-50, 0}, {200, 20}};
|
CGRect expected = {{-50, 0}, {200, 20}};
|
||||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFill);
|
CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFill);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,20 +69,20 @@ RCTAssertEqualSizes(a.size, b.size); \
|
||||||
CGSize target = {100, 20};
|
CGSize target = {100, 20};
|
||||||
|
|
||||||
{
|
{
|
||||||
CGRect expected = {CGPointZero, {10, 20}};
|
CGRect expected = {CGPointZero, {100, 20}};
|
||||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleToFill);
|
CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleToFill);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CGRect expected = {CGPointZero, {2, 20}};
|
CGRect expected = {CGPointZero, {2, 20}};
|
||||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFit);
|
CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFit);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CGRect expected = {{0, -49}, {10, 100}};
|
CGRect expected = {{0, -490}, {100, 1000}};
|
||||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFill);
|
CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFill);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,20 +93,20 @@ RCTAssertEqualSizes(a.size, b.size); \
|
||||||
CGSize target = {20, 50};
|
CGSize target = {20, 50};
|
||||||
|
|
||||||
{
|
{
|
||||||
CGRect expected = {CGPointZero, {10, 50}};
|
CGRect expected = {CGPointZero, {20, 50}};
|
||||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleToFill);
|
CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleToFill);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CGRect expected = {CGPointZero, {5, 50}};
|
CGRect expected = {CGPointZero, {5, 50}};
|
||||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFit);
|
CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFit);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CGRect expected = {{0, -37.5}, {10, 100}};
|
CGRect expected = {{0, -75}, {20, 200}};
|
||||||
CGRect result = RCTClipRect(content, 2, target, 2, UIViewContentModeScaleAspectFill);
|
CGRect result = RCTTargetRect(content, target, 2, UIViewContentModeScaleAspectFill);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,8 @@ RCTAssertEqualSizes(a.size, b.size); \
|
||||||
CGSize target = {20, 50};
|
CGSize target = {20, 50};
|
||||||
|
|
||||||
{
|
{
|
||||||
CGRect expected = {{0, -38}, {10, 100}};
|
CGRect expected = {{0, -75}, {20, 200}};
|
||||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFill);
|
CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFill);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ RCTAssertEqualSizes(a.size, b.size); \
|
||||||
CGSize target = {3, 3};
|
CGSize target = {3, 3};
|
||||||
|
|
||||||
CGRect expected = {CGPointZero, {3, 3}};
|
CGRect expected = {CGPointZero, {3, 3}};
|
||||||
CGRect result = RCTClipRect(content, 2, target, 1, UIViewContentModeScaleToFill);
|
CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleToFill);
|
||||||
RCTAssertEqualRects(expected, result);
|
RCTAssertEqualRects(expected, result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,6 @@
|
||||||
#import "RCTNetworking.h"
|
#import "RCTNetworking.h"
|
||||||
#import "RCTUtils.h"
|
#import "RCTUtils.h"
|
||||||
|
|
||||||
CGSize RCTTargetSizeForClipRect(CGRect);
|
|
||||||
CGRect RCTClipRect(CGSize, CGFloat, CGSize, CGFloat, UIViewContentMode);
|
|
||||||
|
|
||||||
@implementation RCTImageDownloader
|
@implementation RCTImageDownloader
|
||||||
{
|
{
|
||||||
NSURLCache *_cache;
|
NSURLCache *_cache;
|
||||||
|
@ -131,14 +128,14 @@ RCT_EXPORT_MODULE()
|
||||||
UIImage *image = [UIImage imageWithData:data scale:scale];
|
UIImage *image = [UIImage imageWithData:data scale:scale];
|
||||||
if (image && !CGSizeEqualToSize(size, CGSizeZero)) {
|
if (image && !CGSizeEqualToSize(size, CGSizeZero)) {
|
||||||
|
|
||||||
// Get scale and size
|
// Get destination size
|
||||||
CGRect imageRect = RCTClipRect(image.size, scale, size, scale, resizeMode);
|
CGSize targetSize = RCTTargetSize(image.size, image.scale,
|
||||||
CGSize destSize = RCTTargetSizeForClipRect(imageRect);
|
size, scale, resizeMode, NO);
|
||||||
|
|
||||||
// Decompress image at required size
|
// Decompress image at required size
|
||||||
BOOL opaque = !RCTImageHasAlpha(image.CGImage);
|
BOOL opaque = !RCTImageHasAlpha(image.CGImage);
|
||||||
UIGraphicsBeginImageContextWithOptions(destSize, opaque, scale);
|
UIGraphicsBeginImageContextWithOptions(targetSize, opaque, scale);
|
||||||
[image drawInRect:imageRect];
|
[image drawInRect:(CGRect){CGPointZero, targetSize}];
|
||||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||||
UIGraphicsEndImageContext();
|
UIGraphicsEndImageContext();
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,8 +85,8 @@ static UIImage *RCTScaledImageForAsset(ALAssetRepresentation *representation,
|
||||||
}
|
}
|
||||||
|
|
||||||
CGSize sourceSize = representation.dimensions;
|
CGSize sourceSize = representation.dimensions;
|
||||||
CGRect targetRect = RCTClipRect(sourceSize, representation.scale, size, scale, resizeMode);
|
CGSize targetSize = RCTTargetSize(sourceSize, representation.scale,
|
||||||
CGSize targetSize = targetRect.size;
|
size, scale, resizeMode, NO);
|
||||||
|
|
||||||
NSDictionary *options = @{
|
NSDictionary *options = @{
|
||||||
(id)kCGImageSourceShouldAllowFloat: @YES,
|
(id)kCGImageSourceShouldAllowFloat: @YES,
|
||||||
|
|
|
@ -13,20 +13,24 @@
|
||||||
#import "RCTDefines.h"
|
#import "RCTDefines.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the optimal context size for an image drawn using the clip rect
|
* This function takes an input content size (typically from an image), a target
|
||||||
* returned by RCTClipRect.
|
* size and scale that it will be drawn at (typically in a CGContext) and then
|
||||||
|
* calculates the rectangle to draw the image into so that it will be sized and
|
||||||
|
* positioned correctly if drawn using the specified content mode.
|
||||||
*/
|
*/
|
||||||
RCT_EXTERN CGSize RCTTargetSizeForClipRect(CGRect clipRect);
|
RCT_EXTERN CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,
|
||||||
|
CGFloat destScale, UIViewContentMode resizeMode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function takes an input content size & scale (typically from an image),
|
* This function takes an input content size & scale (typically from an image),
|
||||||
* a target size & scale that it will be drawn into (typically a CGContext) and
|
* a target size & scale at which it will be displayed (typically in a
|
||||||
* then calculates the optimal rectangle to draw the image into so that it will
|
* UIImageView) and then calculates the optimal size at which to redraw the
|
||||||
* be sized and positioned correctly if drawn using the specified content mode.
|
* image so that it will be displayed correctly with the specified content mode.
|
||||||
*/
|
*/
|
||||||
RCT_EXTERN CGRect RCTClipRect(CGSize sourceSize, CGFloat sourceScale,
|
RCT_EXTERN CGSize RCTTargetSize(CGSize sourceSize, CGFloat sourceScale,
|
||||||
CGSize destSize, CGFloat destScale,
|
CGSize destSize, CGFloat destScale,
|
||||||
UIViewContentMode resizeMode);
|
UIViewContentMode resizeMode,
|
||||||
|
BOOL allowUpscaling);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function takes an input content size & scale (typically from an image),
|
* This function takes an input content size & scale (typically from an image),
|
||||||
|
|
|
@ -29,28 +29,14 @@ static CGSize RCTCeilSize(CGSize size, CGFloat scale)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
CGSize RCTTargetSizeForClipRect(CGRect clipRect)
|
CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,
|
||||||
{
|
CGFloat destScale, UIViewContentMode resizeMode)
|
||||||
return (CGSize){
|
|
||||||
clipRect.size.width + clipRect.origin.x * 2,
|
|
||||||
clipRect.size.height + clipRect.origin.y * 2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
CGRect RCTClipRect(CGSize sourceSize, CGFloat sourceScale,
|
|
||||||
CGSize destSize, CGFloat destScale,
|
|
||||||
UIViewContentMode resizeMode)
|
|
||||||
{
|
{
|
||||||
if (CGSizeEqualToSize(destSize, CGSizeZero)) {
|
if (CGSizeEqualToSize(destSize, CGSizeZero)) {
|
||||||
// Assume we require the largest size available
|
// Assume we require the largest size available
|
||||||
return (CGRect){CGPointZero, sourceSize};
|
return (CGRect){CGPointZero, sourceSize};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Precompensate for scale
|
|
||||||
CGFloat scale = sourceScale / destScale;
|
|
||||||
sourceSize.width *= scale;
|
|
||||||
sourceSize.height *= scale;
|
|
||||||
|
|
||||||
CGFloat aspect = sourceSize.width / sourceSize.height;
|
CGFloat aspect = sourceSize.width / sourceSize.height;
|
||||||
// If only one dimension in destSize is non-zero (for example, an Image
|
// If only one dimension in destSize is non-zero (for example, an Image
|
||||||
// with `flex: 1` whose height is indeterminate), calculate the unknown
|
// with `flex: 1` whose height is indeterminate), calculate the unknown
|
||||||
|
@ -61,7 +47,7 @@ CGRect RCTClipRect(CGSize sourceSize, CGFloat sourceScale,
|
||||||
if (destSize.height == 0) {
|
if (destSize.height == 0) {
|
||||||
destSize.height = destSize.width / aspect;
|
destSize.height = destSize.width / aspect;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate target aspect ratio if needed (don't bother if resizeMode == stretch)
|
// Calculate target aspect ratio if needed (don't bother if resizeMode == stretch)
|
||||||
CGFloat targetAspect = 0.0;
|
CGFloat targetAspect = 0.0;
|
||||||
if (resizeMode != UIViewContentModeScaleToFill) {
|
if (resizeMode != UIViewContentModeScaleToFill) {
|
||||||
|
@ -74,20 +60,18 @@ CGRect RCTClipRect(CGSize sourceSize, CGFloat sourceScale,
|
||||||
switch (resizeMode) {
|
switch (resizeMode) {
|
||||||
case UIViewContentModeScaleToFill: // stretch
|
case UIViewContentModeScaleToFill: // stretch
|
||||||
|
|
||||||
sourceSize.width = MIN(destSize.width, sourceSize.width);
|
return (CGRect){CGPointZero, RCTCeilSize(destSize, destScale)};
|
||||||
sourceSize.height = MIN(destSize.height, sourceSize.height);
|
|
||||||
return (CGRect){CGPointZero, RCTCeilSize(sourceSize, destScale)};
|
|
||||||
|
|
||||||
case UIViewContentModeScaleAspectFit: // contain
|
case UIViewContentModeScaleAspectFit: // contain
|
||||||
|
|
||||||
if (targetAspect <= aspect) { // target is taller than content
|
if (targetAspect <= aspect) { // target is taller than content
|
||||||
|
|
||||||
sourceSize.width = destSize.width = MIN(sourceSize.width, destSize.width);
|
sourceSize.width = destSize.width = destSize.width;
|
||||||
sourceSize.height = sourceSize.width / aspect;
|
sourceSize.height = sourceSize.width / aspect;
|
||||||
|
|
||||||
} else { // target is wider than content
|
} else { // target is wider than content
|
||||||
|
|
||||||
sourceSize.height = destSize.height = MIN(sourceSize.height, destSize.height);
|
sourceSize.height = destSize.height = destSize.height;
|
||||||
sourceSize.width = sourceSize.height * aspect;
|
sourceSize.width = sourceSize.height * aspect;
|
||||||
}
|
}
|
||||||
return (CGRect){CGPointZero, RCTCeilSize(sourceSize, destScale)};
|
return (CGRect){CGPointZero, RCTCeilSize(sourceSize, destScale)};
|
||||||
|
@ -96,7 +80,7 @@ CGRect RCTClipRect(CGSize sourceSize, CGFloat sourceScale,
|
||||||
|
|
||||||
if (targetAspect <= aspect) { // target is taller than content
|
if (targetAspect <= aspect) { // target is taller than content
|
||||||
|
|
||||||
sourceSize.height = destSize.height = MIN(sourceSize.height, destSize.height);
|
sourceSize.height = destSize.height = destSize.height;
|
||||||
sourceSize.width = sourceSize.height * aspect;
|
sourceSize.width = sourceSize.height * aspect;
|
||||||
destSize.width = destSize.height * targetAspect;
|
destSize.width = destSize.height * targetAspect;
|
||||||
return (CGRect){
|
return (CGRect){
|
||||||
|
@ -106,7 +90,7 @@ CGRect RCTClipRect(CGSize sourceSize, CGFloat sourceScale,
|
||||||
|
|
||||||
} else { // target is wider than content
|
} else { // target is wider than content
|
||||||
|
|
||||||
sourceSize.width = destSize.width = MIN(sourceSize.width, destSize.width);
|
sourceSize.width = destSize.width = destSize.width;
|
||||||
sourceSize.height = sourceSize.width / aspect;
|
sourceSize.height = sourceSize.width / aspect;
|
||||||
destSize.height = destSize.width / targetAspect;
|
destSize.height = destSize.width / targetAspect;
|
||||||
return (CGRect){
|
return (CGRect){
|
||||||
|
@ -122,9 +106,39 @@ CGRect RCTClipRect(CGSize sourceSize, CGFloat sourceScale,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXTERN BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
|
CGSize RCTTargetSize(CGSize sourceSize, CGFloat sourceScale,
|
||||||
CGSize destSize, CGFloat destScale,
|
CGSize destSize, CGFloat destScale,
|
||||||
UIViewContentMode resizeMode)
|
UIViewContentMode resizeMode,
|
||||||
|
BOOL allowUpscaling)
|
||||||
|
{
|
||||||
|
switch (resizeMode) {
|
||||||
|
case UIViewContentModeScaleToFill: // stretch
|
||||||
|
|
||||||
|
if (!allowUpscaling) {
|
||||||
|
CGFloat scale = sourceScale / destScale;
|
||||||
|
destSize.width = MIN(sourceSize.width * scale, destSize.width);
|
||||||
|
destSize.height = MIN(sourceSize.height * scale, destSize.height);
|
||||||
|
}
|
||||||
|
return RCTCeilSize(destSize, destScale);
|
||||||
|
|
||||||
|
default: {
|
||||||
|
|
||||||
|
// Get target size
|
||||||
|
CGSize size = RCTTargetRect(sourceSize, destSize, destScale, resizeMode).size;
|
||||||
|
if (!allowUpscaling) {
|
||||||
|
// return sourceSize if target size is larger
|
||||||
|
if (sourceSize.width * sourceScale < size.width * destScale) {
|
||||||
|
return sourceSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
|
||||||
|
CGSize destSize, CGFloat destScale,
|
||||||
|
UIViewContentMode resizeMode)
|
||||||
{
|
{
|
||||||
if (CGSizeEqualToSize(destSize, CGSizeZero)) {
|
if (CGSizeEqualToSize(destSize, CGSizeZero)) {
|
||||||
// Assume we require the largest size available
|
// Assume we require the largest size available
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#import "RCTEventDispatcher.h"
|
#import "RCTEventDispatcher.h"
|
||||||
#import "RCTGIFImage.h"
|
#import "RCTGIFImage.h"
|
||||||
#import "RCTImageLoader.h"
|
#import "RCTImageLoader.h"
|
||||||
|
#import "RCTImageUtils.h"
|
||||||
#import "RCTUtils.h"
|
#import "RCTUtils.h"
|
||||||
|
|
||||||
#import "UIView+React.h"
|
#import "UIView+React.h"
|
||||||
|
@ -43,7 +44,7 @@
|
||||||
|
|
||||||
RCT_NOT_IMPLEMENTED(-init)
|
RCT_NOT_IMPLEMENTED(-init)
|
||||||
|
|
||||||
- (void)_updateImage
|
- (void)updateImage
|
||||||
{
|
{
|
||||||
UIImage *image = self.image;
|
UIImage *image = self.image;
|
||||||
if (!image) {
|
if (!image) {
|
||||||
|
@ -72,7 +73,7 @@ RCT_NOT_IMPLEMENTED(-init)
|
||||||
image = image ?: _defaultImage;
|
image = image ?: _defaultImage;
|
||||||
if (image != super.image) {
|
if (image != super.image) {
|
||||||
super.image = image;
|
super.image = image;
|
||||||
[self _updateImage];
|
[self updateImage];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ RCT_NOT_IMPLEMENTED(-init)
|
||||||
{
|
{
|
||||||
if (!UIEdgeInsetsEqualToEdgeInsets(_capInsets, capInsets)) {
|
if (!UIEdgeInsetsEqualToEdgeInsets(_capInsets, capInsets)) {
|
||||||
_capInsets = capInsets;
|
_capInsets = capInsets;
|
||||||
[self _updateImage];
|
[self updateImage];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ RCT_NOT_IMPLEMENTED(-init)
|
||||||
{
|
{
|
||||||
if (_renderingMode != renderingMode) {
|
if (_renderingMode != renderingMode) {
|
||||||
_renderingMode = renderingMode;
|
_renderingMode = renderingMode;
|
||||||
[self _updateImage];
|
[self updateImage];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +101,16 @@ RCT_NOT_IMPLEMENTED(-init)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setContentMode:(UIViewContentMode)contentMode
|
||||||
|
{
|
||||||
|
if (self.contentMode != contentMode) {
|
||||||
|
super.contentMode = contentMode;
|
||||||
|
if ([RCTImageLoader isAssetLibraryImage:_src] || [RCTImageLoader isRemoteImage:_src]) {
|
||||||
|
[self reloadImage];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)reloadImage
|
- (void)reloadImage
|
||||||
{
|
{
|
||||||
if (_src && !CGSizeEqualToSize(self.frame.size, CGSizeZero)) {
|
if (_src && !CGSizeEqualToSize(self.frame.size, CGSizeZero)) {
|
||||||
|
@ -165,12 +176,15 @@ RCT_NOT_IMPLEMENTED(-init)
|
||||||
if (self.image == nil) {
|
if (self.image == nil) {
|
||||||
[self reloadImage];
|
[self reloadImage];
|
||||||
} else if ([RCTImageLoader isAssetLibraryImage:_src] || [RCTImageLoader isRemoteImage:_src]) {
|
} else if ([RCTImageLoader isAssetLibraryImage:_src] || [RCTImageLoader isRemoteImage:_src]) {
|
||||||
CGSize imageSize = {
|
|
||||||
self.image.size.width / RCTScreenScale(),
|
// Get optimal image size
|
||||||
self.image.size.height / RCTScreenScale()
|
CGSize currentSize = self.image.size;
|
||||||
};
|
CGSize idealSize = RCTTargetSize(self.image.size, self.image.scale, frame.size,
|
||||||
CGFloat widthChangeFraction = imageSize.width ? ABS(imageSize.width - frame.size.width) / imageSize.width : 1;
|
RCTScreenScale(), self.contentMode, YES);
|
||||||
CGFloat heightChangeFraction = imageSize.height ? ABS(imageSize.height - frame.size.height) / imageSize.height : 1;
|
|
||||||
|
CGFloat widthChangeFraction = ABS(currentSize.width - idealSize.width) / currentSize.width;
|
||||||
|
CGFloat heightChangeFraction = ABS(currentSize.height - idealSize.height) / currentSize.height;
|
||||||
|
|
||||||
// If the combined change is more than 20%, reload the asset in case there is a better size.
|
// If the combined change is more than 20%, reload the asset in case there is a better size.
|
||||||
if (widthChangeFraction + heightChangeFraction > 0.2) {
|
if (widthChangeFraction + heightChangeFraction > 0.2) {
|
||||||
[self reloadImage];
|
[self reloadImage];
|
||||||
|
|
Loading…
Reference in New Issue