How to create transparent background in gd without blurring image? - php

I'm trying to create a pie chart, which will display browser stats.
But, when I try to create a transparent background to chart, text goes blurry than normal background.
define('FONT', "C:/Windows/fonts/Arial.ttf");
$data = ['edge' => 3, 'ie' => 4, 'firefox' => 12, 'chrome' => 40, 'opera' => 9, 'android' => 18];
function textWidth($text, $fontSize) {
$sizes = array_map(function($x){ return $x * .75; }, imagettfbbox($fontSize, 0, FONT, $text));
return $sizes[6] - $sizes[4];
}
asort($data);
$total = array_sum($data);
$before = -90;
$w = 300;
$h = 300;
$graph = imagecreatetruecolor($w * 2, $h * 2);
// this is the part where background blurrs: remove this part to compare
imagealphablending($graph, false);
$transparency = imagecolorallocatealpha($graph, 0, 0, 0, 127);
imagefill($graph, 0, 0, $transparency);
imagesavealpha($graph, true);
//part end
$text_color = imagecolorallocate($graph, 0, 0, 0);
foreach ($data as $key => $value) {
$ratio = 100 / $total * $value;
$deg = $before + 3.6 * $ratio;
$color = imagecolorallocate($graph, rand(128,255), rand(128,255), rand(128,255));
imagefilledarc($graph, $w, $h, $w * 2, $h * 2, $before, $deg, $color, IMG_ARC_PIE);
$posX = $w + $w * cos(deg2rad($deg - 1.8 * $ratio)) * .75;
$posY = $w + $w * sin(deg2rad($deg - 1.8 * $ratio)) * .75;
$ratio = floor($ratio);
imagettftext($graph, 16, 0, $posX + textWidth($key, 18) / 2, $posY, $text_color, FONT, $key);
imagettftext($graph, 16, 0, $posX + textWidth($ratio . "%", 18) / 2, $posY + 30, $text_color, FONT, $ratio . "%");
$before = $deg;
}
header('Content-type: image/png');
imagepng($graph);
imagedestroy($graph);
I've tried to create transparent background after drawing each parts of graph, but it didn't worked.
Any help would be appreciated. Thanks!

You can either remove the following line:
imagealphablending($graph, false);
Or re-enable alpha blending after setting the transparency:
imagealphablending($graph, false);
$transparency = imagecolorallocatealpha($graph, 0, 0, 0, 127);
imagefill($graph, 0, 0, $transparency);
imagealphablending($graph, true); // add this
imagesavealpha($graph, true);
Result:

Related

PHP GD - image damaged when using imagettftext()

I'am using PHP 7.4, with Symfony 5.2, memory_limit = 1024M in php.ini
I implement an API which put a quote in an image, using imagettftext() method.
My problem is that the image is damaged. It seems to be because of the length of the text.
When the text is short, the result is ok:
image ok
When the text is longer, the image is damaged (color spots appear):
image damaged
Here is my code:
private function createResource(string $imageContent, array $quote)
{
$image = \imagecreatefromstring($imageContent);
$heigh = \imagesy($image);
$width = \imagesx($image);
$text = $quote['quote'];
$charsArray = \str_split($text, 1);
$charsTotalNb = \count($charsArray);
$charsNbPerLine = (int) floor(($width - 50) / 10);
$lineNb = (int) ceil($charsTotalNb / $charsNbPerLine);
$text = \wordwrap($text, $charsNbPerLine, "|", \false);
$quoteHeigh = 60 + $lineNb * 25;
$card = \imagecreatetruecolor($width, $heigh + $quoteHeigh);
$black = \imagecolorallocate($card, 0, 0, 0);
$white = imagecolorallocate($card, 255, 255, 255);
\imagefill($card, 0, 0, $black);
\imagecopymerge($card, $image, 0, 0, 0, 0, $width, $heigh, $quoteHeigh);
\imagedestroy($image);
$font = __DIR__ . '/../../public/fonts/Averia_Serif_Libre.ttf';
\imagettftext($card, 15, 0, 25, $heigh + 30, $white, $font, $text);
$author = $quote['author'];
if (empty($author)) {
$author = 'Anonymous';
}
\imagettftext(
$card,
12,
0,
(int) $width/2,
$heigh + 40 + $lineNb * 25,
$white,
$font,
'-' . $author . '-'
);
for ($i = 0 ; $i < 7 ; $i++ ) {
\imageline($card, 0 + $i, 0 + $i, 0 + $i , \imagesy($card), $black);
\imageline($card, 0, 0 + $i, \imagesx($card) , 0 + $i, $black);
\imageline($card, \imagesx($card) - $i, 0, \imagesx($card) - $i, \imagesy($card), $black);
}
if (empty(\get_resource_type($card))) {
throw new Exception("Error Processing Request in CardService::createCard()");
}
return $card;
}
How fix my problem ? How to remedy the deterioration of the cat's image?
Thanks for your answers.
I found the problem in my code :
The following line is wrong because of the last argument :
\imagecopymerge($card, $image, 0, 0, 0, 0, $width, $heigh, $quoteHeigh);
The correction is :
\imagecopymerge($card, $image, 0, 0, 0, 0, $width, $heigh, 100);
```

imagecopyresampled after rotating the image

I am trying to copy image (to $img) after rotating image (many images $im) but I get weird behavior. Once I un-comment the line //$img = I only get the rotated image on my final output. Can I rotate the inner $im and copy it to final image$img?
<?php
$height = 80;
$width = 300;
$img = imagecreate($width, $height);
$c = imagecolorallocate ($img , 135, 135, 135);
imagefill($img, 0, 0, imagecolorallocate($img, 255, 255, 255));
for($i=0; $i<=5; $i++){
$im = imagecreatetruecolor(35, 35);
$gry = imagecolorallocate($im, 135, 135, 135);
$wht = imagecolorallocate($im, 255, 255, 255);
$j = mt_rand(0, 1);
$ch = mt_rand(0,1)?chr(rand(65, 90)):chr(rand(97, 122));
if($j == 0){
imagefill($im, 0, 0, $wht);
imagefttext($im, 20, 0, 3, 21, $gry, 'AHGBold.ttf', $ch);
//$img = imagerotate($im, mt_rand(0,10)-5, $wht);
}else{
imagefill($im, 0, 0, $gry);
imagefttext($im, 20, 0, 3, 21, $wht, 'AHGBold.ttf', $ch);
//$img = imagerotate($im, mt_rand(0,10)-5, $gry);
}
imagecopyresampled($img, $im, 5 + $i*42, $height/2 - 12, 0, 0, 40, 40, 25, 25);
}
header('Content-type: image/png');
imagepng($img);
change
$img = imagerotate($im, mt_rand(0,10)-5, $wht);
and
$img = imagerotate($im, mt_rand(0,10)-5, $gry);
to
$im = imagerotate($im, mt_rand(0,10)-5, $wht);
and
$im = imagerotate($im, mt_rand(0,10)-5, $gry);
in cases that imagerotes does not work you can use the following function to rotate an image:
function imagerotateEquivalent(&$srcImg, $angle, $bgcolor, $ignore_transparent = 0)
{
$srcw = imagesx($srcImg);
$srch = imagesy($srcImg);
if($angle == 0) return $srcImg;
// Convert the angle to radians
$theta = deg2rad ($angle);
// Calculate the width of the destination image.
$temp = array ( rotateX(0, 0, 0-$theta),
rotateX($srcw, 0, 0-$theta),
rotateX(0, $srch, 0-$theta),
rotateX($srcw, $srch, 0-$theta)
);
$minX = floor(min($temp));
$maxX = ceil(max($temp));
$width = $maxX - $minX;
// Calculate the height of the destination image.
$temp = array ( rotateY(0, 0, 0-$theta),
rotateY($srcw, 0, 0-$theta),
rotateY(0, $srch, 0-$theta),
rotateY($srcw, $srch, 0-$theta)
);
$minY = floor(min($temp));
$maxY = ceil(max($temp));
$height = $maxY - $minY;
$destimg = imagecreatetruecolor($width, $height);
imagefill($destimg, 0, 0, imagecolorallocate($destimg, 0,255, 0));
// sets all pixels in the new image
for($x=$minX;$x<$maxX;$x++) {
for($y=$minY;$y<$maxY;$y++)
{
// fetch corresponding pixel from the source image
$srcX = round(rotateX($x, $y, $theta));
$srcY = round(rotateY($x, $y, $theta));
if($srcX >= 0 && $srcX < $srcw && $srcY >= 0 && $srcY < $srch)
{
$color = imagecolorat($srcImg, $srcX, $srcY );
}
else
{
$color = $bgcolor;
}
imagesetpixel($destimg, $x-$minX, $y-$minY, $color);
}
}
return $destimg;
}
function rotateX($x, $y, $theta){
return $x * cos($theta) - $y * sin($theta);
}
function rotateY($x, $y, $theta){
return $x * sin($theta) + $y * cos($theta);
}
I got the above code from a note in php.net

PHP GD generating image with an extra 20(hex) in the file

Using PHP GD library to generate a PNG image, everything seems working perfectly fine, no errors.
But the browser just cannot render my Image.
I downloaded the generated PNG and compare it with normal PNGs in Ultraedit, I found there is an extra 20 (in Hex mode) in the beginning of the file. After I remove the 20 from ultraedit, the PNG works fine.
I've check through my code, and I cannot find any line that gives a 0x20.
Relative Part of Code as follow:
public function imggen($string = "Enter your own lyric.",
$size = 35,
$lineheight = 50,
$font = "./fonts/w6.ttf",
$meta = "Project Gy Picture Generation",
$metasize = 10,
$metalineh = 25,
$bg_src = "./img/bg/bg1.png",
$textcolor = "w",
$width=640,
$height=596,
$x_offset = 30,
$y_offset = 30,
$position="cc",
$bgpos = 5){
$logo_src ='./img/bg/wtm-'.$position[1].'-'.$textcolor.'.png';
$logo = ImageCreateFromPNG($logo_src);
$bg = ImageCreateFromPNG($bg_src);
$bgcrop = imagecreatetruecolor($width,$height);
$bgW = ImageSX($bg);
$bgH = ImageSY($bg);
if ($bgpos == 1||$bgpos == 2||$bgpos == 3){$src_y = 0;}
elseif ($bgpos == 4||$bgpos == 5||$bgpos == 6){$src_y = ($bgH - $height)/2;}
else{$src_y = $bgH - $height;}
if ($bgpos == 1||$bgpos == 4||$bgpos == 7){$src_x = 0;}
elseif ($bgpos == 2||$bgpos == 5||$bgpos == 8){$src_x = ($bgW - $width)/2;}
else{$src_x = $bgW - $width;}
imagecopyresized($bgcrop,$bg,0,0,$src_x,$src_y,$width,$height,$width,$height);
ImageDestroy($bg);
$logoW = ImageSX($logo);
$logoH = ImageSY($logo);
$strings = explode("\n", $string);
$color = ($textcolor == "b") ? imagecolorallocate($bgcrop, 0, 0, 0) : imagecolorallocate($bgcrop, 255, 255, 255);
if ($position[1]=="l"){$anchorX = $x_offset;}//Horiz. left
elseif($position[1]=="c"){$anchorX = $width / 2;} //Horiz. Center
elseif($position[1]=="r"){$anchorX = $width - $x_offset;} //Horiz Right
if ($position[0]=="t"){$anchorY = $y_offset;} //Vert. Top
elseif($position[0]=="c"){$anchorY = ($height / 2)-(($lineheight * count($strings) + $metalineh + 20+$logoH)/2);} //Vert. Center
elseif($position[0]=="b"){$anchorY = $height - ($lineheight * count($strings) + $metalineh + 20 + $logoH + $y_offset);} //Vert. Bottom
$lineacuu = $anchorY + $lineheight;
//imageline($bgcrop,0,($lineacuu),300,($lineacuu),$color);
foreach($strings as $line){
if ($position[1]=="l"){imagettftext($bgcrop, $size, 0, ($anchorX), ($lineacuu), $color, $font, $line);}//Horiz. left
elseif($position[1]=="c"){$this->imagettftext_ca($bgcrop, $size, 0, ($anchorX), ($lineacuu), $color, $font, $line);} //Horiz. Center
elseif($position[1]=="r"){$this->imagettftext_ra($bgcrop, $size, 0, ($anchorX), ($lineacuu), $color, $font, $line);} //Horiz Right
$lineacuu += $lineheight;
}
$lineacuu += $metalineh - $lineheight;
if ($position[1]=="l"){imagettftext($bgcrop, $metasize, 0, ($anchorX), ($lineacuu), $color, $font, $meta);}//Horiz. left
elseif($position[1]=="c"){$this->imagettftext_ca($bgcrop, $metasize, 0, ($anchorX), ($lineacuu), $color, $font, $meta);} //Horiz. Center
elseif($position[1]=="r"){$this->imagettftext_ra($bgcrop, $metasize, 0, ($anchorX), ($lineacuu), $color, $font, $meta);}
imageline($bgcrop,0,($lineacuu+10),1500,($lineacuu+10),$color);
ImageAlphaBlending($bgcrop, true);
if ($position[1]=="l"){$logoX = $x_offset;}//Horiz. left
elseif($position[1]=="c"){$logoX = $width / 2 - $logoW/2;} //Horiz. Center
elseif($position[1]=="r"){$logoX = $width - $x_offset - $logoW;}
ImageCopy($bgcrop, $logo, ($logoX), ($lineacuu + 20), 0, 0, $logoW, $logoH);
ImagePng($bgcrop);
}
public function imggen_db($img_id)
{
$fname = $this->config->item('fname');
$fpath = $this->config->item('fpath');
$post = $this->get_by_id($img_id);
$bgpath = "./img/bg/bg".$post->background.".png";
$this->imggen($post->lyric,
$post->size,
$post->lineheight,
str_replace($fname,$fpath,$post->font),
$post->meta,
$post->metasize,
$post->metalineh,
$bgpath,
$post->textcolor,
$post->width,
$post->height,
$post->x_offset,
$post->y_offset,
$post->style,
$post->bgpos);
}
Full code available at https://github.com/1a23/project-gy
This code works in a CodeIgniter framework
./application/config/version.php has a space before <?php

PHP Captcha-generator does not generate transparent PNG. Why?

I have set imagealphablending on every image I create, still there is a black background. What could be the problem?
$systemSettings = array(
'captcha' => array(
'colors' => array(array(30, 80, 180), array(20, 160, 40), array(220, 40, 10)),
'fonts' => array('AntykwaBold.ttf', 'Candice.ttf', 'Carbon.ttf', 'Duality.ttf', 'Heineken.ttf', 'Jura.ttf', 'StayPuft.ttf', 'TimesNewRomanBold.ttf', 'VeraSansBold.ttf'),
'size' => array('width' => '200', 'height' => '50')
)
);
function generateCaptcha() {
global $systemSettings;
$randomLetters = "abcdef";
$scale = 3;
$width = $systemSettings['captcha']['size']['width'];
$height = $systemSettings['captcha']['size']['height'];
$im = imagecreatetruecolor($width * $scale, $height * $scale);
imagealphablending($im, true);
//$GdBgColor = imagecolorallocate($im, 250, 250, 250);
//imagefilledrectangle($im, 0, 0, $width * $scale, $height * $scale, $GdBgColor);
$color = $systemSettings['captcha']['colors'][mt_rand(0, sizeof($systemSettings['captcha']['colors']) - 1)];
$GdFgColor = imagecolorallocate($im, $color[0], $color[1], $color[2]);
$fontfile = 'visual/fonts/' . $systemSettings['captcha']['fonts'][array_rand($systemSettings['captcha']['fonts'])];
$x = 20 * $scale;
$y = round(($height * 0.75) * $scale);
$length = strlen($randomLetters);
for ($i = 0; $i < $length; $i++) {
$degree = rand(-10, 10);
$fontsize = rand(20, 25) * $scale;
$letter = substr($randomLetters, $i, 1);
$coords = imagettftext($im, $fontsize, $degree, $x, $y, $GdFgColor, $fontfile, $letter);
$x += ($coords[2] - $x);
}
$k = rand(0, 100);
$xp = $scale * 12 * rand(1, 3);
for ($i = 0; $i < ($width * $scale); $i++)
imagecopy($im, $im, $i - 1, sin($k + $i / $xp) * ($scale * 5), $i, 0, 1, $height * $scale);
$k = rand(0, 100);
$yp = $scale * 12 * rand(1, 3);
for ($i = 0; $i < ($height * $scale); $i++)
imagecopy($im, $im, sin($k + $i / $yp) * ($scale * 14), $i - 1, 0, $i, $width * $scale, 1);
imagefilter($im, IMG_FILTER_GAUSSIAN_BLUR);
$imResampled = imagecreatetruecolor($width, $height);
imagecopyresampled($imResampled, $im, 0, 0, 0, 0, $width, $height, $width * $scale, $height * $scale);
imagealphablending($imResampled, true);
header("Content-type: image/png");
imagepng($imResampled);
imagedestroy($im);
imagedestroy($imResampled);
}
try this
$systemSettings = array(
'captcha' => array(
'colors' => array(array(30, 80, 180), array(20, 160, 40), array(220, 40, 10)),
'fonts' => array('AntykwaBold.ttf', 'Candice.ttf', 'Carbon.ttf', 'Duality.ttf', 'Heineken.ttf', 'Jura.ttf', 'StayPuft.ttf', 'TimesNewRomanBold.ttf', 'VeraSansBold.ttf'),
'size' => array('width' => '200', 'height' => '50')
)
);
function generateCaptcha() {
global $systemSettings;
$randomLetters = "abcdef";
$scale = 3;
$width = $systemSettings['captcha']['size']['width'];
$height = $systemSettings['captcha']['size']['height'];
$im = imagecreatetruecolor($width * $scale, $height * $scale);
// enable alpha blending on the destination image.
imagealphablending($im, true);
// Allocate a transparent color and fill the new image with it.
// Without this the image will have a black background instead of being transparent.
$transparent = imagecolorallocatealpha( $im, 0, 0, 0, 127 );
imagefill( $im, 0, 0, $transparent );
// disable alpha blending on the destination image.
imagealphablending($im, false);
// save the alpha
imagesavealpha($im,true);
//$GdBgColor = imagecolorallocate($im, 250, 250, 250);
//imagefilledrectangle($im, 0, 0, $width * $scale, $height * $scale, $GdBgColor);
$color = $systemSettings['captcha']['colors'][mt_rand(0, sizeof($systemSettings['captcha']['colors']) - 1)];
$GdFgColor = imagecolorallocate($im, $color[0], $color[1], $color[2]);
$fontfile = 'visual/fonts/' . $systemSettings['captcha']['fonts'][array_rand($systemSettings['captcha']['fonts'])];
$x = 20 * $scale;
$y = round(($height * 0.75) * $scale);
$length = strlen($randomLetters);
for ($i = 0; $i < $length; $i++) {
$degree = rand(-10, 10);
$fontsize = rand(20, 25) * $scale;
$letter = substr($randomLetters, $i, 1);
$coords = imagettftext($im, $fontsize, $degree, $x, $y, $GdFgColor, $fontfile, $letter);
$x += ($coords[2] - $x);
}
$k = rand(0, 100);
$xp = $scale * 12 * rand(1, 3);
for ($i = 0; $i < ($width * $scale); $i++)
imagecopy($im, $im, $i - 1, sin($k + $i / $xp) * ($scale * 5), $i, 0, 1, $height * $scale);
$k = rand(0, 100);
$yp = $scale * 12 * rand(1, 3);
for ($i = 0; $i < ($height * $scale); $i++)
imagecopy($im, $im, sin($k + $i / $yp) * ($scale * 14), $i - 1, 0, $i, $width * $scale, 1);
imagefilter($im, IMG_FILTER_GAUSSIAN_BLUR);
$imResampled = imagecreatetruecolor($width, $height);
// enable alpha blending on the destination image.
imagealphablending($imResampled, true);
// Allocate a transparent color and fill the new image with it.
// Without this the image will have a black background instead of being transparent.
$transparent = imagecolorallocatealpha( $imResampled, 0, 0, 0, 127 );
imagefill( $imResampled, 0, 0, $transparent );
// disable alpha blending on the destination image.
imagealphablending($imResampled, false);
// save the alpha
imagesavealpha($imResampled,true);
imagecopyresampled($imResampled, $im, 0, 0, 0, 0, $width, $height, $width * $scale, $height * $scale);
header("Content-type: image/png");
imagepng($imResampled);
imagedestroy($im);
imagedestroy($imResampled);
}

Combining images in PHP while retaining transparency

Have a look here: http://tyilo.jbusers.com/PNG/progress.php?l=100&p=20
I want to remove the white-thingy at the end of the blue part, but I have tried many different things that didn't work.
If needed the pngs can be found in http://tyilo.jbusers.com/PNG/ folder (http://tyilo.jbusers.com/PNG/Empty.png)
header('Content-type: image/png');
echo imagepng(progressbar($_GET['l'], $_GET['p']));
function progressbar($length, $percentage)
{
$length = round($length / 2) * 2;
$percentage = min(100, max(0, $percentage));
if($length > 0)
{
$bar = imagecreate($length, 14);
$empty = imagecreatefrompng('Empty.png');
$fill = imagecreatefrompng('Fill.png');
$lempty = imagecreatefrompng('LeftEmpty.png');
$lfill = imagecreatefrompng('LeftFill.png');
$rempty = imagecreatefrompng('RightEmpty.png');
$rfill = imagecreatefrompng('RightFill.png');
$emptycaplength = min(7, $length / 2); //5
imagecopy($bar, $lempty, 0, 0, 0, 0, $emptycaplength, 14);
imagecopy($bar, $rempty, $length - $emptycaplength, 0, 7 - $emptycaplength, 0, $emptycaplength, 14);
if($length > 14)
{
imagecopyresized($bar, $empty, 7, 0, 0, 0, $length - 14, 14, 1, 14);
}
$filllength = round(($length * ($percentage / 100)) / 2) * 2;
$fillcaplength = min(7, $filllength / 2);
imagecopy($bar, $lfill, 0, 0, 0, 0, $fillcaplength, 14);
imagecopy($bar, $rfill, $filllength - $fillcaplength, 0, 7 - $fillcaplength, 0, $fillcaplength, 14);
if($filllength > 14)
{
imagecopyresized($bar, $fill, 7, 0, 0, 0, $filllength - 14, 14, 1, 14);
}
return $bar;
}
else
{
return false;
}
}
try using imagecreatetruecolor() to create your image.
http://www.php.net/manual/en/function.imagecreatetruecolor.php
I think you need to set the Alpha blend of the image...
imagealphablending($cropimg, false);
imagesavealpha($cropimg, true);
I've also found that it helps to set the Color Allocation.
imageColorAllocate ($cropimg, 0, 0, 0);
I think you will need to call those three functions on all your filled images. Sorry for the incomplete answer, I'm in a rush but thought I'd throw you a bone.

Categories