summaryrefslogtreecommitdiffstats
path: root/Classes/AsyncImageView.m
diff options
context:
space:
mode:
Diffstat (limited to 'Classes/AsyncImageView.m')
-rw-r--r--Classes/AsyncImageView.m144
1 files changed, 144 insertions, 0 deletions
diff --git a/Classes/AsyncImageView.m b/Classes/AsyncImageView.m
new file mode 100644
index 0000000..d978e82
--- /dev/null
+++ b/Classes/AsyncImageView.m
@@ -0,0 +1,144 @@
+//
+// 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