Skip to Content »

FlashApe » Getting getbytesTotal for dynamically generated images

 Getting getbytesTotal for dynamically generated images

  • April 17th, 2006
  • 7:45 pm

*this is a repost...I lost the original in the great blog disaster of '06. I went looking for this info and had to pull it off of google cache, so here it is again.

Ok this one kicked my ass for a few days, I'm posting it here so maybe someone else wont have to go through it.

I was dynamically generating images from a php script using the imagejpeg() function:

PHP:
  1. $filename = $_GET['fileName'];
  2.  
  3.  
  4. // Set a maximum height and width
  5. $width = $_GET['width'];
  6. $height = $_GET['height'];
  7.  
  8.  
  9. //a little security
  10. while(strpos($_GET['fileName'], '..') !== FALSE){
  11.     $filename = str_replace('..', '.', $filename);
  12. }
  13.  
  14. // Get new dimensions
  15. list($width_orig, $height_orig) = getimagesize($filename);
  16.  
  17. if ($width) {
  18.     $width = ($height / $height_orig) * $width_orig;
  19. } else {
  20.     $height = ($width / $width_orig) * $height_orig;
  21. }
  22.  
  23. // Resample
  24. $image_p = imagecreatetruecolor($width, $height);
  25. $image = imagecreatefromjpeg($filename);
  26. imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);

That worked fine, but if i tried to track the dowload using a bytesLoaded / bytesTotal combo, I was finding the bytesTotal wasn't being set. I figured that was probably a header I needed to set in php, and I was right. You need to set the size in the 'Content-Length' header.

Now my problem was how to get the size of a file you are about to output with the imagejpeg function. There were some notes in the php docs for strlen() that that function will return the size in bites if it is called on a binary object...but that went nowhere.

Turns out, what you need to do is start an output buffer using ob_start(). This will capture all the output from the script instead of outputting it to the browser. After you've created the buffer, you can call imagejpeg() and the image will be outputted to the buffer. After you've outputted the jpg to the buffer, you can call ob_get_length(); and store the size of the output buffer in a variable. After you've got the size of the buffer, you can call ob_end_clean() and discard the buffer....you'll still have access to the variable:

PHP:
  1. ob_start(); // start a new output buffer
  2.     imagejpeg($image_p);
  3.     $imgLength = ob_get_length();
  4. ob_end_clean(); // stop this output buffer

Now that you've got what you need (the total bytes of the image), you can add that to the Content-Length header, and output the jpg:

PHP:
  1. header('Content-type: image/jpeg');
  2. header("Content-Length: " . $imgLength);
  3.  
  4. imagejpeg($image_p);
  5.  
  6. imagedestroy($image_p);

I think it looks a litle more complicated than what it is because I've broken up the code and explained it. Here is the code in it's entirety:

PHP:
  1. $filename = $_GET['fileName'];
  2.  
  3.  
  4. // Set a maximum height and width
  5. $width = $_GET['width'];
  6. $height = $_GET['height'];
  7.  
  8.  
  9. //a little security
  10. while(strpos($_GET['fileName'], '..') !== FALSE){
  11.     $filename = str_replace('..', '.', $filename);
  12. }
  13.  
  14. // Get new dimensions
  15. list($width_orig, $height_orig) = getimagesize($filename);
  16.  
  17. if ($width) {
  18.     $width = ($height / $height_orig) * $width_orig;
  19. } else {
  20.     $height = ($width / $width_orig) * $height_orig;
  21. }
  22.  
  23. // Resample
  24. $image_p = imagecreatetruecolor($width, $height);
  25. $image = imagecreatefromjpeg($filename);
  26. imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);
  27.  
  28.  
  29. ob_start(); // start a new output buffer
  30.     imagejpeg($image_p);
  31.     $imgLength = ob_get_length();
  32. ob_end_clean(); // stop this output buffer
  33.  
  34. header('Content-type: image/jpeg');
  35. header("Content-Length: " . $imgLength);
  36.  
  37. imagejpeg($image_p);
  38.  
  39. imagedestroy($image_p);

3 People had this to say...

Gravatar

Thanks a lot ! I was looking for a way to do this and I knew it was possible but never found it... Very helpful, yeah !
Well... I now have to apply it to my "Talk a Pic" project !

Gravatar
  • dr Dave
  • September 29th, 2006
  • 9:08 am

Hey, thanks for taking the time to write that down. It's a neat trick...

But I was wondering if it couldn't be improved by using ob_flush() instead of ob_end_clean() (after outputting the headers). That way you do not have to call image_jpeg() again, which I reckon can only improve performance...

I'm about to try it, but was wondering if you saw any reason it wouldn't be a good idea...

Gravatar
  • rich
  • September 29th, 2006
  • 1:47 pm

yes, there was a sepcific reason why I didn't just use ob_flush()...it was giving me problems, but i don't remember exactly what the problem was. let me know if you get it to work.

Want your say?

* Required fields. Your e-mail address will not be published on this site


You can use the following XHTML tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>