Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Allowed memory size of 20971520 bytes exhausted 1

Status
Not open for further replies.

petersJazz

Programmer
Jan 28, 2002
222
EU
I have my PHP pages on a web hotel where I have problems reading large image files. I want to automatically reduce the size but I get the message:

Fatal error: Allowed memory size of 20971520 bytes exhausted (tried to allocate 4800 bytes) in /hsphere/local/home/petersja/irpk.web.surftown.se/php/uploadpicture.php on line 35

Is it possible to load part of an image with something similar to imagecreatefromjpeg to then be able to do the scaling like a puzzle?

regards
Peter
 
are the images really that large? if so try overriding the memory limit with a local php.ini file
 
The file is not very big (2 M) but I have to open it and then resize it and then I run into memory problems. I can not use ini_set('memory_limit', '50M');, it gives me the same result.

regards
Peter
 
i suspect it is your code then.

can you post the code you are using to perform the resize?

and btw i was not suggesting using ini_set but a php.ini file stored locally.
 
I have no control over php.ini, I have asked web hotell about more memory usage but got a no. Here is relevant part of code. I havent found any way to minimize memory usage in call to imagecreatefromjpeg.

Code:
<?
...
  $size=getimagesize($filenamex);
  if (..big file, resize and store..) {
   $isrc=imagecreatefromjpeg($filenamex);
   $s0=$size[0];
   $s1=$size[1];
   if ($s0>$maxwi) {
    $s1=(int)$s1*$maxwi/$s0;
    $s0=$maxwi;
   }
   if ($s1>$maxhe) {
    $s0=(int)$s0*$maxhe/$s1;
    $s1=$maxhe;
   }
   $idst=imagecreatetruecolor($s0,$s1);
   fastimagecopyresampled($idst,$isrc,0,0,0,0,$s0,$s1,$size[0],$size[1]);
   imagejpeg($idst,$uploadfile,90);
   imagedestroy($isrc);
   imagedestroy($idst);
   $size[0]=$s0;
   $size[1]=$s1;
  }
  if (!dbchange('INSERT INTO tttimage values (....)')) {
   setmessage('Fel vid registrering av bild<br><br>');
   header('location:loadpicture.php');
  }
  // make downscaled copies
  if (strpos(strtoupper($ffname),'.JPG')>0) {
    if ($size[0]>200) {
      $w=130;
      $isrc=imagecreatefromjpeg('../pics/'.$ffname);
      $h=(int)$w*$size[1]/$size[0];
      $idst=imagecreatetruecolor($w,$h);
      imagecopyresampled($idst,$isrc,0,0,0,0,$w,$h,$size[0],$size[1]);
      imagejpeg($idst,'../pics'.$w.'/'.$ffname,90);
      imagedestroy($idst);
    }
    if ($size[0]>300) {
      $w=220;
      $h=(int)$w*$size[1]/$size[0];
      $idst=imagecreatetruecolor($w,$h);
      imagecopyresampled($idst,$isrc,0,0,0,0,$w,$h,$size[0],$size[1]);
      imagejpeg($idst,'../pics'.$w.'/'.$ffname,90);
      imagedestroy($idst);
    }
    if ($size[0]>360) {
      $w=286;
      $h=(int)$w*$size[1]/$size[0];
      $idst=imagecreatetruecolor($w,$h);
      imagecopyresampled($idst,$isrc,0,0,0,0,$w,$h,$size[0],$size[1]);
      imagejpeg($idst,'../pics'.$w.'/'.$ffname,90);
      imagedestroy($idst);
    }
    if ($size[0]>630) {
      $w=583;
      $h=(int)$w*$size[1]/$size[0];
      $idst=imagecreatetruecolor($w,$h);
      imagecopyresampled($idst,$isrc,0,0,0,0,$w,$h,$size[0],$size[1]);
      imagejpeg($idst,'../pics'.$w.'/'.$ffname,90);
      imagedestroy($idst);
      imagedestroy($isrc);
    }
  }
  header('location:loadpicture.php');
...
?>
 
why are you resizing the image so many times in one operation? if $size[0] is greater than 630 pixels you will have performed 4 resizes in one script.

i'm not sure that your code effectively maintains the aspect ratio although i have not looked at it in detail though. can you try this resize script and see whether it is still giving you the same memory outage? Regrettably I don't think there is any way to measure memory usage reliably in a php script, otherwise we could actively see what's going on in your script. i'll give some thought to this as there ought to be a way...

Code:
<?php

	//usage
	
	if(	TRUE === ($result = resizeImage('.', 'olimage.jpeg', 200, '.', 'newimage.jpeg'))){
		echo "Image successfully resized<br/><img src=\"newimage.jpeg\">";
	}else{
		echo "Problem resizing image.  Error message was: $result";
	}
	
	/**
	*	function for down-sizing jpegs
	*	
	*	@param string $path		the current path of the image
	*	@param string $image	the filename of the current image
	*	@param integer $maxSize the maximum size constraint in pixels
	*	@param string $destPath	the path for saving the resultant image
	*	@param string $destFile the filename for saving the resultant image
	*	@return	bool|string 	true on succes or an error string on failure 
	*/
	
    function resizeImage($path, $image, $maxSize, $destPath, $destFile){
    	if(substr($path,-1) !== DIRECTORY_SEPARATOR){
    		$path .= DIRECTORY_SEPARATOR;
    	}
    	if(substr($destPath,-1) !== DIRECTORY_SEPARATOR){
    		$destPath .= DIRECTORY_SEPARATOR;
    	}
		if(!is_writable($destPath)){
			return "cannot write to destination path.  Destination path was $destPath";
		}
    	if (!file_exists($path.$image)){
    		return "source file does not exist";
    	}
		//get current size of the image
		list($oldwidth, $oldheight) = getimagesize($path.$image);
		
		//determine new size
		if($oldwidth > $oldheight){
			//landscape
			if ($oldwidth>$maxSize){
				$newwidth=$maxSize;
				$newheight = intval($oldheight * ($newwidth/$oldwidth));
			}else{
				return "no need to downsize";
			}
		} else {
			//portrait or square
			if ($oldheight > $maxSize){
				$newheight = $maxSize;
				$newwidth = intval($oldwidth * ($newheight/$oldheight));
			}else{
				return "no need to downsize";
			}
		}
		
		//create new image canvas
		$dest = imagecreatetruecolor($newwidth, $newheight);
		
		//create source image
		$src = imagecreatefromjpeg($path.$image);
		
		//resample image
		imagecopyresampled($dest, $src, 0, 0, 0, 0, $newwidth, $newheight, $oldwidth, $oldheight);
		
		//destroy original image to release memory
		imagedestroy($src);
		$src = NULL;
		
		//save new image
		imagejpeg($dest, $destPath.$destFile, 90);
		
		//destroy new image
		imagedestroy($dest);
		$dest = NULL;
		return true;
    }
?>
 
hi,

I have tested your code and it gives me the same result. An analyse of your code gives that it does the same steps as my code (but its nice to see some good php code, thank you for that).

The problem must be that if the code opens a big jpg file (like 2000x1200 pixel) to resize it to 1200x1000 this operation will need a lot of memory. I will try to do it in parts, thats why I asked if there is a possibility to open part of an image file.

You ask why I resize the image so many times and thats because I would like to have different sizes on different pages, but that is not the problem since both your and my code destroys image in memory for every image created.
 
they both destroy the image, yes. but i have read in a number of places that some versions of the GD library have memory leaks.

i was wondering whether you would get the same problem if you just tried one resize operation rather than several.

if you are using php as a cgi (not uncommon in hosted environments) you _should_ be able to upload a local php.ini file. just create a file called php.ini with a higher figure for memory and upload it to the script directory. that's all you need. it works fine with my hosts (who use FastCGI) and i've heard successful reports from elsewhere - worth a try.

In any event the next steps are:

1. upgrade your php installation to make sure that you are using the latest version of the GD lib and controlling code.
2. start some debugging/benchmarking of your code. I have thought of a way to perform some rudimentary memory benchmarking and will post some code in a short while.
 
thank you for your advice,

I have tested with just one resize and gets the same problem. Problem is that orginal image, new image and the resize operation takes to much memory. It works of course for smaller images.

I dont know if I use php as a cgi. How should the php.ini file look if I were too test it?

I can not upgrade the php installation, its on a big web hotel (surftown.se).

I have debugged it (echo...) to see in what cases it will fail. My idee is to do the resizing in parts, open orginal image, create 1/9 of new image, resize that part into new image, temporary store new image, do this for the 9 parts, then open the 9 parts and put it together into destination. Sounds a bit tricky but it should be able to do.
 
here is the same code as above with some memory tracking thrown in. My results are also shown

Code:
<?php
    //usage
    define('DEBUG', true);
	echo "<table border=\"1\">";
	echo "<tr><th>Execution time<br/>(cumulative microsecs)</th><th>Event</th><th align=\"center\">memory usage<br/>bytes</th></tr>";
	outputMemoryUsage("about to call function");
	
    $result = resizeImage('.', 'IMG_7646.jpg', 600, '.', 'newimage.jpeg');
	
	echo "</table>";
	
	if ($result){
        echo "Image successfully resized<br/><img src=\"newimage.jpeg\">";
    }else{
        echo "Problem resizing image.  Error message was: $result";
    }
    
    /**
    *    function for down-sizing jpegs
    *    
    *    @param string $path        the current path of the image
    *    @param string $image    the filename of the current image
    *    @param integer $maxSize the maximum size constraint in pixels
    *    @param string $destPath    the path for saving the resultant image
    *    @param string $destFile the filename for saving the resultant image
    *    @return    bool|string     true on succes or an error string on failure 
    */
    function outputMemoryUsage($event=NULL){
    	if (!DEBUG) return;
    	static $start;
		if (empty($start)) $start = microtime(true);
		$curTime = number_format(microtime(true)  - $start, 4);
		echo "<tr><td>$curTime</td><td>$event</td><td align=\"right\">".memory_get_usage()."</td></tr>";
    }
	
	
    function resizeImage($path, $image, $maxSize, $destPath, $destFile){

    	outputMemoryUsage("starting function");
        if(substr($path,-1) !== DIRECTORY_SEPARATOR){
            $path .= DIRECTORY_SEPARATOR;
        }
        if(substr($destPath,-1) !== DIRECTORY_SEPARATOR){
            $destPath .= DIRECTORY_SEPARATOR;
        }
        if(!is_writable($destPath)){
            return "cannot write to destination path.  Destination path was $destPath";
        }
        if (!file_exists($path.$image)){
            return "source file does not exist";
        }
		
		$filesize = filesize($path.$image);
		
		
        //get current size of the image
        list($oldwidth, $oldheight) = getimagesize($path.$image);
		outputMemoryUsage("getsize");
        
        //determine new size
        if($oldwidth > $oldheight){
            //landscape
            if ($oldwidth>$maxSize){
                $newwidth=$maxSize;
                $newheight = intval($oldheight * ($newwidth/$oldwidth));
            }else{
                return "no need to downsize";
            }
        } else {
            //portrait or square
            if ($oldheight > $maxSize){
                $newheight = $maxSize;
                $newwidth = intval($oldwidth * ($newheight/$oldheight));
            }else{
                return "no need to downsize";
            }
        }
		
		outputMemoryUsage("calculate dimensions");
        
        //create new image canvas
        $dest = imagecreatetruecolor($newwidth, $newheight);
        
		outputMemoryUsage("create a new blank canvas");
		
        //create source image
		outputMemoryUsage("Size of input image is : $filesize" );
		
        $src = imagecreatefromjpeg($path.$image);
        outputMemoryUsage("load up image to downsize");
		
        //resample image
        imagecopyresampled($dest, $src, 0, 0, 0, 0, $newwidth, $newheight, $oldwidth, $oldheight);

		outputMemoryUsage("downsize the image");
		
        //destroy original image to release memory
        imagedestroy($src);
		outputMemoryUsage("destroy the image");
        $src = NULL;
        
        //save new image
        imagejpeg($dest, $destPath.$destFile, 90);
		outputMemoryUsage("save the image");
        
        //destroy new image
        imagedestroy($dest);
		outputMemoryUsage("destroy the new canvas");
		
        $dest = NULL;
        outputMemoryUsage("kill the holding variable");
		return true;
    }
?>

Code:
Execution time
(cumulative microsecs)	Event	memory usage
bytes
0.0000	about to call function	77096
0.0001	starting function	79064
0.0005	getsize	79880
0.0005	calculate dimensions	80108
0.0043	create a new blank canvas	1301908
0.0044	Size of input image is : 2791103	1302008
0.7082	load up image to downsize	41205488
1.6832	downsize the image	41205564
1.7078	destroy the image	1302236
1.7367	save the image	1302236
1.7372	destroy the new canvas	80580
1.7372	kill the holding variable	80660
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top