123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- // 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"
- #import "UIImage+RoundedCorner.h"
- #import "UIImage+Alpha.h"
- // Private helper methods
- @interface UIImage (PrivateRoundedCorner)
- - (UIImage *)resizedImage:(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.
- // This method ignores the image's imageOrientation setting.
- - (UIImage *)croppedImage:(CGRect)bounds {
- CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds);
- UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
- CGImageRelease(imageRef);
- return croppedImage;
- }
- // Returns a copy of this image that is squared to the thumbnail size.
- // If transparentBorder is non-zero, a transparent border of the given size will be added around the edges of the thumbnail. (Adding a transparent border of at least one pixel in size has the side-effect of antialiasing the edges of the image when rotating it using Core Animation.)
- - (UIImage *)thumbnailImage:(NSInteger)thumbnailSize
- transparentBorder:(NSUInteger)borderSize
- cornerRadius:(NSUInteger)cornerRadius
- interpolationQuality:(CGInterpolationQuality)quality {
- UIImage *resizedImage = [self resizedImageWithContentMode:UIViewContentModeScaleAspectFill
- bounds:CGSizeMake(thumbnailSize, thumbnailSize)
- interpolationQuality:quality];
-
- // Crop out any part of the image that's larger than the thumbnail size
- // The cropped rect must be centered on the resized image
- // Round the origin points so that the size isn't altered when CGRectIntegral is later invoked
- CGRect cropRect = CGRectMake(round((resizedImage.size.width - thumbnailSize) / 2),
- round((resizedImage.size.height - thumbnailSize) / 2),
- thumbnailSize,
- thumbnailSize);
- UIImage *croppedImage = [resizedImage croppedImage:cropRect];
-
- UIImage *transparentBorderImage = borderSize ? [croppedImage transparentBorderImage:borderSize] : croppedImage;
- return [transparentBorderImage roundedCornerImage:cornerRadius borderSize:borderSize];
- }
- // 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", (int)contentMode];
- }
-
- CGSize newSize = CGSizeMake(roundf(self.size.width * ratio), roundf(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
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- CGContextRef bitmap = CGBitmapContextCreate(NULL,
- newRect.size.width,
- newRect.size.height,
- 8,
- 0,
- colorSpace,
- (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
-
- // 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);
- CGColorSpaceRelease(colorSpace);
-
- 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;
-
- default:
- 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;
-
- default:
- break;
- }
-
- return transform;
- }
- @end
|