I'm trying to spice up my website by using custom fonts for headings. For me, the most appropriate way to do this is using PHP and GD. I have written a little script which will output the dynamic text based on the $_GET value, however sometimes the image is too wide, which moves everything else about.
How can I get the image to adjust the width of it, based on the width of the text? Here is the code I've written so far:
<?php
// Settings
$sText = $_GET['t']; // Text of heading
$sFont = "font/AvantGarde-Book.ttf"; // Default font for headings
$sMain = $_GET['c'] ? $_GET['c'] : 0xF2AB27; // Get a font or default it
// Create the image
header("content-type: image/png"); // Set the content-type
$hImage = imagecreatetruecolor(200, 24);
ImageFill($hImage, 0, 0, IMG_COLOR_TRANSPARENT);
imagesavealpha($hImage, true);
imagealphablending($hImage, false);
imagettftext($hImage, 20, 0, 0, 24, $sMain, $sFont, $sText); // Draw the text
imagepng($hImage); // Generate the image
imagedestroy($hImage); // Destroy it from the cache ?>
Thanks!
Ok, I figured it out! For anyone else who may have this problem, you need to add:
// Calcuate the width of the image
$arSize = imagettfbbox(24, 0, $sFont, $sText);
$iWidth = abs($arSize[2] - $arSize[0]);
$iHeight = abs($arSize[7] - $arSize[1]);
Before the imagecreatetruecolor()
The function imagettfbbox will calculate the size of what the text will be based on the font you picked. Use the results in your call to imagecreatetruecolor.
Related
I want to stay away from using exec if possible. I have a jpg image on the server that never changes. I just want to place some text over the top of it but I want that text to be curved and virticle. So far I have created the virticle curved text with a transparent background. Now I just want to slide it over an image that is already made and sitting on the server. Is this possible to do with out saving the generated text image I have?
I have been playing with compositeImage but I am messing something up because the page fails to load with no error.
Here is what I have so far:
$phone='555-555-5555';
$draw = new ImagickDraw();
$draw->setFontSize(48);
$draw->setStrokeAntialias(true);
$draw->setTextAntialias(true);
$draw->setFillColor('#'.$color);
$textOnly = new Imagick();
$textOnly->newImage(900, 300, "none");
$textOnly->setImageFormat('png');
$textOnly->annotateImage($draw, 0, 100, 0, $phone);
$distort = array(270);
$textOnly->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT);
$textOnly->setImageMatte(true);
$textOnly->distortImage(Imagick::DISTORTION_ARC, $distort, false);
$textOnly->setImagePage(0, 0, 0, 0);
$textOnly->setformat('png');
$textOnly->cropImage(170, 445, 45, 105);
header("Content-Type: image/png");
print $textOnly->getimageblob();
I have also tried the above code with this at the end but I get 500 errors:
$bgImage->readImage(BASE_PATH.'/src-images/background.jpg');
$bgImage->compositeImage($textOnly, Imagick::COMPOSITE_DEFAULT, 10, 20);
header("Content-Type: image/png");
echo $bgImage->getimageblob();
Here is the resulting image when I get it working with text only and without trying to add the second image:
This resolved it....
$bgImage = new Imagick
NOT
$bgImage->readImage
Hello I am using a function that I found in Internet to display a barCode using a TrueType font, here is the code:
//For displaying barcodes
//Arguments are:
// code Number you want outputted as a barcode
//You can use this script in two ways:
// From a webpage/PHP script <img src='/images/barcode.php?code=12345'/>
// Directly in your web browser http://www.example.com/images/barcode.php?code=12345
//Outputs the code as a barcode, surrounded by an asterisk (as per standard)
//Will only output numbers, text will appear as gaps
//Image width is dynamic, depending on how much data there is
header("Content-type: image/png");
$file = "barcode.png"; // path to base png image
$im = imagecreatefrompng($file); // open the blank image
$string = "123123123"; // get the code from URL
imagealphablending($im, true); // set alpha blending on
imagesavealpha($im, true); // save alphablending setting (important)
$black = imagecolorallocate($im, 0, 0, 0); // colour of barcode
$font_height=40; // barcode font size. anything smaller and it will appear jumbled and will not be able to be read by scanners
$newwidth=((strlen($string)*20)+41); // allocate width of barcode. each character is 20px across, plus add in the asterisk's
$thumb = imagecreatetruecolor($newwidth, 40); // generate a new image with correct dimensions
imagecopyresized($thumb, $im, 0, 0, 0, 0, $newwidth, 40, 10, 10); // copy image to thumb
imagettftext($thumb, $font_height, 0, 1, 40, $black, 'B2FI25HRc.ttf', '*'.$string.'*'); // add text to image
//show the image
imagepng($thumb);
imagedestroy($thumb);
I cannot find the error why the function doesn't display the image. Any ideas? The font is in the same directory with the php function and I tried relative and absolute paths to the font with no results. Any suggestion?
Thank you very much
You need to check for error messages.
For debugging, comment out the header line and add these lines on the top to show all errors:
ini_set('display_errors',true);
error_reporting(E_ALL);
In many cases the error messages will tell you pretty clear whats wrong.
I am trying to merge two images in PHP, overlapping each other in the middle like in here : http://i.stack.imgur.com/ejdDQ.jpg
However, I am having no luck.
On the ImageMagick page, they are using this method to do it in the command line:
http://www.imagemagick.org/Usage/photos/#overlap
But since I cannot use exec on my server, I have to do it somehow with the help of the imagick extension installed on the server (http://us1.php.net/manual/en/book.imagick.php).
Is there any way to make this work?
Using the source files from the link and the code below generates the image:
//Load the images
$left = new Imagick(realpath('../images/im/holocaust_tn.gif'));
$right = new Imagick(realpath('../images/im/spiral_stairs_tn.gif'));
$gradient = new Imagick(realpath('../images/im/overlap_mask.png'));
//The right bit will be offset by a certain amount - avoid recalculating.
$offsetX = $gradient->getImageWidth() - $right->getImageWidth();
//When doing the fading of the images, ImageMagick uses "White == show image".
//The gradient is setup with black on the left, white on the right. So the for
//the left image we need to reverse the gradient to make it white on the left.
$negativeGradient = clone $gradient;
$negativeGradient->negateimage(false);
//Fade out the left part
$left->compositeimage(
$negativeGradient,
Imagick::COMPOSITE_COPYOPACITY,
0, 0
);
//Fade out the right part - offset the gradient
//to make it align in the final image
$right->compositeimage(
$gradient,
Imagick::COMPOSITE_COPYOPACITY,
-$offsetX, 0
);
//Create a new canvas to render everything in to.
$canvas = new Imagick();
$canvas->newImage($gradient->getImageWidth(), $gradient->getImageHeight(), new ImagickPixel('black'));
//Blend left half into final image
$canvas->compositeimage(
$left,
Imagick::COMPOSITE_BLEND,
0, 0
);
//Blend Right half into final image
$canvas->compositeimage(
$right,
Imagick::COMPOSITE_BLEND,
$offsetX, 0
);
//Output the final image
$canvas->setImageFormat('png');
header("Content-Type: image/png");
echo $canvas->getImageBlob();
// And Robert is your father's brother.
I am working on improving one of my Facebook apps by allowing the user to upload an image and apply a styled border, or frame to it (i.e. clouds, stars, sky etc). The user chould also be able to save the image, with the border after it has been applied. This explains a little better what I need:
http://zbrowntechnology.info/ImgDisp/imgdisp.php
If you have any other questions or need more details, please let me know.. I'll edit this post.
Use imagecopy(). The example on that page is done using the transparency option with imagecopymerge() but I don't think you need that.
Using imagecopy() you'll specify the X/Y coordinates to use for positioning:
imagecopy( $borderimage, $topimage, 20, 20, 0, 0, $width, $height);
Where $width and $height will be the entire width and height of the top image. You'll want to replace 20 and 20 with the measurement for how much of the border image will be showing around the borders. You will probably have to resize the top image to the exact dimensions you want, or else it might overlap the border a little too far to the right or bottom. (see imagecopyresampled())
Edit:
Here's a rough way to do the whole process (assuming chosenborder.png is the border they chose, and uploadedimage.png is the image they uploaded. If it's a different image type you'll use the corresponding function).
$borderx = 20; // The width of our border
$border = imagecreatefrompng("chosenborder.png");
$topimage = imagecreatefrompng("uploadedimage.png");
$bordersize = getimagesize($border);
$topimagesize = getimagesize($topimage);
/* The new dimensions of topimage. $borderx*2 means we account for
the border on both left and right, top and bottom. */
$newx = $bordersize[0] - ($borderx*2);
$newy = $bordersize[1] - ($borderx*2);
imagecopyresampled( $topimage_scaled, $topimage, 0, 0, 0, 0,
$newx, $newy, $topimagesize[0], $topimagesize[1]);
/* Merge the images */
imagecopy( $border, $topimage_scaled, $borderx, $borderx,
0, 0, $width, $height);
/* Output the image */
imagepng($border, "newimage.png");
/* Free up the memory occupied by the image resources */
imagedestroy($border);
imagedestroy($topimage);
After the user uploads their image, find chosenborder.png and uploadedimage.png, run the above script, then display newimage.png to the user and you're good to go. Just make sure you call imagedestroy() on the temporary image resources or they'll eat up memory.
If you don't want to keep the generated image on your server, you can omit the second argument to imagepng() which will make it send the image information directly as an image to the browser, in which case you'll want to write the correct image HTTP headers.
Client-side solution by using css3:
checkout the css3 property border-image
(dosen't meet the requirement of saving the img with the border)
Server-side solution by merging 2 different images:
<?php
$imgFile = 'img.jpg';
$brdFile = 'brd.jpg';
$img = addBorder($imgFile,$brdFile);
outputImage($img);
function addBorder($imgFile,$brdFile)
{
$img=imagecreatefromjpeg($imgFile);
$brd=imagecreatefromjpeg($brdFile);
$imgSize = getimagesize($imgFile);
$brdSize = getimagesize($brdFile);
//NOTE: the border img MUST be bigger then the src img
$dst_x = ceil(($brdSize[0] - $imgSize[0])/2);
$dst_y = ceil(($brdSize[1] - $imgSize[1])/2);
imagecopymerge ( $brd, $img, $dst_x, $dst_y, 0, 0, $imgSize[0], $imgSize[1] ,100 );
return $brd;
}
function outputImage($img)
{
header('Content-type: image/png');
imagepng($img);
}
?>
I have a 1 pixel tall by 760 pixel wide image that I use as a repeating vertical background image. The right side of this image is filled with a spot color (the remaining left side of the image is white).
The purpose of this background image, in my css based layout, is that it provides the illusion that the sidebar background color runs all the way down the page (easy to do with tables, but no so much with CSS positioning).
What I need to do is to figure a way to feed a php script (background-image.php) which contains the imagecreatefromgif function, a hex number and have it use that to repaint the spot color of the image to match the spot color that's passed in and save the resulting image onto the server, overwriting the default one.
Ideally, I'd not like to have to call this function everytime the template loads, and onlydo it when the user elects to change the template colors. So once they do that, I'd just like to modify the existing image I've got on the server which will always be called "sidebar_bg.gif"
Any ideas on how to do this are much appreciated.
Something like this could do it:
$token = md5(serialize(array($red, $green, $blue)));
if (!file_exists('cachedir/'.$token.'.gif'))
{
$img = imagecreatefromgif('origfilename.gif');
$color = imagecolorallocate($img, $red, $green, $blue);
for ($i = $startPixel-1; $i < $endPixel; $i++)
{
imagesetpixel($img, $i, 0, $color);
}
imagegif($img, 'cachedir/'.$token.'.gif');
}
serveFile($token);
EDIT: Added caching to example code
Just an addition to this post. You can convert HEX color into RGB notation with the folowing function:
function hexToRGB ($hexColor)
{
$output = array();
$output['red'] = hexdec($hexColor[0].$hexColor[1]);
$output['green'] = hexdec($hexColor[2].$hexColor[3]);
$output['blue'] = hexdec($hexColor[4].$hexColor[5]);
return $output;
}
e.g. try:
var_dump(hexToRGB("FFFFFF"));