Skip to content

Commit 0dd09d1

Browse files
Add camera torch (flashlight) support (#435)
Co-authored-by: Glenn Jocher <glenn.jocher@ultralytics.com>
1 parent 4b77b32 commit 0dd09d1

File tree

8 files changed

+84
-1
lines changed

8 files changed

+84
-1
lines changed

android/src/main/kotlin/com/ultralytics/yolo/YOLOPlatformView.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,15 @@ class YOLOPlatformView(
391391
yoloView.switchCamera()
392392
result.success(null)
393393
}
394+
"setTorchMode" -> {
395+
val enabled = call.argument<Boolean>("enabled")
396+
if (enabled != null) {
397+
yoloView.setTorchMode(enabled)
398+
result.success(null)
399+
} else {
400+
result.error("invalid_args", "enabled is required", null)
401+
}
402+
}
394403
"setZoomLevel" -> {
395404
val zoomLevel = call.argument<Double>("zoomLevel")
396405
if (zoomLevel != null) {
@@ -500,4 +509,4 @@ class YOLOPlatformView(
500509
else -> modelPath
501510
}
502511
}
503-
}
512+
}

android/src/main/kotlin/com/ultralytics/yolo/YOLOView.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,14 @@ class YOLOView @JvmOverloads constructor(
395395
}
396396
}
397397

398+
fun setTorchMode(enabled: Boolean) {
399+
camera?.let { cam ->
400+
if (cam.cameraInfo.hasFlashUnit()) {
401+
cam.cameraControl.enableTorch(enabled)
402+
}
403+
}
404+
}
405+
398406
// endregion
399407

400408
// region Model / Task

doc/api.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,16 @@ Switch between front and back camera.
361361
Future<void> switchCamera()
362362
```
363363

364+
##### `setTorchMode()`
365+
366+
Turn the active camera torch on or off when supported.
367+
368+
```dart
369+
Future<void> setTorchMode(bool enabled)
370+
```
371+
372+
**Parameters**: `enabled` - `true` to enable the torch, `false` to disable it
373+
364374
##### `switchModel()`
365375

366376
Dynamically switch to a different model without restarting the camera.

ios/Classes/SwiftYOLOPlatformView.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,18 @@ public class SwiftYOLOPlatformView: NSObject, FlutterPlatformView, FlutterStream
330330
self.yoloView?.switchCameraTapped()
331331
result(nil) // Success
332332

333+
case "setTorchMode":
334+
if let args = call.arguments as? [String: Any],
335+
let enabled = args["enabled"] as? Bool
336+
{
337+
self.yoloView?.setTorchMode(enabled)
338+
result(nil) // Success
339+
} else {
340+
result(
341+
FlutterError(
342+
code: "invalid_args", message: "Invalid arguments for setTorchMode", details: nil))
343+
}
344+
333345
case "setZoomLevel":
334346
if let args = call.arguments as? [String: Any],
335347
let zoomLevel = args["zoomLevel"] as? Double

ios/Classes/YOLOView.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,25 @@ public class YOLOView: UIView, VideoCaptureDelegate {
12141214
}
12151215
}
12161216

1217+
public func setTorchMode(_ enabled: Bool) {
1218+
guard let device = videoCapture.captureDevice, device.hasTorch else { return }
1219+
1220+
do {
1221+
try device.lockForConfiguration()
1222+
defer {
1223+
device.unlockForConfiguration()
1224+
}
1225+
1226+
if enabled {
1227+
try device.setTorchModeOn(level: AVCaptureDevice.maxAvailableTorchLevel)
1228+
} else {
1229+
device.torchMode = .off
1230+
}
1231+
} catch {
1232+
print("Failed to set torch mode: \(error.localizedDescription)")
1233+
}
1234+
}
1235+
12171236
@objc func playTapped() {
12181237
selection.selectionChanged()
12191238
self.videoCapture.start()

lib/widgets/yolo_controller.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,18 @@ class YOLOViewController {
117117
}
118118
}
119119

120+
Future<void> setTorchMode(bool enabled) async {
121+
if (_methodChannel != null) {
122+
try {
123+
await _methodChannel!.invokeMethod('setTorchMode', {
124+
'enabled': enabled,
125+
});
126+
} catch (e) {
127+
logInfo('Error setting torch mode: $e');
128+
}
129+
}
130+
}
131+
120132
Future<void> zoomIn() async {
121133
if (_methodChannel != null) {
122134
try {

test/utils/test_helpers.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ class YOLOTestHelpers {
5555
return true;
5656
case 'switchCamera':
5757
return true;
58+
case 'setTorchMode':
59+
return true;
5860
case 'zoomIn':
5961
return true;
6062
case 'zoomOut':
@@ -407,6 +409,10 @@ class YOLOTestHelpers {
407409
log.add(call);
408410
return true;
409411
},
412+
'setTorchMode': (call) {
413+
log.add(call);
414+
return true;
415+
},
410416
'zoomIn': (call) {
411417
log.add(call);
412418
return true;

test/yolo_controller_test.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ void main() {
7676
await controller.switchCamera();
7777
YOLOTestHelpers.assertMethodCalled(log, 'switchCamera');
7878

79+
await controller.setTorchMode(true);
80+
YOLOTestHelpers.assertMethodCalled(
81+
log,
82+
'setTorchMode',
83+
arguments: {'enabled': true},
84+
);
85+
7986
await controller.zoomIn();
8087
YOLOTestHelpers.assertMethodCalled(log, 'zoomIn');
8188

0 commit comments

Comments
 (0)