# Como gerar um thumbnail (miniatura)

> Redimensionar uma imagem para uma miniatura com resize(), escolhendo modo e qualidade.

Source: https://crossfly.dev/pt/docs/cookbook/images/thumbnail — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Como gerar um thumbnail (miniatura)

**Propósito.** Reduzir uma imagem grande a uma miniatura persistente (uma **nova** `Image` com
pixels realmente reduzidos), em vez de apenas escalar no desenho. Isso economiza memória de textura
e banda de GPU quando você exibe muitas miniaturas.

## APIs usadas
- `Image resize(int newWidth, int newHeight, ResizeMode mode, ResizeQuality quality) throws ImageException` — ponto de entrada principal. Retorna uma **nova** `Image`; a original não é modificada.
- `Image resize(int newWidth, int newHeight, ResizeMode mode)` — overload que usa `ResizeQuality.SMOOTH`.
- `Image resize(int newWidth, int newHeight)` — overload que usa `ResizeMode.STRETCH` + `ResizeQuality.SMOOTH`.
- `Image resizeWidth(int newWidth[, ResizeQuality])` / `Image resizeHeight(int newHeight[, ResizeQuality])` — redimensionam preservando a proporção a partir de uma largura ou altura alvo (ideal para thumbnails).

### Enums (verificados em `UIConstants`)
`ResizeMode { STRETCH, FIT, FILL }`
- `STRETCH` — força exatamente `w`×`h` (pode distorcer).
- `FIT` — mantém a proporção e cabe **inteira** dentro de `w`×`h` (letter-box; resultado pode ser menor que o alvo).
- `FILL` — mantém a proporção e **preenche** `w`×`h`, cortando o excesso pelo centro.

`ResizeQuality { FAST, SMOOTH, HARDWARE }`
- `FAST` — amostragem rápida (nearest); use para caches em tempo real.
- `SMOOTH` — reamostragem de alta qualidade; use para thumbnails que ficam salvos/exibidos.
- `HARDWARE` — mantém os pixels de origem e delega a escala à GPU no desenho (não reduz memória de pixmap).

## Exemplo completo (copiar, colar e rodar)

```java
package com.exemplo;

import java.io.IOException;

import dev.crossfly.ui.*;                     // Window, ImageView, UIConstants.ImageSize
import dev.crossfly.ui.layout.*;             // VerticalLayout, LAY_AUTO
import dev.crossfly.ui.image.*;              // Image, ImageException
import dev.crossfly.ui.UIConstants.ResizeMode;
import dev.crossfly.ui.UIConstants.ResizeQuality;

/** Tela principal executável. Aponte o launcher (classname) e rode: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      try {
         Image original = new Image("/sdcard/foto.jpg");

         // Miniatura 128x128 preenchendo e cortando o excesso, com boa qualidade:
         Image thumb = original.resize(128, 128, ResizeMode.FILL, ResizeQuality.SMOOTH);

         // Alternativa preservando proporção a partir da largura (sem cortar):
         Image thumbW = original.resizeWidth(128, ResizeQuality.SMOOTH);

         add(new ImageView(thumb, UIConstants.ImageSize.ORIGINAL), LAY_AUTO);
         add(new ImageView(thumbW, UIConstants.ImageSize.ORIGINAL), LAY_AUTO);
      } catch (ImageException | IOException e) {
         // arquivo não encontrado ou falha no resize (ex.: "Out of memory")
      }
   }
}
```

> O trecho abaixo mostra **só o miolo**. Para rodar, coloque-o no esqueleto `MainWindow` acima.

## Trecho mínimo

```java
// verificado na fonte: Image.java resize(...) linha 870; enums em UIConstants (795, 806)
import dev.crossfly.ui.image.*;   // Image, ImageException
import dev.crossfly.ui.UIConstants.ResizeMode;
import dev.crossfly.ui.UIConstants.ResizeQuality;

Image original = new Image("/sdcard/foto.jpg");

// Miniatura 128x128 preenchendo e cortando o excesso, com boa qualidade:
Image thumb = original.resize(128, 128, ResizeMode.FILL, ResizeQuality.SMOOTH);

// Alternativa preservando proporção a partir da largura (sem cortar):
Image thumbW = original.resizeWidth(128, ResizeQuality.SMOOTH);
```

> Nota de implementação (fonte): com `ResizeMode.FIT`/`FILL`, o `resize` primeiro escala uniformemente
> e, no caso `FILL`, recorta pelo centro via `getArea(...)`. Com `STRETCH` chama diretamente o
> escalonamento exato. `resize` lança `ImageException` (ex.: "Out of memory" em imagens muito grandes)
> e `IllegalArgumentException` se `newWidth`/`newHeight` ≤ 0.

> Não confunda `resize(...)` (cria pixels novos) com `renderScaleX/renderScaleY` e
> `setRenderScale(...)`, que apenas escalam **no desenho** via GPU sem alterar o pixmap.

## Aprofunde-se
- [Imagens](/docs/ui/images-and-graphics/images) — diferença entre resize destrutivo e render-scale.
- Receita irmã: [salvar-imagem.md](/docs/cookbook/images/salvar-imagem) — grave o thumbnail em disco depois de gerá-lo.
