Hi all,
Follow below steps to create lazy image-view with image having shadow effect.
Step 1 : Create two files named as "NPImageView.h" and "NPImageView.m"
#import <UIKit/UIKit.h>
@interface NPImageView : UIImageView
+ (NSOperationQueue *)processingQueue;
+ (NSCache *)processedImageCache;
@property (nonatomic, assign, getter = isAsynchronous) BOOL asynchronous;
@property (nonatomic, assign) CGFloat reflectionGap;
@property (nonatomic, assign) CGFloat reflectionScale;
@property (nonatomic, assign) CGFloat reflectionAlpha;
@property (nonatomic, strong) UIColor *shadowColor;
@property (nonatomic, assign) CGSize shadowOffset;
@property (nonatomic, assign) CGFloat shadowBlur;
@property (nonatomic, assign) CGFloat cornerRadius;
@property (nonatomic, strong) UIImage *processedImage;
@property (nonatomic, copy) UIImage *(^customEffectsBlock)(UIImage *image);
@property (nonatomic, copy) NSString *cacheKey;
- (void)setImageWithContentsOfFile:(NSString *)file;
- (void)setImageWithContentsOfURL:(NSURL *)URL;
@end
#import "FXImageView.h"
#import "UIImage+FX.h"
#import <objc/message.h>
@interface NPImageOperation : NSOperation
@property (nonatomic, strong) NPImageView *target;
@end
@interface NPImageView ()
@property (nonatomic, assign) UIActivityIndicatorView *loading;
@property (nonatomic, strong) UIImage *originalImage;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) NSURL *imageContentURL;
- (void)processImage;
@end
@implementation NPImageOperation
@synthesize target = _target;
- (void)main
{
@autoreleasepool
{
[_target processImage];
}
}
#if !__has_feature(objc_arc)
- (void)dealloc
{
[_target release];
[super dealloc];
}
#endif
@end
@implementation NPImageView
@synthesize asynchronous = _asynchronous;
@synthesize reflectionGap = _reflectionGap;
@synthesize reflectionScale = _reflectionScale;
@synthesize reflectionAlpha = _reflectionAlpha;
@synthesize shadowColor = _shadowColor;
@synthesize shadowOffset = _shadowOffset;
@synthesize shadowBlur = _shadowBlur;
@synthesize cornerRadius = _cornerRadius;
@synthesize customEffectsBlock = _customEffectsBlock;
@synthesize cacheKey = _cacheKey;
@synthesize originalImage = _originalImage;
@synthesize imageView = _imageView;
@synthesize imageContentURL = _imageContentURL;
@synthesize loading = _loading;
#pragma mark -
#pragma mark Shared storage
+ (NSOperationQueue *)processingQueue
{
static NSOperationQueue *sharedQueue = nil;
if (sharedQueue == nil)
{
sharedQueue = [[NSOperationQueue alloc] init];
[sharedQueue setMaxConcurrentOperationCount:4];
}
return sharedQueue;
}
+ (NSCache *)processedImageCache
{
static NSCache *sharedCache = nil;
if (sharedCache == nil)
{
sharedCache = [[NSCache alloc] init];
}
return sharedCache;
}
#pragma mark -
#pragma mark Setup
- (void)setUp
{
self.shadowColor = [UIColor blackColor];
_imageView = [[UIImageView alloc] initWithFrame:self.bounds];
_imageView.contentMode = UIViewContentModeCenter;
[self addSubview:_imageView];
_loading = [[UIActivityIndicatorView alloc]init];
_loading.frame = CGRectMake((_imageView.frame.size.width/2.0)-10.0, (_imageView.frame.size.height/2.0)-10.0, 20.0, 20.0);
[_loading setHidesWhenStopped:YES];
[_imageView addSubview:_loading];
[self setImage:super.image];
super.image = nil;
}
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
[self setUp];
}
return self;
}
- (id)initWithImage:(UIImage *)image
{
if ((self = [super initWithImage:image]))
{
[self setUp];
}
return self;
}
- (id)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage
{
if ((self = [super initWithImage:image highlightedImage:highlightedImage]))
{
[self setUp];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
{
[self setUp];
}
return self;
}
#if !__has_feature(objc_arc)
- (void)dealloc
{
[_customEffectsBlock release];
[_cacheKey release];
[_originalImage release];
[_shadowColor release];
[_imageView release];
[_imageContentURL release];
[_loading release];
[super dealloc];
}
#endif
#pragma mark -
#pragma mark Caching
- (NSString *)colorHash:(UIColor *)color
{
NSString *colorString = @"{0.00,0.00}";
if (color && ![color isEqual:[UIColor clearColor]])
{
NSInteger componentCount = CGColorGetNumberOfComponents(color.CGColor);
const CGFloat *components = CGColorGetComponents(color.CGColor);
NSMutableArray *parts = [NSMutableArray arrayWithCapacity:componentCount];
for (int i = 0; i < componentCount; i++)
{
[parts addObject:[NSString stringWithFormat:@"%.2f", components[i]]];
}
colorString = [NSString stringWithFormat:@"{%@}", [parts componentsJoinedByString:@","]];
}
return colorString;
}
- (NSString *)imageHash:(UIImage *)image
{
static NSInteger hashKey = 1;
NSString *number = objc_getAssociatedObject(image, @"FXImageHash");
if (!number && image)
{
number = [NSString stringWithFormat:@"%i", hashKey++];
objc_setAssociatedObject(image, @"FXImageHash", number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return number;
}
- (NSString *)cacheKey
{
if (_cacheKey) return _cacheKey;
return [NSString stringWithFormat:@"%@_%@_%.2f_%.2f_%.2f_%@_%@_%.2f_%.2f_%i",
_imageContentURL ?: [self imageHash:_originalImage],
NSStringFromCGSize(self.bounds.size),
_reflectionGap,
_reflectionScale,
_reflectionAlpha,
[self colorHash:_shadowColor],
NSStringFromCGSize(_shadowOffset),
_shadowBlur,
_cornerRadius,
self.contentMode];
}
- (void)cacheProcessedImage:(UIImage *)processedImage forKey:(NSString *)cacheKey
{
[[[self class] processedImageCache] setObject:processedImage forKey:cacheKey];
}
- (UIImage *)cachedProcessedImage
{
return [[[self class] processedImageCache] objectForKey:[self cacheKey]];
}
#pragma mark -
#pragma mark Processing
- (void)setProcessedImageOnMainThread:(NSArray *)array
{
//get images
NSString *cacheKey = [array objectAtIndex:1];
UIImage *processedImage = [array objectAtIndex:0];
processedImage = ([processedImage isKindOfClass:[NSNull class]])? nil: processedImage;
if (processedImage)
{
//cache image
[self cacheProcessedImage:processedImage forKey:cacheKey];
}
//set image
if ([[self cacheKey] isEqualToString:cacheKey])
{
//implement crossfade transition without needing to import QuartzCore
id animation = objc_msgSend(NSClassFromString(@"CATransition"), @selector(animation));
objc_msgSend(animation, @selector(setType:), @"kCATransitionFade");
objc_msgSend(self.layer, @selector(addAnimation:forKey:), animation, nil);
//set processed image
[self willChangeValueForKey:@"processedImage"];
_imageView.image = processedImage;
[self didChangeValueForKey:@"processedImage"];
}
}
- (void)processImage
{
//get properties
NSString *cacheKey = [self cacheKey];
UIImage *image = _originalImage;
NSURL *imageURL = _imageContentURL;
CGSize size = self.bounds.size;
CGFloat reflectionGap = _reflectionGap;
CGFloat reflectionScale = _reflectionScale;
CGFloat reflectionAlpha = _reflectionAlpha;
UIColor *shadowColor = _shadowColor;
CGSize shadowOffset = _shadowOffset;
CGFloat shadowBlur = _shadowBlur;
CGFloat cornerRadius = _cornerRadius;
UIImage *(^customEffectsBlock)(UIImage *image) = [_customEffectsBlock copy];
UIViewContentMode contentMode = self.contentMode;
#if !__has_feature(objc_arc)
[[image retain] autorelease];
[[imageURL retain] autorelease];
[[shadowColor retain] autorelease];
[customEffectsBlock autorelease];
#endif
//check cache
UIImage *processedImage = [self cachedProcessedImage];
if (!processedImage)
{
//load image
if (imageURL)
{
NSURLRequest *request = [NSURLRequest requestWithURL:imageURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30.0];
[_loading startAnimating];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error)
{
NSLog(@"Error loading image for URL: %@, %@", imageURL, error);
return;
}
else
{
image = [UIImage imageWithData:data];
[_loading stopAnimating];
if ([[[imageURL path] stringByDeletingPathExtension] hasSuffix:@"@2x"])
{
image = [UIImage imageWithCGImage:image.CGImage scale:2.0f orientation:image.imageOrientation];
}
}
}
if (image)
{
//crop and scale image
processedImage = [image imageCroppedAndScaledToSize:size
contentMode:contentMode
padToFit:NO];
//apply custom processing
if (customEffectsBlock)
{
processedImage = customEffectsBlock(processedImage);
}
//clip corners
if (cornerRadius)
{
processedImage = [processedImage imageWithCornerRadius:cornerRadius];
}
//apply shadow
if (shadowColor && ![shadowColor isEqual:[UIColor clearColor]] &&
(shadowBlur || !CGSizeEqualToSize(shadowOffset, CGSizeZero)))
{
reflectionGap -= 2.0f * (fabsf(shadowOffset.height) + shadowBlur);
processedImage = [processedImage imageWithShadowColor:shadowColor
offset:shadowOffset
blur:shadowBlur];
}
//apply reflection
if (reflectionScale && reflectionAlpha)
{
processedImage = [processedImage imageWithReflectionWithScale:reflectionScale
gap:reflectionGap
alpha:reflectionAlpha];
}
}
}
//cache and set image
if ([[NSThread currentThread] isMainThread])
{
if (processedImage)
{
[self cacheProcessedImage:processedImage forKey:cacheKey];
}
[self willChangeValueForKey:@"processedImage"];
_imageView.image = processedImage;
[self didChangeValueForKey:@"processedImage"];
}
else
{
[self performSelectorOnMainThread:@selector(setProcessedImageOnMainThread:)
withObject:[NSArray arrayWithObjects:
processedImage ?: [NSNull null],
cacheKey,
nil]
waitUntilDone:YES];
}
}
- (void)queueProcessingOperation:(FXImageOperation *)operation
{
//suspend operation queue
NSOperationQueue *queue = [[self class] processingQueue];
[queue setSuspended:YES];
//check for existing operations
for (FXImageOperation *op in queue.operations)
{
if ([op isKindOfClass:[FXImageOperation class]])
{
if (op.target == self && ![op isExecuting])
{
//already queued
[queue setSuspended:NO];
return;
}
}
}
//make op a dependency of all queued ops
NSInteger maxOperations = ([queue maxConcurrentOperationCount] > 0) ? [queue maxConcurrentOperationCount]: INT_MAX;
NSInteger index = [queue operationCount] - maxOperations;
if (index >= 0)
{
NSOperation *op = [[queue operations] objectAtIndex:index];
if (![op isExecuting])
{
[op addDependency:operation];
}
}
//add operation to queue
[queue addOperation:operation];
//resume queue
[queue setSuspended:NO];
}
- (void)queueImageForProcessing
{
//create processing operation
FXImageOperation *operation = [[FXImageOperation alloc] init];
operation.target = self;
//set operation thread priority
[operation setThreadPriority:1.0];
//queue operation
[self queueProcessingOperation:operation];
#if !__has_feature(objc_arc)
[operation release];
#endif
}
- (void)updateProcessedImage
{
id processedImage = [self cachedProcessedImage];
if (!processedImage && !_originalImage && !_imageContentURL)
{
processedImage = [NSNull null];
}
if (processedImage)
{
//use cached version
[self willChangeValueForKey:@"processedImage"];
_imageView.image = ([processedImage isKindOfClass:[NSNull class]])? nil: processedImage;
[self didChangeValueForKey:@"processedImage"];
}
else if (_asynchronous)
{
//process in background
[self queueImageForProcessing];
}
else
{
//process on main thread
[self processImage];
}
}
- (void)layoutSubviews
{
_imageView.frame = self.bounds;
if (_imageContentURL || self.image)
{
[self updateProcessedImage];
}
}
#pragma mark -
#pragma mark Setters and getters
- (UIImage *)processedImage
{
return _imageView.image;
}
- (void)setProcessedImage:(UIImage *)image
{
self.imageContentURL = nil;
[self willChangeValueForKey:@"image"];
self.originalImage = nil;
[self didChangeValueForKey:@"image"];
_imageView.image = image;
}
- (UIImage *)image
{
return _originalImage;
}
- (void)setImage:(UIImage *)image
{
if (_imageContentURL || ![image isEqual:_originalImage])
{
//update processed image
self.imageContentURL = nil;
self.originalImage = image;
[self updateProcessedImage];
}
}
- (void)setReflectionGap:(CGFloat)reflectionGap
{
if (_reflectionGap != reflectionGap)
{
_reflectionGap = reflectionGap;
[self setNeedsLayout];
}
}
- (void)setReflectionScale:(CGFloat)reflectionScale
{
if (_reflectionScale != reflectionScale)
{
_reflectionScale = reflectionScale;
[self setNeedsLayout];
}
}
- (void)setReflectionAlpha:(CGFloat)reflectionAlpha
{
if (_reflectionAlpha != reflectionAlpha)
{
_reflectionAlpha = reflectionAlpha;
[self setNeedsLayout];
}
}
- (void)setShadowColor:(UIColor *)shadowColor
{
if (![_shadowColor isEqual:shadowColor])
{
#if !__has_feature(objc_arc)
[_shadowColor release];
_shadowColor = [shadowColor retain];
#else
_shadowColor = shadowColor;
#endif
[self setNeedsLayout];
}
}
- (void)setShadowOffset:(CGSize)shadowOffset
{
if (!CGSizeEqualToSize(_shadowOffset, shadowOffset))
{
_shadowOffset = shadowOffset;
[self setNeedsLayout];
}
}
- (void)setShadowBlur:(CGFloat)shadowBlur
{
if (_shadowBlur != shadowBlur)
{
_shadowBlur = shadowBlur;
[self setNeedsLayout];
}
}
- (void)setContentMode:(UIViewContentMode)contentMode
{
if (self.contentMode != contentMode)
{
super.contentMode = contentMode;
[self setNeedsLayout];
}
}
- (void)setCustomEffectsBlock:(UIImage *(^)(UIImage *))customEffectsBlock
{
if (![customEffectsBlock isEqual:_customEffectsBlock])
{
_customEffectsBlock = [customEffectsBlock copy];
[self setNeedsLayout];
}
}
- (void)setCacheKey:(NSString *)cacheKey
{
if (![cacheKey isEqual:_cacheKey])
{
_cacheKey = [cacheKey copy];
[self setNeedsLayout];
}
}
#pragma mark -
#pragma mark loading
- (void)setImageWithContentsOfFile:(NSString *)file
{
if ([[file pathExtension] length] == 0)
{
file = [file stringByAppendingPathExtension:@"png"];
}
if (![file isAbsolutePath])
{
file = [[NSBundle mainBundle] pathForResource:file ofType:nil];
}
if ([UIScreen mainScreen].scale == 2.0f)
{
NSString *temp = [[[file stringByDeletingPathExtension] stringByAppendingString:@"@2x"] stringByAppendingPathExtension:[file pathExtension]];
if ([[NSFileManager defaultManager] fileExistsAtPath:temp])
{
file = temp;
}
}
[self setImageWithContentsOfURL:[NSURL fileURLWithPath:file]];
}
- (void)setImageWithContentsOfURL:(NSURL *)URL
{
if (![URL isEqual:_imageContentURL])
{
//update processed image
[self willChangeValueForKey:@"image"];
self.originalImage = nil;
[self didChangeValueForKey:@"image"];
self.imageContentURL = URL;
[self updateProcessedImage];
}
}
@end
Step 2 : Create two files named as "UIImage+NP.h" and "UIImage+NP.m" for generating UIImage category.
#import <UIKit/UIKit.h>
@interface UIImage (NP)
- (UIImage *)imageCroppedToRect:(CGRect)rect;
- (UIImage *)imageScaledToSize:(CGSize)size;
- (UIImage *)imageScaledToFitSize:(CGSize)size;
- (UIImage *)imageScaledToFillSize:(CGSize)size;
- (UIImage *)imageCroppedAndScaledToSize:(CGSize)size
contentMode:(UIViewContentMode)contentMode
padToFit:(BOOL)padToFit;
- (UIImage *)reflectedImageWithScale:(CGFloat)scale;
- (UIImage *)imageWithReflectionWithScale:(CGFloat)scale gap:(CGFloat)gap alpha:(CGFloat)alpha;
- (UIImage *)imageWithShadowColor:(UIColor *)color offset:(CGSize)offset blur:(CGFloat)blur;
- (UIImage *)imageWithCornerRadius:(CGFloat)radius;
- (UIImage *)imageWithAlpha:(CGFloat)alpha;
- (UIImage *)imageWithMask:(UIImage *)maskImage;
- (UIImage *)maskImageFromImageAlpha;
@end
#import "UIImage+NP.h"
@implementation UIImage (NP)
- (UIImage *)imageCroppedToRect:(CGRect)rect
{
//create drawing context
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0f);
//draw
[self drawAtPoint:CGPointMake(-rect.origin.x, -rect.origin.y)];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageScaledToSize:(CGSize)size
{
//avoid redundant drawing
if (CGSizeEqualToSize(self.size, size))
{
return self;
}
//create drawing context
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
//draw
[self drawInRect:CGRectMake(0.0f, 0.0f, size.width, size.height)];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageScaledToFitSize:(CGSize)size
{
//calculate rect
CGFloat aspect = self.size.width / self.size.height;
if (size.width / aspect <= size.height)
{
return [self imageScaledToSize:CGSizeMake(size.width, size.width / aspect)];
}
else
{
return [self imageScaledToSize:CGSizeMake(size.height * aspect, size.height)];
}
}
- (UIImage *)imageScaledToFillSize:(CGSize)size
{
if (CGSizeEqualToSize(self.size, size))
{
return self;
}
//calculate rect
CGFloat aspect = self.size.width / self.size.height;
if (size.width / aspect >= size.height)
{
return [self imageScaledToSize:CGSizeMake(size.width, size.width / aspect)];
}
else
{
return [self imageScaledToSize:CGSizeMake(size.height * aspect, size.height)];
}
}
- (UIImage *)imageCroppedAndScaledToSize:(CGSize)size
contentMode:(UIViewContentMode)contentMode
padToFit:(BOOL)padToFit;
{
//calculate rect
CGRect rect = CGRectZero;
switch (contentMode)
{
case UIViewContentModeScaleAspectFit:
{
CGFloat aspect = self.size.width / self.size.height;
if (size.width / aspect <= size.height)
{
rect = CGRectMake(0.0f, (size.height - size.width / aspect) / 2.0f, size.width, size.width / aspect);
}
else
{
rect = CGRectMake((size.width - size.height * aspect) / 2.0f, 0.0f, size.height * aspect, size.height);
}
break;
}
case UIViewContentModeScaleAspectFill:
{
CGFloat aspect = self.size.width / self.size.height;
if (size.width / aspect >= size.height)
{
rect = CGRectMake(0.0f, (size.height - size.width / aspect) / 2.0f, size.width, size.width / aspect);
}
else
{
rect = CGRectMake((size.width - size.height * aspect) / 2.0f, 0.0f, size.height * aspect, size.height);
}
break;
}
case UIViewContentModeCenter:
{
rect = CGRectMake((size.width - self.size.width) / 2.0f, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeTop:
{
rect = CGRectMake((size.width - self.size.width) / 2.0f, 0.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeBottom:
{
rect = CGRectMake((size.width - self.size.width) / 2.0f, size.height - self.size.height, self.size.width, self.size.height);
break;
}
case UIViewContentModeLeft:
{
rect = CGRectMake(0.0f, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeRight:
{
rect = CGRectMake(size.width - self.size.width, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeTopLeft:
{
rect = CGRectMake(0.0f, 0.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeTopRight:
{
rect = CGRectMake(size.width - self.size.width, 0.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeBottomLeft:
{
rect = CGRectMake(0.0f, size.height - self.size.height, self.size.width, self.size.height);
break;
}
case UIViewContentModeBottomRight:
{
rect = CGRectMake(size.width - self.size.width, size.height - self.size.height, self.size.width, self.size.height);
break;
}
default:
{
rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
break;
}
}
if (!padToFit)
{
//remove padding
if (rect.size.width < size.width)
{
size.width = rect.size.width;
rect.origin.x = 0.0f;
}
if (rect.size.height < size.height)
{
size.height = rect.size.height;
rect.origin.y = 0.0f;
}
}
//avoid redundant drawing
if (CGSizeEqualToSize(self.size, size))
{
return self;
}
//create drawing context
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
//draw
[self drawInRect:rect];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
+ (CGImageRef)gradientMask
{
static CGImageRef sharedMask = NULL;
if (sharedMask == NULL)
{
//create gradient mask
UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, 256), YES, 0.0);
CGContextRef gradientContext = UIGraphicsGetCurrentContext();
CGFloat colors[] = {0.0, 1.0, 1.0, 1.0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
CGPoint gradientStartPoint = CGPointMake(0, 0);
CGPoint gradientEndPoint = CGPointMake(0, 256);
CGContextDrawLinearGradient(gradientContext, gradient, gradientStartPoint,
gradientEndPoint, kCGGradientDrawsAfterEndLocation);
sharedMask = CGBitmapContextCreateImage(gradientContext);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
UIGraphicsEndImageContext();
}
return sharedMask;
}
- (UIImage *)reflectedImageWithScale:(CGFloat)scale
{
//get reflection dimensions
CGFloat height = ceil(self.size.height * scale);
CGSize size = CGSizeMake(self.size.width, height);
CGRect bounds = CGRectMake(0.0f, 0.0f, size.width, size.height);
//create drawing context
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
//clip to gradient
CGContextClipToMask(context, bounds, [[self class] gradientMask]);
//draw reflected image
CGContextScaleCTM(context, 1.0f, -1.0f);
CGContextTranslateCTM(context, 0.0f, -self.size.height);
[self drawInRect:CGRectMake(0.0f, 0.0f, self.size.width, self.size.height)];
//capture resultant image
UIImage *reflection = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return reflection image
return reflection;
}
- (UIImage *)imageWithReflectionWithScale:(CGFloat)scale gap:(CGFloat)gap alpha:(CGFloat)alpha
{
//get reflected image
UIImage *reflection = [self reflectedImageWithScale:scale];
CGFloat reflectionOffset = reflection.size.height + gap;
//create drawing context
UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.size.width, self.size.height + reflectionOffset * 2.0f), NO, 0.0f);
//draw reflection
[reflection drawAtPoint:CGPointMake(0.0f, reflectionOffset + self.size.height + gap) blendMode:kCGBlendModeNormal alpha:alpha];
//draw image
[self drawAtPoint:CGPointMake(0.0f, reflectionOffset)];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageWithShadowColor:(UIColor *)color offset:(CGSize)offset blur:(CGFloat)blur
{
//get size
CGSize border = CGSizeMake(fabsf(offset.width) + blur, fabsf(offset.height) + blur);
CGSize size = CGSizeMake(self.size.width + border.width * 2.0f, self.size.height + border.height * 2.0f);
//create drawing context
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
//set up shadow
CGContextSetShadowWithColor(context, offset, blur, color.CGColor);
//draw with shadow
[self drawAtPoint:CGPointMake(border.width, border.height)];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageWithCornerRadius:(CGFloat)radius
{
//create drawing context
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
//clip image
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0.0f, radius);
CGContextAddLineToPoint(context, 0.0f, self.size.height - radius);
CGContextAddArc(context, radius, self.size.height - radius, radius, M_PI, M_PI / 2.0f, 1);
CGContextAddLineToPoint(context, self.size.width - radius, self.size.height);
CGContextAddArc(context, self.size.width - radius, self.size.height - radius, radius, M_PI / 2.0f, 0.0f, 1);
CGContextAddLineToPoint(context, self.size.width, radius);
CGContextAddArc(context, self.size.width - radius, radius, radius, 0.0f, -M_PI / 2.0f, 1);
CGContextAddLineToPoint(context, radius, 0.0f);
CGContextAddArc(context, radius, radius, radius, -M_PI / 2.0f, M_PI, 1);
CGContextClip(context);
//draw image
[self drawAtPoint:CGPointZero];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageWithAlpha:(CGFloat)alpha
{
//create drawing context
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
//draw with alpha
[self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageWithMask:(UIImage *)maskImage;
{
//create drawing context
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
//apply mask
CGContextClipToMask(context, CGRectMake(0.0f, 0.0f, self.size.width, self.size.height), maskImage.CGImage);
//draw image
[self drawAtPoint:CGPointZero];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)maskImageFromImageAlpha
{
//get dimensions
NSInteger width = CGImageGetWidth(self.CGImage);
NSInteger height = CGImageGetHeight(self.CGImage);
//create alpha image
NSInteger bytesPerRow = ((width + 3) / 4) * 4;
void *data = calloc(bytesPerRow * height, sizeof(unsigned char *));
CGContextRef context = CGBitmapContextCreate(data, width, height, 8, bytesPerRow, NULL, kCGImageAlphaOnly);
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), self.CGImage);
//invert alpha pixels
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
NSInteger index = y * bytesPerRow + x;
((unsigned char *)data)[index] = 255 - ((unsigned char *)data)[index];
}
}
//create mask image
CGImageRef maskRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
UIImage *mask = [UIImage imageWithCGImage:maskRef];
CGImageRelease(maskRef);
free(data);
//return image
return mask;
}
@end
Step 3 : Now you can use LazyImage view with shadow image by just puting below code into your class file.
FXImageView *imageView = [[[FXImageView alloc] initWithFrame:CGRectMake(0, 0, BUTTON_WIDTH, BUTTON_HEIGHT)] autorelease];
imageView.contentMode = UIViewContentModeScaleToFill;
imageView.asynchronous = YES;
imageView.reflectionScale = 0.5f;
imageView.reflectionAlpha = 0.0f;
imageView.reflectionGap = 10.0f;
imageView.shadowOffset = CGSizeMake(0.0f, 2.0f);
imageView.shadowBlur = 5.0f;
imageView.cornerRadius = 10.0f;
//set image
[((FXImageView *)view) setImageWithContentsOfURL:[NSURL URLWithString:@"ImageUrlPath"]];
Enjoy and implement the code.. !!!!!
Regards,
Nilesh M. Prajapati
-->
Follow below steps to create lazy image-view with image having shadow effect.
Step 1 : Create two files named as "NPImageView.h" and "NPImageView.m"
#import <UIKit/UIKit.h>
@interface NPImageView : UIImageView
+ (NSOperationQueue *)processingQueue;
+ (NSCache *)processedImageCache;
@property (nonatomic, assign, getter = isAsynchronous) BOOL asynchronous;
@property (nonatomic, assign) CGFloat reflectionGap;
@property (nonatomic, assign) CGFloat reflectionScale;
@property (nonatomic, assign) CGFloat reflectionAlpha;
@property (nonatomic, strong) UIColor *shadowColor;
@property (nonatomic, assign) CGSize shadowOffset;
@property (nonatomic, assign) CGFloat shadowBlur;
@property (nonatomic, assign) CGFloat cornerRadius;
@property (nonatomic, strong) UIImage *processedImage;
@property (nonatomic, copy) UIImage *(^customEffectsBlock)(UIImage *image);
@property (nonatomic, copy) NSString *cacheKey;
- (void)setImageWithContentsOfFile:(NSString *)file;
- (void)setImageWithContentsOfURL:(NSURL *)URL;
@end
#import "FXImageView.h"
#import "UIImage+FX.h"
#import <objc/message.h>
@interface NPImageOperation : NSOperation
@property (nonatomic, strong) NPImageView *target;
@end
@interface NPImageView ()
@property (nonatomic, assign) UIActivityIndicatorView *loading;
@property (nonatomic, strong) UIImage *originalImage;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) NSURL *imageContentURL;
- (void)processImage;
@end
@implementation NPImageOperation
@synthesize target = _target;
- (void)main
{
@autoreleasepool
{
[_target processImage];
}
}
#if !__has_feature(objc_arc)
- (void)dealloc
{
[_target release];
[super dealloc];
}
#endif
@end
@implementation NPImageView
@synthesize asynchronous = _asynchronous;
@synthesize reflectionGap = _reflectionGap;
@synthesize reflectionScale = _reflectionScale;
@synthesize reflectionAlpha = _reflectionAlpha;
@synthesize shadowColor = _shadowColor;
@synthesize shadowOffset = _shadowOffset;
@synthesize shadowBlur = _shadowBlur;
@synthesize cornerRadius = _cornerRadius;
@synthesize customEffectsBlock = _customEffectsBlock;
@synthesize cacheKey = _cacheKey;
@synthesize originalImage = _originalImage;
@synthesize imageView = _imageView;
@synthesize imageContentURL = _imageContentURL;
@synthesize loading = _loading;
#pragma mark -
#pragma mark Shared storage
+ (NSOperationQueue *)processingQueue
{
static NSOperationQueue *sharedQueue = nil;
if (sharedQueue == nil)
{
sharedQueue = [[NSOperationQueue alloc] init];
[sharedQueue setMaxConcurrentOperationCount:4];
}
return sharedQueue;
}
+ (NSCache *)processedImageCache
{
static NSCache *sharedCache = nil;
if (sharedCache == nil)
{
sharedCache = [[NSCache alloc] init];
}
return sharedCache;
}
#pragma mark -
#pragma mark Setup
- (void)setUp
{
self.shadowColor = [UIColor blackColor];
_imageView = [[UIImageView alloc] initWithFrame:self.bounds];
_imageView.contentMode = UIViewContentModeCenter;
[self addSubview:_imageView];
_loading = [[UIActivityIndicatorView alloc]init];
_loading.frame = CGRectMake((_imageView.frame.size.width/2.0)-10.0, (_imageView.frame.size.height/2.0)-10.0, 20.0, 20.0);
[_loading setHidesWhenStopped:YES];
[_imageView addSubview:_loading];
[self setImage:super.image];
super.image = nil;
}
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
[self setUp];
}
return self;
}
- (id)initWithImage:(UIImage *)image
{
if ((self = [super initWithImage:image]))
{
[self setUp];
}
return self;
}
- (id)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage
{
if ((self = [super initWithImage:image highlightedImage:highlightedImage]))
{
[self setUp];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
{
[self setUp];
}
return self;
}
#if !__has_feature(objc_arc)
- (void)dealloc
{
[_customEffectsBlock release];
[_cacheKey release];
[_originalImage release];
[_shadowColor release];
[_imageView release];
[_imageContentURL release];
[_loading release];
[super dealloc];
}
#endif
#pragma mark -
#pragma mark Caching
- (NSString *)colorHash:(UIColor *)color
{
NSString *colorString = @"{0.00,0.00}";
if (color && ![color isEqual:[UIColor clearColor]])
{
NSInteger componentCount = CGColorGetNumberOfComponents(color.CGColor);
const CGFloat *components = CGColorGetComponents(color.CGColor);
NSMutableArray *parts = [NSMutableArray arrayWithCapacity:componentCount];
for (int i = 0; i < componentCount; i++)
{
[parts addObject:[NSString stringWithFormat:@"%.2f", components[i]]];
}
colorString = [NSString stringWithFormat:@"{%@}", [parts componentsJoinedByString:@","]];
}
return colorString;
}
- (NSString *)imageHash:(UIImage *)image
{
static NSInteger hashKey = 1;
NSString *number = objc_getAssociatedObject(image, @"FXImageHash");
if (!number && image)
{
number = [NSString stringWithFormat:@"%i", hashKey++];
objc_setAssociatedObject(image, @"FXImageHash", number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return number;
}
- (NSString *)cacheKey
{
if (_cacheKey) return _cacheKey;
return [NSString stringWithFormat:@"%@_%@_%.2f_%.2f_%.2f_%@_%@_%.2f_%.2f_%i",
_imageContentURL ?: [self imageHash:_originalImage],
NSStringFromCGSize(self.bounds.size),
_reflectionGap,
_reflectionScale,
_reflectionAlpha,
[self colorHash:_shadowColor],
NSStringFromCGSize(_shadowOffset),
_shadowBlur,
_cornerRadius,
self.contentMode];
}
- (void)cacheProcessedImage:(UIImage *)processedImage forKey:(NSString *)cacheKey
{
[[[self class] processedImageCache] setObject:processedImage forKey:cacheKey];
}
- (UIImage *)cachedProcessedImage
{
return [[[self class] processedImageCache] objectForKey:[self cacheKey]];
}
#pragma mark -
#pragma mark Processing
- (void)setProcessedImageOnMainThread:(NSArray *)array
{
//get images
NSString *cacheKey = [array objectAtIndex:1];
UIImage *processedImage = [array objectAtIndex:0];
processedImage = ([processedImage isKindOfClass:[NSNull class]])? nil: processedImage;
if (processedImage)
{
//cache image
[self cacheProcessedImage:processedImage forKey:cacheKey];
}
//set image
if ([[self cacheKey] isEqualToString:cacheKey])
{
//implement crossfade transition without needing to import QuartzCore
id animation = objc_msgSend(NSClassFromString(@"CATransition"), @selector(animation));
objc_msgSend(animation, @selector(setType:), @"kCATransitionFade");
objc_msgSend(self.layer, @selector(addAnimation:forKey:), animation, nil);
//set processed image
[self willChangeValueForKey:@"processedImage"];
_imageView.image = processedImage;
[self didChangeValueForKey:@"processedImage"];
}
}
- (void)processImage
{
//get properties
NSString *cacheKey = [self cacheKey];
UIImage *image = _originalImage;
NSURL *imageURL = _imageContentURL;
CGSize size = self.bounds.size;
CGFloat reflectionGap = _reflectionGap;
CGFloat reflectionScale = _reflectionScale;
CGFloat reflectionAlpha = _reflectionAlpha;
UIColor *shadowColor = _shadowColor;
CGSize shadowOffset = _shadowOffset;
CGFloat shadowBlur = _shadowBlur;
CGFloat cornerRadius = _cornerRadius;
UIImage *(^customEffectsBlock)(UIImage *image) = [_customEffectsBlock copy];
UIViewContentMode contentMode = self.contentMode;
#if !__has_feature(objc_arc)
[[image retain] autorelease];
[[imageURL retain] autorelease];
[[shadowColor retain] autorelease];
[customEffectsBlock autorelease];
#endif
//check cache
UIImage *processedImage = [self cachedProcessedImage];
if (!processedImage)
{
//load image
if (imageURL)
{
NSURLRequest *request = [NSURLRequest requestWithURL:imageURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30.0];
[_loading startAnimating];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error)
{
NSLog(@"Error loading image for URL: %@, %@", imageURL, error);
return;
}
else
{
image = [UIImage imageWithData:data];
[_loading stopAnimating];
if ([[[imageURL path] stringByDeletingPathExtension] hasSuffix:@"@2x"])
{
image = [UIImage imageWithCGImage:image.CGImage scale:2.0f orientation:image.imageOrientation];
}
}
}
if (image)
{
//crop and scale image
processedImage = [image imageCroppedAndScaledToSize:size
contentMode:contentMode
padToFit:NO];
//apply custom processing
if (customEffectsBlock)
{
processedImage = customEffectsBlock(processedImage);
}
//clip corners
if (cornerRadius)
{
processedImage = [processedImage imageWithCornerRadius:cornerRadius];
}
//apply shadow
if (shadowColor && ![shadowColor isEqual:[UIColor clearColor]] &&
(shadowBlur || !CGSizeEqualToSize(shadowOffset, CGSizeZero)))
{
reflectionGap -= 2.0f * (fabsf(shadowOffset.height) + shadowBlur);
processedImage = [processedImage imageWithShadowColor:shadowColor
offset:shadowOffset
blur:shadowBlur];
}
//apply reflection
if (reflectionScale && reflectionAlpha)
{
processedImage = [processedImage imageWithReflectionWithScale:reflectionScale
gap:reflectionGap
alpha:reflectionAlpha];
}
}
}
//cache and set image
if ([[NSThread currentThread] isMainThread])
{
if (processedImage)
{
[self cacheProcessedImage:processedImage forKey:cacheKey];
}
[self willChangeValueForKey:@"processedImage"];
_imageView.image = processedImage;
[self didChangeValueForKey:@"processedImage"];
}
else
{
[self performSelectorOnMainThread:@selector(setProcessedImageOnMainThread:)
withObject:[NSArray arrayWithObjects:
processedImage ?: [NSNull null],
cacheKey,
nil]
waitUntilDone:YES];
}
}
- (void)queueProcessingOperation:(FXImageOperation *)operation
{
//suspend operation queue
NSOperationQueue *queue = [[self class] processingQueue];
[queue setSuspended:YES];
//check for existing operations
for (FXImageOperation *op in queue.operations)
{
if ([op isKindOfClass:[FXImageOperation class]])
{
if (op.target == self && ![op isExecuting])
{
//already queued
[queue setSuspended:NO];
return;
}
}
}
//make op a dependency of all queued ops
NSInteger maxOperations = ([queue maxConcurrentOperationCount] > 0) ? [queue maxConcurrentOperationCount]: INT_MAX;
NSInteger index = [queue operationCount] - maxOperations;
if (index >= 0)
{
NSOperation *op = [[queue operations] objectAtIndex:index];
if (![op isExecuting])
{
[op addDependency:operation];
}
}
//add operation to queue
[queue addOperation:operation];
//resume queue
[queue setSuspended:NO];
}
- (void)queueImageForProcessing
{
//create processing operation
FXImageOperation *operation = [[FXImageOperation alloc] init];
operation.target = self;
//set operation thread priority
[operation setThreadPriority:1.0];
//queue operation
[self queueProcessingOperation:operation];
#if !__has_feature(objc_arc)
[operation release];
#endif
}
- (void)updateProcessedImage
{
id processedImage = [self cachedProcessedImage];
if (!processedImage && !_originalImage && !_imageContentURL)
{
processedImage = [NSNull null];
}
if (processedImage)
{
//use cached version
[self willChangeValueForKey:@"processedImage"];
_imageView.image = ([processedImage isKindOfClass:[NSNull class]])? nil: processedImage;
[self didChangeValueForKey:@"processedImage"];
}
else if (_asynchronous)
{
//process in background
[self queueImageForProcessing];
}
else
{
//process on main thread
[self processImage];
}
}
- (void)layoutSubviews
{
_imageView.frame = self.bounds;
if (_imageContentURL || self.image)
{
[self updateProcessedImage];
}
}
#pragma mark -
#pragma mark Setters and getters
- (UIImage *)processedImage
{
return _imageView.image;
}
- (void)setProcessedImage:(UIImage *)image
{
self.imageContentURL = nil;
[self willChangeValueForKey:@"image"];
self.originalImage = nil;
[self didChangeValueForKey:@"image"];
_imageView.image = image;
}
- (UIImage *)image
{
return _originalImage;
}
- (void)setImage:(UIImage *)image
{
if (_imageContentURL || ![image isEqual:_originalImage])
{
//update processed image
self.imageContentURL = nil;
self.originalImage = image;
[self updateProcessedImage];
}
}
- (void)setReflectionGap:(CGFloat)reflectionGap
{
if (_reflectionGap != reflectionGap)
{
_reflectionGap = reflectionGap;
[self setNeedsLayout];
}
}
- (void)setReflectionScale:(CGFloat)reflectionScale
{
if (_reflectionScale != reflectionScale)
{
_reflectionScale = reflectionScale;
[self setNeedsLayout];
}
}
- (void)setReflectionAlpha:(CGFloat)reflectionAlpha
{
if (_reflectionAlpha != reflectionAlpha)
{
_reflectionAlpha = reflectionAlpha;
[self setNeedsLayout];
}
}
- (void)setShadowColor:(UIColor *)shadowColor
{
if (![_shadowColor isEqual:shadowColor])
{
#if !__has_feature(objc_arc)
[_shadowColor release];
_shadowColor = [shadowColor retain];
#else
_shadowColor = shadowColor;
#endif
[self setNeedsLayout];
}
}
- (void)setShadowOffset:(CGSize)shadowOffset
{
if (!CGSizeEqualToSize(_shadowOffset, shadowOffset))
{
_shadowOffset = shadowOffset;
[self setNeedsLayout];
}
}
- (void)setShadowBlur:(CGFloat)shadowBlur
{
if (_shadowBlur != shadowBlur)
{
_shadowBlur = shadowBlur;
[self setNeedsLayout];
}
}
- (void)setContentMode:(UIViewContentMode)contentMode
{
if (self.contentMode != contentMode)
{
super.contentMode = contentMode;
[self setNeedsLayout];
}
}
- (void)setCustomEffectsBlock:(UIImage *(^)(UIImage *))customEffectsBlock
{
if (![customEffectsBlock isEqual:_customEffectsBlock])
{
_customEffectsBlock = [customEffectsBlock copy];
[self setNeedsLayout];
}
}
- (void)setCacheKey:(NSString *)cacheKey
{
if (![cacheKey isEqual:_cacheKey])
{
_cacheKey = [cacheKey copy];
[self setNeedsLayout];
}
}
#pragma mark -
#pragma mark loading
- (void)setImageWithContentsOfFile:(NSString *)file
{
if ([[file pathExtension] length] == 0)
{
file = [file stringByAppendingPathExtension:@"png"];
}
if (![file isAbsolutePath])
{
file = [[NSBundle mainBundle] pathForResource:file ofType:nil];
}
if ([UIScreen mainScreen].scale == 2.0f)
{
NSString *temp = [[[file stringByDeletingPathExtension] stringByAppendingString:@"@2x"] stringByAppendingPathExtension:[file pathExtension]];
if ([[NSFileManager defaultManager] fileExistsAtPath:temp])
{
file = temp;
}
}
[self setImageWithContentsOfURL:[NSURL fileURLWithPath:file]];
}
- (void)setImageWithContentsOfURL:(NSURL *)URL
{
if (![URL isEqual:_imageContentURL])
{
//update processed image
[self willChangeValueForKey:@"image"];
self.originalImage = nil;
[self didChangeValueForKey:@"image"];
self.imageContentURL = URL;
[self updateProcessedImage];
}
}
@end
Step 2 : Create two files named as "UIImage+NP.h" and "UIImage+NP.m" for generating UIImage category.
#import <UIKit/UIKit.h>
@interface UIImage (NP)
- (UIImage *)imageCroppedToRect:(CGRect)rect;
- (UIImage *)imageScaledToSize:(CGSize)size;
- (UIImage *)imageScaledToFitSize:(CGSize)size;
- (UIImage *)imageScaledToFillSize:(CGSize)size;
- (UIImage *)imageCroppedAndScaledToSize:(CGSize)size
contentMode:(UIViewContentMode)contentMode
padToFit:(BOOL)padToFit;
- (UIImage *)reflectedImageWithScale:(CGFloat)scale;
- (UIImage *)imageWithReflectionWithScale:(CGFloat)scale gap:(CGFloat)gap alpha:(CGFloat)alpha;
- (UIImage *)imageWithShadowColor:(UIColor *)color offset:(CGSize)offset blur:(CGFloat)blur;
- (UIImage *)imageWithCornerRadius:(CGFloat)radius;
- (UIImage *)imageWithAlpha:(CGFloat)alpha;
- (UIImage *)imageWithMask:(UIImage *)maskImage;
- (UIImage *)maskImageFromImageAlpha;
@end
#import "UIImage+NP.h"
@implementation UIImage (NP)
- (UIImage *)imageCroppedToRect:(CGRect)rect
{
//create drawing context
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0f);
//draw
[self drawAtPoint:CGPointMake(-rect.origin.x, -rect.origin.y)];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageScaledToSize:(CGSize)size
{
//avoid redundant drawing
if (CGSizeEqualToSize(self.size, size))
{
return self;
}
//create drawing context
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
//draw
[self drawInRect:CGRectMake(0.0f, 0.0f, size.width, size.height)];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageScaledToFitSize:(CGSize)size
{
//calculate rect
CGFloat aspect = self.size.width / self.size.height;
if (size.width / aspect <= size.height)
{
return [self imageScaledToSize:CGSizeMake(size.width, size.width / aspect)];
}
else
{
return [self imageScaledToSize:CGSizeMake(size.height * aspect, size.height)];
}
}
- (UIImage *)imageScaledToFillSize:(CGSize)size
{
if (CGSizeEqualToSize(self.size, size))
{
return self;
}
//calculate rect
CGFloat aspect = self.size.width / self.size.height;
if (size.width / aspect >= size.height)
{
return [self imageScaledToSize:CGSizeMake(size.width, size.width / aspect)];
}
else
{
return [self imageScaledToSize:CGSizeMake(size.height * aspect, size.height)];
}
}
- (UIImage *)imageCroppedAndScaledToSize:(CGSize)size
contentMode:(UIViewContentMode)contentMode
padToFit:(BOOL)padToFit;
{
//calculate rect
CGRect rect = CGRectZero;
switch (contentMode)
{
case UIViewContentModeScaleAspectFit:
{
CGFloat aspect = self.size.width / self.size.height;
if (size.width / aspect <= size.height)
{
rect = CGRectMake(0.0f, (size.height - size.width / aspect) / 2.0f, size.width, size.width / aspect);
}
else
{
rect = CGRectMake((size.width - size.height * aspect) / 2.0f, 0.0f, size.height * aspect, size.height);
}
break;
}
case UIViewContentModeScaleAspectFill:
{
CGFloat aspect = self.size.width / self.size.height;
if (size.width / aspect >= size.height)
{
rect = CGRectMake(0.0f, (size.height - size.width / aspect) / 2.0f, size.width, size.width / aspect);
}
else
{
rect = CGRectMake((size.width - size.height * aspect) / 2.0f, 0.0f, size.height * aspect, size.height);
}
break;
}
case UIViewContentModeCenter:
{
rect = CGRectMake((size.width - self.size.width) / 2.0f, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeTop:
{
rect = CGRectMake((size.width - self.size.width) / 2.0f, 0.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeBottom:
{
rect = CGRectMake((size.width - self.size.width) / 2.0f, size.height - self.size.height, self.size.width, self.size.height);
break;
}
case UIViewContentModeLeft:
{
rect = CGRectMake(0.0f, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeRight:
{
rect = CGRectMake(size.width - self.size.width, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeTopLeft:
{
rect = CGRectMake(0.0f, 0.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeTopRight:
{
rect = CGRectMake(size.width - self.size.width, 0.0f, self.size.width, self.size.height);
break;
}
case UIViewContentModeBottomLeft:
{
rect = CGRectMake(0.0f, size.height - self.size.height, self.size.width, self.size.height);
break;
}
case UIViewContentModeBottomRight:
{
rect = CGRectMake(size.width - self.size.width, size.height - self.size.height, self.size.width, self.size.height);
break;
}
default:
{
rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
break;
}
}
if (!padToFit)
{
//remove padding
if (rect.size.width < size.width)
{
size.width = rect.size.width;
rect.origin.x = 0.0f;
}
if (rect.size.height < size.height)
{
size.height = rect.size.height;
rect.origin.y = 0.0f;
}
}
//avoid redundant drawing
if (CGSizeEqualToSize(self.size, size))
{
return self;
}
//create drawing context
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
//draw
[self drawInRect:rect];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
+ (CGImageRef)gradientMask
{
static CGImageRef sharedMask = NULL;
if (sharedMask == NULL)
{
//create gradient mask
UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, 256), YES, 0.0);
CGContextRef gradientContext = UIGraphicsGetCurrentContext();
CGFloat colors[] = {0.0, 1.0, 1.0, 1.0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
CGPoint gradientStartPoint = CGPointMake(0, 0);
CGPoint gradientEndPoint = CGPointMake(0, 256);
CGContextDrawLinearGradient(gradientContext, gradient, gradientStartPoint,
gradientEndPoint, kCGGradientDrawsAfterEndLocation);
sharedMask = CGBitmapContextCreateImage(gradientContext);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
UIGraphicsEndImageContext();
}
return sharedMask;
}
- (UIImage *)reflectedImageWithScale:(CGFloat)scale
{
//get reflection dimensions
CGFloat height = ceil(self.size.height * scale);
CGSize size = CGSizeMake(self.size.width, height);
CGRect bounds = CGRectMake(0.0f, 0.0f, size.width, size.height);
//create drawing context
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
//clip to gradient
CGContextClipToMask(context, bounds, [[self class] gradientMask]);
//draw reflected image
CGContextScaleCTM(context, 1.0f, -1.0f);
CGContextTranslateCTM(context, 0.0f, -self.size.height);
[self drawInRect:CGRectMake(0.0f, 0.0f, self.size.width, self.size.height)];
//capture resultant image
UIImage *reflection = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return reflection image
return reflection;
}
- (UIImage *)imageWithReflectionWithScale:(CGFloat)scale gap:(CGFloat)gap alpha:(CGFloat)alpha
{
//get reflected image
UIImage *reflection = [self reflectedImageWithScale:scale];
CGFloat reflectionOffset = reflection.size.height + gap;
//create drawing context
UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.size.width, self.size.height + reflectionOffset * 2.0f), NO, 0.0f);
//draw reflection
[reflection drawAtPoint:CGPointMake(0.0f, reflectionOffset + self.size.height + gap) blendMode:kCGBlendModeNormal alpha:alpha];
//draw image
[self drawAtPoint:CGPointMake(0.0f, reflectionOffset)];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageWithShadowColor:(UIColor *)color offset:(CGSize)offset blur:(CGFloat)blur
{
//get size
CGSize border = CGSizeMake(fabsf(offset.width) + blur, fabsf(offset.height) + blur);
CGSize size = CGSizeMake(self.size.width + border.width * 2.0f, self.size.height + border.height * 2.0f);
//create drawing context
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
//set up shadow
CGContextSetShadowWithColor(context, offset, blur, color.CGColor);
//draw with shadow
[self drawAtPoint:CGPointMake(border.width, border.height)];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageWithCornerRadius:(CGFloat)radius
{
//create drawing context
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
//clip image
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0.0f, radius);
CGContextAddLineToPoint(context, 0.0f, self.size.height - radius);
CGContextAddArc(context, radius, self.size.height - radius, radius, M_PI, M_PI / 2.0f, 1);
CGContextAddLineToPoint(context, self.size.width - radius, self.size.height);
CGContextAddArc(context, self.size.width - radius, self.size.height - radius, radius, M_PI / 2.0f, 0.0f, 1);
CGContextAddLineToPoint(context, self.size.width, radius);
CGContextAddArc(context, self.size.width - radius, radius, radius, 0.0f, -M_PI / 2.0f, 1);
CGContextAddLineToPoint(context, radius, 0.0f);
CGContextAddArc(context, radius, radius, radius, -M_PI / 2.0f, M_PI, 1);
CGContextClip(context);
//draw image
[self drawAtPoint:CGPointZero];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageWithAlpha:(CGFloat)alpha
{
//create drawing context
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
//draw with alpha
[self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)imageWithMask:(UIImage *)maskImage;
{
//create drawing context
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
//apply mask
CGContextClipToMask(context, CGRectMake(0.0f, 0.0f, self.size.width, self.size.height), maskImage.CGImage);
//draw image
[self drawAtPoint:CGPointZero];
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return image
return image;
}
- (UIImage *)maskImageFromImageAlpha
{
//get dimensions
NSInteger width = CGImageGetWidth(self.CGImage);
NSInteger height = CGImageGetHeight(self.CGImage);
//create alpha image
NSInteger bytesPerRow = ((width + 3) / 4) * 4;
void *data = calloc(bytesPerRow * height, sizeof(unsigned char *));
CGContextRef context = CGBitmapContextCreate(data, width, height, 8, bytesPerRow, NULL, kCGImageAlphaOnly);
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), self.CGImage);
//invert alpha pixels
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
NSInteger index = y * bytesPerRow + x;
((unsigned char *)data)[index] = 255 - ((unsigned char *)data)[index];
}
}
//create mask image
CGImageRef maskRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
UIImage *mask = [UIImage imageWithCGImage:maskRef];
CGImageRelease(maskRef);
free(data);
//return image
return mask;
}
@end
Step 3 : Now you can use LazyImage view with shadow image by just puting below code into your class file.
FXImageView *imageView = [[[FXImageView alloc] initWithFrame:CGRectMake(0, 0, BUTTON_WIDTH, BUTTON_HEIGHT)] autorelease];
imageView.contentMode = UIViewContentModeScaleToFill;
imageView.asynchronous = YES;
imageView.reflectionScale = 0.5f;
imageView.reflectionAlpha = 0.0f;
imageView.reflectionGap = 10.0f;
imageView.shadowOffset = CGSizeMake(0.0f, 2.0f);
imageView.shadowBlur = 5.0f;
imageView.cornerRadius = 10.0f;
//set image
[((FXImageView *)view) setImageWithContentsOfURL:[NSURL URLWithString:@"ImageUrlPath"]];
Enjoy and implement the code.. !!!!!
Regards,
Nilesh M. Prajapati
-->
No comments:
Post a Comment