diff --git a/UIImage+Transforms.h b/UIImage+Transforms.h index 9896056..bc41f33 100755 --- a/UIImage+Transforms.h +++ b/UIImage+Transforms.h @@ -12,14 +12,33 @@ + (UIImage *)blankImage; + (UIImage *)imageOfColor:(UIColor *)color; ++ (UIImage*) grayishImage: (UIImage*) inputImage; - (UIImage *)tintedGradientImageWithColor:(UIColor *)tintColor; - (UIImage *)tintedImageWithColor:(UIColor *)tintColor; - (UIImage *)imageScaledToSize:(CGSize)size; - (UIImage *)imageSmoothlyScaledToSize:(CGSize)size; + (UIImage *)imageFromLayer:(CALayer *)layer; -+ (UIImage *)paddedImage:(UIImage *)image paddingInsets:(UIEdgeInsets)insets; + (UIImage *)stitchImages:(NSArray *)images vertically:(BOOL)vertically; - (UIImage *)colorizeImageWithColor:(UIColor *)color; - (UIImage *)colorizeImageWithColor:(UIColor *)color withBlendMode:(CGBlendMode)blendMode; ++ (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage ; + + + + + +- (UIImage *)croppedImage:(CGRect)bounds; +- (UIImage *)thumbnailImage:(NSInteger)thumbnailSize + transparentBorder:(NSUInteger)borderSize + cornerRadius:(NSUInteger)cornerRadius + interpolationQuality:(CGInterpolationQuality)quality; +- (UIImage *)resizedImage:(CGSize)newSize + interpolationQuality:(CGInterpolationQuality)quality; +- (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode + bounds:(CGSize)bounds + interpolationQuality:(CGInterpolationQuality)quality; +- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize; + + @end diff --git a/UIImage+Transforms.m b/UIImage+Transforms.m index b510357..d5c739e 100755 --- a/UIImage+Transforms.m +++ b/UIImage+Transforms.m @@ -8,6 +8,16 @@ #import "UIImage+Transforms.h" + +@interface UIImage () +- (UIImage *)resizedImage:(CGSize)newSize + transform:(CGAffineTransform)transform + drawTransposed:(BOOL)transpose + interpolationQuality:(CGInterpolationQuality)quality; +- (CGAffineTransform)transformForOrientation:(CGSize)newSize; +@end + + @implementation UIImage (Transforms) + (UIImage *)blankImage @@ -32,6 +42,23 @@ + (UIImage *)imageOfColor:(UIColor *)color return image; } ++ (UIImage*) grayishImage: (UIImage*) inputImage { + + // Create a graphic context. + UIGraphicsBeginImageContextWithOptions(inputImage.size, YES, 1.0); + CGRect imageRect = CGRectMake(0, 0, inputImage.size.width, inputImage.size.height); + + // Draw the image with the luminosity blend mode. + // On top of a white background, this will give a black and white image. + [inputImage drawInRect:imageRect blendMode:kCGBlendModeLuminosity alpha:1.0]; + + // Get the resulting image. + UIImage *filteredImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return filteredImage; + +} - (UIImage *)tintedGradientImageWithColor:(UIColor *)tintColor { @@ -173,27 +200,6 @@ - (UIImage *)colorizeImageWithColor:(UIColor *)color withBlendMode:(CGBlendMode) } -+ (UIImage *)paddedImage:(UIImage *)image paddingInsets:(UIEdgeInsets)insets -{ -// UIEdgeInsetsMake(<#CGFloat top#>, <#CGFloat left#>, <#CGFloat bottom#>, <#CGFloat right#>) -// leftPadding:(CGFloat)left rightPadding:(CGFloat)right topPadding:(CGFloat)top bottomPadding:(CGFloat)bottom - CGFloat const width = image.size.width+insets.left+insets.right; - CGFloat const height = image.size.height+insets.top+insets.bottom; - - UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, 0.0); - CGContextRef context = UIGraphicsGetCurrentContext(); - UIGraphicsPushContext(context); - - CGPoint origin = CGPointMake(insets.left, insets.top); - [image drawAtPoint:origin]; - - UIGraphicsPopContext(); - UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - return newImage; -} - //////////////////////////////////////////////////////////////////////////////// #pragma mark - Private methods @@ -215,4 +221,251 @@ - (UIImage *)tintedImageWithColor:(UIColor *)tintColor blendingMode:(CGBlendMode return tintedImage; } ++ (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage { + + CGImageRef maskRef = maskImage.CGImage; + + CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), + CGImageGetHeight(maskRef), + CGImageGetBitsPerComponent(maskRef), + CGImageGetBitsPerPixel(maskRef), + CGImageGetBytesPerRow(maskRef), + CGImageGetDataProvider(maskRef), NULL, false); + + CGImageRef masked = CGImageCreateWithMask([image CGImage], mask); + return [UIImage imageWithCGImage:masked]; +} + + + + + + + + + + + + + + + +// 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 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]; +} + + + +- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize +{ + UIImage *sourceImage = self; + UIImage *newImage = nil; + CGSize imageSize = sourceImage.size; + CGFloat width = imageSize.width; + CGFloat height = imageSize.height; + CGFloat targetWidth = targetSize.width; + CGFloat targetHeight = targetSize.height; + CGFloat scaleFactor = 0.0; + CGFloat scaledWidth = targetWidth; + CGFloat scaledHeight = targetHeight; + CGPoint thumbnailPoint = CGPointMake(0.0,0.0); + + if (CGSizeEqualToSize(imageSize, targetSize) == NO) + { + CGFloat widthFactor = targetWidth / width; + CGFloat heightFactor = targetHeight / height; + + if (widthFactor > heightFactor) + { + scaleFactor = widthFactor; // scale to fit height + } + else + { + scaleFactor = heightFactor; // scale to fit width + } + + scaledWidth = width * scaleFactor; + scaledHeight = height * scaleFactor; + + // center the image + if (widthFactor > heightFactor) + { + thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; + } + else + { + if (widthFactor < heightFactor) + { + thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; + } + } + } + + UIGraphicsBeginImageContext(targetSize); // this will crop + + CGRect thumbnailRect = CGRectZero; + thumbnailRect.origin = thumbnailPoint; + thumbnailRect.size.width = scaledWidth; + thumbnailRect.size.height = scaledHeight; + + [sourceImage drawInRect:thumbnailRect]; + + newImage = UIGraphicsGetImageFromCurrentImageContext(); + + if(newImage == nil) + { + NSLog(@"could not scale image"); + } + + //pop the context to get back to the default + UIGraphicsEndImageContext(); + + return newImage; +} + +#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 + CGContextRef bitmap = CGBitmapContextCreate(NULL, + newRect.size.width, + newRect.size.height, + CGImageGetBitsPerComponent(imageRef), + 0, + CGImageGetColorSpace(imageRef), + CGImageGetBitmapInfo(imageRef)); + + // 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