imagettftext(): calculate font size to ensure text fits image width - php

I'm using imagettftext() to write dynamic text on an image and I want it to fit my image width.
How can I calculate the font size by the text lenght?

You can calculate the bounding box of TTF text before outputting it with the imagettfbbox function. Unfortunately there is no direct way of scaling to fit a width, so you'll have to do it yourself.
One way of doing it is to pass the text with a default font size of, say 20, to imagettfbbox and retrieve the width from it. You can then calculate how much smaller or bigger the text should be to fit the size you want by calculating a scale factor:
scale = targetWidth / bboxWidth;
Then draw the text with the proper size:
fontSize = 20 * scale;
using the imagettftext function. Fonts don't scale 100% perfectly this way, but you'll get a very good approximation.
See the documentation of imagettfbox here.

while (itsTooBigAccordingToimagettftext() && $fontSize > 0) {
$fontSize--;
}

Related

How does IMG_CROP_THRESHOLD work compared to IMG_CROP_SIDES?

What is the main difference between IMG_CROP_THRESHOLD and IMG_CROP_SIDES?
I have been trying to roughly crop the background out of a photo of a document, but either way I am not able to get the outcome I am aiming for.
Also, I took the null, 16777215 from https://www.php.net/manual/en/function.imagecropauto.php, but I honestly don't understand what they actually do. I would have expected to put something like 0.1, #FFFFFF to crop out a background that is white or close to it. What is the null, 16777215 all about?
$cropped = imagecropauto($img, IMG_CROP_THRESHOLD, null, 16777215);
$cropped = imagecropauto($img, IMG_CROP_SIDES);
IMG_CROP_SIDES works by automatically calculating the average color of the pixels around the border of an image an crops off anything within 50% of that value. -
Correction
IMG_CROP_SIDES uses gdGuessBackgroundColorFromCorners which essentially finds the distance from the corner colors to the closest color in the existing palette and then uses this distance for pixel selection to crop.
IMG_CROP_THRESHOLD does NOT calculate the background color but it does provide more flexibility in this calculation as it allows the dev to specify the border color and also the threshold. Documentation is poor on the threshold stating it's a percentage however this actually means an integer or float between 0 and 100 (e.g. not 0.25 but 25).
If IMG_CROP_SIDES is cutting into a bright image, use IMG_CROP_THRESHOLD instead.
For example with a 25 threshold - Approx anything lighter than #E8E8E8 is border.
$cropped = imagecropauto($img, IMG_CROP_THRESHOLD, 25, 16777215);
https://github.com/libgd/libgd/blob/167ea1f4f0003f3e9f7ca1e586189e99cf33d47f/src/gd.c#L460
https://github.com/libgd/libgd/blob/1e47a89a65d49a9003d8365da4e26a7c1a32aa51/src/gd_crop.c#L112

text resize with php while using GD functions

I did found a topic similar to this, but I do not know if the solution is the same. So here is my question:
I'm using the GD functions to bild a web card generating program. The thing is that the card's backgound is generating by the $image = imagecreatefrompng(); function.
The card need's also a $cardname as "title" and a $desription as desription. For that I used the imagettftext(); function. But there is a problem, the card's size is 333x485, I need the text to be resized in order to fit in the background without resizing its height, but only the width!
To be more to the point, the $cardname should have width = 240 and height = 34, but if it doesn't fit, it goes off the background, I need a function that will resize its width in order to fit in 240px and leave the height to 34px always!
To understand it more look here: http://yugiohcardmaker.net. in the "name" you can add as much text you like, it will always fit in and in the right width and height!
I'm not going to try and code this as it will take too long, but here's the basic process:
Get the size of the bounding box for your text with imagettfbbox();
Create a new image with imagecreatetruecolor();
Write your text into your new image with imagettftext();
Use imagecopyresampled() to copy the new image with your text to your existing card, setting the parameters to shrink the width but not the height.
Note: the bounding box parameters returned by imagettfbbox()) can be fiddly to work with
You'll also need to be careful about alphablending and background colors to ensure that only your text pixels are copied.
Good luck!

php how to fit a text into a box

I have the bounds of a rectangular box.
Is it possible to fit a text (with custom font) into the box while not knowing the text size.
I mean, is there a php function which sets the proper text size so that the text is fitted into the user-defined box?
I do not need text wrapping.
The only functions I found are imagettfbbox and imagettftext.
imagettfbbox does exactly the opposite(gives the bounds, provided a font size) while imagettftext is used to write text on an image, only if fontSize is known.
Are you using php gd? If so, then I would use imagettfbbox. Just define all the parameters except size. Then outside of that loop on size until it is small enough to fit in your defined space. I've done this before. It doesn't do any actual image creative in memory, so it's very fast (much faster than actually creating the image).
for($size=40;$size>5;$size--){
$sizearray=imagettfbbox ( $size , 0- , 'font.ttf' , $message );
$width=$sizearray[0] + $sizearray[4];
if($width<$threshold/*you define*/){
//you've got your $size
break;
}
}

Resize panoramic image to fixed size

I want to resize the images to fixed width and height (i.e. 150px). However, theres a problem, if there is lots of difference in height and width of original photo (for example, panoramic photo), the resized thumbnail looks bad. Is there any any smart solution to resize the photos to a fixed width and height? For example, please have a look at this
image:
Here's my code:
<?php
$params = getimagesize($tempFile);
$width = $params[0];
$height = $params[1];
$newwidth=150;
$newheight= 150;
$tmp=imagecreatetruecolor($newwidth,$newheight);
imagecopyresampled($tmp,$src,0,0,0,0,$newwidth,$newheight,$width,$height);
imagejpeg($tmp,$img_name,80);
imagedestroy($src);
imagedestroy($tmp);
?>
Is there any smart way to resize the images in smart way?
Thanks.
There's a smart solution, it's called Seam Carving, and if your server supports ImageMagick, you do it like this:
<?php
$im = new Imagick( 'image.jpg' );
$im->liquidRescaleImage( 600, 100, 3, 25 );
header( 'Content-Type: image/jpg' );
echo $im;
?>
Or alternatively, if it doesn't support, use exec() (carefully) in order to pass image as an argument to executable which can perform seam carving.
BTW it looks like twitpic just crop's the squared image extract.
In one of my previous projects I used following code:
if ($image->width > $image->height){
//crop image in proportions 4/3, then resize to 500x300 (or proportionally lower resolution),
//sharp it a little and decrease quality.
//I used one of the Yii framework extensions.
$image->crop($image->width, $image->width/4*3)->resize(500, 300, Image::WIDTH)->sharpen(15)->quality(75);
}
It looks like twitpic is finding out how long the short axis is, then takes a square centered on the original image with sides equal to the short axis length, then shrinking that down to 150x150.
Not, resmaple, get only center 150x150 pixels.
You will need to calculate the appropriate coordinates for the original area you want to copy:
imagecopyresampled($tmp,$src,0,0,[THIS VALUE],[THIS VALUE],$newwidth,$newheight, [THIS VALUE],[THIS VALUE]);
As of now, you take the area from 0,0 (x,y) to width,height (x,y) of the original area and try to cramp it into 150x150.
you will need to calculate which of width and height that is the "biggest" and crop that and make sure that the ratio is the same as your resulting image (in your case, ratio is 1.0 because of 150x150).
In your example, where width is 1050 and height is 317 pixels so you want a portion of the original image that is 317x317 (ratio 1.0), you need to:
subtract 317 from 1050 = 733; // this is the excessive area for both sides
divide by 2 =~ 366; // to get the excessive area for one side
Now, use first x coordinate 366, to start 366 pixels from the left.
Use second x coordinate 1050 - 366 start 366 pixels from the right.
So your example should be (just guessing here):
imagecopyresampled($tmp,$src,0,0,366,0,$newwidth,$newheight, $width - 366, 0);
You will of course need some logic in order to calculate this correctly for any other size.

Imagemagick desaturate black/white?

Would like to turn this into black and white.. can't figure out what to use from imagick..
$handle_data = file_get_contents('http://www.bungie.net/Stats/Reach/Nightmap.ashx');
//http://www.bungie.net/Stats/Halo3/Nightmap.ashx
$img = new Imagick();
$img->readImageBlob($handle_data);
$img->writeImage('nightmap/'.$time.'.gif');
Using Imagick::modulateImage could be a quick&dirty solution. Dirty because color theory is a rather complex field, and there can be done more to create grayscale images than just desaturating the image (like applying different weights to the single color channels).
bool Imagick::modulateImage (float $brightness , float $saturation , float $hue)
Given an image, keep brightness and hue at 100%, while setting saturation to 0%. There is an example at the bottom of the documentation page that does exactly that.
There's a much better (and just as simple) solution: $im = $im->fxImage('intensity');
That applies a function to the image, where intensity is equal to 0.299*red+0.587*green+0.114*blue.
That formula is based on how our eyes are more sensitive to different colours, and as such the difference between that and a "flat" grayscale image really is night and day.
More details here:
http://php.net/manual/en/imagick.fximage.php
http://www.imagemagick.org/script/fx.php

Categories