Ícone do site Linha de Comando

Gerar miniaturas WebP em PHP com GD para otimizar imagens

Imagens em alta resolução podem aumentar significativamente o tempo de carregamento de uma página, principalmente em galerias com dezenas de arquivos. Uma solução é gerar miniaturas WebP em PHP e carregar essas versões menores na listagem, mantendo a imagem original apenas para visualização ampliada. Neste exemplo, utilizaremos a extensão GD do PHP para redimensionar e converter automaticamente as imagens.

Por que gerar miniaturas WebP em PHP?

Imagine uma galeria contendo 50 fotografias, cada uma com aproximadamente 3 MB. Se o navegador carregar todas as imagens originais, a página poderá transferir mais de 150 MB apenas em imagens.

Mesmo quando o CSS limita visualmente uma imagem para 300 ou 400 pixels, o navegador continua baixando o arquivo original completo. Portanto, utilizar apenas width e height no HTML não resolve o problema de transferência.

A estratégia é manter dois arquivos:

Uma estrutura possível fica assim:

uploads/
└── fotos/
    └── 104/
        ├── foto1.jpg
        ├── foto2.jpg
        └── mini/
            ├── foto1.webp
            └── foto2.webp

Dessa forma, a página inicial da galeria pode transferir arquivos muito menores, enquanto a resolução original continua disponível quando realmente necessária.

Requisitos para gerar miniaturas WebP em PHP

A implementação utiliza a extensão GD. Além disso, a instalação do PHP precisa possuir suporte à função imagewebp().

O próprio código pode verificar esses requisitos antes de tentar processar a imagem:

if (!extension_loaded('gd') || !function_exists('imagewebp')) {
    return false;
}

Também é possível verificar a extensão GD diretamente no PHP:

var_dump(extension_loaded('gd'));
var_dump(function_exists('imagewebp'));

Quando as duas verificações retornarem true, o ambiente possui os recursos necessários para executar a função apresentada a seguir.

Função para gerar miniaturas WebP em PHP

A função gerarMiniatura() recebe o caminho absoluto da imagem original, define uma largura máxima para a miniatura e permite controlar a qualidade do arquivo WebP.

Por padrão, a miniatura terá no máximo 600 pixels de largura e qualidade 80.

/**
 * Gera uma miniatura WebP ao lado da imagem enviada, na pasta "mini".
 *
 * @param string $caminhoImagem Caminho absoluto da imagem original.
 * @param int $larguraMaxima Largura máxima da miniatura, em pixels.
 * @param int $qualidade Qualidade da imagem WebP (0 a 100).
 * @return string|false Caminho absoluto da miniatura ou false em caso de falha.
 */
function gerarMiniatura(string $caminhoImagem, int $larguraMaxima = 600, int $qualidade = 80)
{
    if (
        $larguraMaxima < 1
        || $qualidade < 0
        || $qualidade > 100
        || !is_file($caminhoImagem)
        || !extension_loaded('gd')
        || !function_exists('imagewebp')
    ) {
        return false;
    }

    $dadosImagem = @getimagesize($caminhoImagem);
    $conteudo = @file_get_contents($caminhoImagem);
    $imagemOriginal = $conteudo !== false ? @imagecreatefromstring($conteudo) : false;

    if ($dadosImagem === false || $imagemOriginal === false) {
        return false;
    }

    [$larguraOriginal, $alturaOriginal] = $dadosImagem;

    if ($larguraOriginal < 1 || $alturaOriginal < 1) {
        imagedestroy($imagemOriginal);
        return false;
    }

    $larguraMini = min($larguraOriginal, $larguraMaxima);
    $alturaMini = (int) round($alturaOriginal * ($larguraMini / $larguraOriginal));
    $imagemMini = imagecreatetruecolor($larguraMini, $alturaMini);

    if ($imagemMini === false) {
        imagedestroy($imagemOriginal);
        return false;
    }

    imagealphablending($imagemMini, false);
    imagesavealpha($imagemMini, true);

    $pastaMini = dirname($caminhoImagem) . DIRECTORY_SEPARATOR . 'mini';

    if (
        !is_dir($pastaMini)
        && !mkdir($pastaMini, 0755, true)
        && !is_dir($pastaMini)
    ) {
        imagedestroy($imagemMini);
        imagedestroy($imagemOriginal);
        return false;
    }

    $nomeMiniatura = pathinfo($caminhoImagem, PATHINFO_FILENAME) . '.webp';
    $caminhoMiniatura = $pastaMini . DIRECTORY_SEPARATOR . $nomeMiniatura;

    $redimensionada = imagecopyresampled(
        $imagemMini,
        $imagemOriginal,
        0,
        0,
        0,
        0,
        $larguraMini,
        $alturaMini,
        $larguraOriginal,
        $alturaOriginal
    );

    $salva = $redimensionada
        && imagewebp(
            $imagemMini,
            $caminhoMiniatura,
            $qualidade
        );

    imagedestroy($imagemMini);
    imagedestroy($imagemOriginal);

    if (!$salva) {
        if (is_file($caminhoMiniatura)) {
            unlink($caminhoMiniatura);
        }

        return false;
    }

    return $caminhoMiniatura;
}

Como a função gerarMiniatura funciona

1. Validação dos parâmetros e do ambiente

Antes de processar qualquer arquivo, a função verifica se a largura e a qualidade são válidas, se a imagem realmente existe e se o PHP possui suporte ao GD e ao WebP.

if (
    $larguraMaxima < 1
    || $qualidade < 0
    || $qualidade > 100
    || !is_file($caminhoImagem)
    || !extension_loaded('gd')
    || !function_exists('imagewebp')
) {
    return false;
}

Isso evita executar o restante do processamento em um ambiente incompatível ou com parâmetros incorretos.

2. Carregamento da imagem original

A função utiliza getimagesize() para identificar as dimensões do arquivo e imagecreatefromstring() para criar o recurso de imagem que será manipulado pelo GD.

$dadosImagem = @getimagesize($caminhoImagem);
$conteudo = @file_get_contents($caminhoImagem);
$imagemOriginal = $conteudo !== false
    ? @imagecreatefromstring($conteudo)
    : false;

Uma vantagem dessa abordagem é não precisar selecionar manualmente uma função diferente para JPEG, PNG ou outros formatos que possam ser interpretados pela instalação do GD.

3. Cálculo proporcional da miniatura

A largura é limitada pelo parâmetro $larguraMaxima, enquanto a altura é calculada proporcionalmente.

$larguraMini = min($larguraOriginal, $larguraMaxima);

$alturaMini = (int) round(
    $alturaOriginal * ($larguraMini / $larguraOriginal)
);

Se uma fotografia possuir 3962 pixels de largura, por exemplo, ela poderá ser reduzida para 600 pixels sem alterar sua proporção.

O uso de min() também impede que uma imagem originalmente menor seja ampliada desnecessariamente.

4. Criação automática da pasta mini

A pasta mini é criada dentro do mesmo diretório da fotografia original.

$pastaMini = dirname($caminhoImagem)
    . DIRECTORY_SEPARATOR
    . 'mini';

if (
    !is_dir($pastaMini)
    && !mkdir($pastaMini, 0755, true)
    && !is_dir($pastaMini)
) {
    return false;
}

Assim, uma imagem armazenada em:

uploads/fotos/104/foto1.jpg

terá sua miniatura armazenada em:

uploads/fotos/104/mini/foto1.webp

5. Redimensionamento com imagecopyresampled

O redimensionamento é realizado com imagecopyresampled(), utilizando as dimensões originais e as dimensões calculadas para a miniatura.

$redimensionada = imagecopyresampled(
    $imagemMini,
    $imagemOriginal,
    0,
    0,
    0,
    0,
    $larguraMini,
    $alturaMini,
    $larguraOriginal,
    $alturaOriginal
);

O objetivo é produzir uma versão menor da fotografia preservando sua proporção.

6. Conversão para WebP

Independentemente da extensão da imagem de origem, a miniatura gerada recebe a extensão .webp.

$nomeMiniatura = pathinfo(
    $caminhoImagem,
    PATHINFO_FILENAME
) . '.webp';

O arquivo final é salvo com imagewebp():

$salva = $redimensionada
    && imagewebp(
        $imagemMini,
        $caminhoMiniatura,
        $qualidade
    );

O parâmetro $qualidade permite ajustar a relação entre tamanho do arquivo e qualidade visual. Neste exemplo, o valor padrão utilizado é 80.

Como chamar a função

Considerando que a aplicação conhece o caminho absoluto da imagem, basta chamar:

$caminhoMiniatura = gerarMiniatura(
    '/caminho/absoluto/uploads/fotos/104/foto1.jpg'
);

if ($caminhoMiniatura !== false) {
    echo 'Miniatura criada: ' . $caminhoMiniatura;
} else {
    echo 'Não foi possível gerar a miniatura.';
}

Também é possível informar largura e qualidade diferentes:

$caminhoMiniatura = gerarMiniatura(
    '/caminho/absoluto/uploads/fotos/104/foto1.jpg',
    400,
    75
);

Nesse caso, a miniatura terá no máximo 400 pixels de largura e será salva com qualidade WebP 75.

Usando a miniatura na galeria

A principal vantagem aparece quando a página passa a utilizar o arquivo localizado em mini na listagem, deixando o arquivo original para o link de ampliação.

Conceitualmente, o HTML pode seguir esta estrutura:


    

Nesse exemplo, o navegador baixa inicialmente foto1.webp. Quando o usuário acessa a fotografia ampliada, a aplicação utiliza foto1.jpg.

O atributo loading="lazy" também pode ajudar em galerias extensas, pois permite adiar o carregamento de imagens que ainda estão fora da área visível da página.

Quando gerar as miniaturas

Existem duas estratégias principais. A miniatura pode ser criada imediatamente após o upload da fotografia ou pode ser gerada posteriormente por um script que percorra as imagens existentes.

Para novos uploads, gerar a miniatura no momento em que o arquivo é recebido normalmente simplifica o funcionamento da aplicação. Para um acervo que já possui centenas ou milhares de imagens, pode ser mais conveniente executar uma rotina separada para criar as miniaturas existentes.

Como validar a geração da miniatura

Após executar gerarMiniatura(), verifique primeiro se a função retornou um caminho em vez de false.

Em seguida, confirme se foi criada a pasta:

mini/

e se dentro dela existe o arquivo correspondente com extensão .webp.

Por exemplo:

foto1.jpg
mini/
└── foto1.webp

Também é recomendável comparar o tamanho dos dois arquivos. Em fotografias de alta resolução, a miniatura deverá possuir dimensões e tamanho em disco consideravelmente menores que o arquivo original.

Problemas comuns ao gerar miniaturas

A função sempre retorna false

Verifique inicialmente se a extensão GD está habilitada e se existe suporte ao WebP:

var_dump(extension_loaded('gd'));
var_dump(function_exists('imagewebp'));

Também confirme se o caminho informado para gerarMiniatura() é absoluto e aponta para um arquivo existente.

A pasta mini não é criada

O processo responsável pela execução do PHP precisa possuir permissão para criar a pasta dentro do diretório da imagem. A função utiliza mkdir() com permissão 0755.

Não é recomendado resolver problemas de permissão simplesmente aplicando chmod 777. O ideal é verificar proprietário, grupo e permissões adequadas ao servidor utilizado.

Imagens muito grandes consomem muita memória

Um ponto importante é que o GD precisa carregar a imagem original em memória antes de redimensioná-la. O tamanho do JPEG armazenado em disco não representa necessariamente a quantidade de memória necessária durante o processamento.

Em aplicações que recebem imagens com resoluções muito altas, é importante considerar esse consumo e os limites configurados no PHP.

Resumo prático

Gerar miniaturas WebP em PHP é uma solução simples para reduzir o volume de dados transferidos em galerias de imagens. A fotografia original permanece disponível para ampliação, enquanto a página utiliza uma versão reduzida no carregamento inicial.

A função apresentada cria automaticamente a pasta mini, mantém a proporção da fotografia, limita a largura, converte a miniatura para WebP e permite configurar a qualidade da imagem.

Para galerias com muitas fotografias em alta resolução, combinar miniaturas WebP com loading="lazy" pode reduzir significativamente o carregamento desnecessário de arquivos originais.

Sair da versão mobile