2014-05-12 423 views
3

我正在使用Dropbox Core API,並且在我正在尋找獲取圖像文件尺寸的方法時卡住了。我在設備上檢索縮略圖,但我需要知道圖像的寬度和高度以處理它們的修改。通過文件URL遠程獲取圖像文件尺寸

我絕對不想在手機上下載整個文件來檢查其尺寸。是否有任何想法獲得它們的技巧?我在元數據中唯一的東西是文件大小,在我的情況下這是無用的。

非常感謝。

+0

棘手的問題,但我想除了下載圖像和計算自己的大小,沒有其他方式。 – satheeshwaran

+0

@satheeshwaran如果您對解決方案感興趣,請檢查答案,避免下載整個文件。可能會有用。不管怎麼說,還是要謝謝你。 – BoilingLime

回答

3

我想出了我的答案。我使用UIImage類別,而不是通過URL下載文件的一部分。一旦它獲得足夠的數據來定義大小,就會停止下載。

我做了一些測試,它下載大約30 kB來獲取圖片的尺寸,無論文件大小爲300 kB還是10 MB大,這真的很快。

它可以用於任何圖像文件,而不僅僅是Dropbox API。

這裏是該類別的標題:

#import <UIKit/UIKit.h> 

typedef void (^UIImageSizeRequestCompleted) (NSURL* imgURL, CGSize size); 

@interface UIImage (RemoteSize) 

+ (void) requestSizeFor: (NSURL*) imgURL completion: (UIImageSizeRequestCompleted) completion; 

@end 

這裏是源文件:

#import "UIImage+RemoteSize.h" 
#import <objc/runtime.h>` 

#import <objc/runtime.h> 

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) { 
     offset += block_length; 

     if(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) requestSizeFor: (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]; 
} 
} 

@end 

非常感謝這個帖子裏面我有很大幫助: Remote image size without downloading

我希望它也能幫助你。

+0

因此,您檢索圖像URL並將其傳遞到此類別,然後該類別將獲取圖像大小。很酷的人,很好的執行。你可以在GitHub上發佈它。 – satheeshwaran