我正在使用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