Skip to content
CrossFly is 100% open sourceFollow us on GitHub
CrossFlyCrossFly
Get started

This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.

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)

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

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

Was this page helpful?