mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
124 lines
5.9 KiB
Plaintext
124 lines
5.9 KiB
Plaintext
//
|
|
// ASImageNode+CGExtras.mm
|
|
// Texture
|
|
//
|
|
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
|
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
|
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
|
|
#import "ASImageNode+CGExtras.h"
|
|
|
|
#import <cmath>
|
|
|
|
// TODO rewrite these to be closer to the intended use -- take UIViewContentMode as param, CGRect destinationBounds, CGSize sourceSize.
|
|
static CGSize _ASSizeFillWithAspectRatio(CGFloat aspectRatio, CGSize constraints);
|
|
static CGSize _ASSizeFitWithAspectRatio(CGFloat aspectRatio, CGSize constraints);
|
|
|
|
static CGSize _ASSizeFillWithAspectRatio(CGFloat sizeToScaleAspectRatio, CGSize destinationSize)
|
|
{
|
|
CGFloat destinationAspectRatio = destinationSize.width / destinationSize.height;
|
|
if (sizeToScaleAspectRatio > destinationAspectRatio) {
|
|
return CGSizeMake(destinationSize.height * sizeToScaleAspectRatio, destinationSize.height);
|
|
} else {
|
|
return CGSizeMake(destinationSize.width, round(destinationSize.width / sizeToScaleAspectRatio));
|
|
}
|
|
}
|
|
|
|
static CGSize _ASSizeFitWithAspectRatio(CGFloat aspectRatio, CGSize constraints)
|
|
{
|
|
CGFloat constraintAspectRatio = constraints.width / constraints.height;
|
|
if (aspectRatio > constraintAspectRatio) {
|
|
return CGSizeMake(constraints.width, constraints.width / aspectRatio);
|
|
} else {
|
|
return CGSizeMake(constraints.height * aspectRatio, constraints.height);
|
|
}
|
|
}
|
|
|
|
void ASCroppedImageBackingSizeAndDrawRectInBounds(CGSize sourceImageSize,
|
|
CGSize boundsSize,
|
|
UIViewContentMode contentMode,
|
|
CGRect cropRect,
|
|
BOOL forceUpscaling,
|
|
CGSize forcedSize,
|
|
CGSize *outBackingSize,
|
|
CGRect *outDrawRect
|
|
)
|
|
{
|
|
|
|
size_t destinationWidth = boundsSize.width;
|
|
size_t destinationHeight = boundsSize.height;
|
|
|
|
// Often, an image is too low resolution to completely fill the width and height provided.
|
|
// Per the API contract as commented in the header, we will adjust input parameters (destinationWidth, destinationHeight) to ensure that the image is not upscaled on the CPU.
|
|
CGFloat boundsAspectRatio = (CGFloat)destinationWidth / (CGFloat)destinationHeight;
|
|
|
|
CGSize scaledSizeForImage = sourceImageSize;
|
|
BOOL cropToRectDimensions = !CGRectIsEmpty(cropRect);
|
|
|
|
if (cropToRectDimensions) {
|
|
scaledSizeForImage = CGSizeMake(boundsSize.width / cropRect.size.width, boundsSize.height / cropRect.size.height);
|
|
} else {
|
|
if (contentMode == UIViewContentModeScaleAspectFill)
|
|
scaledSizeForImage = _ASSizeFillWithAspectRatio(boundsAspectRatio, sourceImageSize);
|
|
else if (contentMode == UIViewContentModeScaleAspectFit)
|
|
scaledSizeForImage = _ASSizeFitWithAspectRatio(boundsAspectRatio, 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), override the function arguments.
|
|
if (CGSizeEqualToSize(CGSizeZero, forcedSize) == NO) {
|
|
destinationWidth = (size_t)round(forcedSize.width);
|
|
destinationHeight = (size_t)round(forcedSize.height);
|
|
} else if (forceUpscaling == NO && (scaledSizeForImage.width * scaledSizeForImage.height) < (destinationWidth * destinationHeight)) {
|
|
destinationWidth = (size_t)round(scaledSizeForImage.width);
|
|
destinationHeight = (size_t)round(scaledSizeForImage.height);
|
|
if (destinationWidth == 0 || destinationHeight == 0) {
|
|
*outBackingSize = CGSizeZero;
|
|
*outDrawRect = CGRectZero;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Figure out the scaled size within the destination bounds.
|
|
CGFloat sourceImageAspectRatio = sourceImageSize.width / sourceImageSize.height;
|
|
CGSize scaledSizeForDestination = CGSizeMake(destinationWidth, destinationHeight);
|
|
|
|
if (cropToRectDimensions) {
|
|
scaledSizeForDestination = CGSizeMake(boundsSize.width / cropRect.size.width, boundsSize.height / cropRect.size.height);
|
|
} else {
|
|
if (contentMode == UIViewContentModeScaleAspectFill)
|
|
scaledSizeForDestination = _ASSizeFillWithAspectRatio(sourceImageAspectRatio, scaledSizeForDestination);
|
|
else if (contentMode == UIViewContentModeScaleAspectFit)
|
|
scaledSizeForDestination = _ASSizeFitWithAspectRatio(sourceImageAspectRatio, scaledSizeForDestination);
|
|
}
|
|
|
|
// Figure out the rectangle into which to draw the image.
|
|
CGRect drawRect = CGRectZero;
|
|
if (cropToRectDimensions) {
|
|
drawRect = CGRectMake(-cropRect.origin.x * scaledSizeForDestination.width,
|
|
-cropRect.origin.y * scaledSizeForDestination.height,
|
|
scaledSizeForDestination.width,
|
|
scaledSizeForDestination.height);
|
|
} else {
|
|
// We want to obey the origin of cropRect in aspect-fill mode.
|
|
if (contentMode == UIViewContentModeScaleAspectFill) {
|
|
drawRect = CGRectMake(((destinationWidth - scaledSizeForDestination.width) * cropRect.origin.x),
|
|
((destinationHeight - scaledSizeForDestination.height) * cropRect.origin.y),
|
|
scaledSizeForDestination.width,
|
|
scaledSizeForDestination.height);
|
|
|
|
}
|
|
// And otherwise just center it.
|
|
else {
|
|
drawRect = CGRectMake(((destinationWidth - scaledSizeForDestination.width) / 2.0),
|
|
((destinationHeight - scaledSizeForDestination.height) / 2.0),
|
|
scaledSizeForDestination.width,
|
|
scaledSizeForDestination.height);
|
|
}
|
|
}
|
|
|
|
*outDrawRect = drawRect;
|
|
*outBackingSize = CGSizeMake(destinationWidth, destinationHeight);
|
|
}
|