donohoe
donohoe

Reputation: 14123

How to determine the size of an image without downloading it (in full)?

I'm looking to get the dimensions, width and height, of a remotely hosted JPG. I have seen how it is possible to do this by downloading the full image.

However, it would be ideal if I could do this by downloading only enough to just get this information.

Typical images are 200K in size and reading in just a few K might at the beginning might be enough for JPGs:

curl_setopt($ch, CURLOPT_RANGE, "0-4096");

For reference, I've followed these answers/comments but to no avail (though they might be on the right track):

Has anyone been able to put the pieces together (withor without ImageMagick)?

Upvotes: 14

Views: 6421

Answers (4)

Mark Setchell
Mark Setchell

Reputation: 207405

How about using ImageMagick's ping functionality like this:

identify -ping -format "%wx%h" http://www.google.com/logos/giroux1.jpg
482x142

Upvotes: 7

afessler
afessler

Reputation: 1374

An improved version of donohoe's answer above. This one retrieves smaller byte ranges for png and gif files as described here.

function remoteImage($url){

    $filename = parse_url($url);
    $pi = pathinfo($filename['path'],PATHINFO_EXTENSION);

    switch ($pi) {
    case "jpg" :
        $range = "0-15000";
        break;
    case "jpeg" :
        $range = "0-10000";
        break;
    case "png":
        $range = "0-100";
        break;
    case "gif":
        $range = "0-10";
        break;
    default:
        $range = "0-15000";
        break;
    }

    $ch = curl_init ($url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
    curl_setopt($ch, CURLOPT_RANGE, $range);

    $fn = "partial2.png";
    $raw = curl_exec($ch);
    $result = array();

    if(file_exists($fn)){
        unlink($fn);
    }

    if ($raw !== false) {

        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if ($status == 200 || $status == 206) {

            $result["w"] = 0;
            $result["h"] = 0;

            $fp = fopen($fn, 'x');
            fwrite($fp, $raw);
            fclose($fp);

            $size = getImageSize($fn);

            if ($size===false) {
                //  Cannot get file size information
            } else {
                //  Return width and height
                list($result["w"], $result["h"]) = $size;

            }

        }
    }

    curl_close ($ch);
    return $result;
}

Upvotes: 4

donohoe
donohoe

Reputation: 14123

I managed to answer my own question and I've included the PHP code snippet.

The only downside (for me at least) is that this writes the partial image download to the file-system prior to reading in the dimensions with getImageSize.

For me 10240 bytes is the safe limit to check for jpg images that were 200 to 400K in size.

function remoteImage($url){
    $ch = curl_init ($url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
    curl_setopt($ch, CURLOPT_RANGE, "0-10240");

    $fn = "partial.jpg";
    $raw = curl_exec($ch);
    $result = array();

    if(file_exists($fn)){
        unlink($fn);
    }

    if ($raw !== false) {

        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if ($status == 200 || $status == 206) {

            $result["w"] = 0;
            $result["h"] = 0;

            $fp = fopen($fn, 'x');
            fwrite($fp, $raw);
            fclose($fp);

            $size = getImageSize($fn);

            if ($size===false) {
            //  Cannot get file size information
            } else {
            //  Return width and height
                list($result["w"], $result["h"]) = $size;
            }

        }
    }

    curl_close ($ch);
    return $result;
}

Upvotes: 3

krtek
krtek

Reputation: 26597

According to Getting Image size of JPEG from its binary, the size of the image isn't stored in a precise location in the file. Depending on the extension, you can have a whole bunch of data in the file before the actual size, a thumbmail for example.

The following C++ code should be a good start for your own PHP implementation : http://www.64lines.com/jpeg-width-height. You can easily adapt this code by accessing the string containing your data like an array : myString{$i} instead of data[i]

You should load a relatively large chunk of data and parse it, then load more if necessary. Or you can load the file block by block, but the overhead caused by the numerous connections defeat the purpose of not loading the entire file.

Anyhow, I'm not sure the benefits will justify the time you spend on this. 200k is nothing nowadays.

Upvotes: 5

Related Questions