PHP GD - 使用Alpha替换颜色可为图像提供边框

I am not sure if the function below works for the most part or not at all. What i am trying to is loop through the pixels and switch the color while maintaining the alpha. I thought I had it working till I made my page background white and saw a small border around the icon.

I thought that the problem was that the color was being applied to a semi transparent pixel. Thus white turned grey into lighter grey on the anti-aliased parts of the images. I decided then to make the pixel completely transparent before setting the new color. This did nothing.

So the question. Why do white images have a small border?

The color conversion function.

function updateThumb($image, $newColor) {
    $img = imagecreatefrompng($image);

    $w = imagesx($img);
    $h = imagesy($img);

    // Work through pixels
    for($y=0;$y<$h;$y++) {
        for($x=0;$x<$w;$x++) {
            // Apply new color + Alpha
            $rgb = imagecolorsforindex($img, imagecolorat($img, $x, $y));

        $transparent = imagecolorallocatealpha($img, 0, 0, 0, 127);
        imagesetpixel($img, $x, $y, $transparent);

            $pixelColor = imagecolorallocatealpha($img, $newColor[0], $newColor[1], $newColor[2], $rgb['alpha']);
            imagesetpixel ($img, $x, $y, $pixelColor);
        }
    }

    // Restore Alpha
    imageAlphaBlending($img, true);
    imageSaveAlpha($img, true);

    return $img;
}

Thumbs need a rollover effect so the image is made in the function below. I don't believe this has anything to do with the issue, I have tried changing the above function to create the image and not return it and the same thing happens.

function makeThumb($path, $top, $bottom=FALSE) {
    $width = imagesx($top);
    $height = imagesy($top);

    $thumbHeight = $bottom != FALSE ? $height * 2 : $height;

    // Create Transparent PNG
    $thumb = imagecreatetruecolor($width, $thumbHeight);
    $transparent = imagecolorallocatealpha($thumb, 0, 0, 0, 127);
    imagefill($thumb, 0, 0, $transparent);

    // Copy Top Image
    imagecopy($thumb, $top, 0, 0, 0, 0, $width, $height);

    // Copy Bottom Image
    if ($bottom != FALSE) {
        imagecopy($thumb, $bottom, 0, $height, 0, 0, $width, $height);
    }

    // Save Image with Alpha
    imageAlphaBlending($thumb, true);
    imageSaveAlpha($thumb, true);
    imagepng($thumb, $path); // save image as gif

}

functions are called like this...

$thumbTop = updateThumb('Path/To/Thumb', array(255,255,255));
makeThumb('output/path', $thumbTop);

This is the icon: http://img171.imageshack.us/i/iconkc.png/

Any ideas?

OMG THANK YOU FOR THIS BIT OF CODE!!!! :D There is somone else i have to thank also, but I cannot find their code on this site sadly. I took, your code and the other guy's code and merged them. I've noticed that you save the image, I haven't figured out how to saved the colored image other then right click and save via the browser, however, the image will change color.

    function updateThumb($image, $newColor) {
    $img = imagecreatefrompng($image);

    $w = imagesx($img);
    $h = imagesy($img);

    // Work through pixels
    for($y=0;$y<$h;$y++) {
        for($x=0;$x<$w;$x++) {
            // Apply new color + Alpha
            $rgb = imagecolorsforindex($img, imagecolorat($img, $x, $y));

            $transparent = imagecolorallocatealpha($img, 0, 0, 0, 127);
            imagesetpixel($img, $x, $y, $transparent);


            // Here, you would make your color transformation.
            $red_set=$newColor[0]/100*$rgb['red'];
            $green_set=$newColor[1]/100*$rgb['green'];
            $blue_set=$newColor[2]/100*$rgb['blue'];
            if($red_set>255)$red_set=255;
            if($green_set>255)$green_set=255;
            if($blue_set>255)$blue_set=255;

            $pixelColor = imagecolorallocatealpha($img, $red_set, $green_set, $blue_set, $rgb['alpha']);
            imagesetpixel ($img, $x, $y, $pixelColor);
        }
    }

    // Restore Alpha
    imageAlphaBlending($img, true);
    imageSaveAlpha($img, true);

    return $img;
}

function makeThumb($path, $top, $bottom=FALSE) {
    $width = imagesx($top);
    $height = imagesy($top);

    $thumbHeight = $bottom != FALSE ? $height * 2 : $height;

    // Create Transparent PNG
    $thumb = imagecreatetruecolor($width, $thumbHeight);
    $transparent = imagecolorallocatealpha($thumb, 0, 0, 0, 127);
    imagefill($thumb, 0, 0, $transparent);

    // Copy Top Image
    imagecopy($thumb, $top, 0, 0, 0, 0, $width, $height);

    // Copy Bottom Image
    if ($bottom != FALSE) {
        imagecopy($thumb, $bottom, 0, $height, 0, 0, $width, $height);
    }

    // Save Image with Alpha
    imageAlphaBlending($thumb, true);
    imageSaveAlpha($thumb, true);
    header('Content-Type: image/png');
    imagepng($thumb, $path); // save image as png

}

$thumbTop = updateThumb('input/path', array(240,105,15));
makeThumb('output/path', $thumbTop);

Thank you for this! You inspired me to use a pixel by pixel way in an image worker i'm building. At first i had the same problem you had but i think i figured out how to fix it.

Problem

it seems to me as if imagesetpixel does not replace the pixel with the new rgba values but instead puts them OVER the old ones.

Solution

function updateThumb($image, $newColor) {
    $img = imagecreatefrompng($image);

    $w = imagesx($img);
    $h = imagesy($img);

    // create a new blank image.
    $target = imagecreatetruecolor($w, $h);
    $transparent = imagecolorallocatealpha($target, 0, 0, 0, 127);
    imagefill($target, 0, 0, $transparent);

    // Work through pixels
    for($y=0;$y<$h;$y++) {
        for($x=0;$x<$w;$x++) {
            // Apply new color + Alpha
            $rgb = imagecolorsforindex($img, imagecolorat($img, $x, $y));

            // and set the new color to the blank image.
            $pixelColor = imagecolorallocatealpha($target, $newColor[0], $newColor[1], $newColor[2], $rgb['alpha']);
            imagesetpixel($target, $x, $y, $pixelColor);
        }
    }

    // Restore Alpha
    imageAlphaBlending($target, true);
    imageSaveAlpha($target, true);

    return $target;
}

What went wrong:

// new image
$target = imagecreatetruecolor(1, 1);

// Set a Pixel
$pixelColor = imagecolorallocatealpha($target, 0, 0, 0, 60);
imagesetpixel($target, 0, 0, $pixelColor);

// "Replace" The Pixel
$pixelColor = imagecolorallocatealpha($target, 255, 255, 255, 60);
imagesetpixel($target, 0, 0, $pixelColor);

// See the rgba values of the pixel
var_dump(imagecolorsforindex($target, imagecolorat($target, 0, 0)));

Expected:

array(4) {  
    ["red"]=> int(255)  
    ["green"]=> int(255)  
    ["blue"]=> int(255)  
    ["alpha"]=> int(60)  
}

Actual:

array(4) {  
    ["red"]=> int(174)  
    ["green"]=> int(174)  
    ["blue"]=> int(174)  
    ["alpha"]=> int(28)  
}