tauri-plugin-camera-kessdev 0.1.1-beta.4 → 0.2.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -10
- package/dist-js/index.cjs +77 -11
- package/dist-js/index.d.ts +50 -7
- package/dist-js/index.js +76 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -128,10 +128,10 @@ import {
|
|
|
128
128
|
stopRecording,
|
|
129
129
|
flipCamera,
|
|
130
130
|
setFlash,
|
|
131
|
-
isFlashAvailable,
|
|
132
131
|
setZoom,
|
|
133
132
|
getZoom,
|
|
134
|
-
|
|
133
|
+
getAvailableCameras,
|
|
134
|
+
getCapabilities,
|
|
135
135
|
saveToGallery,
|
|
136
136
|
checkPermissions,
|
|
137
137
|
requestPermissions,
|
|
@@ -233,14 +233,38 @@ await flipCamera()
|
|
|
233
233
|
await setFlash('on') // 'on' | 'off' | 'auto'
|
|
234
234
|
await setZoom(2.0)
|
|
235
235
|
|
|
236
|
-
//
|
|
237
|
-
const zoom = await getZoom()
|
|
238
|
-
const range = await getZoomRange() // { min, max, current }
|
|
239
|
-
const hasFlash = await isFlashAvailable() // boolean (false on desktop)
|
|
236
|
+
// Live state (mobile):
|
|
237
|
+
const zoom = await getZoom() // number
|
|
240
238
|
```
|
|
241
239
|
|
|
242
|
-
On desktop `getZoom()`
|
|
243
|
-
|
|
240
|
+
On desktop `getZoom()` rejects with a descriptive error (consistent with
|
|
241
|
+
`setZoom`).
|
|
242
|
+
|
|
243
|
+
### Camera introspection
|
|
244
|
+
|
|
245
|
+
Use `getAvailableCameras()` to list the cameras (physical/logical lenses) and
|
|
246
|
+
`getCapabilities()` to know what a camera *can* do, before trying:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const cameras = await getAvailableCameras()
|
|
250
|
+
// [{ id: '0', facing: 'back', lens: 'wide' }, { id: '1', facing: 'front' }, ...]
|
|
251
|
+
|
|
252
|
+
// No argument: the active camera, or the default (back) camera without a preview.
|
|
253
|
+
const caps = await getCapabilities(cameras[0].id)
|
|
254
|
+
// { cameraId, hasFlash, hasTorch, zoomRange?, supportsFocus, focusModes?,
|
|
255
|
+
// photoFormats?, supportsPause }
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
The plugin follows one rule to avoid ambiguity:
|
|
259
|
+
|
|
260
|
+
- **What the hardware can do** -> `getCapabilities()` (declarative).
|
|
261
|
+
- **What a value is right now** -> a dedicated live getter (e.g. `getZoom()`).
|
|
262
|
+
|
|
263
|
+
Both work without an active preview on mobile. On desktop `getAvailableCameras()`
|
|
264
|
+
works cold (labels may stay empty until camera permission has been granted once),
|
|
265
|
+
while the hardware capabilities `zoomRange`, `hasTorch` and `focusModes` are
|
|
266
|
+
omitted until a preview/recording stream is active; `hasFlash` is always `false`
|
|
267
|
+
and `supportsPause` is `true`.
|
|
244
268
|
|
|
245
269
|
### Gallery
|
|
246
270
|
|
|
@@ -391,10 +415,10 @@ destination from the generated Xcode project (`src-tauri/gen/apple`).
|
|
|
391
415
|
| `capture(options?)` | ✓ `ImageCapture` / `AVCapturePhotoOutput` | ✓ canvas |
|
|
392
416
|
| `flipCamera()` | ✓ | ✗ (throws) |
|
|
393
417
|
| `setFlash(mode)` | ✓ | ✗ (throws) |
|
|
394
|
-
| `isFlashAvailable()` | ✓ | `false` |
|
|
395
418
|
| `setZoom(factor)` | ✓ | ✗ (throws) |
|
|
396
419
|
| `getZoom()` | ✓ | ✗ (throws) |
|
|
397
|
-
| `
|
|
420
|
+
| `getAvailableCameras()` | ✓ | ✓ |
|
|
421
|
+
| `getCapabilities(cameraId?)` | ✓ | ✓ (partial) |
|
|
398
422
|
| `startRecording(options?)` | ✓ `VideoCapture` / `AVCaptureMovieFileOutput` | ✓ `MediaRecorder` |
|
|
399
423
|
| `stopRecording(options?)` | ✓ | ✓ |
|
|
400
424
|
| `RecordingProgress` telemetry (`onProgress` channel) | ✓ | ✓ |
|
package/dist-js/index.cjs
CHANGED
|
@@ -188,23 +188,89 @@ async function getZoom() {
|
|
|
188
188
|
}
|
|
189
189
|
throw new Error('getZoom is not supported on desktop.');
|
|
190
190
|
}
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// Introspection (available cameras + declarative capabilities)
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
/** Best-effort facing detection from a device label (desktop). */
|
|
195
|
+
function facingFromLabel(label) {
|
|
196
|
+
const value = label.toLowerCase();
|
|
197
|
+
if (value.includes('front') || value.includes('user'))
|
|
198
|
+
return 'front';
|
|
199
|
+
if (value.includes('back') || value.includes('rear') || value.includes('environment'))
|
|
200
|
+
return 'back';
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
/** Enumerates video input devices on desktop via `enumerateDevices()`. */
|
|
204
|
+
async function enumerateDesktopCameras() {
|
|
205
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
206
|
+
return devices
|
|
207
|
+
.filter((device) => device.kind === 'videoinput')
|
|
208
|
+
.map((device) => {
|
|
209
|
+
const info = { id: device.deviceId };
|
|
210
|
+
const facing = facingFromLabel(device.label);
|
|
211
|
+
if (facing)
|
|
212
|
+
info.facing = facing;
|
|
213
|
+
if (device.label)
|
|
214
|
+
info.label = device.label;
|
|
215
|
+
return info;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Declarative capabilities on desktop. Hardware fields (`zoomRange`, `hasTorch`,
|
|
220
|
+
* `focusModes`) are only known while a preview/recording stream is active; they
|
|
221
|
+
* are omitted otherwise.
|
|
222
|
+
*/
|
|
223
|
+
function desktopCapabilities(cameraId) {
|
|
224
|
+
const caps = {
|
|
225
|
+
hasFlash: false,
|
|
226
|
+
hasTorch: false,
|
|
227
|
+
supportsFocus: false,
|
|
228
|
+
supportsPause: true,
|
|
229
|
+
photoFormats: ['jpeg', 'png', 'webp']
|
|
230
|
+
};
|
|
231
|
+
if (cameraId)
|
|
232
|
+
caps.cameraId = cameraId;
|
|
233
|
+
const track = activeStream?.getVideoTracks?.()[0];
|
|
234
|
+
const trackCaps = track?.getCapabilities?.();
|
|
235
|
+
if (trackCaps) {
|
|
236
|
+
if (trackCaps.zoom) {
|
|
237
|
+
caps.zoomRange = { min: trackCaps.zoom.min, max: trackCaps.zoom.max };
|
|
238
|
+
}
|
|
239
|
+
if (typeof trackCaps.torch === 'boolean') {
|
|
240
|
+
caps.hasTorch = trackCaps.torch;
|
|
241
|
+
}
|
|
242
|
+
if (trackCaps.focusMode && trackCaps.focusMode.length > 0) {
|
|
243
|
+
caps.supportsFocus = true;
|
|
244
|
+
caps.focusModes = trackCaps.focusMode;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return caps;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Lists the cameras (physical or logical lenses) available on the device.
|
|
251
|
+
*
|
|
252
|
+
* Works without an active preview on every platform. On desktop the labels may
|
|
253
|
+
* be empty until camera permission has been granted at least once.
|
|
254
|
+
*/
|
|
255
|
+
async function getAvailableCameras() {
|
|
193
256
|
if (isMobile()) {
|
|
194
|
-
return await core.invoke('plugin:camera-kessdev|
|
|
257
|
+
return await core.invoke('plugin:camera-kessdev|get_available_cameras');
|
|
195
258
|
}
|
|
196
|
-
|
|
259
|
+
return enumerateDesktopCameras();
|
|
197
260
|
}
|
|
198
261
|
/**
|
|
199
|
-
* Returns
|
|
262
|
+
* Returns the declarative capabilities of a camera.
|
|
200
263
|
*
|
|
201
|
-
*
|
|
264
|
+
* Without `cameraId` it describes the active camera, or the default (back)
|
|
265
|
+
* camera when no preview is active. On mobile it works without an active
|
|
266
|
+
* preview; on desktop hardware fields are omitted until a stream is active.
|
|
267
|
+
* Live values are exposed by dedicated getters (e.g. {@link getZoom}).
|
|
202
268
|
*/
|
|
203
|
-
async function
|
|
269
|
+
async function getCapabilities(cameraId) {
|
|
204
270
|
if (isMobile()) {
|
|
205
|
-
return await core.invoke('plugin:camera-kessdev|
|
|
271
|
+
return await core.invoke('plugin:camera-kessdev|get_capabilities', { cameraId });
|
|
206
272
|
}
|
|
207
|
-
return
|
|
273
|
+
return desktopCapabilities(cameraId);
|
|
208
274
|
}
|
|
209
275
|
// ---------------------------------------------------------------------------
|
|
210
276
|
// Video recording
|
|
@@ -363,10 +429,10 @@ Object.defineProperty(exports, "convertFileSrc", {
|
|
|
363
429
|
exports.capture = capture;
|
|
364
430
|
exports.checkPermissions = checkPermissions;
|
|
365
431
|
exports.flipCamera = flipCamera;
|
|
432
|
+
exports.getAvailableCameras = getAvailableCameras;
|
|
433
|
+
exports.getCapabilities = getCapabilities;
|
|
366
434
|
exports.getPreviewStream = getPreviewStream;
|
|
367
435
|
exports.getZoom = getZoom;
|
|
368
|
-
exports.getZoomRange = getZoomRange;
|
|
369
|
-
exports.isFlashAvailable = isFlashAvailable;
|
|
370
436
|
exports.openAppSettings = openAppSettings;
|
|
371
437
|
exports.requestPermissions = requestPermissions;
|
|
372
438
|
exports.saveToGallery = saveToGallery;
|
package/dist-js/index.d.ts
CHANGED
|
@@ -37,11 +37,46 @@ export interface Video {
|
|
|
37
37
|
/** Optional base64-encoded thumbnail, when requested via `stopRecording`. */
|
|
38
38
|
thumbnail?: string;
|
|
39
39
|
}
|
|
40
|
-
/** Supported zoom range of the
|
|
40
|
+
/** Supported zoom range of a camera (declarative, without the live value). */
|
|
41
41
|
export interface ZoomRange {
|
|
42
42
|
min: number;
|
|
43
43
|
max: number;
|
|
44
|
-
|
|
44
|
+
}
|
|
45
|
+
/** Orientation of a camera. */
|
|
46
|
+
export type CameraFacing = 'front' | 'back' | 'external';
|
|
47
|
+
/**
|
|
48
|
+
* Best-effort hint of which lens a camera maps to. Platforms that cannot
|
|
49
|
+
* determine it (notably desktop) omit the field.
|
|
50
|
+
*/
|
|
51
|
+
export type CameraLens = 'wide' | 'ultraWide' | 'telephoto' | (string & {});
|
|
52
|
+
/** A camera (physical or logical lens) available on the device. */
|
|
53
|
+
export interface CameraInfo {
|
|
54
|
+
/** Native, session-stable identifier (usable to reference this camera). */
|
|
55
|
+
id: string;
|
|
56
|
+
/** Orientation, when the platform can determine it. */
|
|
57
|
+
facing?: CameraFacing;
|
|
58
|
+
/** Best-effort lens hint, when the platform can determine it. */
|
|
59
|
+
lens?: CameraLens;
|
|
60
|
+
/** Human-readable label, when available. */
|
|
61
|
+
label?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Declarative capabilities of a camera: what the hardware/platform *can* do.
|
|
65
|
+
*
|
|
66
|
+
* Optional fields are omitted when the platform cannot determine them. Live
|
|
67
|
+
* values (e.g. the current zoom factor) are exposed by dedicated getters such
|
|
68
|
+
* as {@link getZoom}, never here.
|
|
69
|
+
*/
|
|
70
|
+
export interface CameraCapabilities {
|
|
71
|
+
/** Identifier of the camera these capabilities describe, when known. */
|
|
72
|
+
cameraId?: string;
|
|
73
|
+
hasFlash: boolean;
|
|
74
|
+
hasTorch: boolean;
|
|
75
|
+
zoomRange?: ZoomRange;
|
|
76
|
+
supportsFocus: boolean;
|
|
77
|
+
focusModes?: string[];
|
|
78
|
+
photoFormats?: string[];
|
|
79
|
+
supportsPause: boolean;
|
|
45
80
|
}
|
|
46
81
|
/**
|
|
47
82
|
* Live telemetry emitted while a video recording is in progress.
|
|
@@ -103,14 +138,22 @@ export declare function setFlash(mode: FlashMode): Promise<void>;
|
|
|
103
138
|
export declare function setZoom(factor: number): Promise<void>;
|
|
104
139
|
/** Gets the current camera zoom factor (mobile). */
|
|
105
140
|
export declare function getZoom(): Promise<number>;
|
|
106
|
-
/** Gets the supported zoom range of the active camera (mobile). */
|
|
107
|
-
export declare function getZoomRange(): Promise<ZoomRange>;
|
|
108
141
|
/**
|
|
109
|
-
*
|
|
142
|
+
* Lists the cameras (physical or logical lenses) available on the device.
|
|
143
|
+
*
|
|
144
|
+
* Works without an active preview on every platform. On desktop the labels may
|
|
145
|
+
* be empty until camera permission has been granted at least once.
|
|
146
|
+
*/
|
|
147
|
+
export declare function getAvailableCameras(): Promise<CameraInfo[]>;
|
|
148
|
+
/**
|
|
149
|
+
* Returns the declarative capabilities of a camera.
|
|
110
150
|
*
|
|
111
|
-
*
|
|
151
|
+
* Without `cameraId` it describes the active camera, or the default (back)
|
|
152
|
+
* camera when no preview is active. On mobile it works without an active
|
|
153
|
+
* preview; on desktop hardware fields are omitted until a stream is active.
|
|
154
|
+
* Live values are exposed by dedicated getters (e.g. {@link getZoom}).
|
|
112
155
|
*/
|
|
113
|
-
export declare function
|
|
156
|
+
export declare function getCapabilities(cameraId?: string): Promise<CameraCapabilities>;
|
|
114
157
|
/** Starts video recording (with audio). */
|
|
115
158
|
export declare function startRecording(options?: StartRecordingOptions): Promise<void>;
|
|
116
159
|
/** Stops video recording and returns the recorded media. */
|
package/dist-js/index.js
CHANGED
|
@@ -187,23 +187,89 @@ async function getZoom() {
|
|
|
187
187
|
}
|
|
188
188
|
throw new Error('getZoom is not supported on desktop.');
|
|
189
189
|
}
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
// Introspection (available cameras + declarative capabilities)
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
/** Best-effort facing detection from a device label (desktop). */
|
|
194
|
+
function facingFromLabel(label) {
|
|
195
|
+
const value = label.toLowerCase();
|
|
196
|
+
if (value.includes('front') || value.includes('user'))
|
|
197
|
+
return 'front';
|
|
198
|
+
if (value.includes('back') || value.includes('rear') || value.includes('environment'))
|
|
199
|
+
return 'back';
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
/** Enumerates video input devices on desktop via `enumerateDevices()`. */
|
|
203
|
+
async function enumerateDesktopCameras() {
|
|
204
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
205
|
+
return devices
|
|
206
|
+
.filter((device) => device.kind === 'videoinput')
|
|
207
|
+
.map((device) => {
|
|
208
|
+
const info = { id: device.deviceId };
|
|
209
|
+
const facing = facingFromLabel(device.label);
|
|
210
|
+
if (facing)
|
|
211
|
+
info.facing = facing;
|
|
212
|
+
if (device.label)
|
|
213
|
+
info.label = device.label;
|
|
214
|
+
return info;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Declarative capabilities on desktop. Hardware fields (`zoomRange`, `hasTorch`,
|
|
219
|
+
* `focusModes`) are only known while a preview/recording stream is active; they
|
|
220
|
+
* are omitted otherwise.
|
|
221
|
+
*/
|
|
222
|
+
function desktopCapabilities(cameraId) {
|
|
223
|
+
const caps = {
|
|
224
|
+
hasFlash: false,
|
|
225
|
+
hasTorch: false,
|
|
226
|
+
supportsFocus: false,
|
|
227
|
+
supportsPause: true,
|
|
228
|
+
photoFormats: ['jpeg', 'png', 'webp']
|
|
229
|
+
};
|
|
230
|
+
if (cameraId)
|
|
231
|
+
caps.cameraId = cameraId;
|
|
232
|
+
const track = activeStream?.getVideoTracks?.()[0];
|
|
233
|
+
const trackCaps = track?.getCapabilities?.();
|
|
234
|
+
if (trackCaps) {
|
|
235
|
+
if (trackCaps.zoom) {
|
|
236
|
+
caps.zoomRange = { min: trackCaps.zoom.min, max: trackCaps.zoom.max };
|
|
237
|
+
}
|
|
238
|
+
if (typeof trackCaps.torch === 'boolean') {
|
|
239
|
+
caps.hasTorch = trackCaps.torch;
|
|
240
|
+
}
|
|
241
|
+
if (trackCaps.focusMode && trackCaps.focusMode.length > 0) {
|
|
242
|
+
caps.supportsFocus = true;
|
|
243
|
+
caps.focusModes = trackCaps.focusMode;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return caps;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Lists the cameras (physical or logical lenses) available on the device.
|
|
250
|
+
*
|
|
251
|
+
* Works without an active preview on every platform. On desktop the labels may
|
|
252
|
+
* be empty until camera permission has been granted at least once.
|
|
253
|
+
*/
|
|
254
|
+
async function getAvailableCameras() {
|
|
192
255
|
if (isMobile()) {
|
|
193
|
-
return await invoke('plugin:camera-kessdev|
|
|
256
|
+
return await invoke('plugin:camera-kessdev|get_available_cameras');
|
|
194
257
|
}
|
|
195
|
-
|
|
258
|
+
return enumerateDesktopCameras();
|
|
196
259
|
}
|
|
197
260
|
/**
|
|
198
|
-
* Returns
|
|
261
|
+
* Returns the declarative capabilities of a camera.
|
|
199
262
|
*
|
|
200
|
-
*
|
|
263
|
+
* Without `cameraId` it describes the active camera, or the default (back)
|
|
264
|
+
* camera when no preview is active. On mobile it works without an active
|
|
265
|
+
* preview; on desktop hardware fields are omitted until a stream is active.
|
|
266
|
+
* Live values are exposed by dedicated getters (e.g. {@link getZoom}).
|
|
201
267
|
*/
|
|
202
|
-
async function
|
|
268
|
+
async function getCapabilities(cameraId) {
|
|
203
269
|
if (isMobile()) {
|
|
204
|
-
return await invoke('plugin:camera-kessdev|
|
|
270
|
+
return await invoke('plugin:camera-kessdev|get_capabilities', { cameraId });
|
|
205
271
|
}
|
|
206
|
-
return
|
|
272
|
+
return desktopCapabilities(cameraId);
|
|
207
273
|
}
|
|
208
274
|
// ---------------------------------------------------------------------------
|
|
209
275
|
// Video recording
|
|
@@ -355,4 +421,4 @@ async function openAppSettings() {
|
|
|
355
421
|
throw new Error('openAppSettings is not supported on desktop.');
|
|
356
422
|
}
|
|
357
423
|
|
|
358
|
-
export { capture, checkPermissions, flipCamera,
|
|
424
|
+
export { capture, checkPermissions, flipCamera, getAvailableCameras, getCapabilities, getPreviewStream, getZoom, openAppSettings, requestPermissions, saveToGallery, setFlash, setZoom, startPreview, startRecording, stopPreview, stopRecording };
|
package/package.json
CHANGED