// // AsyncImageView.m // Postcard // // Created by markj on 2/18/09. // Copyright 2009 Mark Johnson. You have permission to copy parts of this code into your own projects for any use. // www.markj.net // #import "AsyncImageView.h" @interface UIImage (Extras) - (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize; @end @implementation UIImage (Extras) #pragma mark - #pragma mark Scale and crop image - (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; } @end // This class demonstrates how the URL loading system can be used to make a UIView subclass // that can download and display an image asynchronously so that the app doesn't block or freeze // while the image is downloading. It works fine in a UITableView or other cases where there // are multiple images being downloaded and displayed all at the same time. @implementation AsyncImageView - (void)dealloc { [connection cancel]; //in case the URL is still downloading [connection release]; [data release]; [super dealloc]; } - (void)loadImageFromURL:(NSURL*)url { NSLog(@"%@",url); if (connection!=nil) { [connection release]; } //in case we are downloading a 2nd image if (data!=nil) { [data release]; } NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; //notice how delegate set to self object //TODO error handling, what if connection is nil? } //the URL connection calls this repeatedly as data arrives - (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData { if (data==nil) { data = [[NSMutableData alloc] initWithCapacity:2048]; } [data appendData:incrementalData]; } //the URL connection calls this once all the data has downloaded - (void)connectionDidFinishLoading:(NSURLConnection*)theConnection { //so self data now has the complete image [connection release]; connection=nil; if ([[self subviews] count]>0) { //then this must be another image, the old one is still in subviews [[[self subviews] objectAtIndex:0] removeFromSuperview]; //so remove it (releases it also) } //make an image view for the image UIImageView* imageView = [[[UIImageView alloc] initWithImage:[[UIImage imageWithData:data] imageByScalingAndCroppingForSize:CGSizeMake(100,100)]] autorelease]; //make sizing choices based on your needs, experiment with these. maybe not all the calls below are needed. imageView.contentMode = UIViewContentModeScaleAspectFill; imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth || UIViewAutoresizingFlexibleHeight ); [self addSubview:imageView]; imageView.frame = self.bounds; [imageView setNeedsLayout]; [self setNeedsLayout]; [data release]; //don't need this any more, its in the UIImageView now data=nil; } //just in case you want to get the image directly, here it is in subviews - (UIImage*) image { UIImageView* iv = [[self subviews] objectAtIndex:0]; return [iv image]; } @end