Add colour overlay to non transparent part of a PNG - php

I am trying to accomplish having a colour wheel and it will add an overlay to a PNG image with a 50% opacity so you can still see the outlines of the image behind.
I have tried using intervention fill methods and changing it on a per-pixel basis.
private function colorImage($url, $r = null, $g = null, $b = null) {
$im = imagecreatefrompng($url);
imageAlphaBlending($im, true);
imageSaveAlpha($im, true);
if (imageistruecolor($im)) {
$sx = imagesx($im);
$sy = imagesy($im);
for ($x = 0; $x < $sx; $x++) {
for ($y = 0; $y < $sy; $y++) {
$c = imagecolorat($im, $x, $y);
$a = $c & 0xFF000000;
$newColor = $a | $r << 16 | $g << 8 | $b;
imagesetpixel($im, $x, $y, $newColor);
}
}
}
ob_start();
imagepng($im);
imagedestroy($im);
$image_data = ob_get_contents();
ob_end_clean();
$image_data_base64 = "data:image/png;base64," . base64_encode($image_data);
return $image_data_base64;
}
Before: https://imgur.com/v1xRixQ
Current: https://imgur.com/67M9iCg
Objective: https://imgur.com/RxzaxTP

You can use the Intervention Image image library to do this.
Create an instance that is an image filled with your semi-transparent RGB color, mask it off using the source image, and lay the mask on top of the original as an overlay.
use Intervention\Image\ImageManager;
// setup
$red = 255;
$green = 0;
$blue = 0;
$opacity = 0.25;
$manager = new ImageManager(['driver' => 'gd']);
// the source image
$image = $manager->make('./board.png');
// the fill color
$fill = $manager->canvas(
$image->width(),
$image->height(),
[$red, $green, $blue, $opacity]
);
// use the source image to mask off only the portion of the fill that will be
// used as the overlay
$fill->mask($image, true);
// apply the semi-transparent, masked fill to the source image
$image->insert($fill);
// render as a png
header('Content-Type: image/png');
echo $image->encode('png');
Output: https://imgur.com/oIRP8Ir

Related

Problem pasting one image into another PHP

I want to paste the $original image into the center of $fondo image, i write the following code:
<?php
header('Content-Type: image/png');
// The file
$fondo = imagecreate(1000,1000); // Create 1000x1000 image
$color_fondo = imagecolorallocate($fondo,197,237,206); // Set color of background
$original = imagecreatefromstring(file_get_contents('test.jpg')); // Load image
$wb = imagesx($fondo); // Bakground width
$wi = imagesx($original); // Image width
$hb = imagesy($fondo);
$hi = imagesy($original);
//Want to center in the middle of the image, so calc ($wb/2-$wi/2)
imagecopy($fondo,$original,($wb/2-$wi/2),($hb/2-$hi/2),0,0,imagesx($original),imagesy($original));
imagepng($fondo);
The result i got is this:
As you can see the cyan color is affecting original image:
Any ideas on what i'm wrong? Thank you!
the solution is:
Creating the image as imagecreatetruecolor instead of imagecreate
$fondo = imagecreatetruecolor(1000,1000); // Create 1000x1000 image
$color_fondo = imagecolorallocate($fondo,197,237,206); //Desired color
Then, need to paint the $fondo with
imagefill($fondo,0,0,$color_fondo);
Also, crop as circle using this function
function circulo ($original,$radio){
$src = imagecreatefromstring(file_get_contents($original));
$w = imagesx($src);
$h = imagesy($src);
$newpic = imagecreatetruecolor($w,$h);
imagealphablending($newpic,false);
$transparent = imagecolorallocatealpha($newpic, 0, 0, 0, 127); //Hacer transparente la imagen
$r=$w/$radio; //Radio del circulo
for($x=0;$x<$w;$x++)
for($y=0;$y<$h;$y++){
$c = imagecolorat($src,$x,$y);
$_x = $x - $w/2;
// echo $_x."\n";
$_y = $y - $h/2;
if((($_x*$_x) + ($_y*$_y)) < ($r*$r)){
imagesetpixel($newpic,$x,$y,$c);
}else{
imagesetpixel($newpic,$x,$y,$transparent);
}
}
return $newpic;
}
The result is :

Watermarking: Display the same text on multiple parts of the image

I want to add a text to a image. The text should be displayed in multiple areas of the image (not just one).
For example I want to watermark with a text stack. Stack should be displayed in the image at least 8 times in different areas in the image.
I just learned about imagestring() and imagettftext(), but these two only displays my text on a single spot.
Image is not fixed size, so i cannot specify exact and multiple location in advance. It should work on all sizes of images
<?php
/*
image.php
*/
header("Content-type: image/jpeg");
$imgPath = 'olximage.jpg';
$image = imagecreatefromjpeg($imgPath);
$color = imagecolorallocate($image, 255, 255, 255);
$string = "stack overflow";
$fontSize = 3;
$x = 15;
$y = 185;
imagestring($image, $fontSize, $x, $y, $string, $color);
$x = 15;
$y = 175;
imagestring($image, $fontSize, $x, $y, $string, $color);
imagejpeg($image);
?>
Thanks in advance
For example:
<?php
/*
image.php
*/
header("Content-type: image/jpeg");
$imgPath = 'olximage.jpg';
$image = imagecreatefromjpeg($imgPath);
$color = imagecolorallocate($image, 255, 255, 255);
$string = "stack overflow";
$fontSize = 3;
$imageHeight = imagesy($image);
$distanceY = 10;
$maxImageStrings = max(8, $imageHeight / $distanceY);
$x = 15;
for ($i = 0; $i < $maxImageStrings; $i++) {
$y = $i * $distanceY;
imagestring($image, $fontSize, $x, $y, $string, $color);
}
imagejpeg($image);
You can finetune calculations for your needs.
I'm using Imagick extension for same. If you want to go with this then follow detail:
PHP:
// Create objects
$image = new Imagick('image.png');
$watermark = new Imagick();
// Watermark text
$text = 'Copyright';
// Create a new drawing palette
$draw = new ImagickDraw();
$watermark->newImage(140, 80, new ImagickPixel('none'));
// Set font properties
$draw->setFont('Arial');
$draw->setFillColor('grey');
$draw->setFillOpacity(.5);
// Position text at the top left of the watermark
$draw->setGravity(Imagick::GRAVITY_NORTHWEST);
// Draw text on the watermark
$watermark->annotateImage($draw, 10, 10, 0, $text);
// Position text at the bottom right of the watermark
$draw->setGravity(Imagick::GRAVITY_SOUTHEAST);
// Draw text on the watermark
$watermark->annotateImage($draw, 5, 15, 0, $text);
// Repeatedly overlay watermark on image
for ($w = 0; $w < $image->getImageWidth(); $w += 140) {
for ($h = 0; $h < $image->getImageHeight(); $h += 80) {
$image->compositeImage($watermark, Imagick::COMPOSITE_OVER, $w, $h);
}
}
// Set output image format
$image->setImageFormat('png');
// Output the new image
header('Content-type: image/png');
echo $image;
although there are plenty of command-line examples to be found on the ImageMagick website, so that is where we shall begin.

Change color of non-transparent parts of png in PHP

I want to fill the png non transparent part with any color or image using php.
Following is the base image
Following is the target image
I have used following code of php to fill non transparent part of the png.
$im = imagecreatefrompng(dirname(__FILE__) . '/images/cat_1.png');
$red = imagecolorallocate($im, 255, 0, 0);
imagefill($im, 0, 0, $red);
header('Content-type: image/png');
imagepng($im);
imagedestroy($im);
But it gives me following output.
please help me to complete my task.
Thanks in advance.
Save this version of the base image:
This image has been saved as an indexed-PNG format, making it perfect for colour substitution. In this case, index 0 is the cat's colour, and index 1 is the background (not ideal, but that's what GIMP gave me)
In this case:
$img = imagecreatefrompng("cat_1.png");
imagecolorset($img,0, 255,0,0);
imagepng($img); // output red cat
Image editing in general is made much easier if you have a base image that lends itself to easy editing in this way ;)
This line imagefill($im, 0, 0, $red); fills the image with the color red, at the coordinate (0,0), which is topleft. So it starts filling at the top left and fills everything like when you use the paintbucket in MSPaint. You could use imagefill($im, 150, 150, $red); for example (if 150,150 is the center).
use this function, it returns a base64 image <img src="output">
public static function colorImage($url, $hex = null, $r = null, $g = null, $b = null)
{
if ($hex != null) {
$hex = str_replace("#", "", $hex);
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
}
$im = imagecreatefrompng($url);
imageAlphaBlending($im, true);
imageSaveAlpha($im, true);
if (imageistruecolor($im)) {
$sx = imagesx($im);
$sy = imagesy($im);
for ($x = 0; $x < $sx; $x++) {
for ($y = 0; $y < $sy; $y++) {
$c = imagecolorat($im, $x, $y);
$a = $c & 0xFF000000;
$newColor = $a | $r << 16 | $g << 8 | $b;
imagesetpixel($im, $x, $y, $newColor);
}
}
}
ob_start();
imagepng($im);
imagedestroy($im);
$image_data = ob_get_contents();
ob_end_clean();
$image_data_base64 = "data:image/png;base64," . base64_encode($image_data);
return $image_data_base64;
}

PHP - transparency issue on smaller images

So I'm using a method for re-sizing images that I came across on here the other day and it works great for the initial image it processes but I use the process a second time to create a smaller image to use for a thumb nail. When this second thumb nail is created it comes out with a black background where it should be transparent. I know this is a common problem as I have seen plenty of threads on here with similar complaints. When I was looking last night in the php error logs it was saying that imagecolorat was trying to hit pixels which were out of bounds.....
PHP Notice: imagecolorat(): 0,28 is out of bounds in C:\inetpub\
At least I know whats happening but what I need to know now is how to fix it. Its really strange that for the larger copy of the same image I dont get this error at all and it works just fine producing a nice copy of the larger uploaded copy. Heres the code that Im using to resize everything:
$image_source = imagecreatefromstring($markericon); //original image
$imgHead = "image/jpeg"; //tag for image to be pulled later. images go in are png's
//code to make sure image is never larger than certain size
$image_width = imagesx($image_source);
$image_height = imagesy($image_source);
if($image_width>$max_upload_large_side || $image_height >$max_upload_large_side){
$proportionslarge = $image_width/$image_height;
if($image_width>$image_height){
$new_large_width = $max_upload_large_side;
$new_large_height = round($max_upload_large_side/$proportionslarge);
}
else{
$new_large_height = $max_upload_large_side;
$new_large_width = round($max_upload_large_side*$proportionslarge);
}
$new_large_image = imagecreatetruecolor($new_large_width , $new_large_height);
//code used to retain image transparency
//over write alpha chanel of image destination
imagealphablending($new_large_image, false); // Overwrite alpha
imagesavealpha($new_large_image, true);
// Create a separate alpha channel to blend images with
$alpha_image = imagecreatetruecolor($image_width, $image_height);
imagealphablending($alpha_image, false); // Overwrite alpha
imagesavealpha($alpha_image, true);
//copy data at every pixel in image
for ($x = 0; $x < $image_width; $x++) {
for ($y = 0; $y < $image_height; $y++) {
$alpha = (imagecolorat($image_source, $x, $y) >> 24) & 0xFF;
$color = imagecolorallocatealpha($alpha_image, 0, 0, 0, $alpha);
imagesetpixel($alpha_image, $x, $y, $color);
}
}
// Resize image to destination, using gamma correction
imagegammacorrect($image_source, 2.2, 1.0);
imagecopyresampled($new_large_image, $image_source, 0, 0, 0, 0, $new_large_width, $new_large_height, $image_width, $image_height);
imagegammacorrect($new_large_image, 1.0, 2.2);
// Resize alpha channel
$alpha_resized_image = imagecreatetruecolor($new_large_width, $new_large_height);
imagealphablending($alpha_resized_image, false);
imagesavealpha($alpha_resized_image, true);
imagecopyresampled($alpha_resized_image, $alpha_image, 0, 0, 0, 0, $new_large_width, $new_large_height, $image_width, $image_height);
// Copy alpha channel back to resized image
for ($x = 0; $x < $new_large_width; $x++) {
for ($y = 0; $y < $new_large_height; $y++) {
$alpha = (imagecolorat($alpha_resized_image, $x, $y) >> 24) & 0xFF;
$rgb = imagecolorat($new_large_image, $x, $y);
$r = ($rgb >> 16 ) & 0xFF;
$g = ($rgb >> 8 ) & 0xFF;
$b = $rgb & 0xFF;
$color = imagecolorallocatealpha($new_large_image, $r, $g, $b, $alpha);
imagesetpixel($new_large_image, $x, $y, $color);
}
}
// end of first run//
ob_start(); // Start capturing stdout.
imagePNG($new_large_image);
$lBinaryThumbnail = ob_get_contents(); // the raw jpeg image data.
ob_end_clean(); // Dump the stdout so it does not screw other output.
$lBinaryThumbnail = addslashes($lBinaryThumbnail);
imagedestroy($new_large_image);
} else $lBinaryThumbnail = $imgData;
//start of second image run
if($image_width>$max_upload_small_side || $image_height >$max_upload_small_side){
$proportionssmall = $image_width/$image_height;
if($image_width>$image_height){
$new_small_width = $max_upload_small_side;
$new_small_height = round($max_upload_small_side/$proportionssmall);
}
else{
$new_small_height = $max_upload_small_side;
$new_small_width = round($max_upload_small_side*$proportionssmall);
}
$new_small_image = imagecreatetruecolor($new_small_width , $new_small_height);
//////////////////////////////////////////////////////////////////////////////////
//over write alpha chanel of image destination
imagealphablending($new_small_image, false); // Overwrite alpha
imagesavealpha($new_small_image, true);
// Create a separate alpha channel to blend images with
$alpha_image = imagecreatetruecolor($image_width, $image_height);
imagealphablending($alpha_image, false); // Overwrite alpha
imagesavealpha($alpha_image, true);
//copy data at every pixel in image
for ($x = 0; $x < $image_width; $x++) {
for ($y = 0; $y < $image_height; $y++) {
$alpha = (imagecolorat($image_source, $x, $y) >> 24) & 0xFF;
$color = imagecolorallocatealpha($alpha_image, 0, 0, 0, $alpha);
imagesetpixel($alpha_image, $x, $y, $color);
}
}
// Resize image to destination, using gamma correction
imagegammacorrect($image_source, 2.2, 1.0);
imagecopyresampled($new_small_image, $image_source, 0, 0, 0, 0, $new_small_width , $new_small_height, $image_width, $image_height);
imagegammacorrect($new_small_image, 1.0, 2.2);
// Resize alpha channel
$alpha_resized_image = imagecreatetruecolor( $image_width, $image_height);
imagealphablending($alpha_resized_image, false);
imagesavealpha($alpha_resized_image, true);
imagecopyresampled($alpha_resized_image, $alpha_image, 0, 0, 0, 0, $new_small_width ,$new_small_height, $image_width, $image_height);
// Copy alpha channel back to resized image
for ($x = 0; $x < $new_small_width; $x++) {
for ($y = 0; $y < $new_small_height; $y++) {
$alpha = (imagecolorat($alpha_resized_image, $x, $y) >> 24) & 0xFF;
$rgb = imagecolorat($new_small_image, $x, $y); //this is the line that throws the error first and gives a out of bounds related error.
$r = ($rgb >> 16 ) & 0xFF;
$g = ($rgb >> 8 ) & 0xFF;
$b = $rgb & 0xFF;
$color = imagecolorallocatealpha($new_small_image, $r, $g, $b, $alpha);
imagesetpixel($new_small_image, $x, $y, $color);
}
}
// end of new code //
//imagecopyresampled($new_small_image, $image_source, 0, 0, 0, 0, $new_small_width, $new_small_height, $image_width, $image_height);
ob_start(); // Start capturing stdout.
imagePNG($new_small_image);
$sBinaryThumbnail = ob_get_contents(); // the raw jpeg image data.
ob_end_clean(); // Dump the stdout so it does not screw other output.
$sBinaryThumbnail = addslashes($sBinaryThumbnail);
imagedestroy($new_small_image);
} else $sBinaryThumbnail = $lBinaryThumbnail;
imagedestroy($image_source);
Like I said everything works fine for the first run but for some reason on the second run it farts and throws a out of bounds error. it starts at 0,28 and goes on until the end of the loop process at 50,50
I figured it out :) I took the code I had up above that created the alpha correct copy and turned it all into its own function and now it works just fine.

Check if image is white; if so make transparent

I have an image, and I want to make it transparent if it's completely white. I have the following code already for GD for getting a part of the image:
$srcp = imagecreatefrompng("../images/".$_GET['b'].".png");
$destp = imagecreate(150, 150);
imagecopyresampled($destp, $srcp, 0, 0, 40, 8, 150, 150, 8, 8);
header('Content-type: image/png');
imagepng($destp);
But how can I have it first check if the image is completely white, if so change it to transparent, and apply that to $destp?
EDIT:
Based on re-reading the question, and the discussion below, I believe this is what you're looking for:
$width = 150;
$height = 150;
$srcp = imagecreatefrompng("../images/".$_GET['b'].".png");
$destp = imagecreatetruecolor(150, 150);
$white = 0;
for ($y = 0; $y < $height; $y++)
{
for ($x = 0; $x < $width; $x++)
{
$currentColor = imagecolorat($srcp, $x, $y);
$colorParts = imagecolorsforindex($srcp, $currentColor);
if (($colorParts['red'] == 255 &&
$colorParts['green'] == 255 &&
$colorParts['blue'] == 255))
{
$white++;
}
}
}
if ($white == ($width * $height))
{
imagecopyresampled($destp, $srcp, 0, 0, 40, 8, 150, 150, 8, 8);
}
else
{
imagesavealpha($destp, true);
imagefill($destp, 0, 0, imagecolorallocatealpha($destp, 0, 0, 0, 127));
}
header('Content-type: image/png');
imagepng($destp);
This produces a blank image if the original image's 8x8 slice is all white, otherwise it resamples the 8x8 slice to 150x150.
Original:
I haven't ever done anything with PHP GD before, and thought it would be a fun challenge. Here's how I ended up making this happen:
$filename = 'test.png'; // input image
$image = imagecreatefrompng($filename);
// grab the input image's size
$size = getimagesize($filename);
$width = $size[0];
$height = $size[1];
$newImage = imagecreatetruecolor($width, $height);
// make sure that the image will retain alpha when saved
imagesavealpha($newImage, true);
// fill with transparent pixels first or else you'll
// get black instead of transparent
imagefill($newImage, 0, 0, imagecolorallocatealpha($newImage, 0, 0, 0, 127));
// loop through all the pixels
for ($y = 0; $y < $height; $y++)
{
for ($x = 0; $x < $width; $x++)
{
// get the current pixel's colour
$currentColor = imagecolorat($image, $x, $y);
// then break it into easily parsed bits
$colorParts = imagecolorsforindex($image, $currentColor);
// if it's NOT white
if (!($colorParts['red'] == 255 &&
$colorParts['green'] == 255 &&
$colorParts['blue'] == 255))
{
// then keep the same colour
imagesetpixel($newImage, $x, $y, $currentColor);
}
}
}
// final output, the second arg is the filename
imagepng($newImage, 'newImage.png');
It allowed me to turn this:
Into this (hard to see the alpha here, but you can open it to see):
A simple strightforward solution would be to use imagecolorat and iterate through all the pixels of the png and if all are white change it to transparent.
Hope this helps.
After a quick look through the GD manual pages, I think that the following should work for you (it did on my test server, anyway):
<?php
// Create image instance
$im = imagecreatefromgif('test.gif');
if (imagecolorstotal($im) == 1) {
$rgb = imagecolorat($im, 1, 1); // feel free to test any pixel, but if they're all
// the same colour, then it shouldn't really matter
$colors = imagecolorsforindex($im, $rgb);
if ($colors['red'] == 255 && $colors['green'] == 255 && $colors['blue'] == 255) {
// I'm ignoring $colors['alpha'] but that's optional.
echo "Yup; it's white...";
}
} else {
// if you've got more than one colour then the image has to be at least
// two colours, so not really worth checking if any pixels are white
}
// Free image
imagedestroy($im);
?>
References:
imagecolorat().
imagecolorstotal().

Categories