I am trying to centre a line of text, of known width along a line specified as start and end coordinates.
The purpose is to write text around a polygon, so the lines are not always horizontal.
Currently I have the following function which takes the start x and y and the finish x and y of a line and the width of the text (in pixels).
The text will be drawn starting at x1, y1 at the correct angle to follow the line.
To centre this text on the line I have tried to calculate left padding in pixels which should be applied to x1, y1 to move the text the correct amount from its left origin.
The following function is my attempt at modifying the coordinates to implement the above concept. But its not quite right. I end up with text slightly off line, sometimes x is out sometimes y, depends on the face but neither x or y is correct.
private function CenterTextOnLine(&$x1, &$y1, &$x2, &$y2, $width)
{
$distance = $this->getDistance($x1, $y1, $x2, $y2);
//calculate the left padding required in pixels
$padding = ($distance - $width) / 2;
//what factor do we need to alter x1, y1 by?
$factor = ($distance / $padding);
$gradient = ($y2-$y1)/($x2-$x1); //gradient to alter y by
$x1 += abs($x2-$x1) / $factor; //move start x by factor
$y1 += ($gradient / $factor); //add factor of gradient to start y
return;
}
If anyone can see my error, or knows an algorithm for this purpose, I would very much appreciate your input.
Thanks for your time.
I think this should work:
$y1 += ($y2-$y1)/$factor;
$k = $how_much_distance_I_want/sqrt(1+$gradient*$gradient);
$x1 += $k*$gradient;
$y1 -= $k;
return;
While you are at it, I think the abs in
$x1 += abs($x2-$x1) / $factor;
can lead to unexpected results in case ($x2-$x1) is negative (maybe better to leave it without abs), and depending on how php deals with infinities, you might want to have a plan for the case that $factor === 0.
Related
I want the eyes in the image to be horizontal
$rightEyeY = 446;
$rightEyeX = 625;
$leftEyeY = 433;
$leftEyeX = 733;
// Get middle point of two eyes
$y = $rightEyeY - $leftEyeY;
$x = $rightEyeX - $leftEyeX;
$angle = rad2deg(atan2($y, $x)) - 180; // -6.8 degrees
$manager = new ImageManager(['driver' => 'imagick']);
$image = $manager->make('image.jpg')->rotate($angle);
$a = $angle * pi() / 180.0;
$cosa = cos($a);
$sina = sin($a);
$x = $x * $cosa - $y * $sina; // This one calculates x of the middle point not each eye.
$y = $x * $sina + $y * $cosa; // This one calculates y of the middle point not each eye.
I want those variables at the top
FROM:
rightEyeY = 446
rightEyeX = 625
TO:
rightEyeY = 695
rightEyeX = 510
When I rotate it in Photoshop by -6.86 degrees, it rotates counterclockwise. But in Imagick, it rotates clockwise when using -6.86.
The original image (RightEye Point: 625x446):
The rotated image in Photoshop (RightEye Point: 640x432):
The rotated image with Imagick (RightEye Point: 695x510):
After rotation, the width/height of the image is changing. So the formula for getting the right eye point doesn't give us the exact point.
How can I fix it and get the right eye point?
I'm trying to convert WGS 84 coordinates into pixels using web mercator projection. I want to print the position on a given map. I came across a PHP function which works fine if the map is an image of the whole world. I've been trying hard to extend this function so it also works if the map is just a clip (e.g. North America). I already found a solution for calculating the width but I failed to adjust the height calculation. How do I have to change the function?
($top is the top left corner of the map image [Array], $bottom the bottom right corner / $this->width is map width, $this->height is map height)
function cor($lat = null, $lon = null, $top, $bottom) {
// Width
$width = ($lon-$bottom[1]) * $this->width/($top[1]-$bottom[1]);
// Height
$latrad = ($lat * M_PI) / 180;
$mercN = log(tan((M_PI / 4) + ($latrad / 2)));
$height = (($this->height / 2) - ($this->width * $mercN / (2 * M_PI)));
return Array($width, $height);
}
Thanks very much in advance! :)
I am working on a wheel chart design, I need help in positioning the text on the 360 wheel.
The wheel have 12 sections, each one of 30 degree. The text's offset from the circle outer line should be equal (or similar at least). like in the image below I have mocked up what I need in final result.
So far, What I have tried is splitting each section into separate variable e.g.
$section1_startX = 50;
$section1_endX = 70;
$section1_startY = 310;
$section1_endY = 480;
and then to place text
imagettftext($im, 15, 0, $section1_startX, $section1_startY, $black, $font, "05");
but this is to find/calculate pixels of each line I need to place.
I am sure there is better, dynamic and smart way to put the text at x,y positions based on its values in 360 circle.
can you please help me regarding?
Hi I think you want to find a Point on a given circle with a given degree. Here is a function for calculating point on a circle. I think you can convert this to any other language easily.
public static PointF PointOnCircle(float radius, float angleInDegrees, Point origin)
{
//radius -> Radius of Circle & Origin -> Circle Centre.
// Convert from degrees to radians via multiplication by PI/180
float x = (float)(radius * Math.Cos(angleInDegrees * Math.PI / 180F)) + origin.X;
float y = (float)(radius * Math.Sin(angleInDegrees * Math.PI / 180F)) + origin.Y;
return new PointF(x, y);
}
I have a waveform player but uses flash to generate a PNG waveform which isn't even accurate so I decided to use PHP and installed LAME Encoder on my CentOS 6.4. I found this script on github 'afreiday/php-waveform-png' and it works, based on the file you upload you get the waveform of the audiotrack. The only problem is that it's 'peaky'. An example:
As you can see in the example (a EDM track with a singing part and bassdrop hard clap part) it's just not very useful, you can't scroll to the break because you can't see where it is. Unless you look closely at the very red area in the middle. So I know it's out there and the script works, but as I said before, it's just to 'peaky' and random.
What I want is something like the picture below where you can obviously see the different parts in the track (taken from zippyshare with the same audiofile:
The part of the code where it draws the lines seperately looks like this:
$v = (int) ($data / 255 * $height);
if (!($v / $height == 0.5 && !$draw_flat))
// draw the line on the image using the $v value and centering it vertically on the canvas
imageline(
$img,
// x1
(int) ($data_point / DETAIL),
// y1: height of the image minus $v as a percentage of the height for the wave amplitude
$height * $wav - $v,
// x2
(int) ($data_point / DETAIL),
// y2: same as y1, but from the bottom of the image
$height * $wav - ($height - $v),
imagecolorallocate($img, $r, $g, $b)
);
Where $v is the volume.
Now I tried adding something to get rid of the peaks but that didn't work out well:
if(isset($previous)) {
$diff = abs($v-$previous);
$perc = $diff / $v * 100;
if($perc>40) {
$v = $previous;
}
}
Ofcourse that didn't do the trick but I thought I had something to work with there but it's not. Anybody an idea on how to solve this problem or had a similar experience?
If an alternative to that script is better, let me know. Can't figure this out.
Our dev server was recently upgraded to PHP v5.2.13. With that upgrade we have found that our png images are having kerning (letter spacing) problems. We've tried numerous fonts and haven't found a solution yet.
We are creating images using the GD library and writing text to the images using font files and the imagettftext() or imagefttext() functions.
Has anyone else run into this? Am I misunderstanding something or should this be submitted to PHP as a bug? Are there any cool workarounds I haven't thought of yet?
Here's an example of the new and old tahoma bold. Other fonts (bold and non-bold) have the same problem. Some letters and numbers seem like they're off-center or something like that.
Bad - new PHP
Good - old PHP v5.2.11 (the words are slightly different because this is our dev server and the other one is the live server)
"Tracking" is a similar term for how tight or loose text is set. You might have better luck googling for that, such as this result.
Kerning didn't work for us thanks to the font we used, so we had to put in manual kerning for specific letter combinations like AV, AW ...etc.
/**
* This function lets you write a string with your own letter spacing ($t)
* and kern specific letter combinations like AV
*
* #param type $im An image resource, returned by one of the image creation functions
* #param type $size The font size. Depending on your version of GD, this should be specified as the pixel size (GD1) or point size (GD2).
* #param type $angle The angle in degrees, with 0 degrees being left-to-right reading text. Higher values represent a counter-clockwise rotation. For example, a value of 90 would result in bottom-to-top reading text.
* #param type $t Letter Spacing
* #param type $k Kerning Spacing
* #param type $x The coordinates given by x and y will define the basepoint of the first character (roughly the lower-left corner of the character). This is different from the imagestring(), where x and y define the upper-left corner of the first character. For example, "top left" is 0, 0.
* #param type $y The y-ordinate. This sets the position of the fonts baseline, not the very bottom of the character.
* #param type $color The color index. Using the negative of a color index has the effect of turning off antialiasing. See imagecolorallocate().
* #param type $font The path to the TrueType font you wish to use.
* #param type $text Text to write/print to the image
*/
function ImageTTFTextWithSpacing($im, $size, $angle, $t, $k, $x, $y, $color, $font, $text) {
$numchar = strlen($text);
for($i = 0; $i < $numchar; $i++) {
# Assign character
$char[$i] = substr($text, $i, 1);
//Top is wider than bottom of character
$up = ['Y','V','W'];
//Bottom is wider than top of character
$down = ['A'];
//From the second letter on
if( $i > 0 &&
//check whether we have TOP and BOTTOM type character
//next to each other so we need to adjust spacing
((in_array($char[$i], $up) && in_array($char[$i-1], $down)) ||
(in_array($char[$i-1], $up) && in_array($char[$i], $down)) )) {
$w -= $k;
}
# Write character
imagettftext($im, $size, $angle, ($x + $w + ($i * $t)), $y, $color, $font, $char[$i]);
# Get width of character
$width = imagettfbbox($size, $angle, $font, $char[$i]);
$w = $w + $width[2];
}
}