# DataFirefly Image Optimizer: documentação Shopware 6

> O DataFirefly Image Optimizer transforma automaticamente cada imagem de média do Shopware em variantes WebP e AVIF, recomprime os JPEG e PNG de origem, e reescreve os URLs para o…

- Página: <https://www.datafirefly.com/pt/documentation/dfimageoptimizer/>
- Idioma: pt
- Atualizado em: 2026-09-02
- Outros idiomas: [fr](https://www.datafirefly.com/documentation/dfimageoptimizer/index.md), [en](https://www.datafirefly.com/en/documentation/dfimageoptimizer/index.md), [es](https://www.datafirefly.com/es/documentation/dfimageoptimizer/index.md), [de](https://www.datafirefly.com/de/documentation/dfimageoptimizer/index.md), [it](https://www.datafirefly.com/it/documentation/dfimageoptimizer/index.md), [pl](https://www.datafirefly.com/pl/documentation/dfimageoptimizer/index.md), [nl](https://www.datafirefly.com/nl/documentation/dfimageoptimizer/index.md)
- Índice: <https://www.datafirefly.com/pt/documentation/llms.txt>

O DataFirefly Image Optimizer transforma automaticamente cada imagem de média do Shopware em variantes WebP e AVIF, recomprime os JPEG e PNG de origem, e reescreve os URLs para o seu CDN, sem alterar o tema. Esta documentação cobre a instalação, a configuração completa, a API Twig exposta aos temas e a resolução de problemas.

## Instalação

A extensão é entregue em ZIP. Dois métodos de instalação, funcionalmente equivalentes.

### Pela administração do Shopware

1. Definições → Sistema → Extensões → Carregar uma extensão
2. Selecione `DfImageOptimizer-1.0.0.zip`
3. Clique em Instalar e depois em Ativar
4. Limpe a cache: Definições → Sistema → Cache e Índice → Limpar

### Por CLI (recomendado)

```
cd /caminho/para/shopware
unzip DfImageOptimizer-1.0.0.zip -d custom/plugins/

sudo -u www-data setsid php bin/console plugin:refresh
sudo -u www-data setsid php bin/console plugin:install --activate DfImageOptimizer
sudo -u www-data setsid php bin/console cache:clear
sudo -u www-data setsid php bin/console theme:compile
```

**Dica.** O `theme:compile` é obrigatório depois da instalação para que a sobreposição Twig do componente de miniatura fique ativa no storefront. Sem esse passo, as etiquetas `` não serão geradas, mesmo que o WebP e o AVIF sejam produzidos.

### Verificação após a instalação

Vá ao menu de administração **Catálogos → Image Optimizer**. O painel tem de aparecer com um cartão _Compatibilidade do servidor_ a indicar em tempo real:

- Versão do PHP detetada (8.2 no mínimo)
- Presença do Imagick (recomendado)
- Presença do GD (obrigatório)
- Suporte efetivo a WebP: tem de estar ✓
- Suporte efetivo a AVIF: pode estar ✗ consoante o servidor, não é bloqueante
- Motor recomendado: Imagick ou GD

## Arquitetura em duas palavras

Quando uma imagem é carregada, a extensão escuta o evento de entidade `media.written`, carrega a imagem para um ficheiro temporário local, e produz em paralelo:

- O original recomprimido (substitui o ficheiro de origem se _Comprimir original_ estiver marcado)
- Um irmão WebP ao lado, com extensão acumulada: `foo.jpg` → `foo.jpg.webp`
- Um irmão AVIF ao lado: `foo.jpg` → `foo.jpg.avif`

As miniaturas do Shopware geradas pelo `ThumbnailService` nativo são tratadas da mesma forma. Do lado do storefront, a sobreposição Twig de `storefront/component/image/thumbnail.html.twig` envolve a etiqueta `` num `` com fontes AVIF, WebP e alternativa original: o navegador escolhe automaticamente o formato mais leve que suporta.

## Configuração

Acesso: **Definições → Sistema → Extensões → DfImageOptimizer → Configurar**. Sete cartões agrupam as opções.

### Cartão «Geral»

| Opção | Predefinição | Efeito |
| --- | --- | --- |
| Otimização automática no carregamento | Ativa | Aciona o pipeline de imediato a cada carregamento. Desative se preferir fazer tudo em segundo plano através do cron. |
| Tratar as miniaturas | Ativa | Gera WebP/AVIF também para as miniaturas do Shopware (tipicamente 4 a 6 tamanhos por imagem de origem). |

### Cartão «WebP»

| Opção | Predefinição | Recomendação |
| --- | --- | --- |
| Ativar WebP | Ativo | A manter ativo salvo caso muito específico. O WebP é suportado por 96 % dos navegadores. |
| Qualidade WebP (1-100) | 82 | 75 a 85 para um bom compromisso. 90+ para fotografia de topo, 70 para catálogos volumosos. |
| Lossless para PNG | Desativado | Ative apenas se os seus PNG contiverem texto ou gráficos nítidos (logótipos, ícones). Caso contrário, o modo lossy dá melhores ganhos. |

### Cartão «AVIF»

| Opção | Predefinição | Recomendação |
| --- | --- | --- |
| Ativar AVIF | Desativado | Ative se o painel indicar que o seu servidor suporta AVIF. Ganho típico de 50 % face ao JPEG, mas codificação mais lenta que o WebP. |
| Qualidade AVIF (1-100) | 55 | 45 a 65 para uma excelente renderização. O AVIF tolera qualidades mais baixas do que o JPEG e o WebP graças ao seu codec moderno. |
| Largura máxima para AVIF (px) | 2400 | Salvaguarda de CPU. As imagens acima disso são saltadas para AVIF mas mantêm o seu WebP. Aumente se tiver um servidor potente e precisar de AVIF em imagens grandes. |

**Sobre o AVIF.** A codificação AVIF exige PHP 8.1+ com o sinalizador `IMG_AVIF` compilado, ou Imagick com libheif. O painel _Compatibilidade do servidor_ indica-lhe exatamente o que está disponível. Se o AVIF não for suportado, a opção fica inoperante mesmo que marcada: sem erro, apenas sem geração de AVIF.

### Cartão «Compressão»

| Opção | Predefinição | Recomendação |
| --- | --- | --- |
| Comprimir os JPG/PNG originais | Ativo | Substitui o original pela sua versão recomprimida. Ação **irreversível**: desative se quiser conservar as fontes em bruto para futuras edições. |
| Qualidade JPEG (1-100) | 85 | 85 é a norma da fotografia web. Descer a 80 dá ganho adicional se a qualidade continuar visualmente aceitável. |
| Nível de compressão PNG (0-9) | 7 | 9 = compressão máxima mas 3 a 4× mais lenta. 7 é o equilíbrio normal. |
| Eliminar os metadados EXIF/ICC | Ativo | Ganho típico de 5 a 30 KB por fotografia vinda de câmara. Conserve se gerir conteúdo que exija perfis de cor precisos. |

### Cartão «CDN»

| Opção | Predefinição | Explicação |
| --- | --- | --- |
| Ativar a reescrita para CDN | Desativada | Se estiver desativada, os URLs apontam para a sua origem. Ative depois de configurar o seu CDN. |
| URL de base do CDN | — | Formato: `https://cdn.exemplo.com` sem barra final. Ex.: `https://shop-cdn.b-cdn.net` para BunnyCDN. |
| Âmbito da reescrita | Apenas médias | Ver detalhe abaixo. |
| Conservar as query strings | Ativo | Preserva os parâmetros de cache-busting (`?v=1234`) na reescrita. |

**Detalhe dos três âmbitos:**

- **Apenas médias**: reescreve apenas os URLs que começam por `/media/`. É o mais seguro e cobre 95 % dos casos de uso típicos.
- **Médias e miniaturas**: acrescenta `/thumbnail/`. Útil se o seu storefront servir muitas miniaturas geradas dinamicamente.
- **Todos os recursos estáticos**: acrescenta `/theme/`, `/bundles/` e `/assets/`. Só escolha esta opção se o seu CDN estiver corretamente configurado para pull-cache de todos os recursos e se tiver testado em staging.

### Cartão «Renderização no frontend»

| Opção | Predefinição | Efeito |
| --- | --- | --- |
| Saída em etiqueta `` | Ativa | Envolve as `` do storefront num `` com fontes AVIF/WebP. |
| Acrescentar `loading="lazy"` | Ativo | Lazy-loading nativo do navegador. A manter, salvo se tiver a sua própria solução. |
| Acrescentar `decoding="async"` | Ativo | Permite ao navegador descodificar em paralelo com o parsing do HTML. |
| Forçar `width`/`height` | Ativo | Anti-CLS (Cumulative Layout Shift). O navegador reserva o espaço do visual antes do carregamento. |

### Cartão «Processamento em lote»

| Opção | Predefinição | Recomendação |
| --- | --- | --- |
| Tamanho do lote da tarefa cron | 50 | 50 é um bom equilíbrio. Suba para 100 a 200 se precisar de recuperar um catálogo grande depressa e o seu servidor aguentar. |
| Intervalo do cron (minutos) | 15 | Informação apenas: o intervalo real é definido pela classe `OptimizeImagesTask::getDefaultInterval()`. Para o alterar de facto, mude o valor na tabela `scheduled_task` ou reinstale a extensão depois da alteração. |

## Configurar um CDN: exemplos concretos

### BunnyCDN (recomendado)

1. Crie uma _Pull Zone_ em bunny.net com o seu URL de origem, por exemplo `https://loja.exemplo.com`
2. O BunnyCDN dá-lhe um hostname do tipo `shop-cdn.b-cdn.net`
3. Na configuração da extensão, coloque: `https://shop-cdn.b-cdn.net`
4. Escolha o âmbito _Apenas médias_ para começar
5. Ative a reescrita para CDN

A extensão injeta automaticamente `` e `` no `` do storefront: ganho de 50 a 200 ms no primeiro pedido ao CDN.

### Cloudflare

A Cloudflare em modo proxy DNS normal não exige reescrita de CDN: coloca automaticamente em cache no seu hostname principal. Mas se usar um _Custom Hostname_ Cloudflare dedicado aos recursos (por exemplo `cdn.exemplo.com`), configure-o aqui. Ative também o _Cache Reserve_ ou o _Polish_ do lado da Cloudflare para beneficiar da otimização da Cloudflare por cima da sua.

### KeyCDN

Configuração idêntica à do BunnyCDN: crie uma Pull Zone, obtenha o URL do tipo `shop-12345.kxcdn.com`, e configure-o na extensão com o prefixo `https://`.

### AWS CloudFront

Crie uma distribuição CloudFront com o seu servidor Shopware como origem. O URL de distribuição é do tipo `https://d1234abc.cloudfront.net`, ou o seu domínio personalizado se tiver configurado um alias. Configure o TTL mínimo para 1 dia para aproveitar plenamente a cache.

## Pipeline de otimização em detalhe

Para cada imagem (original ou miniatura) a tratar, a extensão executa os seguintes passos por ordem:

1. Transferência da imagem de origem do filesystem público do Shopware para um ficheiro temporário local (`/tmp/dfimgopt_xxx.jpg`)
2. **Se Comprimir original estiver ativo**: recompressão in-place com a qualidade configurada, eliminação dos metadados se estiver ativa. Se a versão recomprimida for menor do que a original, substitui o ficheiro de origem no filesystem.
3. **Se o WebP estiver ativo**: conversão para WebP, escrita do irmão `foo.jpg.webp` no filesystem público
4. **Se o AVIF estiver ativo e a largura for ≤ largura máxima**: conversão para AVIF, escrita do irmão `foo.jpg.avif`
5. Registo na tabela `df_image_optimizer` com contadores e tamanho poupado
6. Limpeza do ficheiro temporário local através de um bloco `finally` (mesmo em caso de erro)

O Imagick é usado em prioridade quando está disponível (qualidade superior e único motor AVIF através de libheif em muitos servidores). O GD assume caso contrário: suporta WebP há muito tempo e AVIF desde o PHP 8.1.

**Compressão do JPEG original: irreversível.** Quando a opção _Comprimir original_ está marcada, a versão comprimida substitui a original no filesystem. Se precisar de recuperar as fontes em bruto para outros usos (impressão, edições), desative esta opção: continuará a ter os ganhos através do WebP e do AVIF.

## Tarefa agendada: recuperar as imagens existentes

Ativar a extensão numa loja que já tem milhares de imagens na base de dados não desencadeia a otimização retroativa. É intencional: converter 50 000 imagens em AVIF de uma vez saturaria o seu servidor. Em vez disso, a tarefa agendada `df_image_optimizer.optimize_pending` corre a cada 15 minutos por predefinição:

1. Consulta SQL com LEFT JOIN em `df_image_optimizer` para identificar os médias ainda não otimizados
2. Trata um lote de 50 imagens (tamanho de lote configurável)
3. Termina e liberta o worker para a tarefa seguinte

Numa loja de 10 000 imagens, conte cerca de 50 horas para recuperar tudo em segundo plano. Para acelerar:

- Aumente o tamanho do lote na configuração (experimente 100 ou 200)
- Use o botão **Lançar um lote** do painel várias vezes seguidas
- Execute a tarefa em ciclo manualmente por CLI: ``` for i in {1..100}; do sudo -u www-data setsid php bin/console scheduled-task:run-single df_image_optimizer.optimize_pending; done ```

## API Twig exposta aos temas

Estão registados dois helpers Twig, utilizáveis em qualquer template de tema ou de extensão.

### Filtro `|df_cdn`

Reescreve um URL para o CDN se estiver ativo, e devolve o URL inalterado caso contrário. Útil para os recursos que inclui manualmente.

```
<img src="{{ media.url|df_cdn }}" alt="...">
<link rel="preload" as="image" href="{{ heroImage.url|df_cdn }}">
<style>
    .hero { background-image: url("{{ bgImage.url|df_cdn }}"); }
</style>
```

### Função `df_picture()`

Renderiza uma etiqueta `` completa com fontes AVIF, WebP e alternativa original, mais todos os atributos configurados (lazy, async, width/height).

```
{{ df_picture(
    media,
    alt='Descrição acessível',
    classes='product-image card-img',
    sizes='(max-width: 768px) 100vw, 50vw'
) }}
```

Gera:

```
<picture>
    <source type="image/avif"
            srcset="https://cdn.exemplo.com/media/foo.jpg.avif"
            sizes="(max-width: 768px) 100vw, 50vw">
    <source type="image/webp"
            srcset="https://cdn.exemplo.com/media/foo.jpg.webp"
            sizes="(max-width: 768px) 100vw, 50vw">
    <img src="https://cdn.exemplo.com/media/foo.jpg"
         alt="Descrição acessível"
         class="product-image card-img"
         sizes="(max-width: 768px) 100vw, 50vw"
         loading="lazy"
         decoding="async"
         width="1200"
         height="800">
</picture>
```

## Endpoints da API de administração

Estão disponíveis três endpoints REST, autenticados com o Bearer token normal da administração.

| Método | Rota | Descrição |
| --- | --- | --- |
| GET | `/api/_action/df-image-optimizer/stats` | Visão geral, atividade de 30 dias e capacidades do servidor |
| POST | `/api/_action/df-image-optimizer/run-batch` | Lança um lote. Parâmetro POST opcional `batchSize` (predefinição 50, máximo 500) |
| GET | `/api/_action/df-image-optimizer/capabilities` | Deteção do servidor (Imagick / GD / WebP / AVIF) |

**Exemplo com curl:**

```
TOKEN=$(curl -s -X POST https://loja.exemplo.com/api/oauth/token
    -H "Content-Type: application/json"
    -d '{"grant_type":"password","client_id":"administration","scope":"write","username":"admin","password":"shopware"}'
    | jq -r .access_token)

curl -X POST https://loja.exemplo.com/api/_action/df-image-optimizer/run-batch
    -H "Authorization: Bearer $TOKEN"
    -H "Content-Type: application/json"
    -d '{"batchSize":200}'
```

## Tabelas criadas

### `df_image_optimizer`

Uma linha por média otimizado. Chave única em `media_id`: uma nova otimização do mesmo média substitui a linha.

```
id                BINARY(16)   UUID
media_id          BINARY(16)   FK media.id ON DELETE CASCADE, UNIQUE
has_webp          TINYINT(1)
has_avif          TINYINT(1)
compressed        TINYINT(1)
original_size     BIGINT       Peso original em bytes
bytes_saved       BIGINT       Acumulado de poupanças (compressão + delta WebP/AVIF)
sales_channel_id  BINARY(16)   FK sales_channel.id ON DELETE SET NULL
optimized_at      DATETIME(3)
created_at        DATETIME(3)
```

### `df_image_optimizer_log`

Registo opcional dos erros. Só de leitura, para depuração: sem limpeza automática.

## Resolução de problemas

### «O painel mostra AVIF: Indisponível»

O seu servidor não tem a stack AVIF necessária. Opções:

- **Se só tiver GD**: verifique `php -m | grep gd` e `php -i | grep AVIF`. É preciso PHP 8.1+ _e_ GD compilado com `--with-avif`. Em Debian/Ubuntu recentes, vem por predefinição.
- **Se o Imagick estiver disponível**: verifique `php -r "print_r(Imagick::queryFormats('AVIF'));"`. Vazio? O seu Imagick não está compilado com libheif: é necessária recompilação ou passagem para GD.
- **Alternativa aceitável**: deixe o AVIF desativado e concentre-se no WebP. O ganho só com WebP já é enorme face ao JPEG nativo do Shopware.

### «As imagens `.webp` são bem geradas mas o storefront mostra JPEG»

O compilador de tema não teve em conta a sobreposição Twig. Solução:

```
sudo -u www-data setsid php bin/console theme:compile
sudo -u www-data setsid php bin/console cache:clear
```

Verifique depois com as DevTools do navegador (Chrome ou Firefox): abra o separador Rede, recarregue uma página de produto, e veja o tipo MIME das imagens carregadas. Deverá ver `image/avif` ou `image/webp` em vez de `image/jpeg`.

### «O carregamento dos médias ficou lento»

A conversão AVIF em particular é intensiva em CPU: conte 1 a 3 segundos por imagem. Se for incómodo, desative a otimização automática no carregamento (cartão Geral) e deixe apenas a tarefa agendada tratar em segundo plano. Os carregamentos voltam a ser instantâneos e as imagens são otimizadas em 15 minutos no máximo.

### «As miniaturas `.webp` não são geradas»

Verifique que _Tratar as miniaturas_ está marcado no cartão Geral. Regenere depois manualmente as miniaturas para que voltem a passar pelo pipeline:

```
sudo -u www-data setsid php bin/console media:generate-thumbnails
```

### «Como eliminar todos os ficheiros WebP/AVIF gerados?»

A extensão não os elimina automaticamente, nem sequer na desinstalação (para preservar as suas cópias de segurança). Para os limpar manualmente:

```
cd /caminho/para/shopware
find public/media -name "*.webp" -delete
find public/media -name "*.avif" -delete
```

### «Os URLs do CDN não são aplicados em todo o lado»

Verifique o âmbito configurado. Se vir URLs de origem para recursos de tema (`/theme/.../style.css`), é normal com o âmbito predefinido _Apenas médias_. Passe para _Todos os recursos estáticos_ se o seu CDN estiver configurado para servir todos os recursos.

Note também que os URLs reescritos dizem respeito à renderização Twig no servidor. Se o seu frontend chamar a Store API e reconstruir os URLs do lado do JS, terá de aplicar a reescrita do lado do cliente em separado.

## Desinstalação

```
sudo -u www-data setsid php bin/console plugin:uninstall DfImageOptimizer
sudo -u www-data setsid php bin/console plugin:remove DfImageOptimizer
```

Na desinstalação, o Shopware pergunta se quer conservar os dados do utilizador:

- **Conservar** (predefinição): as tabelas `df_image_optimizer` e `df_image_optimizer_log` ficam na base de dados. Reinstalar a extensão retoma o histórico.
- **Não conservar**: as duas tabelas são eliminadas (DROP TABLE).

Nos dois casos, os ficheiros `.webp` e `.avif` no filesystem mantêm-se: use os comandos `find` acima para os limpar se for necessário.

## Para ir mais longe

- Vigie a sua pontuação de Core Web Vitals na Google Search Console: o LCP deve descer nas 2 a 4 semanas seguintes à ativação
- Teste com o PageSpeed Insights antes e depois: ganho típico de 20 a 40 pontos em telemóvel
- Ative também HTTP/2 ou HTTP/3 do lado do servidor para multiplicar o benefício do CDN
- Combine com uma cache de página completa do Shopware para tempos de resposta estáticos
