PHP - transparency issue on smaller images - php

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.

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.

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;
}

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.

Convert images to alpha transparency with PHP

$im = imagecreatefrompng('./test.png');
$white = imagecolorallocate($im, 255, 255, 255);
imagecolortransparent($im, $white);
This code is fine for removing pure white from an image, but I what I want to do is convert all colors to alpha percentages. For example medium gray would be 50% transparent black. So an image that was medium gray would show the image behind it, if placed on top.
Is this possible using PHP or an extension?
I just wrote and tested this script for you.
$imfile = './test.png';
$origim = imagecreatefrompng($imfile);
$im_size = getimagesize($imfile);
$im = imagecreatetruecolor($im_size[0], $im_size[1]);
imagealphablending($im, false);
imagesavealpha($im, true);
for ($x = 0; $x < $im_size[0]; ++$x){
for ($y = 0; $y < $im_size[1]; ++$y){
$rgb = imagecolorat($origim,- $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$color = imagecolorallocatealpha($im, 0, 0, 0, intval(($r+$g+$b)/3/255*127));
imagesetpixel($im, $x, $y, $color);
}
}
It may be a bit slow on large images, but it works just like you want it to. =)
Hope this answer is Acceptable. Good luck.

PHP Image quality issue on rotating and merging

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

Categories