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 novaImage; a original não é modificada.Image resize(int newWidth, int newHeight, ResizeMode mode)— overload que usaResizeQuality.SMOOTH.Image resize(int newWidth, int newHeight)— overload que usaResizeMode.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 exatamentew×h(pode distorcer).FIT— mantém a proporção e cabe inteira dentro dew×h(letter-box; resultado pode ser menor que o alvo).FILL— mantém a proporção e preenchew×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)
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
MainWindowacima.
Trecho mínimo
// 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, oresizeprimeiro escala uniformemente e, no casoFILL, recorta pelo centro viagetArea(...). ComSTRETCHchama diretamente o escalonamento exato.resizelançaImageException(ex.: “Out of memory” em imagens muito grandes) eIllegalArgumentExceptionsenewWidth/newHeight≤ 0.
Não confunda
resize(...)(cria pixels novos) comrenderScaleX/renderScaleYesetRenderScale(...), que apenas escalam no desenho via GPU sem alterar o pixmap.
Aprofunde-se
- Imagens — diferença entre resize destrutivo e render-scale.
- Receita irmã: salvar-imagem.md — grave o thumbnail em disco depois de gerá-lo.