views:

333

answers:

4

On my PHP application, I allow users to upload images.

I then process the images to resize it to a manageable size.

Within my PHP script, I run the following UNIX command (ImageMagick):

convert -size 320x240

This limits/constrains the height/width to be no larger than 320 by 240.

However, I don't know actually what size "convert" resizes the image to.

ImageMagick might make the image: 320x100 or maybe 215x240 ... I just don't know because it's simply contraining the image to be no larger than 320x240 proportionally.

Is there an easy way for me to determine what size "convert" is resizing my images too?

By the way, I've looked into the PHP 'getimagesize' command but that is a very inefficient way to determine the image dimensions given that it needs to download the ENTIRE image even though the dimensions is stored in the few few bytes of the header.

Ideally, it would be great if 'convert' can return the image dimensions after it resizes the images though I'm not certain that can be done.

Thanks in advance

+3  A: 

I think you do what getimagesize, you can reference local files so it doesn't involve an HTTP fetch, if that is what you were worried about (I'm not really sure what you meant by "re-download the image").

Dominic Rodger
If you read the PHP manual, us3.php.net/getimagesize, 'getimagesize' redownloads the entire image regardless of where it's stored. This is inefficient because the image dimenions are stored in the first few bytes of the image file header
HankT
That's not part of the manual, that's a comment on the manual entry. How do you know it is authoritative? Have you actually experienced any performance problems with using `getimagesize`?
Dominic Rodger
The comment is talking about working with large, remote files. If you give this function a URL, PHP will download the entire file behind the scenes, and that can be slow. When working with local files, this doesn't matter.
gnud
@gnud - indeed. But the OP must have a local copy of the file, because he's called convert on it, the output of which is presumably local (and small, the question was talking about images of size 340px x 215px, which hardly constitute large files.
Dominic Rodger
+1  A: 

If you call convert anyway, then just call identify.

Example output:

$ identify images/someimage.jpg
images/someimage.jpg JPEG 421x280 421x280+0+0 8-bit DirectClass 16.9kb
gnud
Sounds very interesting. If I'm calling 'convert' from within a PHP application, how can I pass the result set from 'identify' back to PHP?
HankT
When you use `system` to invoke a command, `system` returns the output string.
gnud
You can format the output using -format. e.g. identify -format "%[fx:w]x%[fx:h]" will give you "421x280" only.
Dan Midwood
Just for the record: I would use `getimagesize()`, so I don't depend on ImageMagick. But, if you use it anyway...
gnud
A: 

From the very page you referenced:

<?php
// Retrieve JPEG width and height without downloading/reading entire image.
function getjpegsize($img_loc) {
    $handle = fopen($img_loc, "rb") or die("Invalid file stream.");
    $new_block = NULL;
    if(!feof($handle)) {
        $new_block = fread($handle, 32);
        $i = 0;
        if($new_block[$i]=="\xFF" && $new_block[$i+1]=="\xD8" && $new_block[$i+2]=="\xFF" && $new_block[$i+3]=="\xE0") {
            $i += 4;
            if($new_block[$i+2]=="\x4A" && $new_block[$i+3]=="\x46" && $new_block[$i+4]=="\x49" && $new_block[$i+5]=="\x46" && $new_block[$i+6]=="\x00") {
                // Read block size and skip ahead to begin cycling through blocks in search of SOF marker
                $block_size = unpack("H*", $new_block[$i] . $new_block[$i+1]);
                $block_size = hexdec($block_size[1]);
                while(!feof($handle)) {
                    $i += $block_size;
                    $new_block .= fread($handle, $block_size);
                    if($new_block[$i]=="\xFF") {
                        // New block detected, check for SOF marker
                        $sof_marker = array("\xC0", "\xC1", "\xC2", "\xC3", "\xC5", "\xC6", "\xC7", "\xC8", "\xC9", "\xCA", "\xCB", "\xCD", "\xCE", "\xCF");
                        if(in_array($new_block[$i+1], $sof_marker)) {
                            // SOF marker detected. Width and height information is contained in bytes 4-7 after this byte.
                            $size_data = $new_block[$i+2] . $new_block[$i+3] . $new_block[$i+4] . $new_block[$i+5] . $new_block[$i+6] . $new_block[$i+7] . $new_block[$i+8];
                            $unpacked = unpack("H*", $size_data);
                            $unpacked = $unpacked[1];
                            $height = hexdec($unpacked[6] . $unpacked[7] . $unpacked[8] . $unpacked[9]);
                            $width = hexdec($unpacked[10] . $unpacked[11] . $unpacked[12] . $unpacked[13]);
                            return array($width, $height);
                        } else {
                            // Skip block marker and read block size
                            $i += 2;
                            $block_size = unpack("H*", $new_block[$i] . $new_block[$i+1]);
                            $block_size = hexdec($block_size[1]);
                        }
                    } else {
                        return FALSE;
                    }
                }
            }
        }
    }
    return FALSE;
}
?>

Do a search for the world "download" on the manual page, it's in the comments.

nasufara
And I'm looking for a way to do this without writing 100 lines of code for something so basic and simply
HankT
A: 

If you like parsing strings, then you can avoid calling identify program (which is overhead). Just specify -verbose switch to convert like this:

c:\>convert -verbose -size 100x100 1.JPG 2.jpg
1.JPG JPEG 857x878=>108x110 108x110+0+0 8-bit DirectClass 136kb
1.JPG=>2.jpg JPEG 857x878=>108x110 108x110+0+0 8-bit DirectClass 2.94kb

As you can see in output, new size is 108x110

Ivan Nevostruev