Related
This is my static function in class 'image_utils.php'
public static function getCaptcha()
{
try {
$width = 200;
$height = 30;
$font = 'fonts/arial.ttf';
//
if (!file_exists($font)) {
throw new Exception('Error Font not found');
}
//
$image = imagecreatetruecolor($width, $height);
$white = imagecolorallocate($image, 255, 255, 255);
$grey = imagecolorallocate($image, 180, 180, 180);
$black = imagecolorallocate($image, 0, 0, 0);
//
for ($sq = 1; $sq <= 10; $sq++) {
$cx = (int)rand(0, $width / 2);
$cy = (int)rand(0, $height);
$h = $cy + (int)rand(0, $height / 5);
$w = $cx + (int)rand($width / 3, $width);
if (!imagefilledrectangle($image, $cx, $cy, $w, $h, $white)) {
throw new Exception('Error in White Fill');
}
}
//
$ellipse_count = 5;
for ($i = 0; $i < $ellipse_count; $i++) {
$cx = (int)rand(-1 * ($width / 2), $width + ($width / 2));
$cy = (int)rand(-1 * ($height / 2), $height + ($height / 2));
$h = (int)rand($height / 2, 2 * $height);
$w = (int)rand($width / 2, 2 * $width);
if (!imageellipse($image, $cx, $cy, $w, $h, $grey)) {
throw new Exception('Error in Grey Fill');
}
}
//
imagefttext($image, 20, 0, 10, 20, $black, $font, 'Captcha');
header('Content-type: image/png');
if (!imagepng($image)) {
throw new Exception('Error in ImagePng');
}
} catch (Exception $ex) {
echo $ex->getMessage();
}
}
Calling it in 'log.php' in img tag:
<img src='<?php image_utils::getCaptcha() ?>'/>
Gives an error 'The image cannot be displayed because it contains errors'. I have create a check for font file as shown in code so the font file is in inclusion. Please throw some light.
Thanks in Advance.
I was hoping to get in touch with someone on a situation that I cannot find the solution to anywhere.
I am trying to create a captcha on my website using php and although I was able to create an image and create the random captcha text.
I am unable to over lay the two. Here is my code:
<?PHP
session_start();
function generateRandomString($length = 10) {
$letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$len = strlen($letters);
$letter = $letters[rand(0, $len - 1)];
$text_color = imagecolorallocate($image, 0, 0, 0);
$word = "";
for ($i = 0; $i < 6; $i++) {
$letter = $letters[rand(0, $len - 1)];
imagestring($image, 7, 5 + ($i * 30), 20, $letter, $text_color);
$word .= $letter;
}
$_SESSION['captcha_string'] = $word;
}
function security_image(){
// $code = isset($_SESSION['captcha']) ? $_SESSION['captcha'] : generate_code();
//$font = 'content/fonts/comic.ttf';
$width = '110';
$height = '20';
$font_size = $height * 0.75;
// $image = #imagecreate($width, $height) or die('GD not installed');
global $image;
$image = imagecreatetruecolor($width, $height) or die("Cannot Initialize new GD image stream");
$background_color = imagecolorallocate($image, 255, 255, 255);
imagefilledrectangle($image,0,0,200,50,$background_color);
$line_color = imagecolorallocate($image, 64,64,64);
for($i=0;$i<10;$i++) {
imageline($image,0,rand()%50,200,rand()%50,$line_color);
}
$pixel_color = imagecolorallocate($image, 0,0,255);
for($i=0;$i<1000;$i++) {
imagesetpixel($image,rand()%200,rand()%50,$pixel_color);
}
//$textbox = imagettfbbox($font_size, 0, $font, $code);
//$textbox = imagettfbbox($font_size, 0, $randomString);
$x = ($width - $textbox[4]) / 2;
$y = ($height - $textbox[5]) / 2;
// imagettftext($image, $font_size, 0, $x, $y, $text_color, $font , $code);
imagettftext($image, $font_size, 0, $x, $y, $text_color , $word);
$images = glob("*.png");
foreach ($images as $image_to_delete) {
#unlink($image_to_delete);
}
imagepng($image, "image" . $_SESSION['count'] . ".png");
header('Content-Type: image/png');
imagepng($image);
imagedestroy($image);
}
security_image();
?>
I have no idea what I’m doing wrong. I’ve spent over 10 hours on this “display text” issue. I don’t understand and I am desperate for help. I even downloaded working captcha version from other resources that break once I upload it to my server. I have no idea whats going on. At first I thought there was something wrong with my server but the fact that I can even create the pixels, lines image means that it is at least working.
Please help!!!!
UPDATE---------------------------------------------
Thank you for your suggestions. Here is the edited code. I'm still getting the same issue.
<?PHP
session_start();
function security_image(){
global $image;
// $code = isset($_SESSION['captcha']) ? $_SESSION['captcha'] : generate_code();
$font = 'content/fonts/comic.ttf';
$width = '110';
$height = '20';
$font_size = $height * 0.75;
$image = imagecreatetruecolor($width, $height) or die("Cannot Initialize new GD image stream");
$background_color = imagecolorallocate($image, 255, 255, 255);
imagefilledrectangle($image,0,0,200,50,$background_color);
$line_color = imagecolorallocate($image, 64,64,64);
for($i=0;$i<10;$i++) {
imageline($image,0,rand()%50,200,rand()%50,$line_color);
}
$pixel_color = imagecolorallocate($image, 0,0,255);
for($i=0;$i<1000;$i++) {
imagesetpixel($image,rand()%200,rand()%50,$pixel_color);
}
$letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$len = strlen($letters);
$letter = $letters[rand(0, $len - 1)];
$text_color = imagecolorallocate($image, 0, 0, 0);
$word = "";
for ($i = 0; $i < 6; $i++) {
$letter = $letters[rand(0, $len - 1)];
imagestring($image, 7, 5 + ($i * 30), 20, $letter, $text_color);
$word .= $letter;
}
$_SESSION['captcha_string'] = $word;
/*texbox unitinitialized (removed for the sake of just showing the word size doesnt matter)
$x = ($width - $textbox[4]) / 2;
$y = ($height - $textbox[5]) / 2;
*/
$x = ($width) / 2;
$y = ($height) / 2;
imagettftext($image,$font, 4, $x, $y, $word);
header('Content-Type: image/png');
imagepng($image);
imagedestroy($image);
}
security_image();?>
i made some suggested changes but the code seems to still do the same thing. Just display the lines and pixels as expected but the text still is missing... ?
There are some several "errors" in your functions, let's fix them:
In generateRandomString()
generateRandomString($length = 10)
$lenght is not used its scope.
$text_color = imagecolorallocate($image, 0, 0, 0);
$image is uninitialized
In security_image() function:
$textbox is uninitialized
$text_color and $word is uninitialized.
And Wrong parameter count for imagettftext() You add 7 parameters, and forget the font file parameter.
found the problem. using this:
http://php.net/manual/en/function.imagettftext.php
i was able to see that the font location was incorrect. using the example on that page and editing it to my needs worked.
i have php code for upload image and add text watermark, but i have a little problem with the output.
my code success result image with text watermark like this: result 1
but i want the output like this: result 2
this is my code:
function UploadImage($img_name){
$vdir_upload = "img/upload/";
$vfile_upload = $vdir_upload . $img_name;
$file_name = basename($_FILES["img_1"]["name"]);
move_uploaded_file($_FILES["img_1"]["tmp_name"], $vfile_upload);
switch (strtolower(pathinfo($file_name, PATHINFO_EXTENSION))) {
case "jpg" :
$im_src = imagecreatefromjpeg($vfile_upload);
break;
case "jpeg" :
$im_src = imagecreatefromjpeg($vfile_upload);
break;
case "gif" :
$im_src = imagecreatefromgif($vfile_upload);
break;
case "png" :
$im_src = imagecreatefrompng($vfile_upload);
break;
default :
trigger_error("Error Bad Extention");
exit();
break;
}
$src_width = imageSX($im_src);
$src_height = imageSY($im_src);
$dst_width = 1979;
$dst_height = ($dst_width/$src_width)*$src_height;
$im = imagecreatetruecolor($dst_width,$dst_height);
imagecopyresampled($im, $im_src, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
$font = 'Aliquam.ttf';
$red = imagecolorallocate($im, 255, 0, 0);
imagettftext($im, 30, 0, 10, 50, $red, $font, $_POST["color"]);
imagejpeg($im,$vdir_upload . $_POST["number"].".jpg");
imagedestroy($im_src);
imagedestroy($im);
}
how can I get the result as above? sorry for my bad english, thanks in advance...
First of all - if you want to extend the width of the image by a margin I would take the original width of the image, add the width of your margin (lets call it $extraWidth and assume it is defined somewhere) and adjust your imagecreatetruecolor call with the new width.
Then you allocate a color and fill the remaining space with a rectangle for your color as shown below.
$im = imagecreatetruecolor($dst_width+$extraWidth, $dst_height);
$color = imagecolorallocate($im, 0, 0, 255); // this is blue - change to what you want
imagefilledrectangle($im, $dst_width, 0, $dst_width+$extraWidth, $dst_height, $color);
Please note I have not tested this code, merely referred to the documentation.
$pixel_height_of_character = 30; // change this to actual pixel height of a char
$pixel_gap_between_chars = 3;
$start_from_edge_of_margin = 3;
$string_chars = str_split($_POST['color']);
$start = ($dst_height / 2) - ((count($string_chars) * ($pixel_height_of_character+$pixel_gap_between_chars)) / 2)
// probably should round this
// also need to deduct one half of pixel gap from the result for centering purposes - i think - double check my math.
$left = $start_from_edge_of_margin + $dst_width;
foreach($string_chars as $char){
$top = $start + $pixel_height_of_character;
imagettftext($im, 30, 0, $left, $top, $red, $font, $char);
$start = $top + $pixel_gap_between_chars;
}
So. That is quite a bit to explain.
Basically you calculate the dimensions of each character - then using those dimensions calculate where the first character must start - then draw on the characters one at a time in a loop.
By no means is this code complete - if the provided word is too long it will exceed the bounds of the image so you should test for that. Also it may not get alignments perfect - but it's a good start.
The modified code:
function UploadImage($img_name){
$vdir_upload = "img/upload/";
$vfile_upload = $vdir_upload . $img_name;
$file_name = basename($_FILES["img_1"]["name"]);
move_uploaded_file($_FILES["img_1"]["tmp_name"], $vfile_upload);
switch (strtolower(pathinfo($file_name, PATHINFO_EXTENSION))) {
case "jpg" :
$im_src = imagecreatefromjpeg($vfile_upload);
break;
case "jpeg" :
$im_src = imagecreatefromjpeg($vfile_upload);
break;
case "gif" :
$im_src = imagecreatefromgif($vfile_upload);
break;
case "png" :
$im_src = imagecreatefrompng($vfile_upload);
break;
default :
trigger_error("Error Bad Extention");
exit();
break;
}
$src_width = imageSX($im_src);
$src_height = imageSY($im_src);
$dst_width = 1979;
$dst_height = ($dst_width/$src_width)*$src_height;
$im = imagecreatetruecolor($dst_width+$extraWidth, $dst_height);
$color = imagecolorallocate($im, 0, 0, 255); // this is blue - change to what you want
imagefilledrectangle($im, $dst_width, 0, $dst_width+$extraWidth, $dst_height, $color);
imagecopyresampled($im, $im_src, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
$font = 'Aliquam.ttf';
$red = imagecolorallocate($im, 255, 0, 0);
$pixel_height_of_character = 30; // change this to actual pixel height of a char
$pixel_gap_between_chars = 3;
$start_from_edge_of_margin = 3;
$string_chars = str_split($_POST['color']);
$start = ($dst_height / 2) - ((count($string_chars) * ($pixel_height_of_character+$pixel_gap_between_chars)) / 2)
// probably should round this
// also need to deduct one half of pixel gap from the result for centering purposes - i think - double check my math.
$left = $start_from_edge_of_margin + $dst_width;
foreach($string_chars as $char){
$top = $start + $pixel_height_of_character;
imagettftext($im, 30, 0, $left, $top, $red, $font, $char);
$start = $top + $pixel_gap_between_chars;
}
imagejpeg($im,$vdir_upload . $_POST["number"].".jpg");
imagedestroy($im_src);
imagedestroy($im);
}
class Watermark {
/**
*
* #var image resource
*/
private $image = null;
/**
*
* #var image resource
*/
private $watermark = null;
/**
*
* #var string
*/
private $output_file = null;
/**
*
* #var int
*/
private $type = '';
const BOTTOM_RIGHT = 1;
const CENTER = 2;
const BOTTOM_RIGHT_SMALL = 3;
/**
*
* #param string $path_to_image
*/
public function __construct($path_to_image = ''){
if (file_exists($path_to_image)){
$this->image = $path_to_image;
}
$this->type = Watermark::BOTTOM_RIGHT;
}
/**
*
* #param string $path_to_watermark
* #return boolean
*/
public function setWatermarkImage($path_to_watermark){
if (file_exists($path_to_watermark) && preg_match('/\.png$/i',$path_to_watermark)){
$this->watermark = $path_to_watermark;
return true;
}
return false;
}
/**
*
* #return boolean
*/
public function save(){
$this->output_file = $this->image;
return $this->process();
}
/**
*
* #param string $path_to_image
* #return boolean
*/
public function saveAs($path_to_image){
$this->output_file = $path_to_image;
return $this->process();
}
/**
*
* #param int $type
*/
public function setType($type){
$this->type = $type;
}
/**
*
* #return boolean
*/
private function process(){
$watermark = imagecreatefrompng($this->watermark);
if ($watermark){
$image = imagecreatefromjpeg($this->image);
if ($image){
switch ($this->type){
case Watermark::BOTTOM_RIGHT:
return $this->watermark_bottom_right($image, $watermark);
break;
case Watermark::CENTER:
return $this->watermark_center($image, $watermark);
break;
case Watermark::BOTTOM_RIGHT_SMALL:
return $this->watermark_bottom_right_small($image, $watermark);
break;
}
return true;
}else{
return false;
}
}else {
return false;
}
}
/**
*
* #param image resource $image
* #param image resource $watermark
* #return boolean
*/
private function watermark_bottom_right(&$image, &$watermark){
$watermark_width = imagesx($watermark);
$watermark_height = imagesy($watermark);
$size = getimagesize($this->image);
$dest_x = $size[0] - $watermark_width - 5;
$dest_y = $size[1] - $watermark_height - 5;
imagecopy($image, $watermark, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height);
imagejpeg($image,$this->output_file,100);
imagedestroy($image);
imagedestroy($watermark);
return true;
}
/**
*
* #param image resource $image
* #param image resource $watermark
* #return booelan
*/
private function watermark_center(&$image, &$watermark){
$size = getimagesize($this->image);
$watermark_x = imagesx($watermark);
$watermark_y = imagesy($watermark);
$im_x = $size[0];
$im_y = $size[1];
$cof = $im_x/($watermark_x*1.3); // 5/1 = im_x/(wx*cof) ; wx*cof = im_x/5 ; cof = im_x/wx*5
$w = intval($watermark_x*$cof);
$h = intval($watermark_y*$cof);
$watermark_mini = ImageCreateTrueColor($w, $h);
imagealphablending($watermark_mini, false);
imagesavealpha($watermark_mini,true);
ImageCopyResampled ($watermark_mini, $watermark, 0, 0, 0, 0, $w, $h, $watermark_x, $watermark_y);
$dest_x = $im_x - $w - (($im_x-$w)/2);
$dest_y = $im_y - $h - (($im_y-$h)/2);
imagecopy($image, $watermark_mini, $dest_x, $dest_y, 0, 0, $w, $h);
imagejpeg($image,$this->output_file,100);
imagedestroy($image);
imagedestroy($watermark);
return true;
}
/**
*
* #param image resource $image
* #param image resource $watermark
* #return boolean
*/
private function watermark_bottom_right_small(&$image, &$watermark){
$size = getimagesize($this->image);
$orig_watermark_x = imagesx($watermark);
$orig_watermark_y = imagesy($watermark);
$im_x = $size[0];
$im_y = $size[1];
$cof = $im_x/($orig_watermark_x*5); // 5/1 = im_x/(wx*cof) ; wx*cof = im_x/5 ; cof = im_x/wx*5
$w = intval($orig_watermark_x*$cof);
$h = intval($orig_watermark_y*$cof);
$watermark_mini = ImageCreateTrueColor($w, $h);
imagealphablending($watermark_mini, false);
imagesavealpha($watermark_mini,true);
ImageCopyResampled ($watermark_mini, $watermark, 0, 0, 0, 0, $w, $h, $orig_watermark_x, $orig_watermark_y);
//
$dest_x = $size[0] - $w - 5;
$dest_y = $size[1] - $h -5;
imagecopy($image, $watermark_mini, $dest_x,$dest_y , 0, 0, $w, $h);
imagejpeg($image,$this->output_file,100);
imagedestroy($image);
imagedestroy($watermark);
imagedestroy($watermark_mini);
return true;
}
}
use
$watermark = new Watermark('file_path.jpg');
$watermark->setWatermarkImage('watermark_path.png');
$watermark->setType(Watermark::CENTER);
$watermark->saveAs('file_path.jpg');
I created a function for generating and saving multiple image sizes when a user uploads an image via a web form. I was wondering, how can I better optimize my code (reduce the number of lines while still being easily readable)
save_image($_FILES['image'], $_GET['member_id'], 250, 300, large) //usage example
The Function
function save_image($file, $id, $sizex, $sizey, $pre){
$image=$_FILES['image']['name'];
$tmpName = $_FILES['image']['tmp_name'];
if ($image){
//get the original name of the file from the clients machine
$filename = stripslashes($_FILES['image']['name']);
//get the extension of the file in a lower case format
$extension = getExtension($filename);
$extension = strtolower($extension);
if (($extension == "jpg") || ($extension == "jpeg")){
$size = getimagesize($tmpName);
$max_x = 180;
$max_y = 300;
$img = imagecreatefromjpeg($file['tmp_name']);
$imagex = imagesx($img);
$imagey = imagesy($img);
$dim = max($imagex/$max_x, $imagey/$max_y);
$nx = $imagex/$dim;
$ny = $imagey/$dim;
$image = imagecreatetruecolor($nx, $ny);
imagecopyresampled($image, $img, 0, 0, 0, 0, $nx, $ny, $imagex, $imagey);
imagejpeg($image, '../images/uploads/'.$id.'-large.jpg');
//Make the thumb
$size = getimagesize($tmpName);
$max_x = 120;
$max_y = 230;
$img = imagecreatefromjpeg($file['tmp_name']);
$imagex = imagesx($img);
$imagey = imagesy($img);
$dim = max($imagex/$max_x, $imagey/$max_y);
$nx = $imagex/$dim;
$ny = $imagey/$dim;
$image = imagecreatetruecolor($nx, $ny);
imagecopyresampled($image, $img, 0, 0, 0, 0, $nx, $ny, $imagex, $imagey);
imagejpeg($image, '../images/uploads/'.$id.'-med.jpg');
$size = getimagesize($tmpName);
$max_x = 60;
$max_y = 115;
$img = imagecreatefromjpeg($file['tmp_name']);
$imagex = imagesx($img);
$imagey = imagesy($img);
$dim = max($imagex/$max_x, $imagey/$max_y);
$nx = $imagex/$dim;
$ny = $imagey/$dim;
$image = imagecreatetruecolor($nx, $ny);
imagecopyresampled($image, $img, 0, 0, 0, 0, $nx, $ny, $imagex, $imagey);
imagejpeg($image, '../images/uploads/'.$id.'-thumb.jpg');
}else{
return false;
}
}else{
return false;
}
return true;
}
First of all I noticed you create a variable and it has not been used.
$size = getimagesize($tmpName);
So why call a function and assign its value when it is not being used.
Secondly to get the width and height you don't have to do
$imagex = imagesx($img);
$imagey = imagesy($img);
So I would suggest you replace the 3 lines mentioned in this code with a single one
list($width, $height, $type, $attr) = getimagesize($tmpName);
Finally instead of duplicating the code create a function with parameters passed and call the function as it is shown in the comments above.
Also noticed that you send "large" i.e image size as the parameter then why are you running through the thumb and med cases. Would suggest use switch cases like change the save function to
function save_image($_FILES['image'], $_GET['member_id'], 250, 300, $type = "large")
and then use a switch on $type.
You have 3 times almost the same code
$size = getimagesize($tmpName);
$max_x = 60;
$max_y = 115;
$img = imagecreatefromjpeg($file['tmp_name']);
$imagex = imagesx($img);
$imagey = imagesy($img);
$dim = max($imagex/$max_x, $imagey/$max_y);
$nx = $imagex/$dim;
$ny = $imagey/$dim;
$image = imagecreatetruecolor($nx, $ny);
imagecopyresampled($image, $img, 0, 0, 0, 0, $nx, $ny, $imagex, $imagey);
imagejpeg($image, '../images/uploads/'.$id.'-thumb.jpg');
You should easily be able to make a function for that, that's a good start.
A lot of your code is redundant.
You could make a little function :
function repetitiveFunctionForPicture($image, $max_x, $max_y,$tmpName, $file){
$size = getimagesize($tmpName);
$img = imagecreatefromjpeg($file['tmp_name']);
$imagex = imagesx($img);
$imagey = imagesy($img);
$dim = max($imagex/$max_x, $imagey/$max_y);
$nx = $imagex/$dim;
$ny = $imagey/$dim;
$image = imagecreatetruecolor($nx, $ny);
imagecopyresampled($image, $img, 0, 0, 0, 0, $nx, $ny, $imagex, $imagey);
imagejpeg($image, '../images/uploads/'.$id.'-large.jpg');
}
which can be called like this :
repetitiveFunctionForPicture($image, 180, 300,$tmpName, $file);
I have a script that generates images from text using PHP. It's working fine except that I would like it to generate multiline text as well with differing colors. How can it be done using PHP, GD and Freetype? Below is the code I use to generate single line text images.
$textval = 'This is some text to be an image';
$textcolor = '666666';
$font="arial.ttf";
$size = 9;
$padding= 1;
$bgcolor= "ffffff";
$transparent = 0;
$antialias = 0;
$fontfile = $fontpath.$font;
$box= imageftbbox( $size, 0, $fontfile, $textval, array());
$boxwidth= $box[4];
$boxheight= abs($box[3]) + abs($box[5]);
$width= $boxwidth + ($padding*2) + 1;
$height= $boxheight + ($padding) + 0;
$textx= $padding;
$texty= ($boxheight - abs($box[3])) + $padding;
// create the image
$png= imagecreate($width, $height);
$color = str_replace("#","",$bgcolor);
$red = hexdec(substr($bgcolor,0,2));
$green = hexdec(substr($bgcolor,2,2));
$blue = hexdec(substr($bgcolor,4,2));
$bg = imagecolorallocate($png, $red, $green, $blue);
$color = str_replace("#","",$textcolor);
$red = hexdec(substr($textcolor,0,2));
$green = hexdec(substr($textcolor,2,2));
$blue = hexdec(substr($textcolor,4,2));
$tx = imagecolorallocate($png, $red, $green, $blue);
imagettftext( $png, $size, 0, $textx, $texty, $tx, $fontfile, $textval );
header("content-type: image/jpeg");
imagejpeg($png);
imagedestroy($png);
exit;
Add this function to wrap the text before it goes into your function.
function wrap($fontSize, $angle, $fontFace, $string, $width){
$ret = "";
$arr = explode(' ', $string);
foreach ( $arr as $word ){
$teststring = $ret.' '.$word;
$testbox = imagettfbbox($fontSize, $angle, $fontFace, $teststring);
if ( $testbox[2] > $width ){
$ret.=($ret==""?"":"\n").$word;
} else {
$ret.=($ret==""?"":' ').$word;
}
}
return $ret;
}
Source: http://www.php.net/imagettftext