Jump to content

Image manipulation - skewing text, text on a curve


Recommended Posts

Sample code for distorting text (as seen in my sig)

 

<?php
/*****************************************************
***              skewedtext.php                    ***
***                                                ***
***          Author : Barand June 2007             ***
******************************************************/

$text = $_GET['text'];

/**
* create the src image containing the text
*/
$src = imagecreate(250, 40);
$white = imagecolorallocate($src, 0xFF, 0xFF, 0xFF);
$black = imagecolorallocate($src, 0x00, 0x00, 0x00);
imagettftext($src, 24, 0, 50, 30, $black, 'c:/windows/fonts/arial.ttf', $text);

/**
* Create the destination image to receive the skewed text;
*/

$dest = imagecreate(250, 60);
$yellow = imagecolorallocate($dest, 0xFF, 0xFF, 0x00);
$red = imagecolorallocate($dest, 0xFF, 0x00, 0x00);


/**
* scan all pixels in the src image
*/

for ($y = 0; $y < imagesy($src); $y++)
{
    for ($x = 0; $x < imagesx($src); $x++)
    {
        $c = imagecolorat($src, $x, $y);       // get the pixel colour
        if ($c == $black)                      // is it part of the text?
        {
            /**
            * skew the text horizontally
            *   pixels pushed to the left (negative offset)
            *   zero pixels at the bottom to a max of maxskew at the top
            */
            $maxskew = -20;
            $offset = $maxskew * (imagesy($src) - $y) / imagesy($src);
            $xd = $x + $offset;
            
            /**
            * calc y pos on a sine curve
            *   amplitude controls the amount of vertical displacement
            *   frequency determines the number of waves 
            */
            $amp = 8;
            $freq = 5;
            $yd = $amp * sin($freq * deg2rad($x)) + $y + 10;     // add 10 to push image away from top edge
            
            /**
            * place pixel in dest image 
            */
            imagesetpixel($dest, $xd, $yd, $red);         
        }
    }
}
/**
* output the image 
*/
header("content-type: image/png");
imagepng($dest);
imagedestroy($src);
imagedestroy($dest);
?>

 

To use

 

<img src="skewedtext.php?text=HelloWorld">

 

That method uses displacement of pixels. I was recently asked about fitting text to an arc. The easiest way to do this is mathematically calculate the position and angle of the individual characters and place them using imagettftext().

 

Example

<?php
/*********************************************
* Fitting text to arc
*
* TextOnArc
* Author   :  Barand July 2007
**********************************************/
$im = imagecreate(400,400);

$white = imagecolorallocate($im, 0xFF, 0xFF, 0xFF);
$grey  = imagecolorallocate($im, 0xCC, 0xCC, 0xCC);
$txtcol = imagecolorallocate($im, 0xFF, 0x00, 0x00);

$s = 220;
$e = 320;
$r = 100;
$cx = 200;
$cy = 200;
$txt = 'Hello World';
$font = 'c:/windows/fonts/arial.ttf';


imagearc($im,$cx,$cy,$r*2,$r*2,$s,$e,$grey);
textOnArc($im,$cx,$cy,$r,$s,$e,$txtcol,$txt,$font,12);

header("content-type: image/png");
imagepng($im);
imagedestroy($im);

function textOnArc($im,$cx,$cy,$r,$s,$e,$txtcol,$txt,$font,$size)
{
    $tlen = strlen($txt);
    $arclen = deg2rad($e - $s);
    $perChar = $arclen/($tlen-1);              // monospaced text - you may want to measure each char and
                                               // space proportionally
    for ($i=0, $theta = deg2rad($s); $i < $tlen; $i++, $theta+=$perChar)
    {
        $ch = $txt{$i};
        $tx = $cx + $r*cos($theta);
        $thank you = $cy + $r*sin($theta);
        $angle = rad2deg(M_PI*3/2 - $theta);
        imagettftext($im, $size, $angle, $tx, $thank you, $txtcol, $font, $ch);
    }
}
?>

 

Building on the above code, this next one spaces the text proportionally based on the charater width. An additional function is provided to print the the text on the inside of the curve (useful for downward curving arcs). The text in both cases is centered on the arc. An extra padding parameter to increase character spacing has been added as text can be a bit cramped on the inside of curves.

<?php
/*********************************************
* Fitting text to arc
*
* TextOnArc
* Author   :  Barand August2007
**********************************************/
$im = imagecreate(400,400);

$white = imagecolorallocate($im, 0xFF, 0xFF, 0xFF);
$grey  = imagecolorallocate($im, 0xCC, 0xCC, 0xCC);
$txtcol = imagecolorallocate($im, 0xFF, 0x00, 0x00);

$r = 150;
$cx = 200;
$cy = 200;
$txt1 = 'Text on an Arc';
$txt2 = 'by Barand';
$font = 'arial.ttf';
#$font = 'bauhausm.ttf';
$size = 48;

imagearc($im,$cx,$cy,$r*2,$r*2,$s,$e,$grey);
$pad = 2;                      // extra char spacing for text
$s = 180;
$e = 360;
textOnArc($im,$cx,$cy,$r,$s,$e,$txtcol,$txt1,$font,$size,$pad);
$pad = 6;                      // extra char spacing for text
$s = 0;
$e = 180;
textInsideArc($im,$cx,$cy,$r,$s,$e,$txtcol,$txt2,$font,$size,$pad);

header("content-type: image/png");
imagepng($im);
imagedestroy($im);

function textWidth($txt, $font, $size)
{
    $bbox = imagettfbbox($size,0,$font,$txt);
    $w = abs($bbox[4]-$bbox[0]);
    return $w;
}

function textOnArc($im,$cx,$cy,$r,$s,$e,$txtcol,$txt,$font,$size, $pad=0)
{
    $tlen = strlen($txt);
    $arccentre = ($e + $s)/2;
    $total_width = textWidth($txt, $font, $size) - ($tlen-1)*$pad;
    $textangle = rad2deg($total_width / $r);
    $s = $arccentre - $textangle/2;
    $e = $arccentre + $textangle/2;
    for ($i=0, $theta = deg2rad($s); $i < $tlen; $i++)
    {
        $ch = $txt{$i};
        $tx = $cx + $r*cos($theta);
        $ty = $cy + $r*sin($theta);
        $dtheta = (textWidth($ch,$font,$size))/$r;
        $angle = rad2deg(M_PI*3/2 - ($dtheta/2 + $theta) );
        imagettftext($im, $size, $angle, $tx, $ty, $txtcol, $font, $ch);
        $theta += $dtheta;
    }
}

function textInsideArc($im,$cx,$cy,$r,$s,$e,$txtcol,$txt,$font,$size, $pad=0)
{
    $tlen = strlen($txt);
    $arccentre = ($e + $s)/2;
    $total_width = textWidth($txt, $font, $size) + ($tlen-1)*$pad;
    $textangle = rad2deg($total_width / $r);
    $s = $arccentre - $textangle/2;
    $e = $arccentre + $textangle/2;
    for ($i=0, $theta = deg2rad($e); $i < $tlen; $i++)
    {
        $ch = $txt{$i};
        $tx = $cx + $r*cos($theta);
        $ty = $cy + $r*sin($theta);
        $dtheta = (textWidth($ch,$font,$size)+$pad)/$r;
        $angle = rad2deg(M_PI/2 - ($theta - $dtheta/2));
        imagettftext($im, $size, $angle, $tx, $ty, $txtcol, $font, $ch);
        $theta -= $dtheta;
    }
}


?>

Link to comment
Share on other sites

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.