Solved

PHP GD image not viewable as an image when saved

Posted on 2011-03-07
14
522 Views
Last Modified: 2012-06-27
I have been playing with the GD image functions creating buttons and placing text on them. Made it work. But I was wondering if someone could give me an explanation to why an image created dynamically by a script cannot be viewed after using  'Save As' . It saves like for example image.php.png and no software can actually open it reporting it's a script. Am I asking a really stupid question here as it is really obvious? Thanks for any contributions to explain this to me.
0
Comment
Question by:czechmate1976
  • 6
  • 4
  • 4
14 Comments
 
LVL 34

Expert Comment

by:Beverley Portlock
ID: 35055975
Try taking the .php out of the file name. Dressing scripts up as images is a known hacker trick. I'm not surprised software reports it as a script.
0
 

Author Comment

by:czechmate1976
ID: 35056264
Ah, I thought it could be one of the reasons.
I tried to take it out but still did not get the image to open in image editing software. The one before, which was done completely by php I managed to open. The one where I used a pre-designed background and only wrote text on it won't display.
0
 
LVL 34

Expert Comment

by:Beverley Portlock
ID: 35056539
I would need to see the PHP code and sample images before I could say why a particular image was not displaying properly.
0
 

Author Comment

by:czechmate1976
ID: 35059264
I have posted up the code and the png graphic. What I get when I save it is the name of the script with png file extension. (image.php.png) Even if I take the php out (image.png) nothing can open the image.

button graphic used in the script
$button_text = $_POST['button_text'];
		$colour = $_POST['colour'];
		
		$im = imagecreatefrompng('images/' . $colour . '-button.png');
		
		if (!$im)
		{
			$error = 'Could not create image.';
		}
		
		$width_image = imagesx($im);
		$height_image = imagesy($im);
		
		//echo $width_image . "<br />";
		//echo $height_image . "<br />";
		// Our images need an 18 a 10 pixel margin in from the edge of the image
		// Set up the button measurements without the margins
		$width_image_wo_margins = $width_image - (2 * 20);
		$height_image_wo_margins = $height_image - (2 * 5);
		
		// button height 50pixels - (2*10 margins) = max font size 30
		$font_size = 30;
		putenv('GDFONTPATH=/Library/Fonts');
		$fontname = 'Tahoma';
		
		// test the size of the text by looking at the bounding box [bbox] of the text.
		// loop, decrementing the font size at each iteration, until the submitted text
		// will fit on the button reasonably: 
		do {
			$font_size--;
			// find out the size of the text at that font size
			$bbox = ImageTTFBBox($font_size, 0, $fontname, $button_text);
			
			$right_text = $bbox[2]; // right co-ordinate
			$left_text = $bbox[0]; // left co-ordinate
			$width_text = $right_text - $left_text; // how wide is it?
			$height_text = abs($bbox[7] - $bbox[1]); // how tall is it?
			//echo '$font_size = ' . $font_size . '<br />';
			//echo '$fontname = ' . $fontname . '<br />';
			//echo '$height_text = ' . $height_text . '<br />';
			//print_r($bbox);
			
		}
		while ($font_size>8 &&
			  (	$height_text>$height_image_wo_margins || $width_text>$width_image_wo_margins ));
			  
		if ($height_text>$height_image_wo_margins || $width_text>$width_image_wo_margins) 
		{
			//no readable font size will fit on button
			$error = '<p style="color: red;">Text given will not fit on button.</p>';
		} 
		else 
		{
		
			// all ok, workout the base position for the start of the text
			// this is the midpoint of the available space
			$text_x = $width_image/2.0 - $width_text/2.0;
			$text_y = $height_image/2.0 - $height_text/2.0;
			
			//Add correction factors to account for the baseline relative coordinate system
			// Thesecorrection factors allow for the baseline and a little adjustment because
			// the image is a bit "top heavy";
			if($left_text < 0) 
			{
				$text_x += abs($left_text); 		// 	add factor for left overhang
				$above_line_text = abs($bbox[7]); 	//	how far above the baseline
				$text_y += $above_line_text;		// 	add baseline factor
				$text_y -= 2;						//	adjustment factor for shape o our template
			}
			// set up the text colour
			$white = imagecolorallocate($im, 255, 255, 255);
			// draw the text onto the button
			ImageTTFText($im, $font_size, 0, $text_x, $text_y, $white, $fontname, $button_text);
			//display image in browser
			Header ('Content-type: image/png');
			imagesavealpha($im, true);
			ImagePNG($im);
			imagedestroy($im);
		}

Open in new window

0
 
LVL 34

Expert Comment

by:Beverley Portlock
ID: 35060642
I suspect that the problem is this line

Header ('Content-type: image/png');

which tells the browser that it is outputting a PNG  so that it appends .png to the script name. I presume that the executing script is called image.png?

Use the other parameters in ImagePng to save it to a file like so

    ImagePNG($im, './newImage.png');

and then you can use the newImage.png file
0
 

Author Comment

by:czechmate1976
ID: 35062010
yes, the file that outputs the image is called image.php, if I save the image, it gets saved as image.png.php.

But how would I output the image without sending the header? The only other option is to output it within the image tag or as you say to save it first
0
 
LVL 34

Expert Comment

by:Beverley Portlock
ID: 35068002
The normal way is just to put the image into the output stream of the browser at the point you want it to show up. Don't use the header tag to reset the output type and the image should just show up. Failing that save it to a temporary file and link it via an <img..../> tag.

To force the script to "save" the image you could save it to a file and then try

header('Content-Disposition: Attachment;filename=imageName.png');
header('Content-type: image/png');

0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:czechmate1976
ID: 35068523
Will try that. Thanks for all the help, mate. I will let you know how I got on. You've done enough already :-)
0
 
LVL 33

Expert Comment

by:Slick812
ID: 35072412
greetings  czechmate1976, , you do not seem to understand what a web browser does with calls for an image from a php script, maybe like -

<img src="http://www.mysite.com/button.php?tx=My%20GD%20Button&cl=green">

as opposed to calling a file image, like -
<img src="images3/green_button.png">

in the  button.php  script you would get the text and color like this

$button_text = $_GET['tx'];
$colour = $_GET['cl'];

and then you can use the -

Header ('Content-type: image/png');
imagesavealpha($im, true);
ImagePNG($im);

as you do in your code, - - -
however as you now have this set up as a "web Form" read, ,  and then post to your button image create php script, you likely can not use the output method of -
Header ('Content-type: image/png');
ImagePNG($im);

I would think you need to rethink how you go about this, if you need to have the user fill in a form and post that data, then you will need a different method to do your image on the resultant page display after sending the Form data.  A short explain of how I would do it -
make a button.php that gets the info from an image tag -
<img src="http://www.mysite.com/button.php?tx=My%20GD%20Button&cl=green">
then do a php script that does the result page after user submit, this would use your -
$button_text = $_POST['button_text'];
$colour = $_POST['colour'];

now check the $button_text and $colour to make sure they have valid strings for the data types you can use.

and add <img tag, something like this to your output page -

<img src="button.php?tx=<?php echo urlencode($button_text).'&cl='.urlencode($colour); ?>" />

but if you have not done this before, you might need more code examples, let me know if this helps?
0
 

Author Comment

by:czechmate1976
ID: 35117290
Thanks for your comment, Slick. It's true I was a bit confused by that. I was trying to understand the process by doing this little exercise and asking questions here.

Nevertheless, I have resolved the problem by saving the image into a file and returning it using the image tag.

Do I understand it correctly that using the way you are describing I would refer to the image-making script in my image tag and send it the submitted (validated) form values. This would create the image on the fly and display it within the page with other content. Then, would I have to put the header(content-type ... ) in the image-making script? Am I right?

Thanks for the help again
0
 
LVL 33

Accepted Solution

by:
Slick812 earned 150 total points
ID: 35118637
czechmate1976,, you seem to have stated the "theory" correctly, but knowing how it works, only gets you half way to your goal. First you maybe should research some about the internet "headers", the ones that you place with -
header ('Content-type: image/png');

 - - - all, or at least most, files from a web server, also send an identification header of the content type, as a text/html , image/gif or other, there are also other headers sent for a browser or receiver to read and use. PHP automatically sets the content type to text/html , when ever you echo anything to the output. If you echo text to the output and then do the -
header ('Content-type: image/png');
, PHP will issue errors, saying header has already been set.
so you CAN NOT mix content types in the same output, - as in - only one content type per browser called php script.

As far as I know a web browser can NOT read but one content type per file, an Image tag <img src="green_button.png"> is a separate web file call to the browser, than the web page index.php that is in the address bar.
I do not have time right now to do a demo php for this type of thing to show you, I will try it tomorrow if time allows, but below is something I use to display the date, from a javascript write to a PHP image tag

<script language='javascript'>today=new Date(); document.write("<img src=\"imgday.php?idt="+today.getMonth()+ "-"+today.getDate()+"-"+today.getFullYear()+'\" style=\"position:absolute;top:0px;right:6px;z-index:1;\">');today =null;</script>


below is the code for the  imgday.php  script
<?php
$lcolor = (empty($_GET['idt'])) ? '+' : $_GET['idt'];
$date2=date("F j, Y");
if (strlen($lcolor)>6) {$bbox = explode('-', $lcolor);
	if (count($bbox) == 3) {
	$ttf=array('January','February','March','April','May','June','July','August','September','October','November','December');
	$date2= $ttf[(int)$bbox[0]].' '.$bbox[1].', '.$bbox[2];
	}
	}
$ttf='/home/user/usephp/tango.ttf';
$fsize=18;
$bbox=imageftbbox($fsize, 0, $ttf, $date2);
$width=abs($bbox[0]) + abs($bbox[2])+5;
$height=abs($bbox[1]) + abs($bbox[5])+3;
$imgs = imagecreatetruecolor($width, $height);
$lcolor = imagecolorallocate($imgs, 128, 138, 148);
$bgcolor = imagecolorallocate($imgs, 32, 204, 230);
imagefilledrectangle($imgs, -1, -1, $width, $height, $bgcolor);
imagettftext($imgs, $fsize, 0, 4, $height-$bbox[3], $lcolor, $ttf, $date2);
$lcolor = imagecolorallocate($imgs, 255, 203, 109);
imagettftext($imgs, $fsize, 0, 2, $height-$bbox[3]-2, $lcolor, $ttf, $date2);
imageline($imgs, 0, 0, 0, $height, $bgcolor);
imagecolortransparent($imgs, $bgcolor);
imagetruecolortopalette($imgs, true, 255);
header('Content-Type: image/gif');
@ImageGIF($imgs);
imagedestroy($imgs);
?>

Open in new window

0
 
LVL 33

Expert Comment

by:Slick812
ID: 35124440
I was able to do the 2 following php scripts, the first is the botton.php , , it receives the text and color info in the web address GET method
<?php
$text = (empty($_GET['tx'])) ? '+' : $_GET['tx'];
$colour = (empty($_GET['cl'])) ? '+' : $_GET['cl'];

$ttf ='/home/user/files/fonts/tracks.ttf';
$error = ''; // set error to empty string
$aryColor = array('red'=>0,'blue'=>1,'yellow'=>2,'green'=>3,'white'=>4);
if (!isset($aryColor[$colour])) $error .= 'Wrong Color, ';
// check input for format errors
if (!isset($text{1})) $error .= 'No Text, ';
if (!file_exists($ttf))  $error .= 'No File, ';// prevent GD error if ttf does not exist
// you can leave the file test if you do not change the font very much

// DO NOT ECHO TEXT FOR ERRORS
// create an error image and write error on image
if (isset($error{1})) {
	$error = 'ERROR - '.$error;
	$img = imagecreatetruecolor(218, 42);
	$icolor = imagecolorallocate($img, 230, 0, 0);
	imagefilledrectangle($img, 2, 2, 216, 40, $icolor);
	$icolor = imagecolorallocate($img, 0, 0, 0);
	imagestring($img, 5, 4, 12, $error, $icolor);
	header('Content-Type: image/png');
	@imagepng($img);
	imagedestroy($img);
	exit;
	}

// below is just TEST code
// place your own CODE below to center and drar your text
$img = imagecreatefrompng('images3/' . $colour . '-button.png');
$icolor = imagecolorallocate($img, 0, 0, 0);
imagestring($img, 5, 20, 16, $text, $icolor);
// imagettftext($img, $fsize, 0, 20, $height-$bbox[3], $icolor, $ttf, $text);
imagesavealpha($img, true);
header('Content-Type: image/png');
@imagepng($img);
imagedestroy($img);
?>

Open in new window

0
 
LVL 33

Expert Comment

by:Slick812
ID: 35124495
the next php script is the FORM submit script  buttonform.php

if is a demo test, so you will need to change the button draw text to you own TTF draw text code

this should give you an idea of method to use for this type of thing, ask questions if you have problems.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>write button script</title></head><body bgcolor="#e3f7ff">
<?php
$error = ''; // set error to empty string
$showIt = false; // no, to showIt , for the new image
if (!empty($_POST['submit'])){ // check to see if there was a POST
	$Text = (empty($_POST['words'])) ? '~' : $_POST['words'];
// I use the NOT empty($_POST[]) because I have had problems with some posts
// and I like to set a variable with a default value
// but just test the Input with any method you like isset() or other
	$Color = (empty($_POST['color'])) ? '-' : $_POST['color'];
	if (!isset($Color{1})) $error .= 'Color Not Set,<br />'; else {
		$aryColor = array('red'=>0,'blue'=>1,'yellow'=>2,'green'=>3,'white'=>4);
// I test with an array and isset() for the color verification, there are many other methods for this
// and you may not need to test for select box entries, but this is just for demo
		if (!isset($aryColor[$Color])) $error .= 'Wrong Color, ';// add to error string
		}
	if (!isset($Text{1})) $error .= 'Text Words Needs to be at least 2 letters long.'; else {
		if (isset($Text{20})) $error .= 'Text Words can NOT be at more than 20 letters long.';
		}
	if (!isset($error{0})) $showIt = true;// if no errors then show the image not the form
	}
if ($showIt) {
// I use the urlencode($Text) because the Text may have spaces and punctuation in it
// you may not need it for color, if it is alfa-numeric
?>
<h2>Result Button Image Below</h2>	
<p><img src="button.php?tx=<?php echo urlencode($Text).'&cl='.urlencode($Color); ?>" /></p>
<a HREF="<?php echo $PHP_SELF;?>" title="Click for Another"><b>Click Here to try Another Image Buttom</b></a>
<?php
} else {
?>
<h2>Make a Text Button Test</h2>
<?php
if (isset($error{0})) echo '<p style="color:red;">'.$error.'</p>';
?>
  <form method="post" action="<?php echo $PHP_SELF;?>"><b>Plaesse Enter your Button Text below -</b><br />
Button Text: <input type="text" size="20" maxlength="20" name="words">:<br />
Select a Color for your Buttton:<br />
<select name="color">
<option value="blue">Blue</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="yellow">Yellow</option>
<option value="white">White</option></select>:<br />
<input type="submit" value=" Make Button! " name="submit">
</form><br />
<?php
}
?>


</body></html>

Open in new window

0
 

Author Closing Comment

by:czechmate1976
ID: 35234756
THANKS A LOT FOR YOUR HELP and sorry for forgetting to get back in time
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Error viewing ASP page 12 99
Fixed div within Bootstrap carousel item 11 30
php variable basic question 12 29
two tables one button 11 20
I've been asked to discuss some of the UX activities that I'm using with my team. Here I will share some details about how we approach UX projects.
Boost your ability to deliver ambitious and competitive web apps by choosing the right JavaScript framework to best suit your project’s needs.
This tutorial demonstrates how to identify and create boundary or building outlines in Google Maps. In this example, I outline the boundaries of an enclosed skatepark within a community park.  Login to your Google Account, then  Google for "Google M…
The viewer will get a basic understanding of what section 508 compliance can entail, learn about skip navigation links, alt text, transcripts, and font size controls.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now