tauri-plugin-camera-kessdev 0.1.1-beta.3 → 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 CHANGED
@@ -129,6 +129,9 @@ import {
129
129
  flipCamera,
130
130
  setFlash,
131
131
  setZoom,
132
+ getZoom,
133
+ getAvailableCameras,
134
+ getCapabilities,
132
135
  saveToGallery,
133
136
  checkPermissions,
134
137
  requestPermissions,
@@ -168,8 +171,23 @@ await startRecording()
168
171
  // ... user records ...
169
172
  const video = await stopRecording()
170
173
  // video: { path, duration } (mobile) | { duration, blob, url } (desktop)
174
+
175
+ // Optionally request a base64 JPEG thumbnail of the recording:
176
+ const withThumbnail = await stopRecording({ thumbnail: true })
177
+ // withThumbnail.thumbnail: string | undefined
171
178
  ```
172
179
 
180
+ ### Video thumbnail
181
+
182
+ Pass `{ thumbnail: true }` to `stopRecording()` to include a base64-encoded JPEG
183
+ poster frame in the `Video` result. It is opt-in because it costs a frame decode
184
+ and encode. When it cannot be generated the field is omitted (the recording still
185
+ succeeds).
186
+
187
+ - **Android**: extracted with `MediaMetadataRetriever` on the recording executor.
188
+ - **iOS**: extracted with `AVAssetImageGenerator` at ~0.1 s (avoids a black first frame).
189
+ - **Desktop**: captured from the live preview stream at stop time.
190
+
173
191
  ### Recording progress (telemetry)
174
192
 
175
193
  Pass an `onProgress` channel to `startRecording()` to receive live telemetry while
@@ -214,14 +232,51 @@ ends. Telemetry is never emitted after `stopRecording()` resolves.
214
232
  await flipCamera()
215
233
  await setFlash('on') // 'on' | 'off' | 'auto'
216
234
  await setZoom(2.0)
235
+
236
+ // Live state (mobile):
237
+ const zoom = await getZoom() // number
238
+ ```
239
+
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 }
217
256
  ```
218
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`.
268
+
219
269
  ### Gallery
220
270
 
221
271
  ```ts
222
- await saveToGallery(photo.path) // mobile only
272
+ await saveToGallery(photo.path) // image
273
+ await saveToGallery(video.path) // video
274
+ await saveToGallery(media.path, { type: 'video' }) // forced type override
223
275
  ```
224
276
 
277
+ Mobile only. The media type is inferred from the file extension (mp4, mov, m4v,
278
+ webm, 3gp, mkv are treated as video); pass `{ type }` to force it.
279
+
225
280
  ### Permissions
226
281
 
227
282
  ```ts
@@ -361,10 +416,14 @@ destination from the generated Xcode project (`src-tauri/gen/apple`).
361
416
  | `flipCamera()` | ✓ | ✗ (throws) |
362
417
  | `setFlash(mode)` | ✓ | ✗ (throws) |
363
418
  | `setZoom(factor)` | ✓ | ✗ (throws) |
419
+ | `getZoom()` | ✓ | ✗ (throws) |
420
+ | `getAvailableCameras()` | ✓ | ✓ |
421
+ | `getCapabilities(cameraId?)` | ✓ | ✓ (partial) |
364
422
  | `startRecording(options?)` | ✓ `VideoCapture` / `AVCaptureMovieFileOutput` | ✓ `MediaRecorder` |
365
- | `stopRecording()` | ✓ | ✓ |
423
+ | `stopRecording(options?)` | ✓ | ✓ |
366
424
  | `RecordingProgress` telemetry (`onProgress` channel) | ✓ | ✓ |
367
- | `saveToGallery(path)` | ✓ | ✗ (throws) |
425
+ | `Video.thumbnail` (`stopRecording({ thumbnail: true })`) | ✓ | ✓ |
426
+ | `saveToGallery(path, options?)` | ✓ image & video | ✗ (throws) |
368
427
  | `checkPermissions()` | ✓ | ✓ |
369
428
  | `requestPermissions()` | ✓ | ✓ |
370
429
  | `openAppSettings()` | ✓ | ✗ (throws) |
package/dist-js/index.cjs CHANGED
@@ -181,6 +181,97 @@ async function setZoom(factor) {
181
181
  }
182
182
  throw new Error('setZoom is not supported on desktop.');
183
183
  }
184
+ /** Gets the current camera zoom factor (mobile). */
185
+ async function getZoom() {
186
+ if (isMobile()) {
187
+ return await core.invoke('plugin:camera-kessdev|get_zoom');
188
+ }
189
+ throw new Error('getZoom is not supported on desktop.');
190
+ }
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() {
256
+ if (isMobile()) {
257
+ return await core.invoke('plugin:camera-kessdev|get_available_cameras');
258
+ }
259
+ return enumerateDesktopCameras();
260
+ }
261
+ /**
262
+ * Returns the declarative capabilities of a camera.
263
+ *
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}).
268
+ */
269
+ async function getCapabilities(cameraId) {
270
+ if (isMobile()) {
271
+ return await core.invoke('plugin:camera-kessdev|get_capabilities', { cameraId });
272
+ }
273
+ return desktopCapabilities(cameraId);
274
+ }
184
275
  // ---------------------------------------------------------------------------
185
276
  // Video recording
186
277
  // ---------------------------------------------------------------------------
@@ -228,14 +319,15 @@ async function startRecording(options) {
228
319
  }
229
320
  }
230
321
  /** Stops video recording and returns the recorded media. */
231
- async function stopRecording() {
322
+ async function stopRecording(options) {
232
323
  if (isMobile()) {
233
- return await core.invoke('plugin:camera-kessdev|stop_recording');
324
+ return await core.invoke('plugin:camera-kessdev|stop_recording', { ...options });
234
325
  }
235
326
  if (!mediaRecorder) {
236
327
  throw new Error('Recording is not active. Call startRecording() first.');
237
328
  }
238
329
  const duration = (performance.now() - recordingStartedAt) / 1000;
330
+ const thumbnail = options?.thumbnail ? captureDesktopThumbnail() : undefined;
239
331
  stopProgressTimer();
240
332
  return await new Promise((resolve, reject) => {
241
333
  mediaRecorder.onstop = () => {
@@ -245,23 +337,48 @@ async function stopRecording() {
245
337
  recordedChunks = [];
246
338
  recordedBytes = 0;
247
339
  mediaRecorder = null;
248
- resolve({ duration, blob, url });
340
+ const result = { duration, blob, url };
341
+ if (thumbnail)
342
+ result.thumbnail = thumbnail;
343
+ resolve(result);
249
344
  };
250
345
  mediaRecorder.onerror = () => reject(new Error('Video recording failed.'));
251
346
  mediaRecorder.stop();
252
347
  });
253
348
  }
349
+ /** Captures the current desktop preview frame as a base64 JPEG thumbnail. */
350
+ function captureDesktopThumbnail() {
351
+ if (!activeVideo || !activeVideo.videoWidth || !activeVideo.videoHeight) {
352
+ return undefined;
353
+ }
354
+ try {
355
+ const canvas = document.createElement('canvas');
356
+ canvas.width = activeVideo.videoWidth;
357
+ canvas.height = activeVideo.videoHeight;
358
+ const ctx = canvas.getContext('2d');
359
+ if (!ctx)
360
+ return undefined;
361
+ ctx.drawImage(activeVideo, 0, 0, canvas.width, canvas.height);
362
+ return canvas.toDataURL('image/jpeg');
363
+ }
364
+ catch {
365
+ return undefined;
366
+ }
367
+ }
254
368
  // ---------------------------------------------------------------------------
255
369
  // Gallery
256
370
  // ---------------------------------------------------------------------------
257
371
  /**
258
- * Saves a captured image to the device photo gallery (mobile).
372
+ * Saves a captured photo or video to the device gallery (mobile).
373
+ *
374
+ * The media type is inferred from the file extension; pass `options.type` to
375
+ * force it. On desktop this is not supported.
259
376
  *
260
- * @param path Absolute path to the image file.
377
+ * @param path Absolute path to the media file.
261
378
  */
262
- async function saveToGallery(path) {
379
+ async function saveToGallery(path, options) {
263
380
  if (isMobile()) {
264
- await core.invoke('plugin:camera-kessdev|save_to_gallery', { path });
381
+ await core.invoke('plugin:camera-kessdev|save_to_gallery', { path, ...options });
265
382
  return;
266
383
  }
267
384
  throw new Error('saveToGallery is not supported on desktop.');
@@ -312,7 +429,10 @@ Object.defineProperty(exports, "convertFileSrc", {
312
429
  exports.capture = capture;
313
430
  exports.checkPermissions = checkPermissions;
314
431
  exports.flipCamera = flipCamera;
432
+ exports.getAvailableCameras = getAvailableCameras;
433
+ exports.getCapabilities = getCapabilities;
315
434
  exports.getPreviewStream = getPreviewStream;
435
+ exports.getZoom = getZoom;
316
436
  exports.openAppSettings = openAppSettings;
317
437
  exports.requestPermissions = requestPermissions;
318
438
  exports.saveToGallery = saveToGallery;
@@ -34,6 +34,49 @@ export interface Video {
34
34
  blob?: Blob;
35
35
  /** Object URL for the recorded video (desktop). */
36
36
  url?: string;
37
+ /** Optional base64-encoded thumbnail, when requested via `stopRecording`. */
38
+ thumbnail?: string;
39
+ }
40
+ /** Supported zoom range of a camera (declarative, without the live value). */
41
+ export interface ZoomRange {
42
+ min: number;
43
+ max: number;
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;
37
80
  }
38
81
  /**
39
82
  * Live telemetry emitted while a video recording is in progress.
@@ -54,6 +97,14 @@ export interface StartRecordingOptions {
54
97
  /** Receives live recording telemetry while the recording is active. */
55
98
  onProgress?: Channel<RecordingProgress>;
56
99
  }
100
+ export interface StopRecordingOptions {
101
+ /** When true, the result includes a base64-encoded `thumbnail`. */
102
+ thumbnail?: boolean;
103
+ }
104
+ export interface SaveToGalleryOptions {
105
+ /** Force the media type instead of inferring it from the file. */
106
+ type?: 'image' | 'video';
107
+ }
57
108
  /**
58
109
  * Starts the camera preview.
59
110
  *
@@ -85,16 +136,37 @@ export declare function flipCamera(): Promise<void>;
85
136
  export declare function setFlash(mode: FlashMode): Promise<void>;
86
137
  /** Sets the camera zoom factor (mobile). */
87
138
  export declare function setZoom(factor: number): Promise<void>;
139
+ /** Gets the current camera zoom factor (mobile). */
140
+ export declare function getZoom(): Promise<number>;
141
+ /**
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.
150
+ *
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}).
155
+ */
156
+ export declare function getCapabilities(cameraId?: string): Promise<CameraCapabilities>;
88
157
  /** Starts video recording (with audio). */
89
158
  export declare function startRecording(options?: StartRecordingOptions): Promise<void>;
90
159
  /** Stops video recording and returns the recorded media. */
91
- export declare function stopRecording(): Promise<Video>;
160
+ export declare function stopRecording(options?: StopRecordingOptions): Promise<Video>;
92
161
  /**
93
- * Saves a captured image to the device photo gallery (mobile).
162
+ * Saves a captured photo or video to the device gallery (mobile).
163
+ *
164
+ * The media type is inferred from the file extension; pass `options.type` to
165
+ * force it. On desktop this is not supported.
94
166
  *
95
- * @param path Absolute path to the image file.
167
+ * @param path Absolute path to the media file.
96
168
  */
97
- export declare function saveToGallery(path: string): Promise<void>;
169
+ export declare function saveToGallery(path: string, options?: SaveToGalleryOptions): Promise<void>;
98
170
  /** Gets the current camera permission state. */
99
171
  export declare function checkPermissions(): Promise<PermissionState>;
100
172
  /** Requests camera permission. */
package/dist-js/index.js CHANGED
@@ -180,6 +180,97 @@ async function setZoom(factor) {
180
180
  }
181
181
  throw new Error('setZoom is not supported on desktop.');
182
182
  }
183
+ /** Gets the current camera zoom factor (mobile). */
184
+ async function getZoom() {
185
+ if (isMobile()) {
186
+ return await invoke('plugin:camera-kessdev|get_zoom');
187
+ }
188
+ throw new Error('getZoom is not supported on desktop.');
189
+ }
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() {
255
+ if (isMobile()) {
256
+ return await invoke('plugin:camera-kessdev|get_available_cameras');
257
+ }
258
+ return enumerateDesktopCameras();
259
+ }
260
+ /**
261
+ * Returns the declarative capabilities of a camera.
262
+ *
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}).
267
+ */
268
+ async function getCapabilities(cameraId) {
269
+ if (isMobile()) {
270
+ return await invoke('plugin:camera-kessdev|get_capabilities', { cameraId });
271
+ }
272
+ return desktopCapabilities(cameraId);
273
+ }
183
274
  // ---------------------------------------------------------------------------
184
275
  // Video recording
185
276
  // ---------------------------------------------------------------------------
@@ -227,14 +318,15 @@ async function startRecording(options) {
227
318
  }
228
319
  }
229
320
  /** Stops video recording and returns the recorded media. */
230
- async function stopRecording() {
321
+ async function stopRecording(options) {
231
322
  if (isMobile()) {
232
- return await invoke('plugin:camera-kessdev|stop_recording');
323
+ return await invoke('plugin:camera-kessdev|stop_recording', { ...options });
233
324
  }
234
325
  if (!mediaRecorder) {
235
326
  throw new Error('Recording is not active. Call startRecording() first.');
236
327
  }
237
328
  const duration = (performance.now() - recordingStartedAt) / 1000;
329
+ const thumbnail = options?.thumbnail ? captureDesktopThumbnail() : undefined;
238
330
  stopProgressTimer();
239
331
  return await new Promise((resolve, reject) => {
240
332
  mediaRecorder.onstop = () => {
@@ -244,23 +336,48 @@ async function stopRecording() {
244
336
  recordedChunks = [];
245
337
  recordedBytes = 0;
246
338
  mediaRecorder = null;
247
- resolve({ duration, blob, url });
339
+ const result = { duration, blob, url };
340
+ if (thumbnail)
341
+ result.thumbnail = thumbnail;
342
+ resolve(result);
248
343
  };
249
344
  mediaRecorder.onerror = () => reject(new Error('Video recording failed.'));
250
345
  mediaRecorder.stop();
251
346
  });
252
347
  }
348
+ /** Captures the current desktop preview frame as a base64 JPEG thumbnail. */
349
+ function captureDesktopThumbnail() {
350
+ if (!activeVideo || !activeVideo.videoWidth || !activeVideo.videoHeight) {
351
+ return undefined;
352
+ }
353
+ try {
354
+ const canvas = document.createElement('canvas');
355
+ canvas.width = activeVideo.videoWidth;
356
+ canvas.height = activeVideo.videoHeight;
357
+ const ctx = canvas.getContext('2d');
358
+ if (!ctx)
359
+ return undefined;
360
+ ctx.drawImage(activeVideo, 0, 0, canvas.width, canvas.height);
361
+ return canvas.toDataURL('image/jpeg');
362
+ }
363
+ catch {
364
+ return undefined;
365
+ }
366
+ }
253
367
  // ---------------------------------------------------------------------------
254
368
  // Gallery
255
369
  // ---------------------------------------------------------------------------
256
370
  /**
257
- * Saves a captured image to the device photo gallery (mobile).
371
+ * Saves a captured photo or video to the device gallery (mobile).
372
+ *
373
+ * The media type is inferred from the file extension; pass `options.type` to
374
+ * force it. On desktop this is not supported.
258
375
  *
259
- * @param path Absolute path to the image file.
376
+ * @param path Absolute path to the media file.
260
377
  */
261
- async function saveToGallery(path) {
378
+ async function saveToGallery(path, options) {
262
379
  if (isMobile()) {
263
- await invoke('plugin:camera-kessdev|save_to_gallery', { path });
380
+ await invoke('plugin:camera-kessdev|save_to_gallery', { path, ...options });
264
381
  return;
265
382
  }
266
383
  throw new Error('saveToGallery is not supported on desktop.');
@@ -304,4 +421,4 @@ async function openAppSettings() {
304
421
  throw new Error('openAppSettings is not supported on desktop.');
305
422
  }
306
423
 
307
- export { capture, checkPermissions, flipCamera, getPreviewStream, openAppSettings, requestPermissions, saveToGallery, setFlash, setZoom, startPreview, startRecording, stopPreview, stopRecording };
424
+ export { capture, checkPermissions, flipCamera, getAvailableCameras, getCapabilities, getPreviewStream, getZoom, openAppSettings, requestPermissions, saveToGallery, setFlash, setZoom, startPreview, startRecording, stopPreview, stopRecording };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tauri-plugin-camera-kessdev",
3
- "version": "0.1.1-beta.3",
3
+ "version": "0.2.0-beta.0",
4
4
  "author": "kess",
5
5
  "description": "Camera plugin for Tauri v2: photo capture, video recording and preview on Android, iOS and desktop.",
6
6
  "license": "MIT",