Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Gostaria de saber se é possível fazer o seguinte com a biblioteca GD:
Tenho uma imagem e quero mudar as cores dela baseadas em uma biblioteca de paletas (arquivo .pal) que tenho. É possível trocar as paletas da imagem por essa nova biblioteca de paletas que tenho utilizando a biblioteca GD? Se possível, poderia me ajudar com algumas dicas do que eu deveria fazer para realizar essa troca de paletas?
Obrigado desde Já!
Encontrei algo semelhante, mas só que não consegui interpretar direito o que foi feito. Acredito que não tenham utilizado a biblioteca GD, só PHP , teria como você me ajudar a interpretar e entender para que eu possa usar ele aqui?
http://rathena.org/board/topic/65477-php-and-palettepal/
Obrigado desde já!
Não costumo mexer muito com a GD mas pelo que pude compreender você vai ler os 1024 bytes do arquivo PAL e montar um array de cores alocadas via imagecolorallocate(). Essa tarefa está mais legível no post #3 do link informado.
Depois fará um loop pelos pixels da imagem e aplicará a cor correspondente àquela coordenada X;Y na paleta lida. Essa tarefa está mais legível na segunda metade do código do post #9.
Tente fazer, mas se não conseguir anexe o arquivo PAL em questão para que tenhamos com o que trabalhar.
Antes de tudo, obrigado por me ajudar Bruno Augusto.
Bom... eu consegui entender até a leitura do arquivo .pal, mas depois para a criação da imagem e a troca das cores me enrolei aqui...
O arquivo é esse daqui:
http://www.mediafire.com/?r3ln2c6j393sya9
No caso dessa .pal com a imagem, quando aplicar a .pal é para mudar a cor do cabelo do desenho.
Fiquei com uma outra duvida aqui também, para abrir o arquivo .pal, seria desta maneira aqui:
$pal = fopen("./image/palete.pal", "rb");
// Loading palette
$pal_data = fread( $pal, 1024 );
não entendi também por que ele ta armazenando todas as informações na vareavel '$this'(eu acho), é para ficar mais fácil de acessar?O resultado esperado seria isso: /applications/core/interface/imageproxy/imageproxy.php?img=http://i.imgur.com/jEKT8el.png&key=f7111c19c52c2951e6cad991b617bc6d4dc26e824f08e1b39b0457cff401a62a" alt="jEKT8el.png" />
Se for, então deu certo. :grin:
Mas prefiro que você aprenda a fazer.
Primeiro sobre sua pergunta a respeito do $this, no tópico em que ele aparece existe "Orientação a Objetos" (entre aspas porque o código só foi disposto numa classe <_<).
Enfim...
Você já leu o arquivo, agora você vai criar um recurso de imagem a partir do original. Para iso você tem várias funções, cada qual para um tipo de arquivo.
Infelizmente parece não existir suporte nativo ao formato BMP. Você pode encontrar alguma implementação de terceiros ou converter os arquivos para PNG. Eu até encontrei uma implementação, mas estava muito confusa de se entender então me utilizei da segunda opção.
Então, você criará um array com as 256 cores alocadas dessa paleta.
Depois você itera pelos pixels da imagem e seta a nova cor localizando a cor do pixel atual (na iteração) no array de cores da paleta anteriormente criado.
Por fim, faz o output com a função mais adequada. Como utilizei imagecreatefrompng() para criar o recurso, usei imagepng() para finalizar.
é isso mesmo que tem que ocorrer ^^
Bom, por mim tudo bem, eu também fico até mais feliz por que pelo menos agora eu sei que funciona. kkkk :)
sobre a pergunta do $this, é que eu nunca usei isso, por isso a duvida...
Então agente vai utilizar 'Orientação a Objetos' ou não vai ser preciso?
voltando...
Eu vou ir por partes aqui passando para você para mim entender melhor cada coisa tudo bem? :pinch:
Vamos desde o inicio entom...
Eu estou configurando aqui a leitura da .pal e a array para armazenar as cores, só que não tenho certeza se está certo, por que eu queria testar para ver se estavam armazenando os valores das cores, mas só que só me mostram o numero da cor. é normal isso mesmo ou era para mostrar os valores da paletta em hexa ou algo do tipo?
Ele também está dando erro na linha 15 por causa de não haver nenhum img relacionada a ela.
Abrindo e alocando as Palettes:
$pal="./image/palette.pal";
$palfopen = fopen($pal, "rb");
// Abrindo Paletta
$pal_data = fread( $palfopen, filesize($pal));
// Alocando os valores da Paletta
$palette = array();
for ( $i=0, $j=0; $i<256; $i++, $j+=4 ) );
}
Não entendi direito por que desses erros...
Tem uma coisa também que eu gostaria de pedir para você ensinar(se não for pedir muito), mas só mais para frente, que seria deixar esse fundo da imagem transparente, mas por enquanto quero entender como funciona a troca de Palettes primeiro. =]
Não, não vamos usar Orientação a Objetos.
Nesse código tem um pequeno erro também no fórum original da dúvida. imagecolorallocate(), não sei por qual motivo, precisa de um recurso de imagem para alocar novas cores.
Quem criou o código se esqueceu disso e colocou um argumento a menos na função, ou seja, antes desse laço você vai precisar criar o recurso no qual aplicar a nova paleta.
Uma coisa que para esse caso não faz muita diferença é usar filesize() na leitura do arquivo, uma vez que uma paleta de cores tem tamanho fixo de 1024 bytes (segundo o autor original).
então o melhor seria fazer assim:
$pal="./image/palette.pal";
$palfopen = fopen($pal, "rb");
// Abrindo Paletta
$pal_data = fread( $palfopen, 1024);
// Armazenando os valores da Paletta
$palette = array();
$image_pal = array();
for ( $i=0, $j=0; $i<256; $i++, $j+=4 ) $image_pal[$i]=imagecreatetruecolor(1, 1);
$palette[$i] = imagecolorallocate(
$image_pal[$i],
ord( $pal_data[$j+0] ),
ord( $pal_data[$j+1] ),
ord( $pal_data[$j+2] )
);
}
Como que você fez para abrir a imagem? Não consegui entender direito o que eu tenho que fazer ali no 'itera pelos pixels da imagem'.
Abre ela com o 'fread' e depois só extrai que nem na paletta?
Não, não. Você não vai criar 1024 recursos da mesma imagem senão seu PC é bem capaz de explodir :yay:
Você cria um único recurso, fora do loop e usa aquela variável em imagecolorallocate().
Quanto a iterar pelos pixels da imagem você vai fazer DEPOIS de montar a paleta.
Se você abrir uma imagem com fread() você vai, como a própria função diz, apenas ler a imagem. Apesar de ser teoricamente possível fazer o que a GD faz utilizando os ponteiros de uma stream, deve ser uma tarefa monstruosamente gigantesca deslocar byte por byte, pixel a pixel.
Veja, se você abrir essa paleta como texto plano não vai entender nada do que há nela porque ela não foi feita para ser lida por um bloco de notas, por exemplo. Como muita coisa da programação, existe um algorítimo ou uma lógica a ser seguida.
Para uma paleta de cores, você tem que são 1024 bytes e cada byte resulta numa string que depois de ter seu caractere ASCII convertido em inteiro por ord() resulta numa cor.
Fazendo tudo certinho, se você der um [inline]print_r()[/inline] na variável [inline]$palette[/inline] você verá 1023 números inteiros, cada uma cor, cores essas que serão utilizadas na segunda metade do código, por imagesetpixel().
Então, acho que agora está certo.
Eu estava achando que como cada paletta seria guardada em uma variável, ela precisava ser armazenada cada uma em uma imagem ou algo do tipo, depois que eu vi que ele só usa a imagem criada.
//----Paletta----
$pal="./image/palette.pal";
$palfopen = fopen($pal, "rb");// Armazenando os valores da Paletta
$palette = array();
$image_pal = imagecreatetruecolor(1, 1);
for ( $i=0, $j=0; $i<256; $i++, $j+=4 ) );
}
vai precisar também separar as palettas de cores da imagem né? por que na hora de trocar as palettas, eu vou precisar saber qual paleta que é para eu trocar pela outra, ou nem precisa fazer isso?
xxxxxxxxxxxxxx Ponto de Mesclagem xxxxxxxxxxxxxx
OBS:
Desculpe o Double Post, pensei que ele juntava tudo pra evitar Spam por que sumiu aqui o botão de edit do post que eu fiz '-'
Certinho, agora depois desse código, você itera pelos pixels da imagem.
Mas há um porém. Você criou um recurso de uma imagem de 1x1. Para o propósito de imagecolorallocate(), tudo bem, mas isso te força a, depois desse primeiro loop, destruir o primeiro recurso para liberarar a memória e criar um novo da imagem original.
Ou você pode fazer como eu fiz e ao invés de criar esse recursos 1x1, criar um a partir da própria imagem que será manipulada. Lembre-se que não há suporte nativo ao formato BMP, e que você precisaria converter manualmente com qualquer editor de imagem para outro formato suportado.
Continuando...
Até esse tópico eu sempre achei que a única forma de fazer essa iteração era com dois for-loops aninhados, sendo o primeiro até a largura e o segundo até a altura da imagem (ou vice-versa).
Mas no tópico referência o autor usou uma abordagem diferente fantástica que permite separar matematicamente o valor do eixo X do Y e, com isso, melhorar a performance do script.
Seja qual for a forma que você vá fazer, a(s) variável(eis) de(as) iteração(ões) você usará como argumentos de imagesetpixel().
Para iterar pelos Pixels da imagem eu devo fazer algo assim então:
//----Imagem----
$imagex=imagesx($image); //$w
$imagey=imagesy($image); //$h
for ($h = 0; $h < $imagey; $h++) {
for ($w = 0; $w < $imagex; $w++) {
// Obtem a cor original do Pixel
$cor1 = imagecolorat($image, $w, $h);
$r1 = ($cor1 >> 16) & 0xFF;
$g1 = ($cor1 >> 8) & 0xFF;
$b1 = ($cor1 >> 0) & 0xFF;
}
}
Só não entendi direito como eu devo fazer para trocar os Pixels da imagem =/
Então você não meu posts inteiros. :assobiando:
A resposta pra sua pergunta é literalmente a última palavra do meu post anterior. . :thumbsup:
mas como eu vou usar o imagesetpixel() para trocar a cor se o imagecolorat() só pega a cor do pixel celecionado, e não o valor da palette que está sendo usada naquela região? por que pelo que eu entendi o imagecolorat() só pega a cor do pixel selecionado, e não o numero da paleta que está sendo usada naquele pixel, então eu não sei o que que eu vou trocar para dar a cor exata da paletta.
Como que você vez essa troca? eu não consegui entender ainda @.@
Tem como você colocar um exemplo para mim?
Eu consegui aqui, foi isso mesmo que você fez?
//----Paletta----
$pal="./image/palette.pal";
$palfopen = fopen($pal, "rb");// Armazenando os valores da Paletta
$palette = array();
//Carregando a Imagem (PNG)
$image=imagecreatefrompng('./image/head2.png');
for ( $i=0, $j=0; $i<256; $i++, $j++ ){
$palette[$i] = imagecolorallocate(
$image,
ord( $pal_data[$j++] ),
ord( $pal_data[$j++] ),
ord( $pal_data[$j++] )
);
}
//----Paletta da Imagem----
$palimg="./image/palette_image.pal";
$palimgfopen = fopen($palimg, "rb");// Armazenando os valores da Paletta
$paletteimg = array();
for ( $i=0, $j=0; $i<256; $i++, $j++ ){
$paletteimg[$i] = imagecolorallocate(
$image,
ord( $palimg_data[$j++] ),
ord( $palimg_data[$j++] ),
ord( $palimg_data[$j++] )
);
}
//----Imagem----
$imagex=imagesx($image); //$w
$imagey=imagesy($image); //$h
for ($h = 0; $h < $imagey; $h++) {
for ($w = 0; $w < $imagex; $w++) {
// Obtem a cor original do Pixel
$image_color = imagecolorat($image, $w, $h);
$r1 = ($image_color >> 16) & 0xFF;
$g1 = ($image_color >> 8) & 0xFF;
$b1 = ($image_color >> 0) & 0xFF;
for ( $i=0, $j=0; $i<256; $i++, $j++ ){
if($paletteimg[$i]==$image_color){$index_img=$i;}
}
imagesetpixel($image, $w, $h, $palette[$index_img]);
}
}
header('Content-Type: image/png');
imagepng($image);
Agora eu só queria saber como que eu faço para deixar aquele fundo transparente, teria como você me explicar?
Sua implementação ficou ligeiramente diferente da minha, porém não renderizou a mesma coisa.
O seu código renderizou pra mim um quadradinho marrom, mais nada.
A menos que haja algo mais que você não tenha explicado, o código da seção Paletta da Imagem não só é desnecessário como está atrapalhando o seu uso de imagesetpixel(). As informações geradas no primeiro loop já são os dados das cores que você vai usar.
Tanto é verdade que se você remover aquele terceiro for-loop (que ainda estou tentando entender o motivo dele existir ali) e trocar $index_img por $image_color já funciona, ficando prontinho para transformar o tom de azul piscina do fundo em pixels transparentes.
Quer que eu poste como eu fiz ou quer tentar de novo?
não renderizou por que falta a paletta da Imagem que será utilizada para ser renderizada, por isso ficou todo preto o desenho.
a paletta da imagem é essa daqui: http://www.mediafire.com/?ysltslse97f05i5
como eu falei para você acima, eu não consegui entender como você fez pra trocar as palettas, então o que eu fiz foi o seguinde:
Criei dois bancos de palettas, um da paletta a ser adicionada e uma da paletta da imagem, por isso aqueles 2 códigos.
e aquele 3° loop abaixo, é para eu saber qual é o numero da paletta que está sendo usado naquele pixel, para que então eu possa trocar pelo mesmo numero da paletta da nova cor que eu quero usar. Por que eu não consegui entender como você fez para trocar a cor do pixel, sem saber o numero da Paletta(ou sabia... xD) da cor da Imagem que estava sendo usada naquele Pixel.
Agora eu não entendi esse imagecolorat(), Por que trocar o $index_img pelo $image_color sendo que o $image_color é a cor do Pixel da imagem, e não o numero da Paletta da Imagem da cor que está sendo utilizada naquele Pixel?
Pode postar, dai nos comparamos os mesmos =]
Quando você troca a paleta de uma imagem sua intenção é de recolorir a mesma. Cada paleta é um conjunto de cores a ser aplicada de cada vez.
O primeiro arquivo que você enviou continha a imagem do garoto ruivo num fundo cinza esverdeado. Aplicar aquela paleta fazia ele ficar loiro sob um fundo azul piscina.
A segunda paleta que você acabou de anexar, tanto quanto eu pude perceber do pixel art em questão, não muda nada na imagem, o Alex (nome padrão dos meus tempos de RPG Maker :grin:) continua sendo ruivo.
Sendo assim, essa segunda paleta é desnecessária, bastaria aplicar a remoção do background.
E aquele loop está errado porque pra você saber qual será a nova cor daquele pixel basta você pegar a cor dele, via imagecolorat() como fez, e usar aquele índice como offset na paleta anteriormente lida.
Lembra que eu disse que não fazia sentido imagecolorat() precisar de um recurso de imagem? Pois então, olha a necessidade aí. Sem ele ou então se usasse uma imagem de tamanho menor ou maior haveriam mais ou menos pixels e esse loop começaria a disparar erros de índices indefinidos.
Agora, se com essa segunda leitura você quiser criar uma paleta a partir das cores originais para depois modificar e ter como automatizar um procedimento de reversão, é outra história, já que a lógica muda um pouco.
Dá uma olhada como eu fiz e veja onde e porquê você está errando:
<?php
// Read palette data
$paletteHandle = fopen( 'palette.pal', 'rb' );
$paletteData = fread( $paletteHandle, 1024 );
fclose( $paletteHandle );
// Create image resource
$resource = imagecreatefrompng( 'head2.png' );
// Allocate palette colors
$palette = array();
for( $i = 0, $j = 0; $i < 256; $i += 1, $j += 4 ) {
$palette[ $i ] = imagecolorallocate(
$resource,
ord( $paletteData[ $j + 0 ] ),
ord( $paletteData[ $j + 1 ] ),
ord( $paletteData[ $j + 2 ] )
);
}
// Define a transparent pixel (the first pixel, at 0;0)
$transparent = imagecolortransparent( $resource, $palette[ 0 ] );
$width = imagesx( $resource );
$height = imagesy( $resource );
$area = ( $width * $height );
for( $i = 0; $i < $area; $i += 1 ) {
$x = $i % $width;
$y = $i / $width | 0;
$colorAt = imagecolorat( $resource, $x, $y );
imagesetpixel(
$resource, $x, $y,
( $colorAt == 0 ? $transparent : $palette[ $colorAt ] )
);
}
header( 'Content-type: image/png' );
imagepng( $resource );
Nesse código já está incluso a remoção do background. A lógica é simples: Pegar a cor do primeiro pixel que 99% das vezes já é a cor do background e alocar ela como transparente via imagecolortransparent().
Na hora de setar a nova cor do pixel você verifica se a cor obtida para aquele ponto é zero. Se for, aplica a transparência, se não for, aplica a cor da paleta.
Não estou bem bem certo o porquê de a condição ter de ser zero, mas acredito não ser importante.
Aquela Paletta que te mandei tem referência a alocação de cores da Paletta da Imagem, e não da alocação da Paletta que quero adicionar a imagem.
Da uma olhada ai =]
http://www.mediafire.com/?yfbp34yn6f6wrd3
E aqui, eu tentei utilizar o seu código e ele ta renderizando para mim essa imagem:/applications/core/interface/imageproxy/imageproxy.php?img=http://img802.imageshack.us/img802/7404/imagemdzg.png&key=aef4469f8826f6137634e552c76ed1959ec9dc045eac6d41ce5506637e0846c6" alt="imagemdzg.png" />
Provavelmente o Valor 0(zero) é por que tem alguns números de palettas que estão como nulo(em branco), mas não entendi o por que também desse código ai...
Vi sua resposta anteontem, mas sua consegui responder hoje.
Você deve estar misturando os arquivos porque no post #7 você disse que o personagem estar loiro com o fundo verde-piscina estava correto. Daí para frente eu só fiz foi remover o fundo.
O código acima foi aplicado utilizando a imagem e a paleta que você anexou no post #5.
Se agora deveria ocorrer outra coisa que não está ocorrendo, então você vai ter de remodelar sua pergunta pois agora o cenário é ou pode ser outro.
Eu também chequei possíveis incompatibilidades entre funções e versão da GD e a única consideração é quanto a imagecolorat() não retornar os canais RGB separados caso a versão seja 2.0 ou superior.
Mas isso é indiferente para o caso pois não estamos usando os canais de cor de forma separada.
ainda continua sendo o caso do post #7, realmente é aquilo que deve ocorrer, mas por algum motivo, ele não está ocorrendo aqui, os arquivos que te enviei são os mesmos, não mudou nada(somente a imagem que foi convertida) e não está ocorrendo o que deveria ocorrer.
O que eu fiz e te enviei no post #20 que está faltando ainda alguns ajustes de código só para melhoria de desempenho com base no seu script está funcionando normalmente, está trocando o cabelo do menino ruivo para loiro e o fundo está deixando transparente, mas não estou utilizando aquele código de for looping que você usa no seu criado com base no autor do post do forum rathena, estou utilizando os dois forlooping alinhados.
E então? Conseguiu resolver? Só para descartarmos problemas com o código, mesmo que improvável, teste com esses arquivos, já que o seu não funciona aqui e, aparentemente, vice-versa.
Se ainda assim não funcionar pode estar havendo alguma coisa não esclarecida pelo manual quanto à versão da GD. Vou postar as minhas e você compara com seu phpinfo():
/applications/core/interface/imageproxy/imageproxy.php?img=http://i.imgur.com/gc8y9NM.png&key=5f42082dd7f0ac68713407da1a74694749b3d1c409a629899368c567996a8ca7" alt="gc8y9NM.png" />
Eu verifiquei aqui, e pensei que estava atualizada minha biblioteca, mas acho que não estava não =/
Acho que possivelmente possa ser isso, vou estar atualizando aqui e qualquer duvida eu volto a postar novamente tudo bem? como vou ficar fora por alguns dias, possa ser que só depois do Carnaval eu venha a dar a resposta para você tudo bem? >.<
gd
GD Support enabled
GD Version bundled (2.0.34 compatible)
FreeType Support enabled
FreeType Linkage with freetype
FreeType Version 2.1.9
T1Lib Support enabled
GIF Read Support enabled
GIF Create Support enabled
JPG Support enabled
PNG Support enabled
WBMP Support enabled
XBM Support enabled
O mais próximo que encontrei se refere a criar um recurso de uma imagem e aplicar imagecolortopalette(), porém nada referente a utilizar um arquivo .PAL.
De repente, se você conseguir ler esse arquivo com algum editor de texto pode conseguir ajustar os argumentos dessa função.