2015-09-11 2 views
2

Я заметил, что Imagick::paintOpaqueImage работает только с пикселями с альфа-значением 1. Это оставляет преобразованные изображения с большим количеством оставшихся пикселей из цветов, которые я пытаюсь заменить. Возьму для примера тестового изображенияImagick :: paintOpaqueImage игнорирует полупрозрачные пиксели

enter image description here

И этот код, чтобы заменить синие пиксели с красными.

$img->paintOpaqueImage('rgb(12,0,245)', 'rgb(255,0,0)', 0); 

В результате заменены только твердые синие пиксели.

enter image description here

Обратите внимание всем пикселей в этом тестовом изображении (в стороне от полностью прозрачных) имеют такой же цвет синие. Единственное отличие - значение альфа. Также обратите внимание, что я использовал значение 0 для параметра $fuzz. Изначально я сталкивался с этим, прежде чем я обнаружил, что такое настоящая проблема, и это вызывало его собственные нежелательные результаты.

Я взломал решение, используя ImagickPixelIterator; это clones текущий пиксель и устанавливает альфа-значение как текущего пикселя, так и клонированного пикселя в 1, чтобы заставить ImagickPixel::isSimilar работать агностически в отношении альфа-значений.

$img  = new Imagick('./test-paint-opaque-image.png'); 
$iterator = new ImagickPixelIterator($img); 
$target = new ImagickPixel('rgb(12,0,245)'); // blue 
$fill  = new ImagickPixel('rgb(255,0,0)'); // red 
$fuzz  = 0; 

foreach($iterator as $pixels) { 
    foreach($pixels as $curPixel) { 
     // Modify the alpha of the comparePixel so it won't throw off the isSimilar() check 
     $comparePixel = clone $curPixel; 
     $fOrigAlpha = $curPixel->getColorValue(Imagick::COLOR_ALPHA); 

     // Bail on fully transparent pixels 
     if($fOrigAlpha == 0) 
      continue; 

     // It seems the only way isSimilar will work is when the alpha is 1 for both pixels... 
     $comparePixel->setColorValue(Imagick::COLOR_ALPHA, 1); 
     $curPixel->setColorValue(Imagick::COLOR_ALPHA, 1); 

     if($comparePixel->isSimilar($target, $fuzz)) { 
      $curPixel->setColorValue(Imagick::COLOR_RED, $fill->getColorValue(Imagick::COLOR_RED)); 
      $curPixel->setColorValue(Imagick::COLOR_GREEN, $fill->getColorValue(Imagick::COLOR_GREEN)); 
      $curPixel->setColorValue(Imagick::COLOR_BLUE, $fill->getColorValue(Imagick::COLOR_BLUE)); 

      // Set the modified alpha back to what it was after the color change 
      if($fOrigAlpha > 0) { 
       echo "Setting alpha to $fOrigAlpha\n"; 
       $curPixel->setColorValue(Imagick::COLOR_ALPHA, $fOrigAlpha); 
      } 
     } 
    } 
    $iterator->syncIterator(); 
} 

В результате получается блестящий красный образ, с полупрозрачными (и полностью прозрачными) пикселей сохранились, как хотелось бы.

enter image description here

Основная проблема, и что, наконец, приносит мне на мой вопрос в том, что этот метод является нечестивым медленно. Есть ли способ использовать PHP Imagick::paintOpaqueImage непосредственно, чтобы сделать такой вид преобразования цвета?

+0

Просто выбрасывая идеи, можно отделить альфа-канал от изображения, применить paintOpaqueImage, а затем восстановить альфа-канал? – Scuzzy

ответ

3

Вы можете отключить альфа-канал до замены значения цвета затем включить его снова после того, как с setImageAlphaChannel(), например, так:

$img = new Imagick('./test-paint-opaque-image.png'); 
$img->setImageAlphaChannel(Imagick::ALPHACHANNEL_DEACTIVATE); 
$img->opaquePaintImage('rgb(12,0,245)', 'rgb(255,0,0)', 0, false); 
$img->setImageAlphaChannel(Imagick::ALPHACHANNEL_ACTIVATE); 
$img->writeImage('./out.png'); 

Результат:

Result


+0

Любая идея, если это применимо ко всем методам, использующим фактор fuzz? – Danack

+1

Мой CPU благодарит вас! – quickshiftin

Смежные вопросы