我正在使用Dropbox Core API,並且在我正在尋找獲取圖像文件尺寸的方法時卡住了。我在設備上檢索縮略圖,但我需要知道圖像的寬度和高度以處理它們的修改。通過文件URL遠程獲取圖像文件尺寸
我絕對不想在手機上下載整個文件來檢查其尺寸。是否有任何想法獲得它們的技巧?我在元數據中唯一的東西是文件大小,在我的情況下這是無用的。
非常感謝。
我正在使用Dropbox Core API,並且在我正在尋找獲取圖像文件尺寸的方法時卡住了。我在設備上檢索縮略圖,但我需要知道圖像的寬度和高度以處理它們的修改。通過文件URL遠程獲取圖像文件尺寸
我絕對不想在手機上下載整個文件來檢查其尺寸。是否有任何想法獲得它們的技巧?我在元數據中唯一的東西是文件大小,在我的情況下這是無用的。
非常感謝。
我想出了我的答案。我使用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
我希望它也能幫助你。
因此,您檢索圖像URL並將其傳遞到此類別,然後該類別將獲取圖像大小。很酷的人,很好的執行。你可以在GitHub上發佈它。 – satheeshwaran
棘手的問題,但我想除了下載圖像和計算自己的大小,沒有其他方式。 – satheeshwaran
@satheeshwaran如果您對解決方案感興趣,請檢查答案,避免下載整個文件。可能會有用。不管怎麼說,還是要謝謝你。 – BoilingLime