I've been experimenting with the imagecopyresampled function in PHP.

It has this example code:

<?php
// The file
$filename = 'test.jpg';

// Set a maximum height and width
$width = 200;
$height = 200;

// Content type
header('Content-type: image/jpeg');

// Get new dimensions
list($width_orig, $height_orig) = getimagesize($filename);

$ratio_orig = $width_orig/$height_orig;

if ($width/$height > $ratio_orig) {
   $width = $height*$ratio_orig;
} else {
   $height = $width/$ratio_orig;
}

// Resample
$image_p = imagecreatetruecolor($width, $height);
$image = imagecreatefromjpeg($filename);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);

// Output
imagejpeg($image_p, null, 100);
?>

However, I've adapted it to use a file upload method and what I'm finding is that if a file is too big, e.g. a 4272 x 2848 and weighing in around 4.5MB I get nothing back from the imagecreatefromjpeg. The file uploads fine (I can grab the content and output that directly) so it's something to do with that function.

The problem is that I can't work out how to tell at what point a file will be too big so I can exit gracefully and error out rather than just leaving the person with no output.

Any ideas?

Cheers

    The problem is that the PHP image functions store a bitmap of the image in memory, which is an uncompressed representation of the image, typically at 32 bits per pixel. So if you multiply the width times the height (in pixels) and multiply that times 4 (bytes/pixel) you'll have the number of bytes that will be needed (which may then be padded with a few overhead bytes).

    At that point, if it's too large, you can either choose to up the max memory usage via [man]ini_set/man and the memory_limit setting (if your PHP config allows it) or else generate an error message and skip processing of the image.

      TheoGB wrote:

      4272 x 2848 and weighing in around 4.5MB

      NogDog wrote:

      ...an uncompressed representation of the image, typically at 32 bits per pixel...

      ...So closer to 45MB.

        Okay, I hadn't realised it decompresses it.

        So I just need to read the memory limit from the PHP settings and then calculate roughly how big a JPG that would translate to with average compression on and use that as my on screen upper limit?

        Okay cheers.

          Well, you have to decompress the image if you want to work on the image data it contains. And of course when you create a new image there's no compression to that either.

          Note that it will be one of the imagecreate* functions that is blowing out the memory limit; you can use the metadata collected by getimagesize (width, height, and bitdepth) to get a good estimate of how much memory would eventually be needed.

            Okay thanks.

            No I just have to get it all working: I'm needing to take a single image and convert it to one 200px wide and one 100px wide and store them both in the Database for display later. On top of that I (ideally) need it to store all images as JPG types but I'm not actually sure how well PHP will handle doing that.

            As to memory: If I copy the image resource to another variable prior to storing this data in database and then do an Imagedestroy() on the resource will I be fine with memory? The temporary variable I copied it to will presumably clear the memory after it goes out of scope?

            And as I'll have to store an image resource in the DB will this cause any memory issues when I retrieve to use in imagejpeg() to output later?

              TheoGB wrote:

              As to memory: If I copy the image resource to another variable prior to storing this data in database and then do an Imagedestroy() on the resource will I be fine with memory?

              A resource is just a pointer to data in memory. In other words, the amount of memory required to store the value of a resource itself is probably only a couple of bytes (e.g. the length it requires to store a memory address). Copying a resource will, I believe, only copy the pointer - not the pointer's value.

              TheoGB wrote:

              The temporary variable I copied it to will presumably clear the memory after it goes out of scope?

              Either then, or if you call [man]unset/man. From the manual on resources:

              Thanks to the reference-counting system introduced with PHP 4's Zend Engine, a resource with no more references to it is detected automatically, and it is freed by the garbage collector. For this reason, it is rarely necessary to free the memory manually.

              TheoGB wrote:

              And as I'll have to store an image resource in the DB will this cause any memory issues when I retrieve to use in imagejpeg() to output later?

              Again, if you open the JPEG using the GD library, you'll have to have enough room in memory to open the image in an uncompressed format.

              Why store it in the DB at all? Why not just store the image on the file system (since that's what a file system is good for - storing files :p) so that you don't have to worry about using tons of memory just to output an image?

              EDIT: Also, before Weedpacket swoops in and tells me how much of that first paragraph above is incorrect, I'll warn you that my information is based on my understanding of pointers in C++ - it may not hold true for what PHP calls a resource. :o

                bradgrafelman;10949330 wrote:

                Why store it in the DB at all? Why not just store the image on the file system (since that's what a file system is good for - storing files :p) so that you don't have to worry about using tons of memory just to output an image?

                Aw nuts, you're saying the image resource is a raw one? Damn, of course. I was thinking it would be a JPG.

                Okay, look I'll start a new thread on this and mark this as closed in the meantime, where I will also outline my reasons for using a DB rather than the file system.

                  TheoGB wrote:

                  I was thinking it would be a JPG.

                  Well, that may very well be (e.g. if you used imagejpeg to output it), but whenever you open an image resource using the GD library, it is opened as an uncompressed image - no matter what form it was in before you opened it.

                    bradgrafelman;10949337 wrote:

                    Well, that may very well be (e.g. if you used imagejpeg to output it), but whenever you open an image resource using the GD library, it is opened as an uncompressed image - no matter what form it was in before you opened it.

                    Okay, I've started the new thread.

                    Yeah I can see imagejpeg will convert it but you can't send that output to a variable for DB store (that I can see - let's leave that to the other thread I started if I'm wrong) and this is just the resource prior to using that function I was going to store. It makes perfect sense that would be uncompressed. Buh!

                      Perhaps the [man]imagick[/man] extension?

                      I'm not familiar enough with it myself, but perhaps its memory consumption doesn't count towards PHP's total. But if it does, Imagemagick still exists as a standalone suite of executables that can be run via command line, and being separate programs do have memory allocated separately.

                        Weedpacket;10949398 wrote:

                        Perhaps the [man]imagick[/man] extension?

                        I'm not familiar enough with it myself, but perhaps its memory consumption doesn't count towards PHP's total. But if it does, Imagemagick still exists as a standalone suite of executables that can be run via command line, and being separate programs do have memory allocated separately.

                        Yeah Brad was talking about it in the other thread. I'm familiar with it from my Ruby on Rails stuff. I'm going to see if my hoster has it installed.

                          Write a Reply...