# How to take a photo and get the file path

> Capture a photo with the device camera and receive the path of the saved JPEG.

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

# How to take a photo and get the file path

**Purpose.** Open the camera, take a photo, and receive the **file path of the recorded JPEG**.
The recommended approach is to use `Camera` with `cameraType = CameraType.PICKER`, which under the hood opens the
`PhotoPicker` (the framework's own capture UI) and returns the path — or `null` if cancelled.

## APIs used
- `Camera` — no-argument constructor; public fields `cameraType` (`CameraType`), `captureMode` (`Preview`, default `PHOTO`), `videoQuality` (`AVQuality`), `videoTimeLimit`.
- `Camera.shot()` → `String` — takes the photo/video according to the fields and returns the **file path** or `null` (cancelled, error, or macOS ARM). There is **no** `click()` method.
- `CameraType` (enum) — `DEFAULT` (OS native camera), `PICKER` (CrossFly UI via `PhotoPicker`), `GALLERY` (pick from the gallery).
- `PhotoPicker(Preview type)` — used internally by `shot()` when `cameraType == PICKER`; exposes `getAnswer()` (path or error string) and `isError()`. `Camera.shot()` already converts an error into `null` for you.

> **Divergence/honesty note.** `PhotoPicker` is **not** abstract and does **not** use an `onAnswer`
> callback: it stores the result in `getAnswer()` and signals failure via `isError()`. `Camera.shot()`
> wraps this flow (`show()` → reads `getAnswer()` → `isError() ? null : ret`), so prefer `shot()`.
> On iOS, when `captureMode != PHOTO`, `shot()` delegates directly to the OS native camera.

## Complete example (copy, paste and run)

```java
package com.exemplo;

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

/** Runnable main screen. Point the launcher (classname) and run: 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() is blocking while the picker is open; run it outside the paint thread.
         new Thread(() ->
         {
            Camera cam = new Camera();
            cam.cameraType  = UIConstants.CameraType.PICKER;   // CrossFly capture UI
            cam.captureMode = UIConstants.Preview.PHOTO;       // photo (default)

            String path = cam.shot();                          // path of the JPEG, or null if cancelled/error

            // The return arrives OUTSIDE the paint thread → return to the UI with onUI(...)
            Component.onUI(() ->
               resultado.setText(path != null ? "Foto: " + path : "Cancelado ou erro"));
         }).start();
      });
      add(LAY_AUTO, acao);
   }
}
```

> The snippet below shows **only the core**. To run it, place it inside the `MainWindow` skeleton above.

## Minimal snippet

```java
// verified at source: Camera.java shot() (lines 75-91); PhotoPicker.java (constructor + getAnswer/isError)
import dev.crossfly.device.*;              // Camera
import dev.crossfly.ui.*;                  // Component (onUI), UIConstants.CameraType/Preview

// shot() is blocking while the picker is open; run it outside the paint thread.
new Thread(() -> {
   Camera cam = new Camera();
   cam.cameraType  = UIConstants.CameraType.PICKER;   // CrossFly capture UI
   cam.captureMode = UIConstants.Preview.PHOTO;       // photo (default)

   String path = cam.shot();                          // path of the JPEG, or null if cancelled/error

   // The return arrives OUTSIDE the paint thread → return to the UI with onUI(...)
   Component.onUI(() -> {
      if (path != null)
         mostrarFoto(path);   // e.g.: load the Image and show it in an ImageView
      // else: user cancelled or there was a camera error
   });
}).start();
```

## Dive deeper
- Camera guide: [Device camera](/docs/data-and-services/device-camera) · Widget: [PhotoPicker](/docs/ui/widgets/photopicker)
- Sibling recipe: [gravar-video.md](/docs/cookbook/device/gravar-video) · [ler-codigo-de-barras.md](/docs/cookbook/device/ler-codigo-de-barras)
