react-native-camera/UIImage+Resize.m

208 lines
8.3 KiB
Objective-C

// UIImage+Resize.m
// Created by Trevor Harmon on 8/5/09.
// Free for personal or commercial use, with or without modification.
// No warranty is expressed or implied.
#import "UIImage+Resize.h"
// Private helper methods
@interface UIImage ()
- (UIImage *)resizedImage:(CGImageRef)imageRef
size:(CGSize)newSize
transform:(CGAffineTransform)transform
drawTransposed:(BOOL)transpose
interpolationQuality:(CGInterpolationQuality)quality;
- (CGAffineTransform)transformForOrientation:(CGSize)newSize;
@end
@implementation UIImage (Resize)
// Returns a copy of this image that is cropped to the given bounds.
// The bounds will be adjusted using CGRectIntegral.
// JPMH-This method no long ignores the image's imageOrientation setting.
- (UIImage *)croppedImage:(CGRect)bounds {
CGAffineTransform txTranslate;
CGAffineTransform txCompound;
CGRect adjustedBounds;
BOOL drawTransposed;
switch (self.imageOrientation) {
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
txTranslate = CGAffineTransformMakeTranslation(self.size.width, self.size.height);
txCompound = CGAffineTransformRotate(txTranslate, M_PI);
adjustedBounds = CGRectApplyAffineTransform(bounds, txCompound);
drawTransposed = NO;
break;
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
txTranslate = CGAffineTransformMakeTranslation(self.size.height, 0.0);
txCompound = CGAffineTransformRotate(txTranslate, M_PI_2);
adjustedBounds = CGRectApplyAffineTransform(bounds, txCompound);
drawTransposed = YES;
break;
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
txTranslate = CGAffineTransformMakeTranslation(0.0, self.size.width);
txCompound = CGAffineTransformRotate(txTranslate, M_PI + M_PI_2);
adjustedBounds = CGRectApplyAffineTransform(bounds, txCompound);
drawTransposed = YES;
break;
default:
adjustedBounds = bounds;
drawTransposed = NO;
}
CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], adjustedBounds);
UIImage *croppedImage;
if (CGRectEqualToRect(adjustedBounds, bounds))
croppedImage = [UIImage imageWithCGImage:imageRef];
else
croppedImage = [self resizedImage:imageRef
size:bounds.size
transform:[self transformForOrientation:bounds.size]
drawTransposed:drawTransposed
interpolationQuality:kCGInterpolationHigh];
CGImageRelease(imageRef);
return croppedImage;
}
// Returns a rescaled copy of the image, taking into account its orientation
// The image will be scaled disproportionately if necessary to fit the bounds specified by the parameter
- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality {
BOOL drawTransposed;
switch (self.imageOrientation) {
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
drawTransposed = YES;
break;
default:
drawTransposed = NO;
}
return [self resizedImage:newSize
transform:[self transformForOrientation:newSize]
drawTransposed:drawTransposed
interpolationQuality:quality];
}
// Resizes the image according to the given content mode, taking into account the image's orientation
- (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode
bounds:(CGSize)bounds
interpolationQuality:(CGInterpolationQuality)quality {
CGFloat horizontalRatio = bounds.width / self.size.width;
CGFloat verticalRatio = bounds.height / self.size.height;
CGFloat ratio;
switch (contentMode) {
case UIViewContentModeScaleAspectFill:
ratio = MAX(horizontalRatio, verticalRatio);
break;
case UIViewContentModeScaleAspectFit:
ratio = MIN(horizontalRatio, verticalRatio);
break;
default:
[NSException raise:NSInvalidArgumentException format:@"Unsupported content mode: %d", contentMode];
}
CGSize newSize = CGSizeMake(self.size.width * ratio, self.size.height * ratio);
return [self resizedImage:newSize interpolationQuality:quality];
}
#pragma mark -
#pragma mark Private helper methods
// Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size
// The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation
// If the new size is not integral, it will be rounded up
- (UIImage *)resizedImage:(CGSize)newSize
transform:(CGAffineTransform)transform
drawTransposed:(BOOL)transpose
interpolationQuality:(CGInterpolationQuality)quality {
CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width);
CGImageRef imageRef = self.CGImage;
// Build a context that's the same dimensions as the new size
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
if((bitmapInfo == kCGImageAlphaLast) || (bitmapInfo == kCGImageAlphaNone))
bitmapInfo = kCGImageAlphaNoneSkipLast;
CGContextRef bitmap = CGBitmapContextCreate(NULL,
newRect.size.width,
newRect.size.height,
CGImageGetBitsPerComponent(imageRef),
0,
CGImageGetColorSpace(imageRef),
bitmapInfo);
// Rotate and/or flip the image if required by its orientation
CGContextConcatCTM(bitmap, transform);
// Set the quality level to use when rescaling
CGContextSetInterpolationQuality(bitmap, quality);
// Draw into the context; this scales the image
CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef);
// Get the resized image from the context and a UIImage
CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
// Clean up
CGContextRelease(bitmap);
CGImageRelease(newImageRef);
return newImage;
}
// Returns an affine transform that takes into account the image orientation when drawing a scaled image
- (CGAffineTransform)transformForOrientation:(CGSize)newSize {
CGAffineTransform transform = CGAffineTransformIdentity;
switch (self.imageOrientation) {
case UIImageOrientationDown: // EXIF = 3
case UIImageOrientationDownMirrored: // EXIF = 4
transform = CGAffineTransformTranslate(transform, newSize.width, newSize.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case UIImageOrientationLeft: // EXIF = 6
case UIImageOrientationLeftMirrored: // EXIF = 5
transform = CGAffineTransformTranslate(transform, newSize.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
case UIImageOrientationRight: // EXIF = 8
case UIImageOrientationRightMirrored: // EXIF = 7
transform = CGAffineTransformTranslate(transform, 0, newSize.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);
break;
}
switch (self.imageOrientation) {
case UIImageOrientationUpMirrored: // EXIF = 2
case UIImageOrientationDownMirrored: // EXIF = 4
transform = CGAffineTransformTranslate(transform, newSize.width, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationLeftMirrored: // EXIF = 5
case UIImageOrientationRightMirrored: // EXIF = 7
transform = CGAffineTransformTranslate(transform, newSize.height, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
}
return transform;
}
@end