I am trying to create a text overlay on an image using php and iMagick. The crucial part is that I want the text size to scale to fill a predefined box, so I do not want to set a fixed font size. I have found the code at ImageMagick - Text into rectangle but need to adapt this code for the iMagick. I seem to be able to do everything except the crucial part -size ${width}x100
Here's the code I have, with a few things that I have tried commented out
$draw = new ImagickDraw();
$draw->setGravity (Imagick::GRAVITY_SOUTHEAST);
$draw->setFont('Bookman-DemiItalic');
//$draw->setFontSize( 30 ); // don't want to set a fixed font size
$draw->setTextUnderColor('#00000075');
//$draw->setSize(0, 0, 200, 200); // error: Call to undefined method ImagickDraw::setSize()
//$draw->setViewBox(200, 200, 800, 800); // appears to do nothing
//$draw->rectangle(200,200,300,300); // this just draws a separate white box
$draw->annotation(100, 100, 'The quick brown fox jumps over the lazy dog'); // works, but it's a default (small) text size and the box simply fits the exact text with no border
$img->drawImage($draw);
Is there a size option that somehow I've missed in the docs?
Note that How can I wrap text using Imagick in PHP so that it is drawn as multiline text? partially addresses this issue, but it doesn't appear to offer scaling of the text to fit a fixed size box, rather a wrapping of text if the selected font size would cause the text to overrun. Though maybe I have misunderstood - I will give it a try!
Related
I have an 8 bit PNG (original is here: https://i.ibb.co/s3024Y8/1000x1500-autumn-leaves.png) and I want to change the colour of the leaves.
I have a list of the hex colours that need to be changed and a list of the colours they need to be changed to - all to be done dynamically. I'm working towards a solution that has to work off those lists - but that can wait. For this question, being able to change the colour of just one leaf will do.
After changing the colour of the leaf I need the image to retain its transparent areas (so I can lay it on top of another image - that part I can do).
I am quite new to the GD library and am getting confused. I understand that an 8-bit PNG (as created in Photoshop) has full alpha - and that needs to be preserved.
That leads me to the start of my code:
$im = ImageCreateFromPNG('https://i.ibb.co/s3024Y8/1000x1500-autumn-leaves.png');
ImageAlphaBlending($im, false);
imagesavealpha($im, true);
Everything I've tried after that fails miserably. By that, I mean that the colour doesn't change. No error message, just no change in colour. It seems that the following has no effect when using that image:
$myColourToChange = imagecolorallocatealpha($im, 100, 24, 11, 0); // colour of dark brown leaf
imagecolorset($im, $myColourToChange, 255, 0, 0, 0); // try changing it to red, fully opaque
I've even tried (which gives 6559755)
$myColourToChange = imagecolorresolvealpha($im, 100, 24, 11, 0);
I think things are failing (ie the colour doesn't change) because the image I'm using isn't a paletted image in the way that GD needs it to be, in order for me to use imagecolorset
I've tried converting it to one using imagetruecolortopalette but that gives unpredictable results on the image, with all sorts of artifacts not visibly present in the original image - and the colour values change slightly.
Note that the following are representations if you want to experiment, use the image link above.
Original image before imagetruecolortopalette - dark brown leaf colour: #64180B
After imagetruecolortopalette - dark brown leaf colour: #631A0C
So how do I specify the colour that needs to be changed and then change it to the given colour? If it means I must use imagetruecolortopalette how do I deal with the artifacts and the colour change I get when using it?
(I won't know in advance the location of colours that need changing, so imagecolorat won't help)
Thanks in advance :)
A client of mine is trying to place text on a background image using imagettftext(). The code was working previously and suddenly went from displaying black text to displaying gray text. The code is properly set to black and changing it to any other color also has no effect.
$im = imagecreatefrompng("/path/to/background.png");
$text = imagecolorallocate($im, 0, 0, 0);
imagettftext($im, 10, 0,96, 201,$text, "vera", $thiscardnumber);
imagepng($im, "/path/to/new/".$imagefilename.".png");
imagedestroy($im);
Any help would be appreciated as nothing was changed in the code or on the server that I am aware of to suddenly stop this from generating proper black text.
You can see the text generated here:
The black text is part of the background image, the gray text is generated by the code above.
EDIT: From comments below
Ah, OK. If you just recreate a the few lines of code separately, do you still get the grey text? Because I get black text with your code. What about if you try a different font, or a different base image just to eliminate them as the culprit? Have you verified what the value of $text is?
ORIGINAL Answer:
There's something amiss here. Your "x" and "y" coordinates are larger than the background image, so the text you are generating is off of the image canvas.
Is there any chance that your background image just has the grey text in it already, and the text you are generating is happening outside of the image?
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!
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;
}
}
I've run into another problem with GD and PHP.
I'm successfully writing text to an image.
However, I've encountered a case where it would be beneficial to place the text - instead of directly on the image - on a rectangle (or any shape) to create a solid background for the text where the image it's being placed on might not allow the text to be read very easily.
My two ideas are, in order of preference:
Fill the background with the color as it writes the text
Write the text to an appropriately sized image with a solid background, and then overlay the image onto the target
I can't figure out how to do #1 and #2 seems overly complex and I don't know how to determine the dimensions of the text so that I can create a new image for it.
For clarity, here is the output that isn't very good:
And here's how I'd like it to look, with a tight box behind the text of any color:
I'm open to any suggestions, but drawing the color on the fly without any other images or hackiness would obviously be my first choice.
Update:
After #Dan suggested using `imagettftext', I decided that it was high time I added support for that function to my library. Everything is working as would be expected except for one major issue.
The text that's written to the image is still transparent, even when written to a solid background (0 transparency).
Here's a script I wrote to test:
<?php
set_include_path('backbone:global:jquery');
require_once('Image.php');
$scout = new Image();
$scout->source = "scout.jpg";
$result = $scout->Write->Font(25, 25, "A Fairly Long String", 12, "#FF0000", 0, "LiberationSans-Regular.ttf", 1, "#FFFF00", .4, 4);
if( !isset($_GET['dev']) )
{
header("Content-Type: " . $scout->contentType());
}
if( $result )
{
$scout->output();
}
?>
The files I used/required:
1. scout
2. liberation font
3. Image Manipulation Library
- Image
- ImageBase
- ImageCombine
- ImageDraw
- ImageManipulate
- ImageWrite
I apologize about all the files, it really only uses Image, ImageBase, ImageCombine, and ImageWrite, but the others are require_onceed by the loader.
Here's a sample of the output from the script above:
And here's output with zero transparency (fully opaque):
$result = $scout->Write->Font(25, 25, "A Fairly Long String", 12, "#FF0000", 0, "LiberationSans-Regular.ttf", 1, "#FFFF00", 1, 4);
Any ideas what could be causing this? It's EXTREMELY possible that it's my code somewhere, but it seems strange that it would work exactly as I thought it should except for this one bug.
In searching desperately for the answer to this problem, I stumbled upon this SO question that's tangentially related to my problem, and contains the answer.
I've never fully understood why you tell imagealphablending false when you want transparency, so I guess my failure to properly understand the code I'm using has led to this issue.
In any case, the following modified code works like a charm in my one single test case.
To write text to a background without forced 100% transparency for the character boxes, you must turn alpha blending ON while writing the text:
imagealphablending($text->handle, true);
$bool = imagettftext($text->handle, $textSize, $angle, $padding, abs($size[5]) + $padding, $this->AllocateColor($rgba[0]['r'], $rgba[0]['g'], $rgba[0]['b'], $rgba[0]['alpha']), $font, $string);
imagealphablending($text->handle, false);
Maybe this will do the job for you if you switch to ttf. http://php.net/manual/en/function.imagettfbbox.php