# 如何生成缩略图（thumbnail）

> 使用 resize() 把图像调整为缩略图，可选择模式和质量。

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

# 如何生成缩略图（thumbnail）

**目的。** 把一张大图缩减为持久化的缩略图（一张像素真正被缩小的**新** `Image`），
而不仅仅是在绘制时缩放。当你显示大量缩略图时，这能节省纹理内存
和 GPU 带宽。

## 使用的 API
- `Image resize(int newWidth, int newHeight, ResizeMode mode, ResizeQuality quality) throws ImageException` — 主入口。返回一张**新** `Image`；原图不被修改。
- `Image resize(int newWidth, int newHeight, ResizeMode mode)` — 使用 `ResizeQuality.SMOOTH` 的重载。
- `Image resize(int newWidth, int newHeight)` — 使用 `ResizeMode.STRETCH` + `ResizeQuality.SMOOTH` 的重载。
- `Image resizeWidth(int newWidth[, ResizeQuality])` / `Image resizeHeight(int newHeight[, ResizeQuality])` — 从目标宽度或高度出发、保持比例地调整尺寸（非常适合缩略图）。

### 枚举（已在 `UIConstants` 中验证）
`ResizeMode { STRETCH, FIT, FILL }`
- `STRETCH` — 精确强制 `w`×`h`（可能变形）。
- `FIT` — 保持比例并把**整幅**装入 `w`×`h`（letter-box；结果可能小于目标）。
- `FILL` — 保持比例并**填充** `w`×`h`，从中心裁掉多余部分。

`ResizeQuality { FAST, SMOOTH, HARDWARE }`
- `FAST` — 快速采样（nearest）；用于实时缓存。
- `SMOOTH` — 高质量重采样；用于会保存/显示的缩略图。
- `HARDWARE` — 保留源像素并在绘制时把缩放委托给 GPU（不减少 pixmap 内存）。

## 完整示例（复制、粘贴并运行）

```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;

/** 可执行的主界面。将 launcher 指向此类（classname）并运行：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");

         // 128x128 缩略图，填充并裁掉多余部分，画质良好：
         Image thumb = original.resize(128, 128, ResizeMode.FILL, ResizeQuality.SMOOTH);

         // 另一种方式：从宽度出发保持比例（不裁剪）：
         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) {
         // 文件未找到或 resize 失败（例如 "Out of memory"）
      }
   }
}
```

> 下面的片段仅展示**核心部分**。要运行它，请把它放入上面的 `MainWindow` 骨架中。

## 最小片段

```java
// 已在源码核实：Image.java resize(...) 870 行；枚举在 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");

// 128x128 缩略图，填充并裁掉多余部分，画质良好：
Image thumb = original.resize(128, 128, ResizeMode.FILL, ResizeQuality.SMOOTH);

// 另一种方式：从宽度出发保持比例（不裁剪）：
Image thumbW = original.resizeWidth(128, ResizeQuality.SMOOTH);
```

> 实现说明（源码）：使用 `ResizeMode.FIT`/`FILL` 时，`resize` 会先均匀缩放，
> 在 `FILL` 情况下再通过 `getArea(...)` 从中心裁切。使用 `STRETCH` 时直接调用
> 精确缩放。`resize` 会抛出 `ImageException`（例如超大图像上的 "Out of memory"），
> 并在 `newWidth`/`newHeight` ≤ 0 时抛出 `IllegalArgumentException`。

> 不要把 `resize(...)`（创建新像素）与 `renderScaleX/renderScaleY` 和
> `setRenderScale(...)` 混淆，后者只是通过 GPU **在绘制时**缩放而不改变 pixmap。

## 深入了解
- [图像](/docs/ui/images-and-graphics/images) — 破坏性 resize 与 render-scale 的区别。
- 姊妹配方：[salvar-imagem.md](/docs/cookbook/images/salvar-imagem) — 生成缩略图后把它保存到磁盘。
