2013-11-12 2 views
0

Исходное изображение PNG будет обрезано PHP с использованием Imagick на основе пользовательского ввода. Результатом является обрезанное изображение, которое может иметь или не иметь прозрачные пиксели. Я ищу способ определить, имеет ли обрезанное изображение прозрачность да или нет, поэтому я могу преобразовать непрозрачные PNG в JPG.Как определить, имеет ли обрезанная PNG прозрачность

Это мой код для загрузки изображения:

// Get user input 
$src = $_POST['src']; 
$resize = json_decode($_POST['selection_data']); 

// Load image (source image has transparency) 
$dst = new Imagick($src); 

// Crop image (the part that will be cropped is fully opaque) 
$dst->cropImage($resize->selW, $resize->selH, $resize->selX, $resize->selY); 
$dst->resizeImage($resize->dstW, $resize->dstH, imagick::FILTER_CATROM, 0.9, false); 

После этого, я могу проверить, альфа-канал, используя $dst->getImageAlphaChannel(). Но это возвращает true независимо от того, содержит ли кадрированное изображение какие-либо прозрачные пиксели, потому что он установлен при загрузке исходного изображения (с прозрачностью).

Другой способ проверить для прозрачных пикселей, смотря каждый пиксель для значения альфа малой, чем 1 *:

$alpha = false; 
for ($x = 0; $x < $resize->dstW; $x++) 
{ 
    for ($y = 0; $y < $resize->dstH; $y++) 
    {    
     if ($dst->getImagePixelColor($x, $y)->getColorValue(Imagick::COLOR_ALPHA) < 1) 
     { 
      $alpha = true; 
      break 2; 
     } 
    } 
} 

Но для больших изображений (1000х1000) он принимает 30 + секунд, чтобы выполнить это, что не является идеальным.

Каков самый быстрый способ определить, имеют ли изображение какие-либо прозрачные пиксели?

*: Непрозрачные пиксели фактически возвращают значение альфа-значения 0.99999999976717 (32-битное плавание) на Debian Wheezy, на котором я сейчас тестирую.

+0

[Аналогичный вопрос для библиотеки GD] (http://stackoverflow.com/questions/5495275/how-to-check-if-an-image-has-transparency-using-gd) – lonesomeday

+0

Я бы посмотрел если вы можете загрузить обрезанное изображение обратно в новый экземпляр Imagick, тогда используйте 'getImageAlphaChannel()' в этом новом экземпляре. – Demonslay335

+0

@ Demonslay335 Я пробовал, но альфа-канал сохраняется внутри изображения, поэтому загрузка изображения обратно приводит к тому же значению для альфа-канала. – Stan

ответ

1

Одно из решений:

  1. Создать новую магу с цветным фоном того же размера, что и изображение, которое вы хотите проверить.

  2. Нарисуйте изображение поверх этого нового холста с помощью compositeImage и COMPOSITE_ATOP.

  3. Получить статистику по всем цветным каналам.

Для любого изображения, полностью свободного от любой прозрачности, два изображения должны иметь точно такую ​​же статистику изображения для каждого цветового канала.

В коде это будет выглядеть так:

$imagick = new Imagick(realpath("../images/fnord.png")); 

$newCanvas = new Imagick(); 
$newCanvas->newImage($imagick->getImageWidth(), $imagick->getImageHeight(), 'rgba(255, 255, 0, 1)', 'png'); 
$newCanvas->compositeimage($imagick, Imagick::COMPOSITE_ATOP, 0, 0); 

function dumpInfo(Imagick $imagick) { 

    $identifyInfo = $imagick->getImageChannelStatistics(); 

    foreach ($identifyInfo as $key => $value) { 

     echo "$key :"; 

     if (is_array($value) == true) { 
      var_dump($value); 
     } 
     else { 
      echo $value; 
     } 

     echo "<br/>"; 
    } 
} 

dumpInfo($imagick); 
echo "<br/><br/>"; 
dumpInfo($newCanvas); 

Для прозрачного изображения дает результат:

0: массив (5) {[ "значит"] => поплавок (0) ["minima"] => float (1.0E + 37) ["maxima"] => float (-1.0E-37) ["standardDeviation"] => float (0) ["depth"] => int (1)} 1: массив (5) {["mean"] => float (5764.6123956044) ["minima"] => float (0) ["maxima"] => float (53619) ["standardDeviation" ] => float (11888.331707876) ["depth"] => int (15)} 2: массив (5) {["mean"] => float (2058.7978021978) ["minima"] => float (0) ["maxima"] => float (34951) ["standardDeviation"] => float (5059.2862080476) ["depth"] => int (15)} 4: array (5) {["mean"] => float (6324.2305054945) ["minima "] => float (0) [" maxima "] => float (46773) [" standardDeviation "] => float (11356.366371237) [" depth "] => int (15)} 8: массив (5) {["mean"] => float (46867.721934066) ["minima"] => float (0) ["maxima"] => float (65535) ["standardDeviation"] => float (26491.889090216) ["depth"] => int (15)} 32 : array (5) { ["mean"] => float (0) ["minima"] => float (1.0E + 37) ["maxima"] => float (-1.0E-37) [" (0) [0] [0] [0] [0] [0] [0] [0] float (0) ["depth"] => int (1)} 1: array (0E) (5) {["mean"] => float (51766.576175824) ["minima"] => float (0) ["maxima"] => float (65535) ["standardDeviation"] => float (19889.498582657) ["depth"] => int (16)} 2: arr ay (5) {["mean"] => float (48461.548131868) ["minima"] => float (0) ["maxima"] => float (65535) ["standardDeviation"] => float (24228.543381351)) ["depth"] => int (16)} 4: массив (5) {["mean"] => float (5353.375032967) ["minima"] => float (0) ["maxima"] => float (43081) ["standardDeviation"] => float (10139.362164338) ["depth"] => int (16)} 8: массив (5) {["mean"] => float (0) ["minima "] => float (0) [" maxima "] => float (0) [" standardDeviation "] => float (0) [" depth "] => int (1)} 32 : array (5) {["mean"] => float (0) ["minima"] => float (1.0E + 37) ["maxima"] => float (-1.0E-37) ["standardDeviation"] => float (0) ["depth"] => int (1)}

И в случае, если это не очевидно, эти два массива, безусловно, не совпадают.

1: Массив (5) {[ "означают"] => поплавка (+5764,6123956044) 1: Массив (5) {[ "означают"] => поплавок (51766,576175824)

Теоретически вы можете просто проверить фактические значения от getImageChannelStatistics - если вы можете понять, что значения фактически означают, но метод сравнения, вероятно, безопаснее.

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