2013-04-10 2 views
1

Следующий блок кода PHP должен принимать this image в качестве входных данных SND производить this image в качестве выходного сигнала (преобразование черного до желтого и светло-синего до черного цвета):Php Преобразование изображения не делает то, что я ожидаю, что это делать

Тем не менее, я получаю this image вместо вывода.

Может ли кто-нибудь увидеть проблему с моим кодом?

$im = imagecreatefrompng("./input.png"); 
$width = imagesx($im); 
$height = imagesy($im); 
$new = imagecreate($width, $height); 
imagecopy($new, $im, 0, 0, 0, 0, $width, $height); 
imagecolorset($new, imagecolorexact($new, 0, 0, 0), 255, 255, 0); 

for($i = 0; $i < $width; $i++) { 
    for($j = 0; $j < $height; $j++) { 
     $index = imagecolorat($new, $i, $j); 
     $rgb = imagecolorsforindex($new, $index); 
     if($rgb['red'] != 255 && $rgb['green'] != 255 && $rgb['blue'] != 0) { 
      echo '(' . $i . ', ' . $j . ')' . 'color => (' . (255 - $rgb['blue']) . ', ' . (255 - $rgb['blue']) . ', 0)<br />'; 
      $color = imagecolorallocate($new, 255 - $rgb['blue'], 255 - $rgb['blue'], 0); 
      imagesetpixel($new, $i, $j, $color); 
     } 
     unset($index); 
     unset($rgb); 
    } 
} 
imagepng($new, 'tesst.png'); 
imagedestroy($im); 
imagedestroy($new); 
+0

http://quicksnaildesign.com/error.png –

+0

что-то со временем исполнения, может быть. он работает, но он прекращает преобразование после 100 пикселей по ширине или около того. –

+0

Я проверяю это «эхо», чтобы увидеть пиксель (x, y), который я достигал в for, и кажется, что я добираюсь до всех из них, и они также действительны (от 0 до 255).Проблема заключается в следующем: $ color = imagecolorallocate ($ new, 255 - $ rgb ['blue'], 255 - $ rgb ['blue'], 0); imagesetpixel ($ new, $ i, $ j, $ color); –

ответ

1

Я считаю, что источником проблемы является то, что при использовании на основе изображения палитры, например, тот, который вы создали, вызвав imagecreate(), можно объявить один и тот же цвет на несколько индексов в пределах палитры.

Это означает, что, потому что вы вызываете imagecolorallocate() на каждой итерации, палитра в конечном итоге становится полной и imagecolorallocate() начинает возвращающиеся false (это можно увидеть, если вы var_dump($color); перед imagesetpixel() вызова). false оценивает ноль при нажатии на целое число - поэтому, когда палитра заполняется, все остальные пиксели эффективно преобразуются в цвет фона.

Есть две вещи, которые вы могли бы сделать по этому поводу, первый и, вероятно, самый простой - просто использовать изображение с истинным цветом, что является простым случаем смены imagecreate($width, $height); на imagecreatetruecolor($width, $height);.

Если вы хотите придерживаться изображения на основе палитры (например, по причине размера выходных данных изображения - с изображением, содержащим так мало цветов, изображение на палитре будет значительно меньше), вам нужно будет кэшировать выделенные цвета вручную, так что вы можете повторно использовать их, что-то вроде этого:

// ... 

$colors = array(); 

for ($x = 0; $x < $width; $x++) { // iterate x axis 
    for ($y = 0; $y < $height; $y++) { // iterate y axis 
     // Get the color at this index 
     $index = imagecolorat($new, $x, $y); 

     // Only allocate a new color if not already done 
     if (!isset($colors[$index])) { 
      $rgb = imagecolorsforindex($new, $index); 
      if ($rgb['red'] != 255 || $rgb['green'] != 255 || $rgb['blue'] != 0) { 
       // If it's not the background color allocate a new color 
       $r = $g = 255 - $rgb['blue']; 
       $b = 0; 

       $colors[$index] = imagecolorallocate($new, $r, $g, $b); 
      } else { 
       // Otherwise set the index to false, we can ignore it 
       $colors[$index] = false; 
      } 
     } 

     // If there's something to do, do it 
     if ($colors[$index] !== false) { 
      imagesetpixel($new, $x, $y, $colors[$index]); 
     } 
    } 
} 

// ... 

вы также можете отслеживать цвета в использовании в изображении, так что вы можете «очистить палитру» впоследствии (т.е. DEALLOCATE любых цветов которые больше не используются в изображении, что еще больше поможет уменьшить размер данных). Хотя, возможно, было бы лучше, в этом случае, начать с чистой палитры и проверить старый ресурс изображения, чтобы получить детали пикселя, вместо копирования оригинала на новый ресурс изображения.

+0

Ты мой блестящий бронированный рыцарь :) –

0

да

$color = imagecolorallocate($new, 255 - $rgb['blue'], 255 - $rgb['blue'], 0); 

Мессинг все вверх ..

если вы хотите тот же результат ... просто вставить строку вне цикла это решит вашу проблему, если вы хотите конкретное изображение :

$color = imagecolorallocate($new, 35, 35, 0); //got from debugging 

И он получит желаемый результат.

Dins

+0

Есть более двух цветов на изображении, есть сглаживание по краям фигур ;-) – DaveRandom

+0

Я согласен. Я не изучал большую часть gd, поэтому не знаю много о внутренней работе, ваш ответ объясняет это хорошо и имеет смысл. – Dinesh

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