PHP GD2:como manter a transparência do canal alfa e corrigir a gama
-
26-09-2020 - |
Pergunta
Fiquei intrigado com esta discussão de dimensionamento de imagem e posteriormente descobri que o código PHP que estou usando para criar miniaturas de imagens enviadas sofre do mesmo problema.Decidi tentar a correção do PHP postada na parte inferior (convertendo gama de 2,2 para 1,0, redimensionando a imagem, convertendo gama de volta de 1,0 para 2,2).Isso funciona para resolver o problema mencionado no artigo, no entanto, essa modificação no código tem o infeliz efeito colateral de eliminar a transparência do canal alfa do PNG.
Aqui está o código que tenho com a correção gama em vigor.
<?php
$image = imagecreatefrompng($source_file);
$resized_image = imagecreatetruecolor($new_width, $new_height);
imagealphablending($resized_image, false);
imagesavealpha($resized_image, true);
imagegammacorrect($image, 2.2, 1.0);
imagecopyresampled($resized_image, $image, 0, 0, 0, 0, $new_width, $new_height, $image_width, $image_height);
imagegammacorrect($resized_image, 1.0, 2.2);
imagepng($resized_image, $dest_file);
?>
Alguém sabe como redimensionar a imagem, empregando o truque de correção gama, mantendo a transparência do canal alfa da imagem original?
Editar
imagens de amostra:
- arquivo original - PNG com transparência de canal alfa
- arquivo redimensionado com ambas as chamadas de função imagegammacorrect() comentadas
- arquivo redimensionado com ambas as chamadas de função imagegammacorrect() em vigor
Você pode ver que a transparência está boa até tentar corrigir a gama.(a maneira mais fácil de ver se a transparência está funcionando abaixo é inspecionar a tag de parágrafo enrolada nas imagens e adicionar um plano de fundo:preto;ao seu atributo de estilo via FireBug ou similar.)
imagem original http://ender.hosting.emarketsouth.com/images/test-image.png sem correção gama http://ender.hosting.emarketsouth.com/images/test-image-resized-no-gamma.png gama corrigida - sem transparência http://ender.hosting.emarketsouth.com/images/test-image-resized.png
Solução
Aqui está um código que funciona.Basicamente, ele separa o canal alfa, redimensiona a imagem usando correção de gama, redimensiona o canal alfa sem correção de gama e, em seguida, copia o canal alfa para a imagem redimensionada que foi feita com correção de gama.
Meu palpite é que a função imagegammacorrect() tem um bug.Talvez o gama se aplique apenas ao RGB e o GD tente fazer o mesmo cálculo também para o canal alfa?A teoria das cores não é meu forte.
De qualquer forma, aqui está o código.Infelizmente não consegui encontrar uma maneira melhor de separar os canais do que percorrer os pixels um por um.Ah bem...
<?php
// Load image
$image = imagecreatefrompng('test-image.png');
// Create destination
$resized_image = imagecreatetruecolor(100, 100);
imagealphablending($resized_image, false); // Overwrite alpha
imagesavealpha($resized_image, true);
// Create a separate alpha channel
$alpha_image = imagecreatetruecolor(200, 200);
imagealphablending($alpha_image, false); // Overwrite alpha
imagesavealpha($alpha_image, true);
for ($x = 0; $x < 200; $x++) {
for ($y = 0; $y < 200; $y++) {
$alpha = (imagecolorat($image, $x, $y) >> 24) & 0xFF;
$color = imagecolorallocatealpha($alpha_image, 0, 0, 0, $alpha);
imagesetpixel($alpha_image, $x, $y, $color);
}
}
// Resize image to destination, using gamma correction
imagegammacorrect($image, 2.2, 1.0);
imagecopyresampled($resized_image, $image, 0, 0, 0, 0, 100, 100, 200, 200);
imagegammacorrect($resized_image, 1.0, 2.2);
// Resize alpha channel
$alpha_resized_image = imagecreatetruecolor(200, 200);
imagealphablending($alpha_resized_image, false);
imagesavealpha($alpha_resized_image, true);
imagecopyresampled($alpha_resized_image, $alpha_image, 0, 0, 0, 0, 100, 100, 200, 200);
// Copy alpha channel back to resized image
for ($x = 0; $x < 100; $x++) {
for ($y = 0; $y < 100; $y++) {
$alpha = (imagecolorat($alpha_resized_image, $x, $y) >> 24) & 0xFF;
$rgb = imagecolorat($resized_image, $x, $y);
$r = ($rgb >> 16 ) & 0xFF;
$g = ($rgb >> 8 ) & 0xFF;
$b = $rgb & 0xFF;
$color = imagecolorallocatealpha($resized_image, $r, $g, $b, $alpha);
imagesetpixel($resized_image, $x, $y, $color);
}
}
imagepng($resized_image, 'test-image-scaled.png');
?>
Substitua valores codificados por variáveis, é claro...E aqui está o resultado que obtenho usando sua imagem e meu código:
(fonte: jejik. com)
Outras dicas
Há um problema com imagecopyresampled() e transparência.Dê uma olhada este comentário no php.net para uma possível solução.