14

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)?

Community
  • 1
  • 1
donohoe
  • 13,867
  • 4
  • 37
  • 59
  • What have you tried? What is your understanding of the JPEG file format? See what you can piece together from http://en.wikipedia.org/wiki/Exchangeable_image_file_format#Example – tripleee Sep 17 '11 at 07:01
  • I tried reading in the first 4096 bytes and failed to find away to run Imagemagick 'identify' or 'grep -n $\xc0' against it (see referenced questions/comments). – donohoe Sep 19 '11 at 03:46

4 Answers4

7

How about using ImageMagick's ping functionality like this:

identify -ping -format "%wx%h" http://www.google.com/logos/giroux1.jpg
482x142
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • Wow, never even knew about `-ping`! Testing shows it is only slightly faster, but saves the step of downloading a temporary file. – bigjosh Mar 19 '16 at 15:58
5

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.

Community
  • 1
  • 1
krtek
  • 26,334
  • 5
  • 56
  • 84
  • I'll check, but might be too much for me. 200K isn't a lot, true - but it would run up to be aprox 500+mb a day though my current approach to download them all in full. – donohoe Sep 19 '11 at 03:47
4

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;
}
afessler
  • 1,374
  • 1
  • 10
  • 8
3

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;
}
donohoe
  • 13,867
  • 4
  • 37
  • 59