# Cómo tomar una foto y obtener la ruta del archivo

> Capturar una foto con la cámara del dispositivo y recibir la ruta del JPEG guardado.

Source: https://crossfly.dev/es/docs/cookbook/device/tirar-foto — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Cómo tomar una foto y obtener la ruta del archivo

**Propósito.** Abrir la cámara, tomar una foto y recibir la **ruta del archivo JPEG** grabado.
La forma recomendada es usar `Camera` con `cameraType = CameraType.PICKER`, que por debajo abre el
`PhotoPicker` (la UI de captura del propio framework) y devuelve la ruta — o `null` si se cancela.

## APIs usadas
- `Camera` — constructor sin argumentos; campos públicos `cameraType` (`CameraType`), `captureMode` (`Preview`, por defecto `PHOTO`), `videoQuality` (`AVQuality`), `videoTimeLimit`.
- `Camera.shot()` → `String` — toma la foto/video según los campos y devuelve la **ruta del archivo** o `null` (cancelado, error, o macOS ARM). **No existe** el método `click()`.
- `CameraType` (enum) — `DEFAULT` (cámara nativa del SO), `PICKER` (UI de CrossFly vía `PhotoPicker`), `GALLERY` (elegir de la galería).
- `PhotoPicker(Preview type)` — usado internamente por `shot()` cuando `cameraType == PICKER`; expone `getAnswer()` (ruta o cadena de error) e `isError()`. `Camera.shot()` ya convierte el error en `null` por ti.

> **Divergencia/nota de honestidad.** `PhotoPicker` **no** es abstracto y **no** usa el callback
> `onAnswer`: graba el resultado en `getAnswer()` y señaliza el fallo en `isError()`. `Camera.shot()`
> encapsula ese flujo (`show()` → lee `getAnswer()` → `isError() ? null : ret`), así que prefiere `shot()`.
> En iOS, cuando `captureMode != PHOTO`, `shot()` delega directamente a la cámara nativa del SO.

## Ejemplo completo (copiar, pegar y ejecutar)

```java
package com.exemplo;

import dev.crossfly.ui.*;                   // Window, Component, Button, Label, UIConstants
import dev.crossfly.ui.layout.*;            // VerticalLayout
import dev.crossfly.device.*;               // Camera

/** 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());

      Label resultado = new Label("");
      add(LAY_AUTO, resultado);

      Button acao = new Button("Tirar foto");
      acao.onAction(c ->
      {
         // shot() es bloqueante mientras el picker está abierto; ejecuta fuera de la paint thread.
         new Thread(() ->
         {
            Camera cam = new Camera();
            cam.cameraType  = UIConstants.CameraType.PICKER;   // UI de captura de CrossFly
            cam.captureMode = UIConstants.Preview.PHOTO;       // foto (default)

            String path = cam.shot();                          // ruta del JPEG, o null si se canceló/error

            // El retorno llega FUERA de la paint thread → vuelve a la UI con onUI(...)
            Component.onUI(() ->
               resultado.setText(path != null ? "Foto: " + path : "Cancelado ou erro"));
         }).start();
      });
      add(LAY_AUTO, acao);
   }
}
```

> 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: Camera.java shot() (líneas 75-91); PhotoPicker.java (constructor + getAnswer/isError)
import dev.crossfly.device.*;              // Camera
import dev.crossfly.ui.*;                  // Component (onUI), UIConstants.CameraType/Preview

// shot() es bloqueante mientras el picker está abierto; ejecuta fuera de la paint thread.
new Thread(() -> {
   Camera cam = new Camera();
   cam.cameraType  = UIConstants.CameraType.PICKER;   // UI de captura de CrossFly
   cam.captureMode = UIConstants.Preview.PHOTO;       // foto (default)

   String path = cam.shot();                          // ruta del JPEG, o null si se canceló/error

   // El retorno llega FUERA de la paint thread → vuelve a la UI con onUI(...)
   Component.onUI(() -> {
      if (path != null)
         mostrarFoto(path);   // ej.: cargar la Image y mostrarla en un ImageView
      // else: el usuario canceló o hubo un error de cámara
   });
}).start();
```

## Profundiza
- Guía de la cámara: [Cámara del dispositivo](/docs/data-and-services/device-camera) · Widget: [PhotoPicker](/docs/ui/widgets/photopicker)
- Receta hermana: [gravar-video.md](/docs/cookbook/device/gravar-video) · [ler-codigo-de-barras.md](/docs/cookbook/device/ler-codigo-de-barras)
