Pular para o conteúdo
charmotion

PNG para GIF animado transparente: halos, bordas e formatos melhores

Por equipe Charmotion · Atualizado em

Ilustração de capa do guia: PNG para GIF animado transparente: halos, bordas e formatos melhores, com personagens de demonstração do Charmotion

Sim, um GIF pode ser transparente, mas só com transparência de 1 bit: cada pixel é totalmente transparente ou totalmente opaco. As bordas suaves do PNG são forçadas para um lado ou para o outro, o que gera bordas serrilhadas ou halos brancos e escuros. Primeiro mescle as bordas com a cor do fundo, converta com palettegen e paletteuse do ffmpeg ou mude para WebP animado, APNG ou WebM.

Principais pontos

  • O GIF marca uma cor da paleta como totalmente transparente; não existe transparência parcial.
  • Os halos vêm de pixels de borda com anti-aliasing que foram mesclados com outro fundo.
  • Se o fundo for conhecido, mescle as bordas com essa cor e mantenha só o recorte de alfa rígido.
  • Com um WebM de origem, coloque -c:v libvpx-vp9 antes de -i, senão o ffmpeg descarta o alfa.
  • APNG e WebP animado mantêm o alfa suave e são compatíveis com todos os principais navegadores; use GIF só onde ele for obrigatório.

Um GIF pode ter fundo transparente?

Sim, com uma grande limitação. O guia de formatos de imagem da MDN explica que os pixels de um GIF "são opacos, a menos que um índice de cor específico seja designado como transparente; nesse caso, os pixels com esse valor ficam totalmente transparentes." Ou seja, um GIF tem uma única entrada da paleta que é vazada e nada no meio-termo. Isso é chamado de transparência de 1 bit.

O GIF também é limitado a uma paleta de no máximo 256 cores por frame, então degradês e sombras suaves recebem dithering. A própria MDN recomenda, para sequências animadas, "considerar WebP, AVIF ou APNG".

Para um logo plano com bordas rígidas, um GIF transparente pode ficar bom. Para um personagem com contornos com anti-aliasing, sombra projetada ou brilho, as bordas vão aparecer.

Por que meu GIF transparente tem um halo branco ou escuro?

Porque os pixels de borda do seu PNG são parcialmente transparentes, e o GIF não consegue armazenar isso. Um contorno suave tem um anel de pixels com, por exemplo, 30% ou 70% de opacidade. Na conversão, cada um desses pixels precisa virar totalmente opaco ou totalmente transparente.

  • Se o conversor os mantém opacos, eles ficam com a cor com que foram mesclados. Se essa cor era branca e o GIF fica sobre uma página escura, aparece uma franja branca.
  • Se o conversor os descarta, o contorno fica em degraus.
Comparação ampliada entre uma borda suave com canal alfa e uma borda serrilhada de GIF de 1 bit sobre um gradiente

Nenhuma configuração elimina isso por completo, porque falta a informação de que o GIF precisaria. As soluções são mesclar as bordas com a cor sobre a qual o GIF vai ficar, aceitar um recorte rígido ou usar um formato com alfa de verdade.

Como transformar um PNG em GIF transparente?

Para um único PNG, o ffmpeg cria uma paleta com uma entrada reservada para a transparência e depois mapeia a imagem nela. alpha_threshold define o limite: pixels com alfa abaixo dele ficam transparentes, e o resto, opaco. No nosso teste, isso manteve intacta a área transparente do logo.

ffmpeg -i logo.png -filter_complex "split[a][b];[a]palettegen=reserve_transparent=1[p];[b][p]paletteuse=alpha_threshold=128" logo.gif

Para uma animação exportada como sequência de PNG (frame_001.png, frame_002.png e assim por diante), o mesmo filtro funciona em todos os frames. Esta versão também reduz para 15 fps e 320 px de largura, o que mantém o arquivo pequeno:

ffmpeg -framerate 30 -i frame_%03d.png -filter_complex "fps=15,scale=320:-1:flags=lanczos,split[a][b];[a]palettegen=reserve_transparent=1[p];[b][p]paletteuse=alpha_threshold=128" -loop 0 character.gif

O que cada parte faz, segundo a documentação de filtros do FFmpeg: palettegen=reserve_transparent=1 reserva "uma entrada da paleta para a transparência"; paletteuse=alpha_threshold=128 define "o limite de alfa para a transparência" (de 0 a 255); split permite que uma única entrada alimente as duas etapas; -loop 0 faz o loop infinito. Aumente o limite para um recorte mais justo, ou diminua para manter mais da borda suave como pixels opacos.

Como converter um WebM transparente em GIF com o ffmpeg?

Use a mesma cadeia de filtros, com uma flag a mais: -c:v libvpx-vp9 antes de -i. O decodificador VP9 nativo do ffmpeg ignora o canal alfa do WebM; o libvpx o lê. No nosso teste, o mesmo comando gerou um GIF com 77% de pixels transparentes com essa flag, e 0% sem ela.

ffmpeg -c:v libvpx-vp9 -i character.webm -filter_complex "fps=15,scale=320:-1:flags=lanczos,split[a][b];[a]palettegen=reserve_transparent=1[p];[b][p]paletteuse=alpha_threshold=128" -loop 0 character.gif

Se você sabe que o GIF sempre vai ficar sobre uma única cor de fundo, como um e-mail branco ou um slide branco, dá para evitar halos mesclando as bordas suaves com essa cor e mantendo o recorte rígido. Este comando compõe o personagem sobre o branco e depois devolve o alfa original para o paletteuse aplicar o limite:

ffmpeg -c:v libvpx-vp9 -i character.webm -filter_complex "[0:v]format=rgba,split=3[fg][al][sz];[sz]drawbox=c=white:t=fill[bg];[bg][fg]overlay[flat];[al]alphaextract[a];[flat][a]alphamerge,fps=15,scale=320:-1:flags=lanczos,split[x][y];[x]palettegen=reserve_transparent=1[p];[y][p]paletteuse=alpha_threshold=128" -loop 0 character-on-white.gif

Troque c=white pela cor do seu fundo. O resultado fica limpo nessa cor e com halo nas outras, então faça um GIF por fundo se precisar de vários.

Quando WebP, APNG ou WebM são melhores que GIF?

Quase sempre, se o destino aceitar esses formatos:

FormatoTransparênciaOnde funciona
GIF1 bitEm todo lugar, incluindo clientes de e-mail e plataformas que exigem GIF (emotes da Twitch, muitos apps de chat)
APNGAlfa completo de 8 bitsTodos os principais navegadores (a MDN lista Chrome 59, Edge 79, Firefox 3, Opera 46, Safari 8); stickers do iMessage
WebP animadoAlfa completoNavegadores modernos; figurinhas do WhatsApp
WebM VP9Alfa completoChrome, Edge, Firefox; o Safari reproduz sem alfa

Use GIF quando for a única opção. Para um site, um par de vídeos com fundo transparente (primeiro HEVC MOV para o Safari, depois WebM) é mais leve e mais nítido; veja vídeo com fundo transparente em sites. Para figurinhas, veja como converter WebM transparente para formatos de figurinha.

Dá para obter um GIF transparente de um conjunto do Charmotion?

Não diretamente. Os GIFs do Charmotion são prévias de 480 px com fundo sólido, feitas para chat, documentos e e-mail, onde um fundo não atrapalha. O Charmotion não exporta GIFs transparentes, porque um GIF de 1 bit levaria o problema de halo descrito acima para todas as bordas suaves do seu personagem.

A transparência vem do vídeo transparente dos planos pagos: um WebM (alfa VP9) e um MOV (alfa HEVC), ambos em 1080×1080. Se uma plataforma exigir um GIF transparente, use esse WebM como character.webm nos comandos acima e escolha a cor de fundo (matte) do lugar onde ele vai aparecer.

Perguntas frequentes

Por que meu GIF convertido fica preto onde deveria ser transparente?

O canal alfa se perdeu antes da etapa da paleta. Com um WebM de origem, coloque -c:v libvpx-vp9 antes de -i para o ffmpeg ler o alfa, e use palettegen=reserve_transparent=1.

O que o alpha_threshold faz no paletteuse do ffmpeg?

Ele decide quais pixels ficam transparentes. Pixels com alfa abaixo do limite (de 0 a 255, padrão 128) ficam totalmente transparentes, e o resto, totalmente opaco, porque o GIF não consegue armazenar nada no meio-termo. Valores mais altos recortam mais justo em volta do personagem.

APNG é melhor que GIF para uma animação transparente?

Em geral, sim. O APNG tem suporte a alfa completo, então bordas suaves e sombras continuam lisas, e a MDN lista suporte no Chrome, Edge, Firefox, Opera e Safari. Use GIF só quando o destino exigir, como emotes da Twitch ou clientes de e-mail antigos.

Respostas rápidas deste guia

Fontes

Guias relacionados