// // UIImage+RemoteSize.m // iOS-Categories (https://github.com/shaojiankui/iOS-Categories) // // Created by Jakey on 15/1/27. // Copyright (c) 2015年 www.skyfox.org. All rights reserved. // #import "UIImage+RemoteSize.h" #import static char *kSizeRequestDataKey = "NSURL.sizeRequestData"; static char *kSizeRequestTypeKey = "NSURL.sizeRequestType"; static char *kSizeRequestCompletionKey = "NSURL.sizeRequestCompletion"; typedef uint32_t dword; @interface NSURL (RemoteSize) @property (nonatomic, strong) NSMutableData* sizeRequestData; @property (nonatomic, strong) NSString* sizeRequestType; @property (nonatomic, copy) UIImageSizeRequestCompleted sizeRequestCompletion; @end @implementation NSURL (RemoteSize) - (void)setSizeRequestCompletion: (UIImageSizeRequestCompleted) block { objc_setAssociatedObject(self, &kSizeRequestCompletionKey, block, OBJC_ASSOCIATION_COPY); } - (UIImageSizeRequestCompleted)sizeRequestCompletion { return objc_getAssociatedObject(self, &kSizeRequestCompletionKey); } - (void)setSizeRequestData:(NSMutableData *)sizeRequestData { objc_setAssociatedObject(self, &kSizeRequestDataKey, sizeRequestData, OBJC_ASSOCIATION_RETAIN); } - (NSMutableData*)sizeRequestData { return objc_getAssociatedObject(self, &kSizeRequestDataKey); } - (void)setSizeRequestType:(NSString *)sizeRequestType { objc_setAssociatedObject(self, &kSizeRequestTypeKey, sizeRequestType, OBJC_ASSOCIATION_RETAIN); } - (NSString*)sizeRequestType { return objc_getAssociatedObject(self, &kSizeRequestTypeKey); } #pragma mark - NSURLConnectionDelegate - (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response { [self.sizeRequestData setLength: 0]; //Redirected => reset data } - (void)connection:(NSURLConnection*)connection didReceiveData:(NSData *)data { NSMutableData* receivedData = self.sizeRequestData; if( !receivedData ) { receivedData = [NSMutableData data]; self.sizeRequestData = receivedData; } [receivedData appendData: data]; //Parse metadata const unsigned char* cString = [receivedData bytes]; const NSInteger length = [receivedData length]; const char pngSignature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; const char bmpSignature[2] = {66, 77}; const char gifSignature[2] = {71, 73}; const char jpgSignature[2] = {255, 216}; if(!self.sizeRequestType ) { if( memcmp(pngSignature, cString, 8) == 0 ) { self.sizeRequestType = @"PNG"; } else if( memcmp(bmpSignature, cString, 2) == 0 ) { self.sizeRequestType = @"BMP"; } else if( memcmp(jpgSignature, cString, 2) == 0 ) { self.sizeRequestType = @"JPG"; } else if( memcmp(gifSignature, cString, 2) == 0 ) { self.sizeRequestType = @"GIF"; } } if( [self.sizeRequestType isEqualToString: @"PNG"] ) { char type[5]; int offset = 8; dword chunkSize = 0; int chunkSizeSize = sizeof(chunkSize); if( offset+chunkSizeSize > length ) return; memcpy(&chunkSize, cString+offset, chunkSizeSize); chunkSize = OSSwapInt32(chunkSize); offset += chunkSizeSize; if( offset + chunkSize > length ) return; memcpy(&type, cString+offset, 4); type[4]='\0'; offset += 4; if( strcmp(type, "IHDR") == 0 ) { //Should always be first dword width = 0, height = 0; memcpy(&width, cString+offset, 4); offset += 4; width = OSSwapInt32(width); memcpy(&height, cString+offset, 4); offset += 4; height = OSSwapInt32(height); if( self.sizeRequestCompletion ) { self.sizeRequestCompletion(self, CGSizeMake(width, height)); } self.sizeRequestCompletion = nil; [connection cancel]; } } else if( [self.sizeRequestType isEqualToString: @"BMP"] ) { int offset = 18; dword width = 0, height = 0; memcpy(&width, cString+offset, 4); offset += 4; memcpy(&height, cString+offset, 4); offset += 4; if( self.sizeRequestCompletion ) { self.sizeRequestCompletion(self, CGSizeMake(width, height)); } self.sizeRequestCompletion = nil; [connection cancel]; } else if( [self.sizeRequestType isEqualToString: @"JPG"] ) { int offset = 4; dword block_length = cString[offset]*256 + cString[offset+1]; while (offset= length ) break; if( cString[offset] != 0xFF ) break; if( cString[offset+1] == 0xC0 || cString[offset+1] == 0xC1 || cString[offset+1] == 0xC2 || cString[offset+1] == 0xC3 || cString[offset+1] == 0xC5 || cString[offset+1] == 0xC6 || cString[offset+1] == 0xC7 || cString[offset+1] == 0xC9 || cString[offset+1] == 0xCA || cString[offset+1] == 0xCB || cString[offset+1] == 0xCD || cString[offset+1] == 0xCE || cString[offset+1] == 0xCF ) { dword width = 0, height = 0; height = cString[offset+5]*256 + cString[offset+6]; width = cString[offset+7]*256 + cString[offset+8]; if( self.sizeRequestCompletion ) { self.sizeRequestCompletion(self, CGSizeMake(width, height)); } self.sizeRequestCompletion = nil; [connection cancel]; } else { offset += 2; block_length = cString[offset]*256 + cString[offset+1]; } } } else if( [self.sizeRequestType isEqualToString: @"GIF"] ) { int offset = 6; dword width = 0, height = 0; memcpy(&width, cString+offset, 2); offset += 2; memcpy(&height, cString+offset, 2); offset += 2; if( self.sizeRequestCompletion ) { self.sizeRequestCompletion(self, CGSizeMake(width, height)); } self.sizeRequestCompletion = nil; [connection cancel]; } } -(void)connection:(NSURLConnection*)connection didFailWithError:(NSError *)error { if( self.sizeRequestCompletion ) self.sizeRequestCompletion(self, CGSizeZero); } -(NSCachedURLResponse*)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { return cachedResponse; } - (void)connectionDidFinishLoading: (NSURLConnection *)connection { // Basically, we failed to obtain the image size using metadata and the // entire image was downloaded... if(!self.sizeRequestData.length) { self.sizeRequestData = nil; } else { //Try parse to UIImage UIImage* image = [UIImage imageWithData: self.sizeRequestData]; if( self.sizeRequestCompletion && image) { self.sizeRequestCompletion(self, [image size]); return; } } self.sizeRequestCompletion(self, CGSizeZero); } @end @implementation UIImage (RemoteSize) + (void)requestSizeNoHeader:(NSURL*)imgURL completion:(UIImageSizeRequestCompleted)completion{ if([imgURL isFileURL] ) { //Load from file stream } else { imgURL.sizeRequestCompletion = completion; NSURLRequest* request = [NSURLRequest requestWithURL:imgURL]; NSURLConnection* conn = [NSURLConnection connectionWithRequest: request delegate: imgURL]; [conn scheduleInRunLoop: [NSRunLoop mainRunLoop] forMode: NSDefaultRunLoopMode]; [conn start]; } } + (void)requestSizeWithHeader:(NSURL*)imgURL completion:(UIImageSizeRequestCompleted)completion{ // NSURLRequest* request = [NSURLRequest requestWithURL:imgURL]; // // [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *resp, NSData *d, NSError *e) { // NSLog(@"respone%@", [(NSHTTPURLResponse*)resp allHeaderFields]); // // // }]; } @end