# 如何把图像保存为 PNG 或 JPEG

> 把 Image 写入磁盘（带时间戳的文件）或写入 OutputStream，以 PNG 或 JPEG 格式。

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

# 如何把图像保存为 PNG 或 JPEG

**目的。** 把一张 `Image` 持久化到磁盘。CrossFly 提供两个层次：*便捷*
（保存一个以时间戳命名的文件并返回路径）和*完全控制*（由你提供
`OutputStream`）。

### 便捷（自动保存文件）
- `String toPng(String... prefix)` — 保存一个名为 `<prefix><timestamp>.png` 的 PNG。在桌面端写入 `Device.homeFolder`；在移动端写入 `/sdcard/`。返回保存的路径，或在出错时返回 `null`（错误在内部通过 `Debug.handle` 处理）。`prefix` 是**可选的**。
- `String toJpg(int... quality)` — 保存一个以时间戳命名的 JPEG。`quality` 是**可选的**（默认 `90`）；`100` = 无压缩，`85` = 良好压缩，`60` = 大幅压缩但有噪点。返回路径，或在出错时返回 `null`。

### 完全控制（由你提供流）
- `void toPng(OutputStream s) throws ImageException, IOException` — 把 PNG 写入流。PNG 为 24 BPP，若图像带 alpha 通道则为 32 BPP。
- `void toJpg(OutputStream s, int quality) throws ImageException, IOException` — 以给定质量（0–100）把 JPEG 写入流。**该流会被调用关闭**。

> 注意重载：`toPng(String...)`/`toJpg(int...)` 会**保存一个文件**并吞掉异常
> （返回 `null`）。而 `toPng(OutputStream)`/`toJpg(OutputStream,int)` 会**传播**
> `ImageException`/`IOException`。根据你是否想处理错误来选择。

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

```java
package com.exemplo;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import dev.crossfly.ui.*;                     // Window
import dev.crossfly.ui.layout.*;             // VerticalLayout
import dev.crossfly.ui.image.*;              // Image, ImageException
import dev.crossfly.util.*;                  // Debug

/** 可执行的主界面。将 launcher 指向此类（classname）并运行：gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      try {
         Image img = new Image("/sdcard/foto.jpg");   // 你已加载或生成的图像

         // 1) 便捷方式：带时间戳的文件；返回路径
         String pngPath = img.toPng("thumb_");   // 例如：.../thumb_20260706153000.png
         String jpgPath = img.toJpg(85);         // 质量 85
         Debug.log("PNG: " + pngPath + " | JPG: " + jpgPath);

         // 2) 完全控制：由你决定目标并处理错误
         try (OutputStream out = new FileOutputStream("/sdcard/saida.png")) {
            img.toPng(out);                      // stream 由该调用关闭；异常会向上传播
         } catch (ImageException | IOException e) {
            // 处理写入/编码失败
         }
      } catch (ImageException | IOException e) {
         // 加载源图像失败
      }
   }
}
```

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

## 最小片段

```java
// 已在源码核实：Image.java toPng/toJpg — 800、811、1454、1479 行
import dev.crossfly.ui.image.*;   // Image, ImageException

Image img = /* 你已加载或生成的图像 */;

// 1) 便捷方式：带时间戳的文件；返回路径
String pngPath = img.toPng("thumb_");   // 例如：.../thumb_20260706153000.png
String jpgPath = img.toJpg(85);         // 质量 85

// 2) 完全控制：由你决定目标并处理错误
try (java.io.OutputStream out = new java.io.FileOutputStream("/sdcard/saida.png")) {
   img.toPng(out);                      // stream 由该调用关闭；异常会向上传播
} catch (ImageException | java.io.IOException e) {
   // 处理写入/编码失败
}
```

## 深入了解
- 姊妹配方：[thumbnail.md](/docs/cookbook/images/thumbnail) — 生成缩略图后用本配方保存它。
- 姊妹配方：[screenshot.md](/docs/cookbook/images/screenshot) — 捕获屏幕并用 `toPng()` 保存。
