2010-09-16 3 views
5

В PHP GD, как вы можете преобразовать полноцветный изображения в палитру без потери любых цвета. С imagetruecolortopallete это не работает. У меня есть функция, которая проходит через все цвета и фильтрует их (например, оттенки серого). и Он не сохраняет все цвета, такие, как эта картина в Lamborghini-PHP GD палитра цветы

Изображение

alt text

Это мой код

$im = imagecreatefrompng("lamborghini.png"); 
$degrees = 0; 

$img = imagecreatetruecolor(imagesx($im), imagesy($im)); 
imagecopy($img, $im, 0, 0, 0, 0, imagesx($im), imagesy($im)); 
imagetruecolortopalette($img, true, 256); 
$t = imagecolorstotal($img); 
for ($i = 0; $i < $t; $i++) { 
    $rgb = imagecolorsforindex($img, $i); 
    $hsv =rgbtohsv($rgb['red'], $rgb['green'], $rgb['blue']); 
    $h = $degrees; 
    $s = $hsv['s']; 
    $v = $hsv['v']; 
    while ($h > 360) {$h -= 360;}; 
     $nrgb = hsvtorgb($h, $s, $v); 
    imagecolorset($img, $i, $nrgb['r'], $nrgb['g'], $nrgb['b']); 
} 
imagecopy($im, $img, 0, 0, 0, 0, imagesx($img), imagesy($img)); 

header('Content-type: image/png'); 

imagepng($im); 
imagedestroy($im); 

И это выглядит следующим образом

alt text

Вы можете увидеть она теряет цвета. Есть любое решение?

Кроме того, я не думаю, что он должен делать с моим кодом, но как imagetruecolortopalette выводит его

+0

Преобразование палитры библиотеки GD происходит быстро, но очень неточно. Если вы хотите использовать палитру, я рекомендую использовать команду [pngquant] (https://github.com/pornel/improved-pngquant) через [popen()] (http://php.net/popen) - пока это будет потерять * некоторые * цвета, потеря не будет такой же плохой. – Kornel

ответ

5

Проверьте возврат на imagecolorstotal, вы всегда получаете 256 цветов в качестве возврата, независимо от того, насколько высока вы устанавливаете количество цветов, которые нужно убрать. PNG-8 & Форматы GIF поддерживают только палитры до 256 цветов. Поэтому, даже если вы можете использовать более 256 палитр, вам придется сохранить их как истинный цвет, чтобы кто-нибудь мог его использовать, тем самым делая весь процесс преобразования пустой тратой времени. Другими словами, imagetruecolortopallete имеет верхний предел в 256 цветов, вы не можете идти выше.

Вот как вы можете это сделать в truecolor, хотя он ресурсоемкий. Возможно, посмотрите на imagemagick, если вы хотите сделать это более эффективно.

$im = imagecreatefrompng("lamb.png"); 
$img = imagecreatetruecolor(imagesx($im), imagesy($im)); 
$degrees = 0; 
if ($degrees > 360) {$degrees = $degrees % 360 ;} 

foreach (range(0, imagesx($im) - 1) as $x) { 
    foreach (range(0, imagesy($im) - 1) as $y) { 
     $rgb = imagecolorat($im, $x, $y); 
     $r = ($rgb >> 16) & 0xFF; 
     $g = ($rgb >> 8) & 0xFF; 
     $b = $rgb & 0xFF; 
     $hsv = rgbtohsv($r,$g,$b); 
     $rgb = hsvtorgb($degrees, $hsv['s'], $hsv['v']); 
     imagesetpixel($img, $x,$y,imagecolorallocate($img, $rgb['r'], $rgb['g'], $rgb['b'])); 
    } 
} 

imagepng($img, 'lamb2.png'); 

Edit: Добавление rgbtohsv & hsvtorgb функции. Я не писал эти функции.

function rgbtohsv ($R, $G, $B) { 
// HSV Results:Number 0-1 
$HSL = array(); 

$var_R = ($R/255); 
$var_G = ($G/255); 
$var_B = ($B/255); 

$var_Min = min($var_R, $var_G, $var_B); 
$var_Max = max($var_R, $var_G, $var_B); 
$del_Max = $var_Max - $var_Min; 

$V = $var_Max; 

if ($del_Max == 0) 
{ 
$H = 0; 
$S = 0; 
} 
else 
{ 
$S = $del_Max/$var_Max; 

$del_R = ((($var_Max - $var_R)/6) + ($del_Max/2))/$del_Max; 
$del_G = ((($var_Max - $var_G)/6) + ($del_Max/2))/$del_Max; 
$del_B = ((($var_Max - $var_B)/6) + ($del_Max/2))/$del_Max; 

if ($var_R == $var_Max) $H = $del_B - $del_G; 
else if ($var_G == $var_Max) $H = (1/3) + $del_R - $del_B; 
else if ($var_B == $var_Max) $H = (2/3) + $del_G - $del_R; 

if ($H<0) $H++; 
if ($H>1) $H--; 
} 

$HSL['h'] = $H; 
$HSL['s'] = $S; 
$HSL['v'] = $V; 

return $HSL; 
} 

function hsvtorgb ($H, $S, $V) 
{ 
$RGB = array(); 

if($S == 0) 
{ 
$R = $G = $B = $V * 255; 
} 
else 
{ 
$var_H = $H * 6; 
$var_i = floor($var_H); 
$var_1 = $V * (1 - $S); 
$var_2 = $V * (1 - $S * ($var_H - $var_i)); 
$var_3 = $V * (1 - $S * (1 - ($var_H - $var_i))); 

if ($var_i == 0) { $var_R = $V ; $var_G = $var_3 ; $var_B = $var_1 ; } 
else if ($var_i == 1) { $var_R = $var_2 ; $var_G = $V ; $var_B = $var_1 ; } 
else if ($var_i == 2) { $var_R = $var_1 ; $var_G = $V ; $var_B = $var_3 ; } 
else if ($var_i == 3) { $var_R = $var_1 ; $var_G = $var_2 ; $var_B = $V ; } 
else if ($var_i == 4) { $var_R = $var_3 ; $var_G = $var_1 ; $var_B = $V ; } 
else { $var_R = $V ; $var_G = $var_1 ; $var_B = $var_2 ; } 

$R = $var_R * 255; 
$G = $var_G * 255; 
$B = $var_B * 255; 
} 

$RGB['r'] = $R; 
$RGB['g'] = $G; 
$RGB['b'] = $B; 

return $RGB; 
} 
+0

Что такое 'rgbtohsv' и' hsvtorgb' – EscoMaji

+0

@EscoMaji Я добавил эти функции в сообщение. – Klinky

0

Как насчет этой функции: http://www.php.net/manual/en/function.imagetruecolortopalette.php. Тем не менее, может потребоваться некоторое количество ошибок, чтобы получить правильное количество цветов.

+0

Что я уже пробовал, см. Мое редактирование –

+0

У вас есть 'dither' включен? И сколько цветов вы указали? –

+0

Это то, что у меня есть 'imagetrucolortopalette ($ img, true, 256);' so yes –

2

преобразование truecolor в палитру всегда будет включать в себя потерю цветов, если только ваш стол для паллет не будет достаточно большим, чтобы удерживать каждый уникальный цвет на изображении. У lamborghini может быть больше, чем (скажем) 255 оттенков только желтого цвета, а затем вам еще нужны палитры для остальной части изображения поверх этого. Вот почему есть изображения truecolor. Там нет палитры, но каждый пиксель может иметь свой собственный выделенный триггер RGB, чтобы более точно представлять исходную сцену.

Это, как говорится, я не вижу, как преобразование изображения truecolor изменится с желтого на красный, как на ваших образцах. Как именно вы делаете это преобразование палитры? Сэмплирование каждого пикселя и выполнение какого-то преобразования на нем?

+0

Позвольте мне отредактировать, чтобы объяснить –

+0

Что произойдет, если вы устраните rgb-> hsv-> rgb roundtrip? Посмотрите, что производит imagetruecolortopalette? Я предполагаю, что у вас возникла ошибка в функции rgbtohsv и/или hsvtorgb, так как даже «плохой» генератор палитр не выдавал бы столько красных из исходного изображения, которое по существу не имеет. –

+0

Нет. Я разрешил проблему, используя опционально палитру (для скорости) и truecolor для обеспечения качества. –