使用PHP的GD库对多个过滤器进行过滤

时间:2013-03-21 17:38:16

标签: php filter gd photoshop

我尝试使用GD库来模拟Photoshop的多重效果,但我还没有找到可行的解决方案。

根据Wikipedia,乘法混合模式:

  

[...]将顶层每个像素的数字与底层的相应像素相乘。结果是一张更黑的画面。

有没有人知道使用PHP实现这一目标的方法?任何帮助将不胜感激。

6 个答案:

答案 0 :(得分:13)

您需要拍摄图像的每个像素,然后将每个RGB值与背景颜色/ 255相乘(这是Photoshop公式)。例如,一个带有红色背景颜色乘法过滤器的JPG文件,保存为PNG文件以获得更好的结果:

<?php 
$filter_r=216;
$filter_g=0;
$filter_b=26;
$suffixe="_red";
$path=YOURPATHFILE;

if(is_file($path)){
    $image=@imagecreatefromjpeg($path);
    $new_path=substr($path,0,strlen($path)-4).$suffixe.".png";

    $imagex = imagesx($image);
    $imagey = imagesy($image);
    for ($x = 0; $x <$imagex; ++$x) {
        for ($y = 0; $y <$imagey; ++$y) {
            $rgb = imagecolorat($image, $x, $y);
            $TabColors=imagecolorsforindex ( $image , $rgb );
            $color_r=floor($TabColors['red']*$filter_r/255);
            $color_g=floor($TabColors['green']*$filter_g/255);
            $color_b=floor($TabColors['blue']*$filter_b/255);
            $newcol = imagecolorallocate($image, $color_r,$color_g,$color_b);
            imagesetpixel($image, $x, $y, $newcol);
        }
    }

    imagepng($image,$new_path);
}
?>

答案 1 :(得分:5)

我一直在寻找两张图片之间的Multiply混合,并且无法找到任何原生php解决方案。似乎只有(现在)手动&#34;手动&#34;设置像素,逐像素。这是我的代码,它在两个图像之间进行乘法混合,假设图像大小相同。如果您愿意,可以调整它以处理不同的尺寸。

function multiplyImage($dst,$src)
{
    $ow = imagesx($dst);
    $oh = imagesy($dst);

    $inv255 = 1.0/255.0;

    $c = imagecreatetruecolor($ow,$oh);
    for ($x = 0; $x <$ow; ++$x) 
    {
        for ($y = 0; $y <$oh; ++$y) 
        {
            $rgb_src = imagecolorsforindex($src,imagecolorat($src, $x, $y));
            $rgb_dst = imagecolorsforindex($dst,imagecolorat($dst, $x, $y));
            $r = $rgb_src['red'] * $rgb_dst['red']*$inv255;
            $g = $rgb_src['green'] * $rgb_dst['green']*$inv255;
            $b = $rgb_src['blue'] * $rgb_dst['blue']*$inv255;
            $rgb = imagecolorallocate($c,$r,$g,$b);
            imagesetpixel($c, $x, $y, $rgb);
        }
    }
    return $c;
}

函数返回图像对象,因此您应该确保在使用它之后进行图像破坏。

使用overlay native-php blend应该有一个解决方法,这表明目标图像的50%灰色像素将受到源像素的影响。从理论上讲,如果你确实需要混合两个黑白图像(没有灰色调),如果设置目标图像的对比度,使白色变为50% - 灰色,然后在其上叠加混合源图像,应该给出你有类似的东西。但是对于彩色图像或灰度图像,这不会起作用 - 上面的方法似乎是唯一的选择。

答案 2 :(得分:2)

当我需要在GD中混合两个图像时,我被带入了这个主题。似乎没有专门用于此的代码,因此我将此处留给此页面的未来访问者。

这是colivier答案中的一个分支,它支持两个图像的多重混合。

两个图像不需要具有相同的尺寸,但是重叠图像将被调整大小并裁剪为底层的大小。我做了一个fit辅助函数来做到这一点,但不要为此烦恼。

即使PNG具有透明度,

imagecolorat也会返回基色。也就是说,将返回50%黑色(可见为(128,128,128)),因为(0,0,0,64)64是α值。此代码考虑了半透明度,并将半透明颜色转换为可见颜色值。

// bottom layer
$img1 = imagecreatefromjpeg(realpath(__DIR__.'/profilePic.jpg'));

// top layer
$img2 = imagecreatefrompng(realpath(__DIR__.'/border2.png'));
imagealphablending($img2, false);
imagesavealpha($img2, true);

$imagex = imagesx($img1);
$imagey = imagesy($img1);

$imagex2 = imagesx($img2);
$imagey2 = imagesy($img2);

// Prereq: Resize img2 to match img1, cropping beyond the aspect ratio
$w1 = max(min($imagex2, $imagex), $imagex);
$h1 = max(min($imagey2, $imagey), $imagey);

$w_using_h1 = round($h1 * $imagex2 / $imagey2);
$h_using_w1 = round($w1 * $imagey2 / $imagex2);

if ($w_using_h1 > $imagex) {
    fit($img2, $imagex, $imagey, 'HEIGHT', true);
}
fit($img2, $imagex, $imagey, 'WIDTH', true);

// Actual multiply filter
for ($x = 0; $x < $imagex; ++$x) {
    for ($y = 0; $y < $imagey; ++$y) {
        $rgb1 = imagecolorat($img1, $x, $y);
        $rgb2 = imagecolorat($img2, $x, $y);
        $idx1 = imagecolorsforindex($img1, $rgb1);
        $idx2 = imagecolorsforindex($img2, $rgb2);

        // Shift left 8, then shift right 7
        // same as multiply by 256 then divide by 128
        // approximate multiply by 255 then divide by 127
        // This is basically multiply by 2 but, expanded to show that
        // we are adding a fraction of white to the translucent image
        // $adder = ($idx2['alpha'] << 8 >> 7);
        $adder = ($idx2['alpha'] << 1);
        $rmul = min(255, $idx2['red']   + $adder);
        $gmul = min(255, $idx2['green'] + $adder);
        $bmul = min(255, $idx2['blue']  + $adder);

        $color_r = floor($idx1['red'] * $rmul / 255);
        $color_g = floor($idx1['green'] * $gmul / 255);
        $color_b = floor($idx1['blue'] * $bmul / 255);

        $newcol = imagecolorallocatealpha($img1, $color_r, $color_g, $color_b, 0);
        imagesetpixel($img1, $x, $y, $newcol);
    }
}
imagejpeg($img1, __DIR__.'/out.jpg');



/**
 * Fits an image to a $w x $h canvas
 * 
 * @param type $w Target width
 * @param type $h Target height
 * @param int $fit_which Which dimension to fit
 * @param bool $upscale If set to true, will scale a smaller image to fit the given dimensions
 * @param bool $padded If set to true, will add padding to achieve given dimensions
 * 
 * @return Image object
 */
function fit(&$img, $w, $h, $fit_which = 'BOTH', $upscale = false, $padded = true) {

    if (!in_array($fit_which, array('WIDTH', 'HEIGHT', 'BOTH'))) {
        $fit_which = 'BOTH';
    }
    $w0 = imagesx($img);
    $h0 = imagesy($img);

    if (!$upscale && $w0 <= $w && $h0 <= $h)
        return $this;

    if ($padded) {
        $w1 = max(min($w0, $w), $w);
        $h1 = max(min($h0, $h), $h);
    }
    else {
        $w1 = min($w0, $w);
        $h1 = min($h0, $h);
    }
    $w_using_h1 = round($h1 * $w0 / $h0);
    $h_using_w1 = round($w1 * $h0 / $w0);

    // Assume width, crop height
    if ($fit_which == 'WIDTH') {
        $w2 = $w1;
        $h2 = $h_using_w1;
    }
    // Assume height, crop width
    elseif ($fit_which == 'HEIGHT') {
        $w2 = $w_using_h1;
        $h2 = $h1;
    }
    elseif ($fit_which == 'BOTH') {
        if (!$padded) {
            $w2 = $w = min($w, $w_using_h1);
            $h2 = $h = min($h, $h_using_w1);
        }
        else {
            // Extend vertically
            if ($h_using_w1 <= $h) {
                $w2 = $w1;
                $h2 = $h_using_w1;
            }
            // Extend horizontally
            else {
                $w2 = $w_using_h1;
                $h2 = $h1;
            }
        }
    }

    $im2 = imagecreatetruecolor($w, $h);
    imagealphablending($im2, true);
    imagesavealpha($im2, true);

    $transparent = imagecolorallocatealpha($im2, 255, 255, 255, 127);
    imagefill($im2, 0, 0, $transparent);

    imagealphablending($img, true);
    imagesavealpha($img, true);
    // imagefill($im, 0, 0, $transparent);

    imagecopyresampled($im2, $img, ($w - $w2) / 2, ($h - $h2) / 2, 0, 0, $w2, $h2, $w0, $h0);

    $img = $im2;    
}

答案 3 :(得分:0)

您是否尝试过使用php manual

  

对于希望对Photoshop中的图像(通常是b&amp; w)图像应用“乘法”效果的人来说,可以使用IMG_FILTER_COLORIZE滤镜实现它。

<?php
function multiplyColor(&$im, $color = array(255, 0, 0)) {
   //get opposite color
   $opposite = array(255 - $color[0], 255 - $color[1], 255 - $color[2]);

   //now we subtract the opposite color from the image
   imagefilter($im, IMG_FILTER_COLORIZE, -$opposite[0], -$opposite[1], -$opposite[2]);
}
?>

答案 4 :(得分:0)

如果与png图像一起使用,alpha必须很好并且效果很好

flex

答案 5 :(得分:0)

我更新了@colivier脚本,以便能够对两个图像进行myltiply,而不仅仅是一个带有颜色的图像:

/**
 * Multiply $pathToDst and $pathToSrc to $resultPath
 *
 * @param string $pathToDst
 * @param string $pathToSrc
 * @param string $resultPath
 */
function multiply($pathToDst, $pathToSrc, $resultPath) {
    switch (pathinfo($pathToDst, PATHINFO_EXTENSION)) {
        case "gif" :
            $resourceDst = imagecreatefromgif($pathToDst);
            break;
        case "png" :
            $resourceDst = imagecreatefrompng($pathToDst);
            break;
        default :
            $resourceDst = imagecreatefromjpeg($pathToDst);
            break;
    }

    switch (pathinfo($pathToSrc, PATHINFO_EXTENSION)) {
        case "gif" :
            $resourceSrc = imagecreatefromgif($pathToSrc);
            break;
        case "png" :
            $resourceSrc = imagecreatefrompng($pathToSrc);
            break;
        default :
            $resourceSrc = imagecreatefromjpeg($pathToSrc);
            break;
    }

    for ($x = 0; $x < 400; ++$x) {
        for ($y = 0; $y < 400; ++$y) {
            $TabColorsFlag = imagecolorsforindex($resourceDst, imagecolorat($resourceDst, $x, $y));
            $TabColorsPerso = imagecolorsforindex($resourceSrc, imagecolorat($resourceSrc, $x, $y));

            $color_r = floor($TabColorsFlag['red'] * $TabColorsPerso['red'] / 255);
            $color_g = floor($TabColorsFlag['green'] * $TabColorsPerso['green'] / 255);
            $color_b = floor($TabColorsFlag['blue'] * $TabColorsPerso['blue'] / 255);
            imagesetpixel($resourceDst, $x, $y, imagecolorallocate($resourceSrc, $color_r, $color_g, $color_b));
        }
    }

    imagepng($resourceDst, $resultPath, 0);
    imagedestroy($resourceDst);
    imagedestroy($resourceSrc);
}