2013-03-21 11 views
5

Próbowałem eksperymentować z biblioteką GD, aby symulować muliply efekt programu Photoshop, ale nie znalazłem jeszcze działającego rozwiązania.Pomnóż filtr z biblioteką GD PHP

Według Wikipedia, wielowarstwowa tryb mieszania:

[...] mnoży liczby dla każdego piksela z górnej warstwy odpowiedniego piksela dla dolnej warstwy. Rezultatem jest ciemniejszy obraz.

Czy ktoś wie o sposobie osiągnięcia tego za pomocą PHP? Każda pomoc byłaby bardzo cenna.

Odpowiedz

13

Trzeba wziąć każdy piksel obrazu, a następnie pomnożyć każdą wartość RGB z kolorem tła/255 (jest to formuła Photoshop). Na przykład, plik JPG z filtrem koloru wielowarstwowego czerwonym tle, zapisane w postaci pliku PNG dla lepszych rezultatów:

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

if(is_file($path)){ 
    [email protected]($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); 
} 
?> 
+0

Dobrze, dziękuję bardzo! Wydaje się, że zapewnia to dokładną funkcjonalność jako filtr wielokrotny Photoshopa. – heintore

+0

Użyłem tego w innym przykładzie, ale stwierdziłem, że ta implementacja jest naprawdę powolna. Najszybszym sposobem byłoby użycie filtru obrazu z IMG_FILTER_COLORIZE. Najpierw odwróć docelową kolorową wartość RGB, a następnie odwróć obraz za pomocą filtru obrazu ($ image, IMG_FILTER_NEGATE), a następnie zastosuj odwrócony kolor do odwróconego obrazu, a następnie odwróć obraz ponownie. Zobacz tutaj http://stackoverflow.com/questions/26005991/php-gd-multiply-image-colors-with-tint-color/26250684#26250684 –

+0

Działa świetnie! Zaktualizowałem go trochę, aby pomnożyć dwa obrazy, a nie tylko obraz z kolorem: http://codepad.org/BSawY5ex –

0

Czy próbowałeś użyć php manual?

Dla osób chcących zastosować efekt „pomnożyć” na obrazach, takich jak ten w Photoshopie (ogólnie b & wagowo nich), można go osiągnąć z filtrem 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]); 
} 
?> 
+0

Próbowałem wykonać tę funkcję, ale m Testy wykazały, że nie przyniosły one takiego samego wyniku, jak filtr wielokrotny Photoshopa. Naturalnym wydaje się dostarczenie koloru tła do pomnażania, a nie tylko odejmowanie przeciwnych kolorów. – heintore

+0

Koncepcja była przydatna przy produkcji dokładnie tego, co robi Photoshop. Przetestowałem to i obrazy są identyczne. –

5

Szukałem na Multiply mieszanki między dwoma obrazami, jak również i nie mógł znaleźć żadnych rodzimy -php rozwiązanie dla niego. Wydaje się, że jedynym sposobem (na razie) jest "ręczne" ustawianie pikseli, piksel po pikselu. Oto mój kod, który polega na wielokrotnym łączeniu dwóch obrazów, zakładając, że obrazy są tego samego rozmiaru. Możesz go dostosować, aby obsługiwać różne rozmiary, jeśli chcesz.

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

Funkcja zwraca obiekt obrazu, więc powinieneś upewnić się, że zrobi się nieoczekiwanie po zakończeniu używania.

Należy zastosować obejście, w którym zastosowano mieszankę natywnego php, co sugeruje, że piksele źródłowe będą mieć wpływ na 50% szarych pikseli obrazu docelowego. Teoretycznie, jeśli chcesz połączyć dwa czarno-białe obrazy (brak szarego tonu), jeśli ustawisz kontrast obrazu docelowego, tak aby biały stał się 50% -prostym, a następnie nad obrazem źródłowym nakładającym się na siebie, powinien nadać coś podobnego do mnożenia. Ale w przypadku obrazów kolorowych lub obrazów w skali szarości nie byłoby to możliwe - powyższa metoda wydaje się być jedyną opcją.

2

Zostałem poprowadzony do tego wątku, kiedy potrzebowałem wymieszać dwa obrazy w GD. Wygląda na to, że nie ma kodu specjalnie dla tego, więc zostawię to tutaj dla przyszłych użytkowników tej strony.

To jest rozwidlenie z odpowiedzi colivier, która obsługuje wielokrotne mieszanie dwóch obrazów.

Te dwa obrazy nie muszą mieć tego samego rozmiaru, ALE obraz nakładki zostanie przeskalowany i przycięty do rozmiaru dolnej warstwy. Zrobiłem funkcję pomocniczą fit, aby to zrobić, ale nie przejmuj się tym.

imagecolorat zwraca kolor bazowy, nawet z plikami PNG z przezroczystością. Oznacza to, że 50% czarny (widoczny jako (128, 128, 128)) zostanie zwrócony jako (0, 0, 0, 64) 64 będący wartością alfa. Ten kod bierze pod uwagę przezierność i konwertuje przezroczyste kolory do widocznych wartości kolorów.

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

Jeśli używany z PNG i alfa musi być dobrze i działa bardzo dobrze

$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);

0

zaktualizowałem skrypt @colivier móc myltiply dwa obrazy, a nie tylko obraz w kolorze:

/** 
* 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); 
} 
Powiązane problemy