Rotate letters in a string

I have the following php page (which is a generated image)


Generated by this function

		 function displayImage($input) {
			//let the browser know an image is coming
			header( "Content-type: image/png" );
			//create a blank image (width & height) and assign it to a variable
			$my_img = imagecreate( 200, 50 );
			//get the background ready (using RGB values)
			$background = imagecolorallocate( $my_img, 204, 255, 204 );
			//get the text color ready (using RGB values)
			$text_color = imagecolorallocate( $my_img, 0, 0, 0 );
			//line (also using RGB)
			$line_color = imagecolorallocate( $my_img, 0, 255, 0 );
			imagesetthickness ( $my_img, 5 );
			//create a border (start_x, start_y,end_x,end_y)
			imageline($my_img, 0, 0, 0, 50, $line_color);
	    	imageline($my_img, 200, 0, 200, 50, $line_color);
			imageline($my_img, 0, 0, 200, 0, $line_color);
			imageline($my_img, 0, 50, 200,50, $line_color);
			//center the text
			//width of character
			$fw = imagefontwidth(5);
			// # of characters     
			$l = strlen($input); 
			//input width         
			$tw = $l * $fw;              
			//image width
			$iw = imagesx($my_img);         
			
			$xpos = ($iw - $tw)/2;
			
			//place user input on the dynamic image (font size,x,y,text,font color)
			imagestring( $my_img, 5, $xpos, 8, $input, $text_color );
			// display image, or add second parameter to save it (imagepng($my_img,"Dynamic_image.png");)
			imagepng( $my_img );
			//free resources just to be sure
			imagecolordeallocate( $text_color );
			imagecolordeallocate( $background );
			imagedestroy( $my_img );
		 }

the next step is to rotate each character by 10 degrees, and was thinking something like…

		 function displayImage($input) {
			//let the browser know an image is coming
			header( "Content-type: image/png" );
			...
			// # of characters     
			$l = strlen($input); 
			...       
			...

                         //rotate each letter
                         for( $i = 0; $i <= $l; $i++ ) {
                         $char = substr( $input, $i, 1 );
                         // $char contains the current character
                         imagerotate($char, 10, 0);
                         }
                        ...
			imagedestroy( $my_img );
		 }

ok?

for( $i = 0; $i <= $l; $i++ ) {

wants to be

for( $i = 0; $i < $l; $i++ ) {

otherwise you’ll overflow the end of the string, because for a five-char string $l = 5, but $i needs to run from 0 to 4, not 0 to 5.

No idea on the rest. What happens when you try it?

ETA - just had a look. This code

$char = substr( $input, $i, 1 );
// $char contains the current character
imagerotate($char, 10, 0);

doesn’t seem to match up with the function definition

resource imagerotate ( resource $image , float $angle , int $bgd_color [, int $ignore_transparent = 0 ] )

It seems that if you want each character rotated by 10 degrees (as opposed to rotating the entire string / image) you’ll have to create an image of each character, rotate it, then merge it into the main image. Can’t you just use an italic font?

1 Like

oh, I guess it is a hard thing to do, sorry bout that, then is this more along the lines

function displayImage($input) {
//let the browser know an image is coming
header( "Content-type: image/png" );
...
// # of characters     
$l = strlen($input); 
...
...
//rotate each letter
    for ( $i = 0; $i < $l; $i++ ) {
    $char = substr( $input, $i, 1 );
    //char contains the current character so make $char an image
    $char = imagecreate(25,50);
    //wouldn't this rotate $char by 10 degrees and have the background be black?
    imagerotate($char, 10, 0);
    //add char to another image
    $my_img += $char;
    }
...
//display $my_img
imagepng( $my_img );
imagedestroy( $my_img );
}

Is this better?

Maybe use SVG?

<?php 
  declare(strict_types=1);
  error_reporting(-1);
  ini_set('display_errors', 'true');

  $title = 'Rotate Text 10 degrees';

?><!DOCTYPE HTML>
<html lang="en">
<head>
<title> <?= $title ?> </title>
<style type="text/css">
    b,
    .rot10 {
        -ms-transform: rotate(10deg); /* IE 9 */
      -webkit-transform: rotate(10deg); /* Chrome, Safari, Opera */
      transform: rotate(10deg);
    }  
 
    .svgBox {
        margin: 2em auto;
        border:dotted 4px red;
        font-size:42px;
    }
</style>
</head>
<body>
    <h1> <?= $title ?>
    <hr>
    
    <?php
      # SVG TEXT
            $no = '12345';
            $xx = '';
            $xPos = 1;
            $yPos = 30;
            for($i2=0; $i2<5; $i2++):
                # echo '<b>' .$no[$i2] .', </b>';
                $xPos += 30; 
                $yPos -= 5; 
                $tmp   = '<text 
                                        x="' .$xPos .'" 
                                        y="' .$yPos .'" 
                                        class="rot10">' .$no[$i2] .'</text>';
                $xx   .= $tmp;
            endfor;
          # echo '<br>'. htmlspecialchars($xx);
    
        echo '<svg class="svgBox" width="6em" height="1em">';
          echo $xx;
        echo '</svg>';
        
    ?>    

    <div style="font-size: 12px; width:88%; margin:2em auto; outline:dotted 2px red; padding:1em;">
      <?php highlight_file(__FILE__) ?>
    </div>

</body>
</html>

I will leave it up to you if you would like to convert the SVG to an image :slight_smile:

1 Like

dang, that seems so much easier!
I gotta put that on the back burner for now though (Was looking online for a tutorial as i’ve soo many questions.
like what does that declare thing do at the top, what do the php variables mean, why is the variable $i2 used in the for loop.

But the assignments calls for me to do it all with PHP, so im just trying to do a 10 degree rotation on each of the 5 characters, does this make sense?

//see how many characters are in the input
$l = strlen($input); 
//do stuff to each char
for ( $i = 0; $i < $l; $i++ ) {
    $char = substr( $input, $i, 1 );
    //char contains the current character so make $char an image
    $char = imagecreate(25,50);
    //wouldn't this rotate $char by 10 degrees and have the background be black?
    imagerotate($char, 10, 0);
    //add char to another image
    $my_img += $char; 
}
//display $my_img
imagepng( $my_img );

Thanks

Google "declare(strict_types=1); "

why is the variable $i2 used in the for loop.

Force of habit because a very early editor used to expand i into an if and I never found a solution except to use $i2 :slight_smile:

But the assignments calls for me to do it all with PHP,

It does only use PHP and SVG instead of an image. Have you a copy of the assignment question?
Here’s an update that uses a function:

<?php 
  declare(strict_types=1); // if and only if PHP 7
  error_reporting(-1); 
  ini_set('display_errors', 'true');

  $title = 'Rotate Text 10 degrees';

//================================================
function rotateText($input="No text to rotate???")
{
  $css	= 'ms-transform: rotate(10deg);' 			/* IE 9 */
	.'-webkit-transform: rotate(10deg);' 	/* Chrome, Safari, Opera */
	. 'transform:	rotate(10deg)';
	
  # SVG TEXT
   $xPos = 1;
   $yPos = 14;
   $xx   = '';
   for($i2=0; $i2<strlen($input); $i2++):
      $tmp = ''
           . '<text'
	    .  ' x="' .$xPos .'"'
	    ' y="' .$yPos .'"' 
	 .  ' style="' .$css.'">' .$input[$i2] .'</text>';

	 $xPos += 30; 
	 $yPos -= 5.2; 
         $xx   .= $tmp;
    endfor;

    $wid    = intval(strlen($input) / 0.6) .'em'; 
    $result = '<svg style="background-color: #ddd;" width="' .$wid .'" height="1em">'
	     .   $xx
             . '</svg>';
		        
    return $result;		        
} # ==============================================


?><!DOCTYPE HTML>
<html lang="en">
<head>
<title> <?= $title ?> </title>
<style type="text/css">
  #src {font-size: 12px; 
  width:88%; margin:2em auto; 
  outline: dotted 2px red; 
  padding:1em;
  background-color:#eee; color:#000;}
</style>
</head>
<body>
  <h1> <?= $title ?>
  <hr>
	
  <?php
    echo '<h4>' .rotateText() .'<h4>';
    echo '<h4>' .rotateText('This is a test to see if it works') .'<h4>';
    echo '<h4>' .rotateText('Looks OK?') .'<h4>';

    # echo '<div id="src">'; highlight_file(__FILE__); echo '</div>'; 
  ?>

</body>
</html>

http://scratchpad.io/dramatic-support-5538

sure, heres the question…
Create a self referencing form which will allow the user to enter a five character string. Legal characters are alphanumeric (A-Z,a-z, 0-9), $,^, and @. If the string is of the wrong length, or illegal characters are entered, return the user to the entry form with an appropriate error message.

Display the characters in a CAPTCHA style PNG image, with dimensions of 200px wide, 50px tall. The image should be comprised of:

5-10 random lines
50-100 random pixels
The users five character string
One background color
Three different foreground colors
Characters
Pixels
Lines
For each character of the user string added to the image, the angle of rotation should be increased by 10°. The angle of rotation for the first character can be in the range of 0-20°.

No characters in the user string should overlap in the image. The characters should appear in order from left to right. The font size should be at lease 20pt. Character spacing can be whatever you choose, while fitting all characters within the image dimensions.

The HTML form and final user output delivered to the client by your PHP script should be valid XHTML or HTML5. If you choose to include CSS, it must be in an external style sheet document.

Thanks for the help

I did wonder whether this is what it meant - not rotating each character by ten degrees, but rotating each character by ten degrees more than the previous character was rotated.

ok, your right, the assignment calls for what you said in terms of the angle.

is this ok?
http://php_class.teamluke.net/Assignment_8/index2.php
I changed the function to

	    function validate($input) {
		  $pattern = '/^[a-zA-Z0-9\^\$\@]{5}$/';
		  if(preg_match($pattern, $input)) {
			   return true;	  
		  } else {
			  return false;
		  }
	  }  

	function rotateText($input="Nope?")
	{
	  # SVG TEXT
	   $xPos = 1;
	   $yPos = 14;
	   $xx   = '';
	   for($i2=0; $i2<strlen($input); $i2++):
		  $tmp = ''
			   . '<text'
			.  ' x="' .$xPos .'"'
			. ' y="' .$yPos .'">' .$input[$i2] .'</text>';
	
		 $xPos += 30; 
		// $yPos -= 5.2; 
			 $xx   .= $tmp;
		endfor;
	
		$wid    = intval(strlen($input) / 0.6) .'em'; 
		$result = '<svg>'
			 .   $xx
				 . '</svg>';
					
		return $result;		        
	}

this is how I call it

if(validate($_POST['input']) == true) {

    echo "<div align='center'>".rotateText($_POST['input'])."</div>";

} else {
	////cant do this as headers allready sent, so use javascript
    //header('Location: index.php?error');
    echo "<script>";
	echo "window.location = 'index2.php?error'"; 
	echo "</script>";

}

heres the result


why does the text seem to be drooping gown (if every characters rotation is increased by 10 degrees, shouldn’t only its angle increase?

Svg text output displays text followed by a line feed.

Why did you Rem $yPos? It is hard coded to ensure the text output is on a single line.

Please also note that the svg output background source can be viewed so cannot be used as a CAPTHCHA.

ImageMagick library has a simple one liner to convert the svg source to an image.

ok, thanks.
I heard fropm the teacher andf he said to do it the first way only, but to use SVG for extra credit. So im trying to go back to my first function


the result


How would I rotate each character then?
Andd is there a way to make the font-size bigger?

ok, made a few changes to that annoying function…
This is the result


Thats just a image with no text inside it…
So now since ill add each character one at a time (rotated 10 degrees more than the last I thought this would work

//do stuff to each char
for ( $i = 0; $i = $l; $i++ ) {
$char = substr( $input, $i, 1 );
//char contains the current character so make $char an image
$char_img = imagecreate(25,50);
//create the 1 character image
imagestring($char_img, 5, ($xpos * 5), 20, $char, $text_color); 
imagepng($char_img); 
//wouldn't this rotate the image by 10 degrees more than the last 1?
imagerotate($char, ($i * 10), $background);
//add char to another image
$my_img += $char_img; 
}
//wouldn't this rotate the image by 10 degrees more than the last 1?
imagerotate($char, ($i * 10), $background);

You can’t call imagerotate() on a string like $char, I haven’t tried it but I would expect you to have to call it on $char_img.

I would think that would keep increasing the angle of rotation in the way that you need it to, yes. But if you’re creating a single image for each character, wouldn’t $xpos always be the same, because it’s the position within the single character image? Then you add that single character to your main image. I haven’t done any of this, can you achieve that by just using the += operator?

made a few changes to the for loop

for ( $i = 0; $i < $l; $i++ ) {
$char = substr( $input, $i, 1 );
//char contains the current character so make $char an image
$char_img = imagecreate(25,50);
imagestring($char_img, 5, $xpos, 20, $char, $text_color); 
imagepng($char_img); 
//wouldn't this rotate $char by 10 degrees and have the background be black?
imagerotate($char_img, ($i * 10), 0);
//add char to another image
//$my_img += $char_img; 
$my_img = $my_img + $char_img;
}

The result is a blank page though

ok, checked the error log on my server and found

20161115T153616: php_class.teamluke.net/Assignment_8/index.php 
PHP Warning:  imagepng(): gd-png error: no colors in palette in /hermes/walnaweb10a/b2054/moo.teamluke/PHP_Class/Assignment_8/index.php on line 59 
PHP Warning:  imagepng(): gd-png error: no colors in palette in /hermes/walnaweb10a/b2054/moo.teamluke/PHP_Class/Assignment_8/index.php on line 59 
PHP Warning:  imagepng(): gd-png error: no colors in palette in /hermes/walnaweb10a/b2054/moo.teamluke/PHP_Class/Assignment_8/index.php on line 59 
PHP Warning:  imagepng(): gd-png error: no colors in palette in /hermes 

But heres line 59

imagepng($char_img); 

But whats that mean?

ok, made some changes (I thought the error was because I didn’t use imagefill()
so I changed the function to

 function displayImage($input) {
$background = imagecolorallocate( $my_img, 255, 230, 230 );
$text_color = imagecolorallocate( $my_img, 102, 0, 0 );
...
...
	for ( $i = 0; $i < $l; $i++ ) {
	$char = substr( $input, $i, 1 );
	//char contains the current character so make $char an image
	$char_img = imagecreate(25,50);
	//fill the image with background
        imagefill( $char_img, 0, 0, $background);
	imagestring($char_img, 5, $xpos, 20, $char, $text_color); 
	imagepng($char_img); 
	//wouldn't this rotate $char by 10 degrees and have the background be black?
	//imagerotate($char_img, ($i * 10), 0);
	//add char to another image
	//$my_img += $char_img; 
	//$my_img = $my_img + $char_img;
	}
...
}

the result is a blank page, when I check the error logs…I see

PHP Warning: imagepng(): gd-png error: no colors in palette in /hermes/walnaweb10a/b2054/moo.teamluke/PHP_Class/Assignment_8/index.php on line 65

Are the two variables available in the for loop?

Yes, they will be available inside the loop.

Looking at the doc for imagepng(), it appears to output the image resource in the argument to the browser, in .png format. I suspect this isn’t what you want to do, as you’ll be needing to copy it to the complete image later.

Once you’ve used imagestring() to create the image of the individual character, then used imagerotate() to rotate it, wouldn’t you use imagecopy() to copy it to your “main” image in the correct location, then outside the loop, output your main image?

1 Like

wow, didn’t even know about imagecopy()
I changed the function to

function displayImage($input) {
//create a blank image (width & height) and assign it to a variable
$my_img = imagecreate( 200, 50 );
//get the background ready (using RGB values)
$background = imagecolorallocate( $my_img, 255, 230, 230 );
//get the text color ready (using RGB values)
$text_color = imagecolorallocate( $my_img, 102, 0, 0 );
//line (also using RGB)
$line_color = imagecolorallocate( $my_img, 128, 0, 0 );
//fill the image with background
imagefill( $my_img, 0, 0, $background);
imagesetthickness ( $my_img, 5 );
//create a border (start_x, start_y,end_x,end_y)
imageline($my_img, 0, 0, 0, 50, $line_color);
imageline($my_img, 200, 0, 200, 50, $line_color);
imageline($my_img, 0, 0, 200, 0, $line_color);
ageline($my_img, 0, 50, 200,50, $line_color);
//add random lines
$line_color = imagecolorallocate( $my_img, 204, 0, 0 );
imagesetthickness ( $my_img, 2 );
imageline($my_img, rand(0,200), rand(0,50), rand(0,200), rand(0,50), $line_color);
imageline($my_img, rand(0,200), rand(0,50), rand(0,200), rand(0,50), $line_color);
imageline($my_img, rand(0,200), rand(0,50), rand(0,200), rand(0,50), $line_color);
imageline($my_img, rand(0,200), rand(0,50), rand(0,200), rand(0,50), $line_color);
imageline($my_img, rand(0,200), rand(0,50), rand(0,200), rand(0,50), $line_color);
//add a few pixels
$line_color = imagecolorallocate( $my_img, 0, 0, 0 );
	for($i=0;$i<=1000;$i++) {
		imagesetpixel($my_img, rand(0,200),rand(0,50), $line_color);
	}
// # of characters     
$l = strlen($input); 
//do stuff to each char
	for ( $i = 0; $i < $l; $i++ ) {
		$char = substr( $input, $i, 1 );
		//char contains the current character so make $char an image
		$char_img = imagecreate(10,50);
		//fill the image with background
	        imagefill( $char_img, 0, 0, $background);
		imagestring($char_img, 5, 0, 20, $char, $text_color); 
	        //wouldn't this rotate $char_img by 10 degrees and set its background to the main images
		imagerotate($char_img, ($i * 10), $background);
		//copy new image to main image
               //imagecopy ( resource $dst_im , resource $src_im , int $dst_x , int $dst_y , int $src_x , int $src_y , int $src_w , int $src_h )
		imagecopy( $my_img, $char_img, 20, 50, 0, 0, 10, 50);
	}
//place user input on the dynamic image (font size,x,y,text,font color)
// display image, or add second parameter to save it (imagepng($my_img,"Dynamic_image.png");)
imagepng( $my_img );
//free resources just to be sure
imagecolordeallocate( $my_img, $text_color );
imagecolordeallocate( $my_img, $background );
imagedestroy( $my_img );
}

The result:


So, im not getting an error, but why do the five images not seem to be added to the main image?

Don’t know, but at the very least you’ll need to not put them all in the same destination x-y position, or they’ll overwrite each other. You’ll need to get the width of the $char_img after it’s been rotated, and increment the destination position by that much so they don’t overlap.

ETA - Oh, I do know. See if you can spot it. Look at the size of the main image you created in the first place, and compare that to the destination co-ordinates that you copy the $char_img to.