mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
870 lines
29 KiB
Objective-C
870 lines
29 KiB
Objective-C
#import "TGPhotoEditorUtils.h"
|
|
|
|
#import "LegacyComponentsInternal.h"
|
|
#import "TGImageUtils.h"
|
|
|
|
#import <AVFoundation/AVFoundation.h>
|
|
#import <Accelerate/Accelerate.h>
|
|
|
|
const CGSize TGPhotoEditorResultImageMaxSize = { 1280, 1280 };
|
|
const CGSize TGPhotoEditorResultImageWallpaperMaxSize = { 2048, 2048 };
|
|
const CGSize TGPhotoEditorResultImageAvatarMaxSize = { 2048, 2048 };
|
|
const CGSize TGPhotoEditorScreenImageHardLimitSize = { 1280, 1280 };
|
|
const CGSize TGPhotoEditorScreenImageHardLimitLegacySize = { 750, 750 };
|
|
|
|
CGSize TGPhotoEditorScreenImageMaxSize()
|
|
{
|
|
CGSize screenSize = TGScreenSize();
|
|
CGSize limitSize = screenSize.width == 320 ? TGPhotoEditorScreenImageHardLimitLegacySize : TGPhotoEditorScreenImageHardLimitSize;
|
|
return limitSize;
|
|
}
|
|
|
|
CGSize TGPhotoThumbnailSizeForCurrentScreen()
|
|
{
|
|
CGSize screenSize = TGScreenSize();
|
|
CGFloat widescreenWidth = MAX(screenSize.width, screenSize.height);
|
|
|
|
if ([UIScreen mainScreen].scale >= 2.0f - FLT_EPSILON)
|
|
{
|
|
if (widescreenWidth >= 932.0f - FLT_EPSILON)
|
|
{
|
|
return CGSizeMake(141.0f + TGScreenPixel, 141.0 + TGScreenPixel);
|
|
}
|
|
else if (widescreenWidth >= 926.0f - FLT_EPSILON)
|
|
{
|
|
return CGSizeMake(141.0f + TGScreenPixel, 141.0 + TGScreenPixel);
|
|
}
|
|
else if (widescreenWidth >= 896.0f - FLT_EPSILON)
|
|
{
|
|
return CGSizeMake(137.0f - TGScreenPixel, 137.0f - TGScreenPixel);
|
|
}
|
|
else if (widescreenWidth >= 852.0f - FLT_EPSILON)
|
|
{
|
|
return CGSizeMake(129.0f - TGScreenPixel, 129.0f - TGScreenPixel);
|
|
}
|
|
else if (widescreenWidth >= 844.0f - FLT_EPSILON)
|
|
{
|
|
return CGSizeMake(129.0f - TGScreenPixel, 129.0f - TGScreenPixel);
|
|
}
|
|
else if (widescreenWidth >= 812.0f - FLT_EPSILON)
|
|
{
|
|
return CGSizeMake(124.0f - TGScreenPixel, 124.0f - TGScreenPixel);
|
|
}
|
|
else if (widescreenWidth >= 736.0f - FLT_EPSILON)
|
|
{
|
|
return CGSizeMake(137.0f - TGScreenPixel, 137.0f - TGScreenPixel);
|
|
}
|
|
else if (widescreenWidth >= 667.0f - FLT_EPSILON)
|
|
{
|
|
return CGSizeMake(124.0f - TGScreenPixel, 124.0f - TGScreenPixel);
|
|
}
|
|
else
|
|
{
|
|
return CGSizeMake(106.0f - TGScreenPixel, 106.0f - TGScreenPixel);
|
|
}
|
|
}
|
|
|
|
return CGSizeMake(106.0f, 106.0f);
|
|
}
|
|
|
|
CGSize TGScaleToSize(CGSize size, CGSize maxSize)
|
|
{
|
|
CGSize newSize = size;
|
|
newSize.width = maxSize.width;
|
|
newSize.height = CGFloor(newSize.width * size.height / size.width);
|
|
|
|
if (newSize.height > maxSize.height)
|
|
{
|
|
newSize.height = maxSize.height;
|
|
newSize.width = CGFloor(newSize.height * size.width / size.height);
|
|
}
|
|
|
|
return newSize;
|
|
}
|
|
|
|
CGSize TGScaleToFillSize(CGSize size, CGSize maxSize)
|
|
{
|
|
if (size.width < 1)
|
|
size.width = 1;
|
|
|
|
if (size.height < 1)
|
|
size.height = 1;
|
|
|
|
if (size.height > size.width)
|
|
{
|
|
size.height = CGFloor(maxSize.width * size.height / MAX(1.0f, size.width));
|
|
size.width = maxSize.width;
|
|
}
|
|
else
|
|
{
|
|
size.width = CGFloor(maxSize.height * size.width / MAX(1.0f, size.height));
|
|
size.height = maxSize.height;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
CGFloat TGDegreesToRadians(CGFloat degrees)
|
|
{
|
|
return degrees * (CGFloat)M_PI / 180.0f;
|
|
}
|
|
|
|
CGFloat TGRadiansToDegrees(CGFloat radians)
|
|
{
|
|
return radians * 180.0f / (CGFloat)M_PI;
|
|
}
|
|
|
|
CGImageRef TGPhotoLanczosResize(UIImage *image, CGSize targetSize)
|
|
{
|
|
if (TGOrientationIsSideward(image.imageOrientation, NULL))
|
|
targetSize = CGSizeMake(targetSize.height, targetSize.width);
|
|
|
|
CGImageRef sourceRef = image.CGImage;
|
|
vImage_Buffer srcBuffer;
|
|
vImage_CGImageFormat format =
|
|
{
|
|
.bitsPerComponent = 8,
|
|
.bitsPerPixel = 32,
|
|
.colorSpace = NULL,
|
|
.bitmapInfo = (CGBitmapInfo)kCGImageAlphaFirst,
|
|
.version = 0,
|
|
.decode = NULL,
|
|
.renderingIntent = kCGRenderingIntentDefault,
|
|
};
|
|
vImage_Error ret = vImageBuffer_InitWithCGImage(&srcBuffer, &format, NULL, sourceRef, kvImageNoFlags);
|
|
if (ret != kvImageNoError)
|
|
{
|
|
free(srcBuffer.data);
|
|
return nil;
|
|
}
|
|
|
|
NSUInteger bytesPerPixel = 4;
|
|
NSUInteger dstBytesPerRow = bytesPerPixel * (NSUInteger)targetSize.width;
|
|
uint8_t *dstData = (uint8_t *)calloc((NSUInteger)targetSize.height * (NSUInteger)dstBytesPerRow, sizeof(uint8_t));
|
|
vImage_Buffer dstBuffer =
|
|
{
|
|
.data = dstData,
|
|
.height = (NSUInteger)targetSize.height,
|
|
.width = (NSUInteger)targetSize.width,
|
|
.rowBytes = dstBytesPerRow
|
|
};
|
|
|
|
vImage_Flags flags = kvImageHighQualityResampling;
|
|
if (MAX(image.size.width, image.size.height) > 4200) {
|
|
flags = kvImageNoFlags;
|
|
}
|
|
ret = vImageScale_ARGB8888(&srcBuffer, &dstBuffer, NULL, flags);
|
|
free(srcBuffer.data);
|
|
if (ret != kvImageNoError)
|
|
{
|
|
free(dstData);
|
|
return nil;
|
|
}
|
|
|
|
ret = kvImageNoError;
|
|
CGImageRef destRef = vImageCreateCGImageFromBuffer(&dstBuffer, &format, NULL, NULL, kvImageNoFlags, &ret);
|
|
free(dstData);
|
|
|
|
return destRef;
|
|
}
|
|
|
|
UIImage *TGPhotoEditorFitImage(UIImage *image, CGSize maxSize)
|
|
{
|
|
CGSize fittedImageSize = TGFitSize(image.size, maxSize);
|
|
|
|
if (iosMajorVersion() >= 7)
|
|
{
|
|
CGImageRef imageRef = TGPhotoLanczosResize(image, fittedImageSize);
|
|
|
|
UIImage *resizedImage = [[UIImage alloc] initWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
|
|
CGImageRelease(imageRef);
|
|
|
|
return resizedImage;
|
|
}
|
|
else
|
|
{
|
|
UIGraphicsBeginImageContextWithOptions(fittedImageSize, true, 1.0f);
|
|
|
|
[image drawInRect:CGRectMake(0, 0, fittedImageSize.width, fittedImageSize.height)];
|
|
|
|
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
|
|
return resizedImage;
|
|
}
|
|
}
|
|
|
|
UIImage *TGPhotoEditorLegacyCrop(UIImage *image, UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, bool shouldResize)
|
|
{
|
|
CGSize fittedImageSize = shouldResize ? TGFitSize(rect.size, maxSize) : rect.size;
|
|
|
|
CGSize outputImageSize = fittedImageSize;
|
|
outputImageSize.width = CGFloor(outputImageSize.width);
|
|
outputImageSize.height = CGFloor(outputImageSize.height);
|
|
if (TGOrientationIsSideward(orientation, NULL))
|
|
outputImageSize = CGSizeMake(outputImageSize.height, outputImageSize.width);
|
|
|
|
UIGraphicsBeginImageContextWithOptions(CGSizeMake(outputImageSize.width, outputImageSize.height), true, 1.0f);
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
|
|
CGContextFillRect(context, CGRectMake(0, 0, outputImageSize.width, outputImageSize.height));
|
|
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
|
|
|
|
CGSize rotatedContentSize = TGRotatedContentSize(image.size, rotation);
|
|
CGAffineTransform transform = CGAffineTransformIdentity;
|
|
transform = CGAffineTransformTranslate(transform, outputImageSize.width / 2, outputImageSize.height / 2);
|
|
|
|
transform = CGAffineTransformScale(transform, fittedImageSize.width / rect.size.width, fittedImageSize.height / rect.size.height);
|
|
transform = CGAffineTransformRotate(transform, TGRotationForOrientation(orientation));
|
|
transform = CGAffineTransformTranslate(transform, rotatedContentSize.width / 2 - CGRectGetMidX(rect), rotatedContentSize.height / 2 - CGRectGetMidY(rect));
|
|
transform = CGAffineTransformRotate(transform, rotation);
|
|
CGContextConcatCTM(context, transform);
|
|
|
|
if (mirrored)
|
|
CGContextScaleCTM(context, -1.0f, 1.0f);
|
|
|
|
CGRect frame = CGRectMake(CGCeil(-image.size.width / 2), CGCeil(-image.size.height / 2), image.size.width, image.size.height);
|
|
[image drawInRect:frame];
|
|
if (paintingImage != nil)
|
|
[paintingImage drawInRect:frame];
|
|
|
|
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
|
|
return croppedImage;
|
|
}
|
|
|
|
UIImage *TGPhotoEditorCrop(UIImage *inputImage, UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, CGSize originalSize, bool shouldResize)
|
|
{
|
|
return TGPhotoEditorVideoCrop(inputImage, paintingImage, orientation, rotation, rect, mirrored, maxSize, originalSize, shouldResize, false);
|
|
}
|
|
|
|
UIImage *TGPhotoEditorVideoCrop(UIImage *inputImage, UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, CGSize originalSize, bool shouldResize, bool useImageSize) {
|
|
return TGPhotoEditorVideoExtCrop(inputImage, paintingImage, orientation, rotation, rect, mirrored, maxSize, originalSize, shouldResize, useImageSize, false, false);
|
|
}
|
|
|
|
UIImage *TGPhotoEditorVideoExtCrop(UIImage *inputImage, UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, CGSize originalSize, bool shouldResize, bool useImageSize, bool skipImageTransform, bool fillPainting)
|
|
{
|
|
if (iosMajorVersion() < 7)
|
|
return TGPhotoEditorLegacyCrop(inputImage, paintingImage, orientation, rotation, rect, mirrored, maxSize, shouldResize);
|
|
|
|
CGSize fittedOriginalSize = originalSize;
|
|
if (useImageSize)
|
|
{
|
|
CGFloat ratio = inputImage.size.width / originalSize.width;
|
|
if (skipImageTransform) {
|
|
|
|
}
|
|
rect.origin.x = rect.origin.x * ratio;
|
|
rect.origin.y = rect.origin.y * ratio;
|
|
rect.size.width = rect.size.width * ratio;
|
|
rect.size.height = rect.size.height * ratio;
|
|
|
|
fittedOriginalSize = CGSizeMake(originalSize.width * ratio, originalSize.height * ratio);
|
|
}
|
|
|
|
CGSize fittedImageSize = shouldResize ? TGFitSize(rect.size, maxSize) : rect.size;
|
|
|
|
CGSize outputImageSize = fittedImageSize;
|
|
outputImageSize.width = CGFloor(outputImageSize.width);
|
|
outputImageSize.height = CGFloor(outputImageSize.height);
|
|
if (TGOrientationIsSideward(orientation, NULL))
|
|
outputImageSize = CGSizeMake(outputImageSize.height, outputImageSize.width);
|
|
|
|
UIGraphicsBeginImageContextWithOptions(CGSizeMake(outputImageSize.width, outputImageSize.height), true, 1.0f);
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
|
|
CGContextSaveGState(context);
|
|
|
|
CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
|
|
CGContextFillRect(context, CGRectMake(0, 0, outputImageSize.width, outputImageSize.height));
|
|
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
|
|
|
|
UIImage *image = nil;
|
|
CGSize imageSize = inputImage.size;
|
|
if (shouldResize)
|
|
{
|
|
CGSize referenceSize = useImageSize ? inputImage.size : originalSize;
|
|
CGSize resizedSize = CGSizeMake(referenceSize.width * fittedImageSize.width / rect.size.width, referenceSize.height * fittedImageSize.height / rect.size.height);
|
|
CGImageRef resizedImage = TGPhotoLanczosResize(inputImage, resizedSize);
|
|
image = [UIImage imageWithCGImage:resizedImage scale:0.0f orientation:inputImage.imageOrientation];
|
|
CGImageRelease(resizedImage);
|
|
|
|
if (skipImageTransform) {
|
|
imageSize = CGSizeMake(image.size.width * fittedOriginalSize.width / rect.size.width, image.size.height * fittedOriginalSize.height / rect.size.height);
|
|
} else {
|
|
imageSize = image.size;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
image = inputImage;
|
|
imageSize = image.size;
|
|
}
|
|
|
|
if (skipImageTransform) {
|
|
[image drawInRect:CGRectMake(0.0, 0.0, outputImageSize.width, outputImageSize.height)];
|
|
}
|
|
|
|
CGSize scales = CGSizeMake(fittedImageSize.width / rect.size.width, fittedImageSize.height / rect.size.height);
|
|
CGSize rotatedContentSize = TGRotatedContentSize(inputImage.size, rotation);
|
|
CGAffineTransform transform = CGAffineTransformIdentity;
|
|
transform = CGAffineTransformTranslate(transform, outputImageSize.width / 2, outputImageSize.height / 2);
|
|
transform = CGAffineTransformRotate(transform, TGRotationForOrientation(orientation));
|
|
transform = CGAffineTransformTranslate(transform, (rotatedContentSize.width / 2 - CGRectGetMidX(rect)) * scales.width, (rotatedContentSize.height / 2 - CGRectGetMidY(rect)) * scales.height);
|
|
transform = CGAffineTransformRotate(transform, rotation);
|
|
CGContextConcatCTM(context, transform);
|
|
|
|
if (mirrored)
|
|
CGContextScaleCTM(context, -1.0f, 1.0f);
|
|
|
|
if (!skipImageTransform) {
|
|
[image drawAtPoint:CGPointMake(-image.size.width / 2, -image.size.height / 2)];
|
|
}
|
|
|
|
if (paintingImage != nil)
|
|
{
|
|
if (fillPainting) {
|
|
CGContextRestoreGState(context);
|
|
[paintingImage drawInRect:CGRectMake(0.0, 0.0, outputImageSize.width, outputImageSize.height)];
|
|
} else {
|
|
if (mirrored)
|
|
CGContextScaleCTM(context, -1.0f, 1.0f);
|
|
|
|
[paintingImage drawInRect:CGRectMake(-imageSize.width / 2, -imageSize.height / 2, imageSize.width, imageSize.height)];
|
|
}
|
|
}
|
|
|
|
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
|
|
return croppedImage;
|
|
}
|
|
|
|
UIImage *TGPhotoEditorPaintingCrop(UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, CGSize originalSize, bool shouldResize, bool useImageSize, bool skipImageTransform)
|
|
{
|
|
CGSize fittedOriginalSize = originalSize;
|
|
if (useImageSize)
|
|
{
|
|
CGFloat ratio = paintingImage.size.width / originalSize.width;
|
|
if (skipImageTransform) {
|
|
|
|
}
|
|
rect.origin.x = rect.origin.x * ratio;
|
|
rect.origin.y = rect.origin.y * ratio;
|
|
rect.size.width = rect.size.width * ratio;
|
|
rect.size.height = rect.size.height * ratio;
|
|
|
|
fittedOriginalSize = CGSizeMake(originalSize.width * ratio, originalSize.height * ratio);
|
|
}
|
|
|
|
CGSize fittedImageSize = shouldResize ? TGFitSize(rect.size, maxSize) : rect.size;
|
|
|
|
CGSize outputImageSize = fittedImageSize;
|
|
outputImageSize.width = CGFloor(outputImageSize.width);
|
|
outputImageSize.height = CGFloor(outputImageSize.height);
|
|
if (TGOrientationIsSideward(orientation, NULL))
|
|
outputImageSize = CGSizeMake(outputImageSize.height, outputImageSize.width);
|
|
|
|
UIGraphicsBeginImageContextWithOptions(CGSizeMake(outputImageSize.width, outputImageSize.height), false, 1.0f);
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
|
|
UIImage *image = nil;
|
|
CGSize imageSize = paintingImage.size;
|
|
if (shouldResize)
|
|
{
|
|
CGSize referenceSize = useImageSize ? paintingImage.size : originalSize;
|
|
CGSize resizedSize = CGSizeMake(referenceSize.width * fittedImageSize.width / rect.size.width, referenceSize.height * fittedImageSize.height / rect.size.height);
|
|
|
|
UIGraphicsBeginImageContextWithOptions(resizedSize, false, 1.0f);
|
|
[image drawInRect:CGRectMake(0, 0, resizedSize.width, resizedSize.height) blendMode:kCGBlendModeCopy alpha:1.0f];
|
|
image = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
|
|
if (skipImageTransform) {
|
|
imageSize = CGSizeMake(image.size.width * fittedOriginalSize.width / rect.size.width, image.size.height * fittedOriginalSize.height / rect.size.height);
|
|
} else {
|
|
imageSize = image.size;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
image = paintingImage;
|
|
imageSize = image.size;
|
|
}
|
|
|
|
if (skipImageTransform) {
|
|
[image drawInRect:CGRectMake(0.0, 0.0, outputImageSize.width, outputImageSize.height)];
|
|
}
|
|
|
|
CGSize scales = CGSizeMake(fittedImageSize.width / rect.size.width, fittedImageSize.height / rect.size.height);
|
|
CGSize rotatedContentSize = TGRotatedContentSize(paintingImage.size, rotation);
|
|
CGAffineTransform transform = CGAffineTransformIdentity;
|
|
transform = CGAffineTransformTranslate(transform, outputImageSize.width / 2, outputImageSize.height / 2);
|
|
transform = CGAffineTransformRotate(transform, TGRotationForOrientation(orientation));
|
|
transform = CGAffineTransformTranslate(transform, (rotatedContentSize.width / 2 - CGRectGetMidX(rect)) * scales.width, (rotatedContentSize.height / 2 - CGRectGetMidY(rect)) * scales.height);
|
|
transform = CGAffineTransformRotate(transform, rotation);
|
|
CGContextConcatCTM(context, transform);
|
|
|
|
if (mirrored)
|
|
CGContextScaleCTM(context, -1.0f, 1.0f);
|
|
|
|
if (!skipImageTransform) {
|
|
[image drawAtPoint:CGPointMake(-image.size.width / 2, -image.size.height / 2)];
|
|
}
|
|
|
|
if (paintingImage != nil)
|
|
{
|
|
if (mirrored)
|
|
CGContextScaleCTM(context, -1.0f, 1.0f);
|
|
|
|
[paintingImage drawInRect:CGRectMake(-imageSize.width / 2, -imageSize.height / 2, imageSize.width, imageSize.height)];
|
|
}
|
|
|
|
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
|
|
return croppedImage;
|
|
}
|
|
|
|
CGSize TGRotatedContentSize(CGSize contentSize, CGFloat rotation)
|
|
{
|
|
CGAffineTransform t = CGAffineTransformMakeTranslation(contentSize.width / 2, contentSize.height / 2);
|
|
t = CGAffineTransformRotate(t, rotation);
|
|
t = CGAffineTransformTranslate(t, -contentSize.width / 2, -contentSize.height / 2);
|
|
|
|
return CGRectApplyAffineTransform(CGRectMake(0, 0, contentSize.width, contentSize.height), t).size;
|
|
}
|
|
|
|
UIImageOrientation TGNextCCWOrientationForOrientation(UIImageOrientation orientation)
|
|
{
|
|
switch (orientation)
|
|
{
|
|
case UIImageOrientationUp:
|
|
return UIImageOrientationLeft;
|
|
|
|
case UIImageOrientationLeft:
|
|
return UIImageOrientationDown;
|
|
|
|
case UIImageOrientationDown:
|
|
return UIImageOrientationRight;
|
|
|
|
case UIImageOrientationRight:
|
|
return UIImageOrientationUp;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return UIImageOrientationUp;
|
|
}
|
|
|
|
|
|
UIImageOrientation TGNextCWOrientationForOrientation(UIImageOrientation orientation)
|
|
{
|
|
switch (orientation)
|
|
{
|
|
case UIImageOrientationUp:
|
|
return UIImageOrientationRight;
|
|
|
|
case UIImageOrientationLeft:
|
|
return UIImageOrientationUp;
|
|
|
|
case UIImageOrientationDown:
|
|
return UIImageOrientationLeft;
|
|
|
|
case UIImageOrientationRight:
|
|
return UIImageOrientationDown;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return UIImageOrientationUp;
|
|
}
|
|
|
|
CGFloat TGRotationForOrientation(UIImageOrientation orientation)
|
|
{
|
|
switch (orientation)
|
|
{
|
|
case UIImageOrientationDown:
|
|
return (CGFloat)-M_PI;
|
|
|
|
case UIImageOrientationLeft:
|
|
return (CGFloat)-M_PI_2;
|
|
|
|
case UIImageOrientationRight:
|
|
return (CGFloat)M_PI_2;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0.0f;
|
|
}
|
|
|
|
CGFloat TGCounterRotationForOrientation(UIImageOrientation orientation)
|
|
{
|
|
switch (orientation)
|
|
{
|
|
case UIImageOrientationDown:
|
|
return (CGFloat)-M_PI;
|
|
|
|
case UIImageOrientationLeft:
|
|
return (CGFloat)M_PI_2;
|
|
|
|
case UIImageOrientationRight:
|
|
return (CGFloat)-M_PI_2;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0.0f;
|
|
}
|
|
|
|
CGFloat TGRotationForInterfaceOrientation(UIInterfaceOrientation orientation)
|
|
{
|
|
switch (orientation)
|
|
{
|
|
case UIInterfaceOrientationPortraitUpsideDown:
|
|
return (CGFloat)-M_PI;
|
|
|
|
case UIInterfaceOrientationLandscapeLeft:
|
|
return (CGFloat)-M_PI_2;
|
|
|
|
case UIInterfaceOrientationLandscapeRight:
|
|
return (CGFloat)M_PI_2;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0.0f;
|
|
}
|
|
|
|
CGAffineTransform TGTransformForVideoOrientation(AVCaptureVideoOrientation orientation, bool mirrored)
|
|
{
|
|
CGAffineTransform transform = mirrored ? CGAffineTransformMakeRotation((CGFloat)M_PI) : CGAffineTransformIdentity;
|
|
|
|
switch (orientation)
|
|
{
|
|
case UIDeviceOrientationLandscapeRight:
|
|
{
|
|
transform = mirrored ? CGAffineTransformIdentity : CGAffineTransformMakeRotation((CGFloat)M_PI);
|
|
}
|
|
break;
|
|
|
|
case UIDeviceOrientationPortrait:
|
|
{
|
|
transform = CGAffineTransformMakeRotation((CGFloat)M_PI_2);
|
|
}
|
|
break;
|
|
|
|
case UIDeviceOrientationPortraitUpsideDown:
|
|
{
|
|
transform = CGAffineTransformMakeRotation((CGFloat)M_PI_2 * 3);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (mirrored)
|
|
transform = CGAffineTransformScale(transform, 1, -1);
|
|
|
|
return transform;
|
|
}
|
|
|
|
bool TGOrientationIsSideward(UIImageOrientation orientation, bool *mirrored)
|
|
{
|
|
if (orientation == UIImageOrientationLeft || orientation == UIImageOrientationRight)
|
|
{
|
|
if (mirrored != NULL)
|
|
*mirrored = false;
|
|
|
|
return true;
|
|
}
|
|
else if (orientation == UIImageOrientationLeftMirrored || orientation == UIImageOrientationRightMirrored)
|
|
{
|
|
if (mirrored != NULL)
|
|
*mirrored = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
UIImageOrientation TGMirrorSidewardOrientation(UIImageOrientation orientation)
|
|
{
|
|
if (orientation == UIImageOrientationLeft)
|
|
orientation = UIImageOrientationRight;
|
|
else if (orientation == UIImageOrientationRight)
|
|
orientation = UIImageOrientationLeft;
|
|
|
|
return orientation;
|
|
}
|
|
|
|
UIImageOrientation TGVideoOrientationForAsset(AVAsset *asset, bool *mirrored)
|
|
{
|
|
AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
|
|
CGAffineTransform t = videoTrack.preferredTransform;
|
|
|
|
if (t.a == -1 && t.d == -1) {
|
|
return UIImageOrientationLeft;
|
|
} else if (t.a == 1 && t.d == 1) {
|
|
return UIImageOrientationRight;
|
|
} else if (t.b == -1 && t.c == 1) {
|
|
return UIImageOrientationDown;
|
|
} else if (t.a == -1 && t.d == 1) {
|
|
if (mirrored != NULL) {
|
|
*mirrored = true;
|
|
}
|
|
return UIImageOrientationLeft;
|
|
} else if (t.a == 1 && t.d == -1) {
|
|
if (mirrored != NULL) {
|
|
*mirrored = true;
|
|
}
|
|
return UIImageOrientationRight;
|
|
} else {
|
|
if (t.c == 1) {
|
|
if (mirrored != NULL) {
|
|
*mirrored = true;
|
|
}
|
|
}
|
|
return UIImageOrientationUp;
|
|
}
|
|
}
|
|
|
|
UIImageOrientation TGVideoFinalOrientationForOrientation(UIImageOrientation videoOrientation, UIImageOrientation cropOrientation)
|
|
{
|
|
switch (videoOrientation)
|
|
{
|
|
case UIImageOrientationUp:
|
|
return cropOrientation;
|
|
|
|
case UIImageOrientationDown:
|
|
{
|
|
switch (cropOrientation)
|
|
{
|
|
case UIImageOrientationDown:
|
|
return UIImageOrientationUp;
|
|
|
|
case UIImageOrientationLeft:
|
|
return UIImageOrientationRight;
|
|
|
|
case UIImageOrientationRight:
|
|
return UIImageOrientationLeft;
|
|
|
|
default:
|
|
return videoOrientation;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case UIImageOrientationLeft:
|
|
{
|
|
switch (cropOrientation)
|
|
{
|
|
case UIImageOrientationDown:
|
|
return UIImageOrientationRight;
|
|
|
|
case UIImageOrientationLeft:
|
|
return UIImageOrientationDown;
|
|
|
|
case UIImageOrientationRight:
|
|
return UIImageOrientationUp;
|
|
|
|
default:
|
|
return videoOrientation;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case UIImageOrientationRight:
|
|
{
|
|
switch (cropOrientation)
|
|
{
|
|
case UIImageOrientationDown:
|
|
return UIImageOrientationLeft;
|
|
|
|
case UIImageOrientationLeft:
|
|
return UIImageOrientationUp;
|
|
|
|
case UIImageOrientationRight:
|
|
return UIImageOrientationDown;
|
|
|
|
default:
|
|
return videoOrientation;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return videoOrientation;
|
|
}
|
|
}
|
|
|
|
CGAffineTransform TGVideoTransformForOrientation(UIImageOrientation orientation, CGSize size, CGRect cropRect, bool mirror)
|
|
{
|
|
CGAffineTransform transform = CGAffineTransformIdentity;
|
|
|
|
if (mirror)
|
|
{
|
|
if (TGOrientationIsSideward(orientation, NULL))
|
|
{
|
|
cropRect.origin.y *= - 1;
|
|
transform = CGAffineTransformTranslate(transform, 0, size.height);
|
|
transform = CGAffineTransformScale(transform, 1.0f, -1.0f);
|
|
}
|
|
else
|
|
{
|
|
cropRect.origin.x = size.height - cropRect.origin.x;
|
|
transform = CGAffineTransformScale(transform, -1.0f, 1.0f);
|
|
}
|
|
}
|
|
|
|
switch (orientation)
|
|
{
|
|
case UIImageOrientationUp:
|
|
{
|
|
transform = CGAffineTransformRotate(CGAffineTransformTranslate(transform, size.height - cropRect.origin.x, 0 - cropRect.origin.y), (CGFloat)M_PI_2);
|
|
}
|
|
break;
|
|
|
|
case UIImageOrientationDown:
|
|
{
|
|
transform = CGAffineTransformRotate(CGAffineTransformTranslate(transform, 0 - cropRect.origin.x, size.width - cropRect.origin.y), (CGFloat)-M_PI_2);
|
|
}
|
|
break;
|
|
|
|
case UIImageOrientationRight:
|
|
{
|
|
transform = CGAffineTransformRotate(CGAffineTransformTranslate(transform, 0 - cropRect.origin.x, 0 - cropRect.origin.y), 0);
|
|
}
|
|
break;
|
|
|
|
case UIImageOrientationLeft:
|
|
{
|
|
transform = CGAffineTransformRotate(CGAffineTransformTranslate(transform, size.width - cropRect.origin.x, size.height - cropRect.origin.y), (CGFloat)M_PI);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return transform;
|
|
}
|
|
|
|
CGAffineTransform TGVideoCropTransformForOrientation(UIImageOrientation orientation, CGSize size, bool rotateSize)
|
|
{
|
|
if (rotateSize && TGOrientationIsSideward(orientation, NULL))
|
|
size = CGSizeMake(size.height, size.width);
|
|
|
|
CGAffineTransform transform = CGAffineTransformIdentity;
|
|
switch (orientation)
|
|
{
|
|
case UIImageOrientationDown:
|
|
{
|
|
transform = CGAffineTransformRotate(CGAffineTransformMakeTranslation(size.width, size.height), (CGFloat)M_PI);
|
|
}
|
|
break;
|
|
|
|
case UIImageOrientationRight:
|
|
{
|
|
transform = CGAffineTransformRotate(CGAffineTransformMakeTranslation(size.width, 0), (CGFloat)M_PI_2);
|
|
}
|
|
break;
|
|
|
|
case UIImageOrientationLeft:
|
|
{
|
|
transform = CGAffineTransformRotate(CGAffineTransformMakeTranslation(0, size.height), (CGFloat)-M_PI_2);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return transform;
|
|
}
|
|
|
|
CGAffineTransform TGVideoTransformForCrop(UIImageOrientation orientation, CGSize size, bool mirrored)
|
|
{
|
|
if (TGOrientationIsSideward(orientation, NULL))
|
|
size = CGSizeMake(size.height, size.width);
|
|
|
|
CGAffineTransform transform = CGAffineTransformMakeTranslation(size.width / 2.0f, size.height / 2.0f);
|
|
switch (orientation)
|
|
{
|
|
case UIImageOrientationDown:
|
|
{
|
|
transform = CGAffineTransformRotate(transform, M_PI);
|
|
}
|
|
break;
|
|
|
|
case UIImageOrientationRight:
|
|
{
|
|
transform = CGAffineTransformRotate(transform, M_PI_2);
|
|
}
|
|
break;
|
|
|
|
case UIImageOrientationLeft:
|
|
{
|
|
transform = CGAffineTransformRotate(transform, -M_PI_2);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (mirrored)
|
|
transform = CGAffineTransformScale(transform, -1.0f, 1.0f);
|
|
|
|
if (TGOrientationIsSideward(orientation, NULL))
|
|
size = CGSizeMake(size.height, size.width);
|
|
|
|
transform = CGAffineTransformTranslate(transform, -size.width / 2.0f, -size.height / 2.0f);
|
|
|
|
return transform;
|
|
}
|
|
|
|
CGSize TGTransformDimensionsWithTransform(CGSize dimensions, CGAffineTransform transform)
|
|
{
|
|
CGRect rect = CGRectMake(0, 0, dimensions.width, dimensions.height);
|
|
rect = CGRectApplyAffineTransform(rect, transform);
|
|
return rect.size;
|
|
}
|
|
|
|
CGFloat TGRubberBandDistance(CGFloat offset, CGFloat dimension)
|
|
{
|
|
const CGFloat constant = 0.55f;
|
|
CGFloat result = (constant * ABS(offset) * dimension) / (dimension + constant * ABS(offset));
|
|
|
|
return (offset < 0.0f) ? -result : result;
|
|
}
|
|
|
|
bool _CGPointEqualToPointWithEpsilon(CGPoint point1, CGPoint point2, CGFloat epsilon)
|
|
{
|
|
CGFloat absEpsilon = ABS(epsilon);
|
|
bool xOK = ABS(point1.x - point2.x) < absEpsilon;
|
|
bool yOK = ABS(point1.y - point2.y) < absEpsilon;
|
|
|
|
return xOK && yOK;
|
|
}
|
|
|
|
bool _CGRectEqualToRectWithEpsilon(CGRect rect1, CGRect rect2, CGFloat epsilon)
|
|
{
|
|
CGFloat absEpsilon = ABS(epsilon);
|
|
bool xOK = ABS(rect1.origin.x - rect2.origin.x) < absEpsilon;
|
|
bool yOK = ABS(rect1.origin.y - rect2.origin.y) < absEpsilon;
|
|
bool wOK = ABS(rect1.size.width - rect2.size.width) < absEpsilon * 2;
|
|
bool hOK = ABS(rect1.size.height - rect2.size.height) < absEpsilon * 2;
|
|
|
|
return xOK && yOK && wOK && hOK;
|
|
}
|