# Cómo guardar una imagen en PNG o JPEG

> Grabar una Image en disco (archivo con timestamp) o en un OutputStream, en PNG o JPEG.

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

# Cómo guardar una imagen en PNG o JPEG

**Propósito.** Persistir una `Image` en disco. CrossFly ofrece dos niveles: *conveniencia*
(guarda un archivo con nombre por timestamp y devuelve la ruta) y *control total* (tú proporcionas el
`OutputStream`).

### Conveniencia (guarda el archivo automáticamente)
- `String toPng(String... prefix)` — guarda un PNG con nombre `<prefix><timestamp>.png`. En escritorio graba en `Device.homeFolder`; en móvil graba en `/sdcard/`. Devuelve la ruta guardada, o `null` en caso de error (el error se trata internamente vía `Debug.handle`). El `prefix` es **opcional**.
- `String toJpg(int... quality)` — guarda un JPEG con nombre por timestamp. `quality` es **opcional** (por defecto `90`); `100` = sin compresión, `85` = buena compresión, `60` = gran compresión pero con ruido. Devuelve la ruta, o `null` en caso de error.

### Control total (tú proporcionas el stream)
- `void toPng(OutputStream s) throws ImageException, IOException` — graba el PNG en el stream. El PNG es de 24 BPP, o 32 BPP si la imagen tiene canal alfa.
- `void toJpg(OutputStream s, int quality) throws ImageException, IOException` — graba el JPEG en el stream con la calidad dada (0–100). **El stream se cierra** en la llamada.

> Atención a las sobrecargas: `toPng(String...)`/`toJpg(int...)` **guardan un archivo** y se tragan las excepciones
> (devuelven `null`). En cambio `toPng(OutputStream)`/`toJpg(OutputStream,int)` **propagan**
> `ImageException`/`IOException`. Elige según quieras o no tratar el error.

## Ejemplo completo (copiar, pegar y ejecutar)

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

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: 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");   // tu imagen ya cargada o generada

         // 1) Conveniencia: archivo con timestamp; devuelve la ruta
         String pngPath = img.toPng("thumb_");   // ej.: .../thumb_20260706153000.png
         String jpgPath = img.toJpg(85);         // calidad 85
         Debug.log("PNG: " + pngPath + " | JPG: " + jpgPath);

         // 2) Control total: tú decides el destino y manejas errores
         try (OutputStream out = new FileOutputStream("/sdcard/saida.png")) {
            img.toPng(out);                      // el stream lo cierra la llamada; propaga excepciones
         } catch (ImageException | IOException e) {
            // maneja fallo de escritura/codificación
         }
      } catch (ImageException | IOException e) {
         // fallo al cargar la imagen de origen
      }
   }
}
```

> El fragmento de abajo muestra **solo el núcleo**. Para ejecutarlo, colócalo en el esqueleto `MainWindow` de arriba.

## Fragmento mínimo

```java
// verificado en la fuente: Image.java toPng/toJpg — líneas 800, 811, 1454, 1479
import dev.crossfly.ui.image.*;   // Image, ImageException

Image img = /* tu imagen ya cargada o generada */;

// 1) Conveniencia: archivo con timestamp; devuelve la ruta
String pngPath = img.toPng("thumb_");   // ej.: .../thumb_20260706153000.png
String jpgPath = img.toJpg(85);         // calidad 85

// 2) Control total: tú decides el destino y manejas errores
try (java.io.OutputStream out = new java.io.FileOutputStream("/sdcard/saida.png")) {
   img.toPng(out);                      // el stream lo cierra la llamada; propaga excepciones
} catch (ImageException | java.io.IOException e) {
   // maneja fallo de escritura/codificación
}
```

## Profundiza
- Receta hermana: [thumbnail.md](/docs/cookbook/images/thumbnail) — genera el thumbnail y luego guárdalo con esta receta.
- Receta hermana: [screenshot.md](/docs/cookbook/images/screenshot) — captura la pantalla y guárdala con `toPng()`.
