# 相机与条形码

> 用 Camera.shot() 拍摄照片/视频，用 CameraBarcode.readBarcode 读取条码。

Source: https://crossfly.dev/zh/docs/data-and-services/device-camera — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 相机与条形码

## 拍摄一张照片 —— `Camera.shot()`
```java
Camera cam = new Camera();
cam.cameraType = Camera.CameraType.PICKER;      // ⚠️ 无默认值 — 务必设置
cam.captureMode = Camera.Preview.PHOTO;

new Thread(() -> {
   String caminho = cam.shot();                 // 文件路径，取消则为 null
   if (caminho == null) return;
   Component.onUI(() -> {
      try { imageView.image(new Image(caminho)); Component.repaint(); }
      catch (Exception e) { Debug.log("erro: " + e); }
   });
}).start();
```
> ⚠️ **`click()` 不再存在** —— 捕获方法是 **`shot()`**（返回带路径的 `String`，
> 若用户取消则返回 `null`）。

### 配置
| 字段 | 取值 |
|---|---|
| `cameraType` | `DEFAULT`（内部相机） · `PICKER`（PhotoPicker） · `GALLERY`（相册） —— **无默认值** |
| `captureMode` | `Preview.PHOTO` · `MUTED_VIDEO` · `AUDIO_VIDEO` |
| `videoQuality` | `AVQuality.HIGH/MEDIUM/LOW` |
| `resolutionWidth`/`Height`（静态） | 分辨率（始终为 LANDSCAPE 横向） |

## 读取条形码 —— `CameraBarcode.readBarcode(Image)`
从已捕获的**图像**中读取 1D 和 2D（QR）码（通过 ZXing）：
```java
Image img = new Image(caminho);
com.google.zxing.Result r = CameraBarcode.readBarcode(img);   // 未找到编码则为 null
if (r != null) {
   String codigo = r.getText();
   Debug.log("Código: " + codigo);
}
```

## 实际限制
- **`Camera.shot()`** 会打开原生 UI —— 请**在绘制线程之外**调用，并用 `onUI(...)` 返回。
- **`CameraBarcode.readBarcode` 不是线程安全的** —— 不要同时从多个线程调用。
- 返回 `null` 是正常的（取消 / 未找到码）—— 请始终检查。
- 在 Mac ARM 上捕获可能返回 `null`（平台限制）。

## 最佳实践
- **始终**设置 `cameraType`（没有默认值）。
- 处理 `shot()` 和 `readBarcode(...)` 的 `null` 返回。
- 若只想从相册选择，请使用 [PhotoPicker](/docs/ui/widgets/photopicker)。

## 常见错误
- 调用 `click()`（不存在）而非 `shot()`。
- 未设置 `cameraType`。
- 并发调用 `readBarcode`（非线程安全）。

## 另见
- [PhotoPicker](/docs/ui/widgets/photopicker) · [图像](/docs/ui/images-and-graphics/images) · [各平台权限](/docs/platforms)
