PHP GD lib text rendering with pixilation - php

Here's the problem the text overlayed over the image and gradient has some weird pixilation around the text, but I can't work out why.
-->
Here's the code:
<?php
function hex2rgb($hex) {
$rgb[0] = hexdec(substr($hex, 0, 2));
$rgb[1] = hexdec(substr($hex, 2, 2));
$rgb[2] = hexdec(substr($hex, 4, 2));
return $rgb;
}
$sourceImage = imagecreatefromstring(file_get_contents("source.jpg"));
$imagePadding = 10;
$height = imagesy($sourceImage);
$width = imagesx($sourceImage);
$baseImage = imagecreatetruecolor($width, $height);
$backgroundColor = imagecolorallocate($baseImage, 0, 0, 0);
imagefill($baseImage, 0, 0, $backgroundColor);
imagecopyresampled($baseImage, $sourceImage, 0, 0, 0, 0, $width, $height, $width, $height);
//==== GRADIENT ====//
// Modified from: http://stackoverflow.com/questions/14684622/blend-transparent-gradient-with-an-image-using-php-gd-library
$gradientCanvas = imagecreatetruecolor($width, $height);
$transColor = imagecolorallocatealpha($gradientCanvas, 0, 0, 0, 127);
imagefill($gradientCanvas, 0, 0, $transColor);
$color = hex2rgb("000000");
$start = -40;
$stop = 120;
$range = $stop - $start;
for ($y = 0; $y < $height; ++$y) {
$alpha = $y <= $start ? 0 : round(min(($y - $start) / $range, 1) * 127);
$newColor = imagecolorallocatealpha($gradientCanvas, $color[0], $color[1], $color[2], $alpha);
imageline($gradientCanvas, 0, $y, $width, $y, $newColor);
}
imagecopyresampled($baseImage, $gradientCanvas, 0, 0, 0, 0, $width, $height, $width, $height);
//==== TEXT ====//
putenv('GDFONTPATH=.');
$font = "HelveticaNeueBold.ttf";
$white = imagecolorallocate($baseImage, 255, 255, 255);
imagettftext($baseImage, 14, 0, $imagePadding, $imagePadding + 16, $white, $font, "Foobar");
header('Content-Type: image/jpeg');
imagejpeg($baseImage);
imagedestroy($baseImage);
imagedestroy($sourceImage);
?>

The default quality of imagejpeg http://php.net/manual/en/function.imagejpeg.php is ~75, you will want to set this to 100
imagejpeg($baseImage, null, 100);

The main reason - you are using JPG as output and input image. Editing JPG images often causes the image distortions. Try to use a PNG image as a source.
Or try set the "quality" parameter of imagejpeg() to 100

Related

Image GD Resizing Issue

So I'm trying to take two large images (but later I'll be combinging 6 images in total), resize them to the x, y width, height I have taken from photoshop, and combine them into one 460 x 230 sized image.
This is the code I'm using
<?php
$dest = imagecreatefrompng('https://blzgdapipro-a.akamaihd.net/hero/ana/career-portrait.png');
$src = imagecreatefrompng('https://blzgdapipro-a.akamaihd.net/game/rank-icons/season-2/rank-6.png');
imagealphablending($dest, false);
imagesavealpha($dest, true);
imagealphablending($src, false);
imagesavealpha($src, true);
//imagescale($dest, 396, 161.92);
$some = imagecreate(460, 230);
$dest2 = resize($dest, 396, 162);
$src2 = resize($src, 79.19, 79.19);
//imagecopyresized($dest, $dest, 0, 0, 0, 0, 396, 161.92, 1098, 449);
imagecopyresized($src, $src, 10, 10, 0, 0, 79.19, 79.19, 256, 256);
//$img2 = imagecopymerge($dest, $src, 0, 0, 0, 0, 256, 256, 100); //have to play with these numbers for it to work for you, etc.
imagecopymerge($dest2, $src2, 0, 0, 0, 0, 460, 230, 50);
header('Content-Type: image/png');
imagepng($dest, 'merged2.png');
imagepng($dest2);
//file_put_contents('merged.png', $contents);
imagedestroy($dest);
imagedestroy($src);
imagedestroy($some);
imagedestroy($dest2);
imagedestroy($src2);
imagedestroy($img2);
//imagedestroy($then);
function resize($img, $width, $height, $stretch = false)
{
$temp = imagecreatetruecolor($width, $height);
imagealphablending($temp, true);
imagesavealpha($temp, true);
$bg = imagecolorallocatealpha($temp, 0, 0, 0, 0); // Background color
imagefill($temp, 0, 0, $bg);
if ($stretch)
{
imagecopyresampled($temp, img, 0, 0, 0, 0, $width, $height, imagesx($img), imagesy($img));
}
else
{
if (imagesx($img) <= $width && imagesy($img) <= $height)
{
$fwidth = imagesx($img);
$fheight = imagesy($img);
}
else
{
$wscale = $width / imagesx($img);
$hscale = $height / imagesy($img);
$scale = min($wscale, $hscale);
$fwidth = $scale * imagesx($img);
$fheight = $scale * imagesy($img);
}
imagecopyresampled($temp,
$img,
($width - $fwidth) / 2, ($height - $fheight) / 2,
0, 0,
$fwidth, $fheight,
imagesx($img), imagesy($img)
);
}
return $temp;
}
The issue is that the image rendered is very faded
because of this line:
imagecopymerge($dest2, $src2, 0, 0, 0, 0, 460, 230, 50);
If I change the 50, which is the PCT value to 100, it shows one image with a black background (masking the other image), but if I change it to 0, it shows only the other image with a black background (masking the other image)
If the value is either 0 or 100, the image shown is at its full color though. How do I merge these 2 images together while preserving their transparency and vibrancy of color?
Instead of imagecopymerge use imagecopy. You also always need to correctly specify the dimensions of the source image when copying:
$dest = imagecreatefrompng('https://blzgdapipro-a.akamaihd.net/hero/ana/career-portrait.png');
$src = imagecreatefrompng('https://blzgdapipro-a.akamaihd.net/game/rank-icons/season-2/rank-6.png');
$dest2 = resize($dest, 396, 162);
imagedestroy($dest);
$src2 = resize($src, 79, 79); // should be int not float.
imagedestroy($src);
// the last 2 params must match the width/height of the $src2 image.
imagecopy($dest2, $src2, 0, 0, 0, 0, 79, 79);
imagedestroy($src2);
header('Content-Type: image/png');
imagepng($dest2);
imagedestroy($dest2);
You don't need to change the alpha settings on $dest or $src because they aren't being rendered - you render the new image resource created in, and returned by, your resize function. Because of this you do need to slightly change the function:
function resize($img, $width, $height, $stretch = false)
{
$temp = imagecreatetruecolor($width, $height);
imagealphablending($temp, false); // changed to false.
imagesavealpha($temp, true);
...
Edit:
You might be better off simply using the imagescale function instead of using your own resize function:
$dest = imagecreatefrompng('https://blzgdapipro-a.akamaihd.net/hero/ana/career-portrait.png');
$src = imagecreatefrompng('https://blzgdapipro-a.akamaihd.net/game/rank-icons/season-2/rank-6.png');
$dest2 = imagescale($dest, 396);
imagealphablending($dest2, false);
imagesavealpha($dest2, true);
$src2 = imagescale($src, 79);
imagecopy($dest2, $src2, 0, 0, 0, 0, 79, 79);
header('Content-Type: image/png');
imagepng($dest2);
imagedestroy($dest);
imagedestroy($src);
imagedestroy($dest2);
imagedestroy($src2);

How can I get this images to merge, when both have alpha values

I'm trying to add a border with rounded corners to an image, and I've gotten the outside corners working fine, but I'm having some issues with the inside ones.
The current method produces the output on the right, and I expected it to look like the left hand side.
private function addInnerRoundCorners($radius, $borderColour, $borderWidth){
$radius = max(array(5, $radius));
$quality = ($radius <= 5 ? 5 : 10);
$newWidth = $this->getOverlayWidth() * $quality;
$newHeight = $this->getOverlayHeight() * $quality;
$tmpImage = imagecreatetruecolor($newWidth, $newHeight);
$transparency = imagecolorallocatealpha($tmpImage, 0, 0, 0, 127);
imagefill($tmpImage, 0, 0, $transparency);
imagecopyresampled($tmpImage, $this->getImage(), 0, 0, 0, 0, $newWidth, $newHeight, $this->getOverlayWidth(), $this->getOverlayHeight());
imagealphablending($tmpImage, false);
imagesavealpha($tmpImage, true);
$newBorderWidth = $borderWidth * $quality;
$newRadius = $radius * $quality;
// Top Left
$corner = $this->getInnerCornerShape(0, $newRadius, $borderColour);
imagecopymerge($tmpImage, $corner, $newBorderWidth, $newBorderWidth, 0, 0, $newRadius, $newRadius, 100);
// Top Right
$corner = $this->getInnerCornerShape(270, $newRadius, $borderColour);
imagecopy($tmpImage, $corner, $newWidth - $newBorderWidth - $newRadius, $newBorderWidth, 0, 0, $newRadius, $newRadius);
// Bottom Left
$corner = $this->getInnerCornerShape(90, $newRadius, $borderColour);
imagecopyresampled($tmpImage, $corner, $newBorderWidth, $newHeight - $newBorderWidth - $newRadius, 0, 0, $newRadius, $newRadius, $newRadius, $newRadius);
// Bottom Right
$corner = $this->getInnerCornerShape(180, $newRadius, $borderColour);
imagecopyresampled($tmpImage, $corner, $newWidth - $newBorderWidth - $newRadius, $newHeight - $newBorderWidth - $newRadius, 0, 0, $newRadius, $newRadius, $newRadius, $newRadius);
imagecopyresampled($this->getImage(), $tmpImage, 0, 0, 0, 0, $this->getOverlayWidth(), $this->getOverlayHeight(), $newWidth, $newHeight);
}
/**
*
*/
private $innerCornerImage = null;
private function getInnerCornerShape($angle = 0, $width, $colour){
$trans = null;
if($this->innerCornerImage == null){
$width2 = 250;
$height = 250;
$image = imagecreatetruecolor($width2, $height);
$trans = imagecolorallocatealpha($image, 68, 68, 68, 127);
imagealphablending($image, false);
imagesavealpha($image, true);
imagefill($image, 0, 0, $trans);
imagearc($image, $width2, $height, $width2 * 2 + 1, $height * 2 + 1, 0, 0, $colour);
imagefilltoborder($image, 1, 1, $colour, $colour);
// Image will be a square, so use width for height too.
$newImage = imagecreatetruecolor($width, $width);
imagealphablending($newImage, false);
imagesavealpha($newImage, true);
imagefill($newImage, 0, 0, $trans);
imagecopyresampled($newImage, $image, 0, 0, 0, 0, $width, $width, $width2, $height);
$this->innerCornerImage = $newImage;
} else {
$trans = imagecolorallocatealpha($this->innerCornerImage, 0, 0, 0, 127);
}
$image = imagerotate($this->innerCornerImage, $angle, $trans);
return $image;
}
It creates a inner corner shape, then just rotates it around. It has a fully transparent background, but as you can see it doesn't merge correctly.
Anyone got any ideas how I can make them merge correctly?
Again, below is the expected result (left). versus the current result (right).

Center watermark text on image when unknown size of text

I'm trying to create an image with a watermark text in it and I want it to be central on the image. The text I want to watermark can be anywhere from 5 characters to 15 characters, therefore I cannot put a final size for the text to fit every image.
This is the code I use to create the watermarked image
function watermarkImage ($SourceFile, $WaterMarkText, $DestinationFile) {
list($width, $height) = getimagesize($SourceFile);
$image_p = imagecreatetruecolor($width, $height);
$image = imagecreatefromjpeg($SourceFile);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width, $height);
$black = imagecolorallocate($image_p, 0, 0, 0);
$font = '../fonts/proxima-nova-light.otf';
$font_size = 100;
imagettftext($image_p, $font_size, 0, 303, 190, $black, $font, $WaterMarkText);
if ($DestinationFile<>'') {
imagejpeg ($image_p, $DestinationFile, 100);
} else {
header('Content-Type: image/jpeg');
imagejpeg($image_p, null, 100);
};
imagedestroy($image);
imagedestroy($image_p);
};
Which does an excellent job on some texts but when I try it on longer texts it looks bad.
I want to - somehow - calculate the optimal size of text and choose size, x and y from there.
Any ideas?
After doing some research with help from #Sammitch I was able to figure it out. Here is the working code:
<?php
function watermarkImage ($SourceFile, $WaterMarkText, $DestinationFile) {
$font = 'fonts/your-font-here.ttf';
$font_size = 40;
list($width, $height) = getimagesize($SourceFile);
$image_p = imagecreatetruecolor($width, $height);
$image = imagecreatefromjpeg($SourceFile);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width, $height);
$black = imagecolorallocate($image_p, 0, 0, 0);
$bbox = imagettfbbox($font_size, 0, $font, $WaterMarkText);
$x = $bbox[0] + (imagesx($image) / 2) - ($bbox[4] / 2) + 10;
$y = $bbox[1] + (imagesy($image) / 2) - ($bbox[5] / 2) - 5;
imagettftext($image_p, $font_size, 0, $x, $y, $black, $font, $WaterMarkText);
if ($DestinationFile<>'') {
imagejpeg ($image_p, $DestinationFile, 100);
} else {
header('Content-Type: image/jpeg');
imagejpeg($image_p, null, 100);
};
imagedestroy($image);
imagedestroy($image_p);
};
?>
Calculate the position of the watermark in the output image (the
watermark shall be placed in the Center of the Image)
$watermark_pos_x = (imagesx($image)/2) - (imagesx($watermark)/2) - 15;
$watermark_pos_y = (imagesy($image)/2) - (imagesy($watermark)/2) - 10;
Use this value on function.

Join Multiple transparent png image in Single image into php

Friends i want to generate one png image from multiple transparent PNG image but the issue is that i can generate only last image
Both images can not combine.
My code is given below
$x = 363;
$y = 267;
$im_dest = imagecreatetruecolor ($x, $y);
imagealphablending($im_dest, false);
$im = imagecreatefrompng('2.png');
$im1 = imagecreatefrompng('1.png');
imagecopy($im_dest, $im1, 0, 0, 0, 0, $x, $y);
imagecopy($im_dest, $im, 0, 0, 0, 0, $x, $y);
imagesavealpha($im_dest, true);
imagepng($im_dest, 'small_redfade.png');
These are the images which i am using to join in single image
http://s11.postimg.org/h6lui7yjn/image.png
http://s21.postimg.org/o7zdnwcnb/image.png
Here is code which works:
$width = 210;
$height = 190;
$layers = array();
$layers[] = imagecreatefrompng("img/01_boy_faceB.png");
$layers[] = imagecreatefrompng("img/01_boy_hairB.png");
$image = imagecreatetruecolor($width, $height);
// to make background transparent
imagealphablending($image, false);
$transparency = imagecolorallocatealpha($image, 0, 0, 0, 127);
imagefill($image, 0, 0, $transparency);
imagesavealpha($image, true);
/* if you want to set background color
$white = imagecolorallocate($image, 255, 255, 255);
imagefill($image, 0, 0, $white);
*/
imagealphablending($image, true);
for ($i = 0; $i < count($layers); $i++) {
imagecopy($image, $layers[$i], 0, 0, 0, 0, $width, $height);
}
imagealphablending($image, false);
imagesavealpha($image, true);
imagepng($image, 'final_img.png');
?>
ImageMagick::Composite can handle this, sadly haven't done in GD so will leave others to explain how to do it there.
Something like:
<?php
$firstImage = new Imagick("firstImage.png");
$secondImage = new Imagick("secondImage.png");
$firstImage->compositeImage($secondImage, Imagick::COMPOSITE_COPYOPACITY, 0, 0 );
header('Content-type: image/png');
echo $firstImage;
?>
This should preserve alpha.

imagecopy PHP for progress bar doesn't work

I have a problem making the imagecopy function work in PHP.
I don't even know where to start debugging; images is a new fruit for me.
Portion where I have problem:
imagecopy($png, $bgr, 0, 0, 0, 0, 0, 0, $width, $height);
imagecopy($png, $bgr, 0, 0, 0, 0, 0, 0, imagesx($pbuble), imagesy($pbuble));
Full code (my plan is first to copy on top of $png <- $bgr <- $pbuble):
<?php
//Check for correct GET variables
if (is_numeric($_GET['max']) AND is_numeric($_GET['val'])) {
$max = $_GET['max'];
$val = $_GET['val'];
} else {return false;}
//Create empty placeholder
$png = imagecreate(380, 37);
$black = imagecolorallocate($png, 0, 0, 0);
imagecolortransparent($png, $black);
//Create background image with transparency
$bgr = imagecreatefrompng("progress-bgr.png");
imageAlphaBlending($bgr, true);
imageSaveAlpha($bgr, true);
//Calculate width of progress bar atm
$width = imagesx($bgr);
$height = imagesy($bgr);
$pb_width = $val * $width / $max;
//Percentage buble
$pbuble = imagecreatefrompng("percentage-bubble.png");
imageAlphaBlending($pbuble, true);
imageSaveAlpha($pbuble, true);
$perct = $val * 100 / $max;
$txt = $perct . "%";
$txt_color = imagecolorallocate($pbuble, 255, 255, 255);
$font = "dejavusans-webfont.ttf";
$font_size = 7;
$bbox = imagettfbbox($font_size, 0, $font, $txt);
$x = $bbox[0] + (imagesx($pbuble) / 2) - ($bbox[4] / 2);
//$y = $bbox[1] + (imagesy($pbuble) / 2) - ($bbox[5] / 2);
imagettftext($pbuble, $font_size, 0, $x, 14, $txt_color, $font, $txt);
//
imagecopy($png, $bgr, 0, 0, 0, 0, 0, 0, $width, $height);
imagecopy($png, $bgr, 0, 0, 0, 0, 0, 0, imagesx($pbuble), imagesy($pbuble));
//Output image
header("Content-type: image/png");
imagepng($png);
//
imagedestroy($png);
imagedestroy($bgr);
imagedestroy($pbuble);
?>
Stupid me :)
imagecopy($png, $bgr, 0, 0, 0, 0, 0, 0, $width, $height);
has two extra parameters.
should be:
imagecopy($png, $bgr, 0, 0, 0, 0, $width, $height);

Categories