PHP Image quality issue on rotating and merging - php

When i merge two images as one background and the other as target image. I m using pngs. When I rotate the target image and then merge, yes everything is fine except that the edges of rotated image becomes zigzag i means not smooth. How to make the edges smooth using php GD???
The code I am using:
<?php
// Create image instances
$dest = imagecreatefrompng('bg.png');
$src = imagecreatefrompng('text.png');
$width = imagesx($src);
$height = imagesy($src);
imageantialias($src, true);
$color = imagecolorallocatealpha($src, 0, 0, 0, 127);
$rotated = imagerotate($src, 40, $color);
imagesavealpha($rotated, true);
// $trans_colour = imagecolorallocatealpha($rotated, 0, 0, 0, 127);
// imagefill($rotated, 0, 0, $trans_colour);
imagepng($rotated, 'shahid.png');
$new_img = imagecreatefrompng('shahid.png?');
$width = imagesx($new_img);
$height = imagesy($new_img);
// imagecopymerge($dest, $new_img, 50, 50, 0, 0, $width+60, $height+60, 100);
imagecopymerge_alpha($dest, $new_img, 0, 20, 0, 0, $width, $height, 100);
// Output and free from memory
header('Content-Type: image/png');
imagepng($dest);
imagedestroy($dest);
imagedestroy($src);
function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct)
{
if (!isset($pct)) {
return false;
}
$pct/= 100;
// Get image width and height
$w = imagesx($src_im);
$h = imagesy($src_im);
// Turn alpha blending off
imagealphablending($src_im, false);
// Find the most opaque pixel in the image (the one with the smallest alpha value)
$minalpha = 127;
for ($x = 0; $x < $w; $x++)
for ($y = 0; $y < $h; $y++) {
$alpha = (imagecolorat($src_im, $x, $y) >> 24) & 0xFF;
if ($alpha < $minalpha) {
$minalpha = $alpha;
}
}
// loop through image pixels and modify alpha for each
for ($x = 0; $x < $w; $x++) {
for ($y = 0; $y < $h; $y++) {
// get current alpha value (represents the TANSPARENCY!)
$colorxy = imagecolorat($src_im, $x, $y);
$alpha = ($colorxy >> 24) & 0xFF;
// calculate new alpha
if ($minalpha !== 127) {
$alpha = 127 + 127 * $pct * ($alpha - 127) / (127 - $minalpha);
}
else {
$alpha+= 127 * $pct;
}
// get the color index with new alpha
$alphacolorxy = imagecolorallocatealpha($src_im, ($colorxy >> 16) & 0xFF, ($colorxy >> 8) & 0xFF, $colorxy & 0xFF, $alpha);
// set pixel with the new color + opacity
if (!imagesetpixel($src_im, $x, $y, $alphacolorxy)) {
return false;
}
}
}
// The image copy
imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h);
}
?>

I had this in an old project and worked for me. Anyway, I don't remember if my pngs had really alpha transparency or "gif" transparency...
$image = imagecreatefrompng($href);
$newImage = imagecreatefrompng($href2);
imagealphablending($image, true);
imagealphablending($newImage, true);
$newImage = imagerotate($newImage, $r, -1);
$blue = imagecolorallocate($newImage, 0, 0,255);
imagecolortransparent($newImage, $blue);
imagecopy($image,$newImage,$x,$y,0,0,imagesx($newImage) , imagesy($newImage));
From the manual, in that case, imagealphablending should be replaced by imagesavealpha

Related

PHP Replacing white color in a transparent image

I am working on a php script that replaces the white color with a given one. This is the source image I'm working with:
This is what I'm trying to accomplish:
The first script I tried:
$im = imagecreatefrompng("taxi.png");
imagefilter($im, IMG_FILTER_NEGATE);
imagefilter($im, IMG_FILTER_COLORIZE, 0, 255, 255);
imagefilter($im, IMG_FILTER_NEGATE);
imagealphablending( $im, false );
imagesavealpha( $im, true );
imagepng($im);
imagedestroy($im);
This looked like this:
The second time I tried replacing the each pixel which resulted in having no tolerance, if a pixel was just 1 unit off it wouldn't get replaced.
function ReplaceColour($img, $r1, $g1, $b1, $r2, $g2, $b2)
{
if(!imageistruecolor($img))
imagepalettetotruecolor($img);
$col1 = (($r1 & 0xFF) << 16) + (($g1 & 0xFF) << 8) + ($b1 & 0xFF);
$col2 = (($r2 & 0xFF) << 16) + (($g2 & 0xFF) << 8) + ($b2 & 0xFF);
$width = imagesx($img);
$height = imagesy($img);
for($x=0; $x < $width; $x++)
for($y=0; $y < $height; $y++)
{
$colrgb = imagecolorat($img, $x, $y);
if($col1 !== $colrgb)
continue;
imagesetpixel ($img, $x , $y , $col2);
}
}
header('Content-Type: image/png');
$im = imagecreatefrompng("taxi.png");
ReplaceColour($im,245,245,245,255,0,0);
imagealphablending( $im, false );
imagesavealpha( $im, true );
imagepng($im);
imagedestroy($im);
At the moment I'm thinking about making a mask for the image and changing the mask's color on the fly, but the problem is that I would have to create it for every image I'm adding.

Create a word cloud on selected pixels

I am trying to create a word cloud of a person's face. Similar to this
To achieve this I got a black & white image of a person and turned the darkest pixel to black and lightest pixel to white. And here is my result
Now I have got the area where I would like to place word clouds. Now I can't figure out how do I place words inside the face keeping margin/angle between words.
Here's the code what i have done so far
<?php
set_time_limit(0);
$src = 'person.jpeg';
$im = imagecreatefromjpeg($src);
$size = getimagesize($src);
$width = $size[0];
$height = $size[1];
$image_p = imagecreatetruecolor($width, $height);
imagecopyresampled($image_p, $im, 0, 0, 0, 0, $width, $height, $width, $height);
$white_color = imagecolorallocate($im, 255, 255, 255);
$black_color = imagecolorallocate($im, 0, 0, 0);
$font = __DIR__ . "/testfont.ttf";
$font_size = 16;
$text = "Test text";
$skip = true;
for ($x = 0; $x < $width; $x++) {
for ($y = 0; $y < $height; $y++) {
$rgb = imagecolorat($im, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
if ($r >= 126) {
imagesetpixel($image_p, $x, $y, $white_color);
} else {
imagesetpixel($image_p, $x, $y, $black_color);
if ($x % 20 == 1) {
imagestring($image_p, 5, $x, $y, 'T', $black_color);
//imagettftext($image_p, 16, 0, $x, $y, $black_color, $font, $text);
}
}
//var_dump($r, $g, $b);
//echo "<br/>";
}
}
imagestring($image_p, 5, 0, 0, 'Hello world!', $black_color);
header('Content-Type: image/jpeg');
imagejpeg($image_p, null, 100);
I tried using imagestring & imagettftext
if ($x % 20 == 1) {
imagestring($image_p, 5, $x, $y, 'T', $black_color);
//imagettftext($image_p, 16, 0, $x, $y, $black_color, $font, $text);
}
And got weird output. With imagettftext it takes too long to render and with imagestring this is what I got
Using one of these functions not both of them: imagesetpixel or imagestring
And if you have B/W photo, forget $black_color & $white_color or add them to this codes to customize more. And also add your custom header in the end.
list($w, $h, $type) = getimagesize('person.jpeg');
$resource = imagecreatefromstring(file_get_contents('person.jpeg'));
$img = imagecreatetruecolor($w, $h);
for($y=0; $y<$h; $y+=20)
for($x=0; $x<$w; $x+=20)
imagestring($img, 5, $x, $y, 'Hello world!', imagecolorat($resource, $x, $y));
Here's what works for me. I create a png image template in the Gimp, save it. Trickiest part for me was figuring out the font path aspect, since the font file just had to be in the one directory.
<?php
// Create Image From Existing File
$image = imagecreatefrompng('baseimg.png');
// Allocate A Color For The Text
$black = imagecolorallocate($image, 125, 125, 255);
// Set Path to Font File
$font_path = './FreeSans.ttf';
$text = "Hello World!";
// Print Text On Image
imagettftext($image, 14, 0, 15, 110, $black, $font_path, $text);
//Set the Content Type
header('Content-type: image/png');
// Send Image to Browser
imagepng($image);
// Clear Memory
imagedestroy($image);
exit;
?>

PHP PNG image creation outputting wrong colors

I am trying to put an png overlay over an underlying png file.
The script works just fine, but instead of giving me the overlay colored as it should be, it is outputting it in gray color.
But only the overlay image is gray (bg-color of the overlay, which is basically a border for the underlying image: RGB 20,114,158). And it's 24-bit from PS.
The transparency part (white) works just fine.
<?php
$im = imagecreatefrompng($sourceFile);
$overlay = imagecreatefrompng($overlayFile);
$white = imagecolorallocate($overlay, 255, 255, 255);
imagecolortransparent($overlay, $white);
imagecopymerge($im, $overlay, 0, 0, 0, 0, 173, 173,100);
header('Content-Type: image/png');
imagepng($im);
?>
Any help is much appreciated!
Cheers
Chris
You should just using imagecopy() (you use 100 for the last argument ($pct) of imagecopymerge()).
pct
The two images will be merged according to pct which can range from 0 to 100.
When pct = 0, no action is taken, when 100 this function behaves identically to
imagecopy() for pallete images, except for ignoring alpha components, while it
implements alpha transparency for true colour images.
And don't forget to enable imagealphablending() on both images.
Can you try this (not my code):
<?php
/**
* PNG ALPHA CHANNEL SUPPORT for imagecopymerge();
* This is a function like imagecopymerge but it handle alpha channel well!!!
**/
// A fix to get a function like imagecopymerge WITH ALPHA SUPPORT
// Main script by aiden dot mail at freemail dot hu
// Transformed to imagecopymerge_alpha() by rodrigo dot polo at gmail dot com
function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){
if(!isset($pct)){
return false;
}
$pct /= 100;
// Get image width and height
$w = imagesx( $src_im );
$h = imagesy( $src_im );
// Turn alpha blending off
imagealphablending( $src_im, false );
// Find the most opaque pixel in the image (the one with the smallest alpha value)
$minalpha = 127;
for( $x = 0; $x < $w; $x++ )
for( $y = 0; $y < $h; $y++ ){
$alpha = ( imagecolorat( $src_im, $x, $y ) >> 24 ) & 0xFF;
if( $alpha < $minalpha ){
$minalpha = $alpha;
}
}
//loop through image pixels and modify alpha for each
for( $x = 0; $x < $w; $x++ ){
for( $y = 0; $y < $h; $y++ ){
//get current alpha value (represents the TANSPARENCY!)
$colorxy = imagecolorat( $src_im, $x, $y );
$alpha = ( $colorxy >> 24 ) & 0xFF;
//calculate new alpha
if( $minalpha !== 127 ){
$alpha = 127 + 127 * $pct * ( $alpha - 127 ) / ( 127 - $minalpha );
} else {
$alpha += 127 * $pct;
}
//get the color index with new alpha
$alphacolorxy = imagecolorallocatealpha( $src_im, ( $colorxy >> 16 ) & 0xFF, ( $colorxy >> 8 ) & 0xFF, $colorxy & 0xFF, $alpha );
//set pixel with the new color + opacity
if( !imagesetpixel( $src_im, $x, $y, $alphacolorxy ) ){
return false;
}
}
}
// The image copy
imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h);
}
// USAGE EXAMPLE:
$img_a = imagecreatefrompng('image1.png');
$img_b = imagecreatefrompng('wm2.png');
// SAME COMMANDS:
imagecopymerge_alpha($img_a, $img_b, 10, 10, 0, 0, imagesx($img_b), imagesy($img_b),50);
// OUTPUT IMAGE:
header("Content-Type: image/png");
imagesavealpha($img_a, true);
imagepng($img_a, NULL);
?>
Src: http://www.php.net/manual/en/function.imagecopymerge.php#88456

Rotate a PNG then resave with Image Transparency

I'm having some major issues getting PNG transparency on a PNG that is being rotated.
$filename = 'bird_up.png';
$source = imagecreatefrompng($filename) or die('Error opening file '.$filename);
imagealphablending($source, false);
imagesavealpha($source, true);
$rotation = imagerotate($source, $degrees, imageColorAllocateAlpha($source, 0, 0, 0, 127));
imagealphablending($source, false);
imagesavealpha($source, true);
header('Content-type: image/png');
imagepng($rotation);
imagedestroy($source);
imagedestroy($rotation);
I've added a working commented version below
<?php
// this file writes the image into the http response,
// so we cant have any output other than headers and the file data
ob_start();
$filename = 'tibia.png';
$degrees = 45;
// open the image file
$im = imagecreatefrompng( $filename );
// create a transparent "color" for the areas which will be new after rotation
// r=0,b=0,g=0 ( black ), 127 = 100% transparency - we choose "invisible black"
$transparency = imagecolorallocatealpha( $im,0,0,0,127 );
// rotate, last parameter preserves alpha when true
$rotated = imagerotate( $im, $degrees, $transparency, 1);
// disable blendmode, we want real transparency
imagealphablending( $rotated, false );
// set the flag to save full alpha channel information
imagesavealpha( $rotated, true );
// now we want to start our output
ob_end_clean();
// we send image/png
header( 'Content-Type: image/png' );
imagepng( $rotated );
// clean up the garbage
imagedestroy( $im );
imagedestroy( $rotated );
Demo
Original image from Wikipedia
rotated -45 degrees, new areas with ~50% opacity for a demo
$transparency = imagecolorallocatealpha( $im,0,0,0,55 );
rotated -45 degress, new areas with 100% opacity
$transparency = imagecolorallocatealpha( $im,0,0,0,127 );
<?php
$text ="New"; $font = "fonts/AARDV.ttf"; $size = 100;
function html2rgb()
{
$color='FF0000';
if(strlen($color)==6)
list($r, $g, $b)=array($color[0].$color[1],$color[2].$color[3],$color[4].$color[5]);
elseif (strlen($color) == 3)
list($r, $g, $b) = array($color[0].$color[0], $color[1].$color[1], $color[2].$color[2]);
else
return false;
$r = hexdec($r);
$g = hexdec($g);
$b = hexdec($b);
return array($r, $g, $b);
}
$c=html2rgb();
$bbox = imagettfbbox($size, 0, $font, $text);
$width = abs($bbox[2] - $bbox[0]);
$height = abs($bbox[7] - $bbox[1]);
$image = imagecreatetruecolor($width, $height);
$bgcolor = imagecolorallocate($image, 1, 1,0);
imagecolortransparent($image, $bgcolor);
$color = imagecolorallocate($image, $c[0],$c[1],$c[2]);
$x = $bbox[0] + ($width / 2) - ($bbox[4] / 2);
$y = $bbox[1] + ($height / 2) - ($bbox[5] / 2);
imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $bgcolor);
imagettftext($image, $size, 0, $x, $y, $color, $font, $text);
$last_pixel= imagecolorat($image, 0, 0);
for ($j = 0; $j < $height; $j++)
{
for ($i = 0; $i < $width; $i++)
{
if (isset($blank_left) && $i >= $blank_left)
{
break;
}
if (imagecolorat($image, $i, $j) !== $last_pixel)
{
if (!isset($blank_top))
{
$blank_top=$j;
}
$blank_left=$i;break;
}
$last_pixel=imagecolorat($image, $i, $j);
}
}
$x -= $blank_left;
$y -= $blank_top;
imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $bgcolor);
imagettftext($image, $size, 0, $x, $y, $color, $font, $text);
header('Content-type: image/png');
$transparency = imagecolorallocatealpha( $image,0,0,0,127 );
$image=imagerotate($image, 10, $transparency, 1);
imagealphablending( $image, false );
imagesavealpha( $image, true );
ob_end_clean();
imagepng($image);
imagedestroy($image);
?>
This one not work..Black color
any one please answer this..
enter code here

Can I swap colors in image using GD library in PHP?

I got the image like this (it's a graph):
(source: kitconet.com)
I want to change the colours, so the white is black, the graph line is light blue, etc.. is it possible to achieve with GD and PHP?
This will replace the white color with Gray
$imgname = "test.gif";
$im = imagecreatefromgif ($imgname);
$index = imagecolorclosest ( $im, 255,255,255 ); // get White COlor
imagecolorset($im,$index,92,92,92); // SET NEW COLOR
$imgname = "result.gif";
imagegif($im, $imgname ); // save image as gif
imagedestroy($im);
I had trouble making this solution work. The image cannot be a true color image. Convert it first with imagetruecolortopalette();
$imgname = "test.gif";
$im = imagecreatefromgif ($imgname);
imagetruecolortopalette($im,false, 255);
$index = imagecolorclosest ( $im, 255,255,255 ); // get White COlor
imagecolorset($im,$index,92,92,92); // SET NEW COLOR
$imgname = "result.gif";
imagegif($im, $imgname ); // save image as gif
imagedestroy($im);
I know this is late and after the fact, but I've put together a script that will do this on a slightly larger scale. Hopefully someone who comes across this post can use it. It takes an number of source images that are one-color layers (your choice). You provide it with a source color and the tint of each layer and the script returns a composite image (with full transparency) colored specifically to your provided hex code.
Check out the code below. A more detailed explanation can be found on my blog.
function hexLighter($hex, $factor = 30) {
$new_hex = '';
$base['R'] = hexdec($hex{0}.$hex{1});
$base['G'] = hexdec($hex{2}.$hex{3});
$base['B'] = hexdec($hex{4}.$hex{5});
foreach ($base as $k => $v) {
$amount = 255 - $v;
$amount = $amount / 100;
$amount = round($amount * $factor);
$new_decimal = $v + $amount;
$new_hex_component = dechex($new_decimal);
$new_hex .= sprintf('%02.2s', $new_hex_component);
}
return $new_hex;
}
// Sanitize/Validate provided color variable
if (!isset($_GET['color']) || strlen($_GET['color']) != 6) {
header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request', true, 400);
exit(0);
}
if (file_exists( "cache/{$_GET['color']}.png" )) {
header( 'Content-Type: image/png' );
readfile( "cache/{$_GET['color']}.png" );
exit(0);
}
// Desired final size of image
$n_width = 50;
$n_height = 50;
// Actual size of source images
$width = 125;
$height = 125;
$image = imagecreatetruecolor($width, $height);
imagesavealpha($image, true);
imagealphablending($image, false);
$n_image = imagecreatetruecolor($n_width, $n_height);
imagesavealpha($n_image, true);
imagealphablending($n_image, false);
$black = imagecolorallocate($image, 0, 0, 0);
$transparent = imagecolorallocatealpha($image, 255, 255, 255, 127);
imagefilledrectangle($image, 0, 0, $width, $height, $transparent);
$layers = array();
$layers_processed = array();
$layers[] = array( 'src' => 'layer01.gif', 'level' => 0 ); // Border
$layers[] = array( 'src' => 'layer02.gif', 'level' => 35 ); // Background
$layers[] = array( 'src' => 'layer03.gif', 'level' => 100 ); // White Quotes
foreach ($layers as $idx => $layer) {
$img = imagecreatefromgif( $layer['src'] );
$processed = imagecreatetruecolor($width, $height);
imagesavealpha($processed, true);
imagealphablending($processed, false);
imagefilledrectangle($processed, 0, 0, $width, $height, $transparent);
$color = hexLighter( $_GET['color'], $layer['level'] );
$color = imagecolorallocate($image,
hexdec( $color{0} . $color{1} ),
hexdec( $color{2} . $color{3} ),
hexdec( $color{4} . $color{5} )
);
for ($x = 0; $x < $width; $x++)
for ($y = 0; $y < $height; $y++)
if ($black === imagecolorat($img, $x, $y))
imagesetpixel($processed, $x, $y, $color);
imagecolortransparent($processed, $transparent);
imagealphablending($processed, true);
array_push($layers_processed, $processed);
imagedestroy( $img );
}
foreach ($layers_processed as $processed) {
imagecopymerge($image, $processed, 0, 0, 0, 0, $width, $height, 100);
imagedestroy( $processed );
}
imagealphablending($image, true);
imagecopyresampled($n_image, $image, 0, 0, 0, 0, $n_width, $n_height, $width, $height);
imagealphablending($n_image, true);
header( 'Content-Type: image/png' );
imagepng( $n_image, "cache/{$_GET['color']}.png" );
imagepng( $n_image );
// Free up memory
imagedestroy( $n_image );
imagedestroy( $image );
I haven't tried it myself but you can look at the function imagecolorset() in the GD library It does a color fill like effect, that could help with the white background.
You could try the imagefilter function http://lv.php.net/imagefilter - but that will not give your direct access to replace one color with another, just changing the r/g/b components.
A very low level solution could be implemented using imagesetpixel http://nl2.php.net/imagesetpixel to set the new pixel values.
IMG_FILTER_NEGATE: Reverses all colors of the image.
http://www.php.net/manual/en/function.imagefilter.php
Could that be a solution?
The slow but sure approach, iterating over every pixel.
function ReplaceColour($img, $r1, $g1, $b1, $r2, $g2, $b2)
{
if(!imageistruecolor($img))
imagepalettetotruecolor($img);
$col1 = (($r1 & 0xFF) << 16) + (($g1 & 0xFF) << 8) + ($b1 & 0xFF);
$col2 = (($r2 & 0xFF) << 16) + (($g2 & 0xFF) << 8) + ($b2 & 0xFF);
$width = imagesx($img);
$height = imagesy($img);
for($x=0; $x < $width; $x++)
for($y=0; $y < $height; $y++)
{
$colrgb = imagecolorat($img, $x, $y);
if($col1 !== $colrgb)
continue;
imagesetpixel ($img, $x , $y , $col2);
}
}
I'm not aware of any ready-made functions. But I suppose you could go trough every pixel of the image and change it's colour...

Categories