Fast Way to Get Remote Image Dimensions

Fast way to get remote image dimensions

I think this gem does what you want https://github.com/sdsykes/fastimage

FastImage finds the size or type of an
image given its uri by fetching as
little as needed

Get width height of remote image from url


Get image size with jQuery

function getMeta(url) {
$("<img/>",{
load: function() {
alert( this.width +" "+ this.height );
},
src: url
});
}

Get image size with JavaScript

function getMeta(url) {   
var img = new Image();
img.onload = function() {
alert( this.width +" "+ this.height );
};
img.src = url;
}

Get image size with JavaScript (modern browsers, IE9+ )

function getMeta(url){   
const img = new Image();
img.addEventListener("load", function() {
alert( this.naturalWidth +' '+ this.naturalHeight );
});
img.src = url;
}

Use like: getMeta( "http://example.com/img.jpg" );

https://developer.mozilla.org/en/docs/Web/API/HTMLImageElement

Get remote image dimensions

If you don't want to check the properties of the image by loading it first you can do it with javascript:

<img src="image.jpg" onload="if( this.width > 200 ) this.width = 200;">

Get the width and height of an image without downloading it

You will most likely not be able to do so without actually downloading the image (as in using the bandwidth).

That being said, you can use the FastImage gem to do this for you.

require 'fastimage'

FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
=> [266, 56] # width, height

Super fast getimagesize in php


function ranger($url){
$headers = array(
"Range: bytes=0-32768"
);

$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($curl);
curl_close($curl);
return $data;
}

$start = microtime(true);

$url = "http://news.softpedia.com/images/news2/Debian-Turns-15-2.jpeg";

$raw = ranger($url);
$im = imagecreatefromstring($raw);

$width = imagesx($im);
$height = imagesy($im);

$stop = round(microtime(true) - $start, 5);

echo $width." x ".$height." ({$stop}s)";

test...

640 x 480 (0.20859s)

Loading 32kb of data worked for me.

Get images files dimensions remotely through file URL

I figured out my answer. I use an UIImage Category than download part of the file through an URL. Once it get enough data to define the size it stops the download.

I did some tests and it downloads approximately 30 kB to get the picture's dimensions, whatever if the file 300 kB or 10 MB big, which is really fast.

It could be used for any image file, not only Dropbox API.

Here is the header of the Category :

#import <UIKit/UIKit.h>

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

@interface UIImage (RemoteSize)

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

@end

And here are the source file :

#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

Thanks a lot to this post which help me a lot :
Remote image size without downloading

I hope it will help you too.



Related Topics



Leave a reply



Submit