I am running into a weird font rendering issue when writing text over images using imagefttext().
$img = imagecreatefromjpeg( $canvas_image_path );
imagettftext( $img, $font_size, 0, $x, $y, $font_color, $font_path, $text );
I have a tool which selects a background image (different sizes - JPEGs (.jpg)) to work on and then write the text over it which comes from an WYSIWYG editor.
Using Bodoni-italic font, for certain image sizes the rendering of i is weird.
Spacing looks weird after T
It works absolutely fine for images that are small like 320 x 240 or big like 1536 x 2048 but for other sizes in between that range, i is written as shown in screenshot.
Now the fact that it does show up correctly for certain image sizes rule out the possibility of something being wrong with the font file itself. The only suspect I see here is the image size but I am not sure how to debug the situation from here & find a fix for it.
Any idea on where I should be looking or what can possibly cause this?
Related
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!
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 have pieced together a PHP class to perform various image related functions using GD functions of PHP.
It works great for all image types. Rotate, flip, resize, crop and to a lesser extent, watermark.
All but the latter work perfectly. For example after a few changes, rotated PNG images retained their transparency whereas before they were losing that and the background turning black. Common problem, it appears. But all working now.
Where I'm still getting stuck is watermarking a PNG image with another PNG image. It appears to work fine with JPG and other images. This is the code (simplified):
public function writeWatermarkSimple()
{
$watermarkFile = 'watermark.png';
$watermarkImage = imagecreatefrompng($watermarkFile);
imagealphablending($watermarkImage, false);
imagesavealpha($watermarkImage, true);
$imageFile = 'image.png';
$baseImage = imagecreatefrompng($imageFile);
imagealphablending($baseImage, false);
imagesavealpha($baseImage, true);
$marginH = imagesx($baseImage) - imagesx($watermarkImage);
$marginV = imagesy($baseImage) - imagesy($watermarkImage);
$cut = imagecreatetruecolor(imagesx($watermarkImage), imagesy($watermarkImage));
imagecopy($cut, $baseImage, 0, 0, $marginH, $marginV, imagesx($watermarkImage), imagesy($watermarkImage));
imagecopy($cut, $watermarkImage, 0, 0, 0, 0, imagesx($watermarkImage), imagesy($watermarkImage));
imagecopymerge($baseImage, $cut, $marginH, $marginV, 0, 0, imagesx($watermarkImage), imagesy($watermarkImage), 80);
if (!imagepng($baseImage, 'watermarked_image.png'))
{
return false;
}
return true;
}
This has been pieced together with various guides and advice people have given based on a similar issue. Again, working perfectly with JPG images and PNG watermarks, but not PNG & PNG.
Some example images:
http://i.imgur.com/hHRWinj.png - This is the watermark I'm using.
http://i.imgur.com/6sy8Ncs.png - This is the image I'm applying the watermark to.
http://i.imgur.com/ghovYLm.png - This is the end result.
The bit I find interesting is that any part of the watermark that is overlaid on a non-transparent portion of the image is working fine. Just the rest of it has the black background.
This leads me to believe I'm close, and I hope that the expertise of you fine people may lead me to the solution.
Thanks ever so for reading.
So, I'm not giving up on finding the correct answer to do this using GD. However, I was overjoyed to find that what needed up to 30 lines of code with GD can be achieved using much less with ImageMagick:
$image = new Imagick();
$image->readimage($this->_image);
$watermark = new Imagick();
$watermark->readimage($this->_watermark->_getImage());
$watermark->evaluateImage(Imagick::EVALUATE_DIVIDE, 2, Imagick::CHANNEL_ALPHA);
$image->compositeImage($watermark, imagick::COMPOSITE_OVER, $marginH, $marginV);
So this is before (with GD):
http://i.imgur.com/AlS0TcO.png
And after (with ImageMagick and the code above):
http://i.imgur.com/zBxlC3R.png
If anyone has an answer that is purely GD then I'd be immensely grateful.
Ran into some similar issues recently and while this may not exactly solve your problem, these were some useful discoveries that I made.
In my case, I have an original .jpg image and a watermark .png image. The watermark image has a fully transparent background. I wanted to specify the opacity in my script and have it change the watermark opacity before placing it on top of the origina image. Most posts out there regarding PHP watermarking assume that the original watermark .png file already has the solid watermark portion set to the correct opacity rather than changing it via the script.
gd didn't like a 24 bit .png and caused some goofy issues. Switching to 8 bit resolved that with gd. On the other hand, imagick works very well with a 24 bit .png and the final result seems to be better.
For me, using gd worked just fine if I was opening the original watermark .png and using imagecopymerge() to set the watermark transparency. If however I tried to scale the original watermark .png (which has transparent background) first, then I would get similar results as you with black or white background portion of where watermark image is. See How do I resize pngs with transparency in PHP? for a partial solution by filling the new wm image with transparent rectangle first. For me this still produced an opaque white background on the final result no matter what I tried.
I switched to imagick and was using setImageOpacity() to change the transparency of my watermark .png before applying it on top of my original image and I was still getting the same effect with a black background. Finally read in the PHP doc for setImageOpacity() that if the original .png has any transparent pixels and you try to lower the opacity, those pixels become opaque (black) with the new transparency applied. Instead, need to use the evaluateImage() function. This will instead evaluate each pixel's alpha channel only and divide by the specifid number.
I assume the black / white background issue with gd is likely due to similar ways that it treats alpha channels when scaling / combining as compared to imagick and if you want to do it all in gd you just need to find some similar way to evaluate and manipulate the alpha channel per-pixel because the "easy" ways seem to take an already transparent background and make it opaque.
So, the solution:
Assuming you want to apply your watermark at an opacity of 45% and you're using imagick, then instead of this:
$watermark->setImageOpacity(.45);
do this
$watermark->evaluateImage(Imagick::EVALUATE_DIVIDE, (1/.45), Imagick::CHANNEL_ALPHA);
You need to divide 1 by your opacity to get the demoninator by which the function will divide the alpha channel value for each pixel. In this case, 1/.45 = 2.2222, so then the function will divide the alpha channel of each pixel by 2.2222. This means a solid pixel (alpha of 1) would result in 1/2.2222 or .45 alpha or transparency when finished. Any pixels that were already transparent (alpha 0) would stay transparent because 0 divided by anything is always what? Zero!
After you change the watermark transparency then you can use compositeImage() to merge the watermark onto the original image.
I have a webcam and want to add some annotations to image, but antialiasing works strange. I'll try to explain:
I have an image like this:
Then I add semi-transparent rectangle and put text over it:
// add background black rectangle
$draw->setFillColor('black');
$draw->setFillOpacity(0.5);
$draw->rectangle( 0, 10, $cam['width'], 70 ); // Draw the rectangle
// add lead text
$draw->setFont('ARIALBD.TTF');
$draw->setFontSize(14);
$draw->setFillColor('white');
$draw->annotation(20, 35, $cam['text']);
// add timestamp
$draw->setFont('ARIAL.TTF');
$draw->setFontSize(12);
$draw->setFillColor(new ImagickPixel('#f3ac01'));
$draw->annotation(20, 50, date("Y-m-d H:i:s"));
$img->drawImage($draw);
And get something like this:
Huh, but timestamp looks ulgy(look at minutes/seconds). Trying to disable antialiasing:
$draw->setTextAntialias(false);
and now it looks still ugly(look at hours), but now it has sharp edges:
How can I get result with smart antialiasing, like this(I know PS uses own antialiasing, but IMagickDraw deal real bad result):
For me it looks more like the compression level of the whole image when saved than the antialiasing, have a look at setCompressionQuality, and tweak the compression quality until you avoid the "blurriness" you have in the picture.
Try the different font first. Here is example of open sans (another link) font.
I'm making a skin previewer for my site; I need to rotate parts of an image to create a representation of this for my users to see.
The skin is a PNG file, and all parts of it may have transparency or even none at all.
I need to be able to rotate this image while keeping any transparency inside the image transparent, while also having the extended borders (You know, the area that wasn't part of the image before it was rotated) transparent.
All of my attempts have left a black border around the image itself.
Any help?
Cut out the piece of the image you want to rotate
Rotate preserving alpha using something like this http://www.exorithm.com/algorithm/view/rotate_image_alpha
Merge back in preserving alpha using the following:
-
imagesetbrush($destimg, $srcimg);
// x, y are the center of target paste location
imageline($destimg, $x, $y, $x, $y, IMG_COLOR_BRUSHED);
I use that to rotate a PNG and preserve transparency color. Works like a charm. It's "basic GD".
$rotation = 135;
$handle_rotated = imagerotate($handle_not_rotated,$rotation,0);
imagealphablending($handle_rotated, true);
imagesavealpha($handle_rotated, true);
Don't know if it's what you're looking for?
You may want to check here for some uses for libpng (which will need zlib). If you are on linux you can write something in perl. CPAN GD module might be your ticket.