Page 1 of 1

createImageFromJPEG memory trouble

Posted: Mon Oct 27, 2003 6:32 am
by jollyjumper
Hi Everyone,

I've got a problem. My hosting provider's webserver is using php 4.3.3 with the --enable-memory-limit turned on.
It has been configured with a memory limit of 16 MB.

When I try to upload a file through a form, and open the file with createImageFromJPEG it gives me this error:
Fatal error: Allowed memory size of 16777216 bytes exhausted at (null):0 (tried to allocate 2048 bytes)
I'm absolutely sure that the code is executed once, as I suspected a loop, but this hasn't been the case.

Is this normal with a memory limit of 16 MB, so does it just need to be more, or am I doing something wrong?

Or maybe someone can tell me how I can free some memory?

Thanks in advance.

Greetz Jolly.

Posted: Mon Oct 27, 2003 8:27 am
by volka
what's the size of that image?
Maybe if you show us the code...

Posted: Mon Oct 27, 2003 8:34 am
by jollyjumper
Hi Volka,

The file is 1.2 MB large.

The code is contained in two classes.

1. fileupload which handles the upload process, which inprinciple is this function(the dutch texts are just error messages):

Code: Select all

function Upload() {
    if (($this->upl_file != -1) && ($this->new_filename != -1) && ($this->copy_to != -1)) {
	  if (!($this->upl_file == "none" || $this->upl_file=="")) {
	    if (!file_exists($this->copy_to . "/" . $this->new_filename)) {
          $this->CorrectFilename();
		  if ($this->MustHaveType != "") {
  	        if ($this->MustHaveType !=$this->IsType) {$typeok = false;} else {$typeok = true;}
		  } else {
		    $typeok = true;
		  }
			if ($typeok == false) {
			  $this->error = "Het bestand is niet van het type " . $this->MustHaveType . " en is daarom niet opgeslagen.";
		    } else {
			  if (@copy($this->upl_file,$this->copy_to . "/" . $this->new_filename)) {
			    if (file_exists($this->copy_to . "/" . $this->new_filename)) {
			      return true;
			    } else {
			      $this->error = "Er is iets mis gegaan met het opslaan van het bestand.";
				  return false;
			    }
			  } else {
			    $this->error = "Het bestand is niet goed verstuurd en is daarom niet opgeslagen.";
			    return false;
			  }
			}
		  } else {
		    $this->error = "Het bestand dat u zojuist heeft verstuurd bestaat al en is daarom niet opgeslagen.";
		    return false;
		  }
	    } else {
	     return false;
	    }
     } else {
	   return false;
	 }
   }
2. The image resize:

Code: Select all

function Resize($NewImageWidth="",$NewImageWidthSmall="",$OnlyLarger=0) {
                copy($this->urlafbeelding,$this->tmpurlafbeelding);
                $size = GetImageSize ("$this->tmpurlafbeelding");
                $ImageWidth = $size[0];
                $ImageHeight = $size[1]; 
			 if ($OnlyLarger == 0) {
			   $resize_img = true;
			 } else {
			   if ($ImageWidth > $NewImageWidth) {
			    $resize_img = true;
			   } else {
			    $resize_img = false;
			   }
			 }
			 if ($resize_img) {
                $NewImageHeight = round(($NewImageWidth / $ImageWidth) * $ImageHeight);
              	$src_img = ImageCreateFromJPEG("$this->tmpurlafbeelding"); 
               if ($this->method != 0) {
               	$dst_img = imagecreatetruecolor($NewImageWidth,$NewImageHeight); 
               	imageCopyResampled($dst_img,$src_img,0,0,0,0,$NewImageWidth,$NewImageHeight,$ImageWidth,$ImageHeight); 
			   } else {
               	$dst_img = imagecreate($NewImageWidth,$NewImageHeight); 
               	imageCopyResized($dst_img,$src_img,0,0,0,0,$NewImageWidth,$NewImageHeight,$ImageWidth,$ImageHeight); 
			   }
               	ImageJPEG($dst_img,"$this->urlafbeelding",100); 
			 }

               if ($this->urlafbeelding_small != "") {
               	$NewImageHeight = round(($NewImageWidthSmall / $ImageWidth) * $ImageHeight);
               	$src_img = imagecreatefromjpeg("$this->tmpurlafbeelding"); 
               if ($this->method != 0) {
               	$dst_img = imagecreatetruecolor($NewImageWidthSmall,$NewImageHeight); 
               	imageCopyResampled($dst_img,$src_img,0,0,0,0,$NewImageWidthSmall,$NewImageHeight,$ImageWidth,$ImageHeight); 
			   } else {
               	$dst_img = imagecreate($NewImageWidthSmall,$NewImageHeight); 
               	imageCopyResized($dst_img,$src_img,0,0,0,0,$NewImageWidthSmall,$NewImageHeight,$ImageWidth,$ImageHeight); 
			   }
               	Imagejpeg($dst_img, $this->urlafbeelding_small,100); 				
               }

				unlink($this->tmpurlafbeelding);
  }
[mod_edit changed

Code: Select all

to

Code: Select all

][/size]

Hope this clarifies something.

Greetz Jolly.

Posted: Mon Oct 27, 2003 8:46 am
by volka
hm, can't tell you for certain but it might easily be that the image blows up your memory limit.
1.2MB jpeg get unpacked, gd isn't stingy with memory and you create a second image (for resizing) ...yes, it really might blow up...

Have you tested with a smaller image?

Posted: Mon Oct 27, 2003 8:53 am
by jollyjumper
Hi Volka,

Yes I know the code in principle is correct because it works with smaller images, and it has always worked on our previous hosting provider's server, which didn't contain a memory limit.

But it sounds like it's a normal situation..then I don't worry anymore and just make sure I increase the memory limit before the resize starts. Do you know what a safe value is for resizing images, without screwing up the server?

Greetz Jolly.

Posted: Mon Oct 27, 2003 9:13 am
by volka
never have tested that. I wouldn't use the filesize but the image canvas size.
If you want to try use array getimagesize ( string filename [, array imageinfo]) and always echo the canvas size (and flush) before actually opening the image. Shouldn't take long to find the maximum size (probably almost linear growing with the product of width*height)

If your version of php is setup to provide this function you might also use int memory_get_usage ( void )

Posted: Mon Oct 27, 2003 9:37 am
by jollyjumper
Hi Volka,

Thanks for the suggestion, I'm going to try this out, it sounds logical :-)

Greetz Jolly.

Posted: Mon Feb 09, 2004 5:47 am
by NED334
Have you found a sollution about this memory problem? I am trying to make a thumbnail as well, and i allready get this message when i try to resize an image of +/_ 100kb.

Is there another way to make a thumbnail of an image(like 500kb)?


Please let me know, because i get sick :evil: of the irritating error massage, like this one:
Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to allocate 4800 bytes)


Thanks for your replies!

Posted: Mon Feb 09, 2004 7:52 am
by jollyjumper
Hi NED,

I've found a sollution, but your hosting provider needs to allow you to change this setting, so it also could not work for you.

Place this line before the piece of code that resizes you image:

Code: Select all

ini_set ("memory_limit", "100M");
You can adjust the 100M value to any of your liking, but 100M was enough for me.

Greetz Jolly.

Posted: Mon Feb 09, 2004 8:03 am
by NED334
Thanks Jolly,

but i am not allowed to change the serversettings because i am running my site on a server that is not mine :(

I tried the line that you told me, but there was no result...

Is there no other option then using the imagecreatefromjpeg function, for creating a thumbnail or for resizeing an image, without changeing the serversettings?

Posted: Mon Feb 09, 2004 8:13 am
by jollyjumper
Hi Ned,

I'm afraid not, at least no solution I've found. It's just that resizing a big jpeg costs more than 8 MB of memory.

You could ask the webmaster of your server if he/she would like to change the memory_limit to a higher value than 8 MB. I can't think of anything else that could help.

Maybe someone else who's reading this thread has another sollution?

Greetz Jolly.

Posted: Tue Feb 17, 2004 8:35 am
by woodse
As an alternative approach, check into the netpbm program as it ships with and is used in the Gallery program (http://gallery.menalto.com/).

The handy thing about this is that you shop out the processing work to another program, and this keep you from using up the memory space allocated to php. Also, netpbm produces better graphics. See the Gallery docs on why it was chosen over GD.

Posted: Tue Feb 17, 2004 9:19 am
by NED334
Yeah i allready tried that as well, but i found out that my hosting provider doesn't support NETPBM. Thanks anyway...

But now i solved the memory problem. You get an error message like: Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to allocate 4800 bytes) when you try to rescale an image(for example: 1200px to 105px). The filesize doen't matter. First of all i thought i recieved this message because of the filesize. I was testing with an image that was 1200px * 600px & 468kb. But then i tried an image that was 600px * 400px & 400kb it suddenly worked with no problem.
Now i made a script in Javascript that will not allow image files bigger then 900px wide/height, and the file size may not be bigger then 400kb, otherwise it will return a selfmade error message. 400kb and 900px width/height wil be big enough because otherwise the server space wil decrease very fast. When the Javascript detects that the pointed image is allowed, PHP takes it over, and FTP the image file to the server. After that imagecreatefromjpeg create 6 different image sizes, and store them on the server with some extra data in the database.

This solved the problem for me, with no changes on server level. I used this script for our own CMS system, and by the way: "You have to restrict your users, otherwise it will be a mess".

I hope this message helped some people with the memorylimit problem by using imagecreatefromjpeg in PHP, and saved a lot of time!


Greetz,

Dennis

Posted: Tue Feb 17, 2004 10:09 am
by jollyjumper
Hi Dennis,

Could you post the javascript code you used here, as this might be handy for other users as well.

I'm certainly interested in how you did this..

Greetz Jolly.

Posted: Tue Feb 17, 2004 12:59 pm
by NED334
Hi Jolly,

below you have the javascript code to check the imagefile. Note that this script is made for Internet Explorer 5.0 and bigger, on windows. I don't know how it works on Mac's and others. Our CMS system is made for IE 5.5 and bigger so this was perfect.

This code checks:
* if the given file is an image(When it is not an image you can't click the submit button);
* if the given image is below 400kb(When the image is over 400kb you get a message, and you cannot click the submit button);
* if the given image is smaller then 900px in height or width(When the image is over 900px in height/width you'll recieve a message and you cannot click the submit button);

Please let me know what u think!


Here it is:

<script language="JavaScript">

function Check_IMG(img_size, fileName){
document.file_upload.Check_Submit.disabled = "TRUE";
var imgURL = "file:///" + fileName;
var img = new Image();
img.src = imgURL;
msg = "";
if(img.width > 900){
document.file_upload.Check_Submit.disabled = "TRUE";
msg += "- Your image is to wide!\n";
}
if(img.height > 900){
document.file_upload.Check_Submit.disabled = "TRUE";
msg += "- Your image is to high!\n";
}
if(img_size > 409600){
document.file_upload.Check_Submit.disabled = "TRUE";
size_in_kb = (1/(Math.pow(2,10))) * img_size;
msg += "- The image filesize is to big!\n\nThe file may not be bigger then 400kb";
}
if(msg){
document.file_upload.Check_Submit.disabled = "TRUE";
msg += "\nChoose another image.\nThe image is to high/wide.\n";
alert(msg);
}
else{
document.file_upload.Check_Submit.disabled = "";
}
}
</script>

<form name="file_upload" enctype="multipart/form-data" method="post" action="" onsubmit="JavaScript:this.Submit.disabled=true;">
<fieldset style="padding: 3;"><legend>Your Image: </legend>
<INPUT oncontextmenu="return false" onkeypress="return false" onkeydown="return false" type=file onchange="Check_Submit.disabled='true';img_preview.src=file.value;" name="file">
<IMG WIDTH=0 HEIGHT=0 alt="Image is loading" onerror="Check_Submit.disabled='true';" src="" onload="Check_IMG(img_preview.fileSize, file.value);" name="img_preview">
<input type="button" name="Check_Submit" value="Save image" onclick="document.file_upload.Check_Submit.disabled = 'TRUE';">
</fieldset>
</form>