I have used https://github.com/ttodua/useful-php-scripts/blob/master/text-to-image.php for text to image convertion.
Actually i have to create an image from text and show it on different background colors. for that created a transparent image and showing on red background colour. but showing white color patches around the text while creating the transparent image. How can i create smooth text image on any background color?
Could you please help me on this. below is my code.
My Html
<div class="box--h logo_bg_color1_preview fl-d fl-ac" style="background-color:red;">
<div class="box--l fl-d fl-ac">
<img src="logo.png?q=0.73948100 1606166692">
</div>
</div>
My Converted Image transparent background
public function hexToRgb($hex, $alpha = false) {
$hex = str_replace('#', '', $hex);
$length = strlen($hex);
$rgb['r'] = hexdec($length == 6 ? substr($hex, 0, 2) : ($length == 3 ? str_repeat(substr($hex, 0, 1), 2) : 0));
$rgb['g'] = hexdec($length == 6 ? substr($hex, 2, 2) : ($length == 3 ? str_repeat(substr($hex, 1, 1), 2) : 0));
$rgb['b'] = hexdec($length == 6 ? substr($hex, 4, 2) : ($length == 3 ? str_repeat(substr($hex, 2, 1), 2) : 0));
if ( $alpha ) {
$rgb['a'] = $alpha;
}
return $rgb;
}
function TextToImage($text="hello world",$textColor)
{
$newline_after_letters=40;
$font='./myfont.ttf';
$size=24;
$rotate=0;
$padding=2;
$transparent=true;
$bg_color=array('red'=>255,'grn'=>255,'blu'=>255);
$textRgbColor = $this->hexToRgb($textColor);
$color=array('red'=>$textRgbColor['r'],'grn'=>$textRgbColor['g'],'blu'=>$textRgbColor['b']);
//other version: pastebin(dot).com/XVVUyWGD
$amount_of_lines= ceil(strlen($text)/$newline_after_letters)+substr_count($text, '\n')+1;
$all_lines=explode("\n", $text); $text=""; $amount_of_lines = count($all_lines);
foreach($all_lines as $key=>$value){
while( mb_strlen($value,'utf-8')>$newline_after_letters){
$text_final .= mb_substr($value, 0, $newline_after_letters, 'utf-8')."\n";
$value = mb_substr($value, $newline_after_letters, null, 'utf-8');
}
$text .= mb_substr($value, 0, $newline_after_letters, 'utf-8') . ( $amount_of_lines-1 == $key ? "" : "\n");
}
//
Header("Content-type: image/png");
$width=$height=$offset_x=$offset_y = 0;
if(!is_file($font)) { file_put_contents($font,file_get_contents('https://github.com/potyt/fonts/raw/master/macfonts/Arial%20Unicode%20MS/Arial%20Unicode.ttf')); }
// get the font height.
$bounds = ImageTTFBBox($size, $rotate, $font, "W");
if ($rotate < 0) {$font_height = abs($bounds[7]-$bounds[1]); }
elseif ($rotate > 0) {$font_height = abs($bounds[1]-$bounds[7]); }
else { $font_height = abs($bounds[7]-$bounds[1]);}
// determine bounding box.
$bounds = ImageTTFBBox($size, $rotate, $font, $text);
if ($rotate < 0){
$width = abs($bounds[4]-$bounds[0]);
$height = abs($bounds[3]-$bounds[7]);
$offset_y = $font_height;
$offset_x = 0;
}
elseif ($rotate > 0) {
$width = abs($bounds[2]-$bounds[6]);
$height = abs($bounds[1]-$bounds[5]);
$offset_y = abs($bounds[7]-$bounds[5])+$font_height;
$offset_x = abs($bounds[0]-$bounds[6]);
}
else{
$width = abs($bounds[4]-$bounds[6]);
$height = abs($bounds[7]-$bounds[1]);
$offset_y = $font_height;
$offset_x = 0;
}
$image = imagecreate($width+($padding*2)+1,$height+($padding*2)+1);
$background = ImageColorAllocate($image, $bg_color['red'], $bg_color['grn'], $bg_color['blu']);
$foreground = ImageColorAllocate($image, $color['red'], $color['grn'], $color['blu']);
if ($transparent) ImageColorTransparent($image, $background);
ImageInterlace($image, true);
// render the image
ImageTTFText($image, $size, $rotate, $offset_x+$padding, $offset_y+$padding, $foreground, $font, $text);
imagealphablending($image, true);
imagesavealpha($image, true);
// output PNG object.
$finalImage="abc.png";
imagePNG($image, $finalImage, 0, NULL);
imagedestroy($image);
}
Related
I need to iterate through all pixels in an image to replace all but one color with black so that I can define all regions of a particular color. The code below is not working, the image remains unchanged. What am I doing wrong?
header('Content-Type: image/jpeg');
// open an image
$im = imagecreatefromjpeg('sunset.jpg');
$x_val = imagesx($im);
$y_val = imagesy($im);
$black = imagecolorallocate($im, 0, 0, 0);
for ($i = 0; $i < $x_val; $i++) {
$color_index = imagecolorat($im, $i, $i);
$colourarray = imagecolorsforindex($im, $color_index);
if ($colourarray[0] != 170 && $colourarray[1] != 0 && $colourarray[2] != 0) {
$color_index = imagecolorat($im, $i, $i);
imagecolorset($im, $color_index, 0, 0, 0);
} else {
$color_index = imagecolorat($im, $i, $i);
imagecolorset($im, $color_index, 170, 0, 0);
}
}
imagejpeg($im);
imagedestroy($im);
I'm working on a project where I have to convert some instructions text to images and send them by email.
For testing purpose, I'm trying a simple code to output a converted text as an image on the browser, but it's always returning a small white box like this:
I have GD installed on my server.
Here's my code:
<?php
header("Content-type: image/png");
function drawImage()
{
$width = 0;
$height = 0;
$offset_x = 0;
$offset_y = 0;
$bounds = array();
$image = "";
$msg = "Some Sample Text....";
$font = "ARIAL.TTF";
$size = 24; // default font size.
$rot = 0; // rotation in degrees.
$pad = 0; // padding.
$transparent = 1; // transparency set to on.
$red = 0; // black text...
$grn = 0;
$blu = 0;
$bg_red = 255; // on white background.
$bg_grn = 255;
$bg_blu = 255;
// get the font height.
$bounds = ImageTTFBBox($size, $rot, $font, "W");
if ($rot < 0)
{
$font_height = abs($bounds[7]-$bounds[1]);
}
else if ($rot > 0)
{
$font_height = abs($bounds[1]-$bounds[7]);
}
else
{
$font_height = abs($bounds[7]-$bounds[1]);
}
// determine bounding box.
$bounds = ImageTTFBBox($size, $rot, $font, $msg);
if ($rot < 0)
{
$width = abs($bounds[4]-$bounds[0]);
$height = abs($bounds[3]-$bounds[7]);
$offset_y = $font_height;
$offset_x = 0;
}
else if ($rot > 0)
{
$width = abs($bounds[2]-$bounds[6]);
$height = abs($bounds[1]-$bounds[5]);
$offset_y = abs($bounds[7]-$bounds[5])+$font_height;
$offset_x = abs($bounds[0]-$bounds[6]);
}
else
{
$width = abs($bounds[4]-$bounds[6]);
$height = abs($bounds[7]-$bounds[1]);
$offset_y = $font_height;;
$offset_x = 0;
}
$image = imagecreate($width+($pad*2)+1,$height+($pad*2)+1);
$background = ImageColorAllocate($image, $bg_red, $bg_grn, $bg_blu);
$foreground = ImageColorAllocate($image, $red, $grn, $blu);
if ($transparent) ImageColorTransparent($image, $background);
ImageInterlace($image, false);
// render the image
ImageTTFText($image, $size, $rot, $offset_x+$pad, $offset_y+$pad, $foreground, $font, $msg);
// output PNG object.
imagePNG($image);
}
drawImage();
?>
Is this as simple as changing:
$image = imagereate
to
$image = imagecreate
Looks like a typo to me.
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
I have this code to write some text on a new created image:
class ImageCreator
{
public function Draw($string)
{
$font = "lg.ttf";
$txtsize = imagettfbbox(20, 0, $font, $string);
$image = imagecreatetruecolor($txtsize[2], $txtsize[4]);
imagealphablending($image, false);
$c = imagecolorallocatealpha($image,0,0,0,127);
imagefilledrectangle($image,0,0,$txtsize[2],$txtsize[4], $c);
imagealphablending($image, true);
$c = ImageCreator::hexcol2dec("#FFFFFF");
$white = imagecolorallocate($image, $c[0], $c[1], $c[2]);
$c = ImageCreator::hexcol2dec("#000000");
$black = imagecolorallocate($image, $c[0], $c[1], $c[2]);
$c = ImageCreator::hexcol2dec("#044D8F");
$tcolor = imagecolorallocate($image, $c[0], $c[1], $c[2]);
imagettftext($image, 20, 0, 0, 0, $black, $font, $string);
imagettftext($image, 20, 0, 1, 0, $tcolor, $font, $string);
imagettftext($image, 20, 0, 2, 0, $white, $font, $string);
imagealphablending($image,false);
imagesavealpha($image,true);
ob_start();
imagepng($image);
$imgData = ob_get_contents();
ob_end_clean();
return $imgData;
}
public function hexcol2dec($hexColor)
{
$R=0;
$G=0;
$B=0;
for($i = 0; $i < strlen($hexColor);$i++)
{
if($hexColor[$i] == "#")
{
}
else if($hexColor[$i] == 'A' || $hexColor[$i] == 'a')
{
$dec[$i] = 10;
}
else if($hexColor[$i] == 'B' || $hexColor[$i] == 'b')
{
$dec[$i] = 11;
}
else if($hexColor[$i] == 'C' || $hexColor[$i] == 'c')
{
$dec[$i] = 12;
}
else if($hexColor[$i] == 'D' || $hexColor[$i] == 'd')
{
$dec[$i] = 13;
}
else if($hexColor[$i] == 'E' || $hexColor[$i] == 'e')
{
$dec[$i] = 14;
}
else if($hexColor[$i] == 'F' || $hexColor[$i] == 'f')
{
$dec[$i] = 15;
}
else
{
$dec[$i] = $hexColor[$i];
}
}
if($hexColor[0] == "#")
{
$R = 16*$dec[1]+$dec[2];
$G = 16*$dec[3]+$dec[4];
$B = 16*$dec[5]+$dec[6];
}
else
{
$R = 16*$dec[0]+$dec[1];
$G = 16*$dec[2]+$dec[3];
$B = 16*$dec[4]+$dec[5];
}
return array ($R, $G, $B);
}
}
and i get just the transparent background none of the text is showed. I am new at PHP GD and i can't figure out why isn't writing the text. Please help me figure out
Thanks.
The coordinates returned by imagettfbbox are relative to the basepoint, and as such, can be negative.
So when the angle is 0, the upper Y and left X are negative, and you need to subtract them from the lower Y and right X to get the box size.
$width = $txtsize[2] - $txtsize[0];
$height = $txtsize[1] - $txtsize[5];
$image = imagecreatetruecolor($width, $height);
And then you have then to use the absolute values of the negative coordinates as the basepoint coordinate for drawing the text:
imagettftext($image, 20, 0, -$txtsize[0], -$txtsize[5], $black, $font, $string);
Do you have warnings enabled? There could be an issue with PHP locating the font file, since I noticed it is not a complete path.
Does your server have the FreeType library installed? Use phpinfo() to verify. http://www.freetype.org/
You can use this sandbox to test if your coordinates are right: http://ruquay.com/sandbox/imagettf/.
Remember, the basepoint is the x, y coordsinates you use to draw text with imagettftext. A useful thing to do is take a string like...
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
and use the "aboveBasepoint" value for the height of your font. Now you can draw lines and use "the height of your font * leading" as the distance between lines of text, where leading is a number such as 1.45 (for 45% leading).
Look in the comments at the bottom of the PHP Manual entry for this function for many useful functions: http://php.net/manual/en/function.imagettfbbox.php
I have tried:
$index = imagecolorresolve ( $im, 0,0,0 ); // get black
imagecolorset($im, $index, 255, 0, 255); // SET NEW COLOR
This seems to work with png 8 but not 24, and if I do it with 8 it turns out all weird because of the anti-aliasing.
Here is the full test code I'm using. (this is just test code, so be gentle).
function LoadPNG($imgname, $color = false)
{
$im = #imagecreatefrompng($imgname);
imagealphablending($im, false);
if($color) {
$index = imagecolorresolve ( $im, 0,0,0 ); // get black
imagecolorset($im, $index, 255, 0, 255); // SET NEW COLOR
}
imageAlphaBlending($im, true);
imageSaveAlpha($im, true);
return $im;
}
header('Content-Type: image/png');
$img = LoadPNG("head.png", "red");
imagepng($img);
imagedestroy($img);
Based on the solution of inti, i made a script that works:
$imgname = "yourimage.png";
$im = imagecreatefrompng($imgname);
imagealphablending($im, false);
for ($x = imagesx($im); $x--;) {
for ($y = imagesy($im); $y--;) {
$rgb = imagecolorat($im, $x, $y);
$c = imagecolorsforindex($im, $rgb);
if ($c['red'] < 40 && $c['green'] < 40 && $c['blue'] < 40) { // dark colors
// here we use the new color, but the original alpha channel
$colorB = imagecolorallocatealpha($im, 255, 0, 255, $c['alpha']);
imagesetpixel($im, $x, $y, $colorB);
}
}
}
imageAlphaBlending($im, true);
imageSaveAlpha($im, true);
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
I'd like a way to optimize it, because it is quite slow
You can try the following:
cycle all points
get the color of that point
if it matches your colorA, set that pixel to the desired colorB
Code:
for ($x=imagesx($im); $x--; ) {
for ($y=imagesy($im); $y--; ) {
$c = imagecolorat($im, $x, $y);
if ($c[0] == 0 && $c[1] == 0 && $c[2] == 0) {
// here we use the new color, but the original alpha channel
$colorB = imagecolorallocatealpha($im, 255, 0, 255, $c[3]);
imagesetpixel($im, $x, $y, $colorB);
}
}
}
Hope this helps!
this function will replace either 1 or all colors for 1 new color, maintaining transparency levels (otherwise borders will probably look awful, if PARTIAL transparency was used to draw borders).
COMPLETE ANSWER TO SIMILAR POST
<?php
function colorizeKeepAplhaChannnel( $inputFilePathIn, $targetRedIn, $targetGreenIn, $targetBlueIn, $outputFilePathIn ) {
$im_src = imagecreatefrompng( $inputFilePathIn );
$im_dst = imagecreatefrompng( $inputFilePathIn );
$width = imagesx($im_src);
$height = imagesy($im_src);
// Note this: FILL IMAGE WITH TRANSPARENT BG
imagefill($im_dst, 0, 0, IMG_COLOR_TRANSPARENT);
imagesavealpha($im_dst,true);
imagealphablending($im_dst, true);
$flagOK = 1;
for( $x=0; $x<$width; $x++ ) {
for( $y=0; $y<$height; $y++ ) {
$rgb = imagecolorat( $im_src, $x, $y );
$colorOldRGB = imagecolorsforindex($im_src, $rgb);
$alpha = $colorOldRGB["alpha"];
$colorNew = imagecolorallocatealpha($im_src, $targetRedIn, $targetGreenIn, $targetBlueIn, $alpha);
$flagFoundColor = true;
// uncomment next 3 lines to substitute only 1 color (in this case, BLACK/greys)
/*
$colorOld = imagecolorallocatealpha($im_src, $colorOldRGB["red"], $colorOldRGB["green"], $colorOldRGB["blue"], 0); // original color WITHOUT alpha channel
$color2Change = imagecolorallocatealpha($im_src, 0, 0, 0, 0); // opaque BLACK - change to desired color
$flagFoundColor = ($color2Change == $colorOld);
*/
if ( false === $colorNew ) {
//echo( "FALSE COLOR:$colorNew alpha:$alpha<br/>" );
$flagOK = 0;
} else if ($flagFoundColor) {
imagesetpixel( $im_dst, $x, $y, $colorNew );
//echo "x:$x y:$y col=$colorNew alpha:$alpha<br/>";
}
}
}
$flagOK2 = imagepng($im_dst, $outputFilePathIn);
if ($flagOK && $flagOK2) {
echo ("<strong>Congratulations, your conversion was successful </strong><br/>new file $outputFilePathIn<br/>");
} else if ($flagOK2 && !$flagOK) {
echo ("<strong>ERROR, your conversion was UNsuccessful</strong><br/>Please verify if your PNG is truecolor<br/>input file $inputFilePathIn<br/>");
} else if (!$flagOK2 && $flagOK) {
$dirNameOutput = dirname($outputFilePathIn)."/";
echo ("<strong>ERROR, your conversion was successful, but could not save file</strong><br/>Please verify that you have PERMISSION to save to directory $dirName <br/>input file $inputFilePathIn<br/>");
} else {
$dirNameOutput = dirname($outputFilePathIn)."/";
echo ("<strong>ERROR, your conversion was UNsuccessful AND could not save file</strong><br/>Please verify if your PNG is truecolor<br/>Please verify that you have PERMISSION to save to directory $dirName <br/>input file $inputFilePathIn<br/>");
}
echo ("TargetName:$outputFilePathIn wid:$width height:$height CONVERTED:|$flagOK| SAVED:|$flagOK2|<br/>");
imagedestroy($im_dst);
imagedestroy($im_src);
}
$targetRed = 255;
$targetGreen = 255;
$targetBlue = 0;
//$inputFileName = 'frameSquareBlack_88x110.png';
$inputFileName = 'testMe.png';
$dirName = "../img/profilePics/";
$nameTemp = basename($inputFileName, ".png");
$outputFileName = $nameTemp."_$targetRed"."_$targetGreen"."_$targetBlue.png";
$inputFilePath = $dirName.$inputFileName;
$outputFilePath = $dirName.$outputFileName;
//echo "inputFileName:$inputFilePath<br>outputName:$outputFilePath<br>";
colorizeKeepAplhaChannnel( $inputFilePath, $targetRed, $targetGreen, $targetBlue, $outputFilePath);
?>
<br/><br/>
Original <br/>
<img src="<?php echo $inputFilePath; ?>">
<br /><br />Colorized<br/>
<img src="<?php echo $outputFilePath; ?>">
<br />
A good way to doing it is using paintOpaqueImage(), which also permit using color tolerance
$targetColor = "#0074AD";
$fill = "#0074AA";
$tolerance = 30000;
$im = new Imagick( "yourimage.png");
if ($im->paintOpaqueImage ( $targetColor , $fill , $tolerance) ){
$im->writeImage("yourimage.png");
}
You can see the tolenrance doc in http://www.imagemagick.org/script/command-line-options.php#fuzz
This function work like a charm :
public function ImageToBlackAndWhite($im) {
for ($x = imagesx($im); $x--;) {
for ($y = imagesy($im); $y--;) {
$rgb = imagecolorat($im, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8 ) & 0xFF;
$b = $rgb & 0xFF;
$gray = ($r + $g + $b) / 3;
if ($gray < 0xFF) {
imagesetpixel($im, $x, $y, 0xFFFFFF);
}else
imagesetpixel($im, $x, $y, 0x000000);
}
}
imagefilter($im, IMG_FILTER_NEGATE);
}