PHP - Replace colour within image - php

I hope someone can help,
I have made a script that masks images... however it is reliant on a colour to mask with ( 'green screen' style). The trouble is if the image that I am masking contains that colour it is ruined.
What I am looking to do is prior to masking the image replace any occurance of my keying colour (0,0,255) with a similar colour such as 0,0,254.
I have found a few solutions based around gif's or 256 colour PNG as they are indexed..
So my question is also will it be more efficient to convert it to a gif or 256 png then look through the index and replace the colour or search through every pixel and replace the colours.
Thanks,

You need to open the input file and scan each pixel to check for your chromokey value.
Something like this:
// Open input and output image
$src = imagecreatefromJPEG('input.jpg') or die('Problem with source');
$out = ImageCreateTrueColor(imagesx($src),imagesy($src)) or die('Problem In Creating image');
// scan image pixels
for ($x = 0; $x < imagesx($src); $x++) {
for ($y = 0; $y < imagesy($src); $y++) {
$src_pix = imagecolorat($src,$x,$y);
$src_pix_array = rgb_to_array($src_pix);
// check for chromakey color
if ($src_pix_array[0] == 0 && $src_pix_array[1] == 0 && $src_pix_array[2] == 255) {
$src_pix_array[2] = 254;
}
imagesetpixel($out, $x, $y, imagecolorallocate($out, $src_pix_array[0], $src_pix_array[1], $src_pix_array[2]));
}
}
// write $out to disc
imagejpeg($out, 'output.jpg',100) or die('Problem saving output image');
imagedestroy($out);
// split rgb to components
function rgb_to_array($rgb) {
$a[0] = ($rgb >> 16) & 0xFF;
$a[1] = ($rgb >> 8) & 0xFF;
$a[2] = $rgb & 0xFF;
return $a;
}

Here is the replace colour solution that first converts to 256 pallet:
//Open Image
$Image = imagecreatefromJPEG('input.jpg') or die('Problem with source');
//set the image to 256 colours
imagetruecolortopalette($Image,0,256);
//Find the Chroma colour
$RemChroma = imagecolorexact( $Image, 0,0,255 );
//Replace Chroma Colour
imagecolorset($Image,$RemChroma,0,0,254);
//Use function to convert back to true colour
imagepalettetotruecolor($Image);
function imagepalettetotruecolor(&$img)
{
if (!imageistruecolor($img))
{
$w = imagesx($img);
$h = imagesy($img);
$img1 = imagecreatetruecolor($w,$h);
imagecopy($img1,$img,0,0,0,0,$w,$h);
$img = $img1;
}
}
I personally prefer radio4fans solution as it is lossless, but if speed is your goal this is superior.

Related

Add colour overlay to non transparent part of a PNG

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

Half Grayscale by imagefilter()

I know PHP's GD library can apply grayscale filter to an image, for example:
$img = imagecreatefrompng('test.png');
$img = imagefilter($img, IMG_FILTER_GRAYSCALE);
imagepng($img, 'test_updated.png');
Is there any method that can apply half of the grayscale effects (which is similar to CSS3's filter: grayscale(50%);) ?
I read from this answer, the grayscale filter is actually a reduction of R, G & B channel. Can I customize my own grayscale filter in PHP?
Reference: imagefilter()
Is there any method that can apply half of the grayscale effects
(which is similar to CSS3's filter: grayscale(50%);) ?
Found a script something similar what you are looking for..
<?php
function convertImageToGrayscale($source_file, $percentage)
{
$outputImage = ImageCreateFromJpeg($source_file);
$imgWidth = imagesx($outputImage);
$imgHeight = imagesy($outputImage);
$grayWidth = round($percentage * $imgWidth);
$grayStartX = $imgWidth-$grayWidth;
for ($xPos=$grayStartX; $xPos<$imgWidth; $xPos++)
{
for ($yPos=0; $yPos<$imgHeight; $yPos++)
{
// Get the rgb value for current pixel
$rgb = ImageColorAt($outputImage, $xPos, $yPos);
// extract each value for r, g, b
$rr = ($rgb >> 16) & 0xFF;
$gg = ($rgb >> 8) & 0xFF;
$bb = $rgb & 0xFF;
// Get the gray Value from the RGB value
$g = round(($rr + $gg + $bb) / 3);
// Set the grayscale color identifier
$val = imagecolorallocate($outputImage, $g, $g, $g);
// Set the gray value for the pixel
imagesetpixel ($outputImage, $xPos, $yPos, $val);
}
}
return $outputImage;
}
$image = convertImageToGrayscale("otter.jpg", .25);
header('Content-type: image/jpeg');
imagejpeg($image);
?>
See if that works. I found that here

How can I set the transparancy to image for particular background color in image - using PHP - GD

Suppose I have any image(say passport type images where the background will be same around the user).
What I want to do is make that background image as transparent using PHP GD. So please let me know how can I achieve this? The example image is shown here. I want yellow color to be transparent.
What you basically want to do is replace colors 'close' to your background color. By 'close' I mean colors that are similar to it:
// $src, $dst......
$src = imagecreatefromjpeg("dmvpic.jpg");
// Alter this by experimentation
define( "MAX_DIFFERENCE", 20 );
// How 'far' two colors are from one another / color similarity.
// Since we aren't doing any real calculations with this except comparison,
// you can get better speeds by removing the sqrt and just using the squared portion.
// There may even be a php gd function that compares colors already. Anyone?
function dist($r,$g,$b) {
global $rt, $gt, $bt;
return sqrt( ($r-$rt)*($r-$rt) + ($g-$gt)*($g-$gt) + ($b-$bt)*($b-$bt) );
}
// Alpha color (to be replaced) is defined dynamically as
// the color at the top left corner...
$src_color = imagecolorat( $src ,0,0 );
$rt = ($src_color >> 16) & 0xFF;
$gt = ($src_color >> 8) & 0xFF;
$bt = $src_color & 0xFF;
// Get source image dimensions and create an alpha enabled destination image
$width = imagesx($src);
$height = imagesy($src);
$dst = =imagecreatetruecolor( $width, $height );
imagealphablending($dst, true);
imagesavealpha($dst, true);
// Fill the destination with transparent pixels
$trans = imagecolorallocatealpha( $dst, 0,0,0, 127 ); // our transparent color
imagefill( $dst, 0, 0, $transparent );
// Here we examine every pixel in the source image; Only pixels that are
// too dissimilar from our 'alhpa' or transparent background color are copied
// over to the destination image.
for( $x=0; $x<$width; ++$x ) {
for( $y=0; $y<$height; ++$y ) {
$rgb = imagecolorat($src, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
if( dist($r,$g,$b) > MAX_DIFFERENCE ) {
// Plot the (existing) color, in the new image
$newcolor = imagecolorallocatealpha( $dst, $r,$g,$b, 0 );
imagesetpixel( $dst, $x, $y, $newcolor );
}
}
}
header('Content-Type: image/png');
imagepng($dst);
imagedestroy($dst);
imagedestroy($src);
Please note above code is untested, I just typed it in stackoverflow so I may have some retarded spelling errors, but it should at bare minimal point you in the right direction.

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.

Detecting how many colors an uploaded image has

How can I detect how many colors an image has, adn then return the RGB or Hex values of those colors in PHP? With the standard file formats... PNG, JPG, GIF etc.
Sample image:
Used for:
An online design tool which allows you to upload images for use in the designer. I'm trying to reject all images with over 10 colors (or potentially reduce the colors?). For images with less then 10 colors, I'm trying to return the Hex or RGB values of each color that is present (the more colors present, the more expensive the printing process).
$gd = imagecreatefrompng($filename);
$width = imagesx($gd);
$height = imagesy($gd);
$colors = array();
for($x = 0; $x < $width; $x++)
{
for($y = 0; $y < $height; $y++)
{
$color = imagecolorat($gd, $x, $y);
$hex = sprintf("0x%06x", $color);
if(!in_array($hex, $colors))
{
$colors[] = $hex;
}
}
}

Categories