5

Photoshopのマルチ効果をシミュレートするためにGDライブラリを試してみましたが、まだ実用的な解決策は見つかりませんでした。

ウィキペディアによると、乗算ブレンドモード:

[...]最上層の各ピクセルの数値を、最下層の対応するピクセルで乗算します。その結果、画像が暗くなります。

PHPを使用してこれを実現する方法を知っている人はいますか?どんな助けでも大歓迎です。

4

6 に答える 6

13

画像のすべてのピクセルを取得してから、各RGB値に背景色/ 255を掛ける必要があります(これはPhotoshopの数式です)。たとえば、より良い結果を得るためにPNGファイルとして保存された赤い背景色の乗算フィルターを備えたJPGファイル:

<?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);
}
?>
于 2013-04-01T17:55:01.517 に答える
5

2つの画像間の乗算ブレンドも探していましたが、そのためのネイティブphpソリューションが見つかりませんでした。(今のところ)唯一の方法は、ピクセルごとに「手動で」ピクセルを設定することであるように思われます。これは、画像が同じサイズであると仮定して、2つの画像間で乗算ブレンドを実行する私のコードです。必要に応じて、さまざまなサイズを処理するように調整できます。

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

関数は画像オブジェクトを返すので、使用が終わったら必ず画像を破棄する必要があります。

オーバーレイnative-phpブレンドを使用した回避策があるはずです。これは、宛先画像の50%グレーピクセルがソースピクセルの影響を受けることを示唆しています。理論的には、2つの白黒画像(グレートーンなし)をブレンドする必要がある場合、宛先画像のコントラストを設定して白が50%グレーになり、その上にソース画像をオーバーレイブレンドすると、次のようになります。あなたは乗算に似た何か。ただし、カラー画像またはグレースケール画像の場合、これは機能しません。上記の方法が唯一のオプションのようです。

于 2014-03-29T05:12:11.553 に答える
2

GDで2つの画像をブレンドする必要があるときに、このスレッドに導かれました。そのための特別なコードはないようですので、このページへの今後の訪問者のためにここに残しておきます。

colivierこれは、 2つの画像の乗算ブレンドをサポートするという答えからのフォークです。

2つの画像は同じサイズである必要はありませんが、オーバーレイする画像のサイズが変更され、最下層のサイズにトリミングされます。私はそれを行うためのfitヘルパー関数を作成しましたが、それを気にしないでください。

imagecolorat透明度のあるPNGでも、ベースカラーを返します。つまり、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;    
}
于 2015-08-26T12:11:57.137 に答える
0

PHPマニュアルを使おうとしましたか?

Photoshopのような画像(通常は白黒画像)に「乗算」効果を適用しようとしている人は、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]);
}
?>
于 2013-03-21T17:44:07.543 に答える
0

png画像とアルファで使用する場合はうまくいく必要があり、非常にうまく機能します

    $filter_r=215;
    $filter_g=5;
    $filter_b=5;
    $alpha=70;
    $suffixe="_red";
    $path="./img/foto_220_590.png";
    if(is_file($path)){
        $image=imagecreatefrompng($path);
        $new_path=substr($path,0,strlen($path)-4).$suffixe.".png";

         echo $imagex = imagesx($image);
         echo $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);
                // this new alpha
                $newcol = imagecolorallocatealpha($image, $color_r,$color_g,$color_b,$alpha);
                imagesetpixel($image, $x, $y, $newcol);
            }
        }
         imagepng($image,$new_path);

于 2016-05-06T00:32:07.487 に答える
0

@colivierスクリプトを更新して、色付きの画像だけでなく、2つの画像を表示できるようにしました。

/**
 * 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);
}
于 2016-05-12T16:06:31.303 に答える