ilabs-flir 2.3.0 → 2.3.1
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/android/Flir/src/main/java/flir/android/FlirManager.kt +48 -2
- package/android/Flir/src/main/java/flir/android/FlirModule.kt +22 -0
- package/android/Flir/src/main/java/flir/android/FlirSdkManager.java +50 -7
- package/ios/Flir/src/FlirManager.swift +39 -2
- package/ios/Flir/src/FlirModule.m +28 -0
- package/package.json +1 -1
|
@@ -71,7 +71,19 @@ object FlirManager {
|
|
|
71
71
|
fun isPreferSdkRotation(): Boolean = false
|
|
72
72
|
fun getBatteryLevel(): Int = -1
|
|
73
73
|
fun isBatteryCharging(): Boolean = false
|
|
74
|
-
fun setPalette(name: String) {
|
|
74
|
+
fun setPalette(name: String) {
|
|
75
|
+
sdkManager?.setPalette(name)
|
|
76
|
+
// Also try to update the app's global Var.cool if possible
|
|
77
|
+
try {
|
|
78
|
+
val palettes = listOf("iron", "rainbow", "grayscale", "arctic", "lava", "contrast", "hotcold", "medical")
|
|
79
|
+
val idx = palettes.indexOf(name.lowercase())
|
|
80
|
+
if (idx != -1) {
|
|
81
|
+
// If we found the index, we use the raw value.
|
|
82
|
+
// But if the name itself is passed as a number or from a loop, handle it.
|
|
83
|
+
updateAcol(idx.toFloat())
|
|
84
|
+
}
|
|
85
|
+
} catch (e: Exception) {}
|
|
86
|
+
}
|
|
75
87
|
fun getAvailablePalettes(): List<String> = emptyList()
|
|
76
88
|
|
|
77
89
|
/**
|
|
@@ -227,6 +239,13 @@ object FlirManager {
|
|
|
227
239
|
}
|
|
228
240
|
|
|
229
241
|
/**
|
|
242
|
+
* Capture a high-fidelity radiometric snapshot (saves thermal data)
|
|
243
|
+
*/
|
|
244
|
+
fun captureRadiometricSnapshot(path: String) {
|
|
245
|
+
sdkManager?.captureRadiometricSnapshot(path)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
230
249
|
* Get latest frame as file path (for RN)
|
|
231
250
|
*/
|
|
232
251
|
fun getLatestFramePath(): String? {
|
|
@@ -401,6 +420,33 @@ object FlirManager {
|
|
|
401
420
|
fun enableEmulatorMode() = startDiscovery()
|
|
402
421
|
fun forceEmulatorMode(type: String = "FLIR_ONE_EDGE") { startDiscovery() }
|
|
403
422
|
fun setPreferredEmulatorType(type: String) { }
|
|
404
|
-
fun updateAcol(value: Float) {
|
|
423
|
+
fun updateAcol(value: Float) {
|
|
424
|
+
Log.d(TAG, "updateAcol: $value")
|
|
425
|
+
// Use reflection to update ilabs.libs.io.data.Var.cool to avoid circular dependency
|
|
426
|
+
try {
|
|
427
|
+
val varClass = Class.forName("ilabs.libs.io.data.Var")
|
|
428
|
+
val coolField = varClass.getField("cool")
|
|
429
|
+
|
|
430
|
+
// Modular logic for palettes: if index > 7, wrap around (17 mod 8)
|
|
431
|
+
// But we keep shader variants (14, 15, 16) as-is if within that range
|
|
432
|
+
val rawIdx = value.toInt()
|
|
433
|
+
var shaderIdx = rawIdx
|
|
434
|
+
if (shaderIdx > 16) {
|
|
435
|
+
shaderIdx = shaderIdx % 16 // Shader loop
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
coolField.set(null, shaderIdx)
|
|
439
|
+
Log.d(TAG, "Updated Var.cool to $shaderIdx via reflection (raw=$rawIdx)")
|
|
440
|
+
|
|
441
|
+
// If we are in FLIR mode, also notify the SDK palette with modular loop
|
|
442
|
+
val palettes = listOf("iron", "rainbow", "grayscale", "arctic", "lava", "contrast", "hotcold", "medical")
|
|
443
|
+
val paletteIdx = rawIdx % palettes.size
|
|
444
|
+
val safeIdx = if (paletteIdx < 0) paletteIdx + palettes.size else paletteIdx
|
|
445
|
+
sdkManager?.setPalette(palettes[safeIdx])
|
|
446
|
+
|
|
447
|
+
} catch (e: Exception) {
|
|
448
|
+
Log.w(TAG, "Could not update Var.cool via reflection: ${e.message}")
|
|
449
|
+
}
|
|
450
|
+
}
|
|
405
451
|
fun destroy() { stop() }
|
|
406
452
|
}
|
|
@@ -256,6 +256,28 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
|
|
|
256
256
|
promise?.reject("ERR_FLIR_STOP", e)
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
|
+
|
|
260
|
+
@ReactMethod
|
|
261
|
+
fun updateAcol(value: Float, promise: Promise?) {
|
|
262
|
+
try {
|
|
263
|
+
FlirManager.updateAcol(value)
|
|
264
|
+
promise?.resolve(true)
|
|
265
|
+
} catch (e: Exception) {
|
|
266
|
+
promise?.reject("ERR_FLIR_ACOL", e)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
@ReactMethod
|
|
271
|
+
fun setPalette(name: String?, promise: Promise?) {
|
|
272
|
+
try {
|
|
273
|
+
if (name != null) {
|
|
274
|
+
FlirManager.setPalette(name)
|
|
275
|
+
}
|
|
276
|
+
promise?.resolve(true)
|
|
277
|
+
} catch (e: Exception) {
|
|
278
|
+
promise?.reject("ERR_FLIR_PALETTE", e)
|
|
279
|
+
}
|
|
280
|
+
}
|
|
259
281
|
|
|
260
282
|
@ReactMethod
|
|
261
283
|
fun initializeSDK(promise: Promise?) {
|
|
@@ -8,7 +8,10 @@ import android.util.Log;
|
|
|
8
8
|
import com.flir.thermalsdk.ErrorCode;
|
|
9
9
|
import com.flir.thermalsdk.androidsdk.ThermalSdkAndroid;
|
|
10
10
|
import com.flir.thermalsdk.androidsdk.image.BitmapAndroid;
|
|
11
|
+
import com.flir.thermalsdk.image.Palette;
|
|
12
|
+
import com.flir.thermalsdk.image.PaletteManager;
|
|
11
13
|
import com.flir.thermalsdk.image.Point;
|
|
14
|
+
import com.flir.thermalsdk.image.ThermalImage;
|
|
12
15
|
import com.flir.thermalsdk.image.ThermalValue;
|
|
13
16
|
import com.flir.thermalsdk.live.AuthenticationResponse;
|
|
14
17
|
import com.flir.thermalsdk.live.Camera;
|
|
@@ -48,8 +51,10 @@ public class FlirSdkManager {
|
|
|
48
51
|
private Stream activeStream;
|
|
49
52
|
private final List<Identity> discoveredDevices = Collections.synchronizedList(new ArrayList<>());
|
|
50
53
|
private volatile Bitmap latestBitmap;
|
|
54
|
+
private volatile String currentPaletteName = "iron";
|
|
51
55
|
private final AtomicBoolean isProcessingFrame = new AtomicBoolean(false);
|
|
52
56
|
private boolean useHalfScale = false;
|
|
57
|
+
private String pendingSnapshotPath = null;
|
|
53
58
|
|
|
54
59
|
// Listener
|
|
55
60
|
private Listener listener;
|
|
@@ -337,14 +342,42 @@ public class FlirSdkManager {
|
|
|
337
342
|
if (streamer != null && activeStream != null) {
|
|
338
343
|
streamer.update();
|
|
339
344
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
345
|
+
final String paletteToApply = currentPaletteName;
|
|
346
|
+
final String snapshotPath = pendingSnapshotPath;
|
|
347
|
+
pendingSnapshotPath = null;
|
|
348
|
+
|
|
349
|
+
streamer.withThermalImage(thermalImage -> {
|
|
350
|
+
// 1. Apply Palette
|
|
351
|
+
if (paletteToApply != null) {
|
|
352
|
+
Palette palette =
|
|
353
|
+
PaletteManager.getDefaultPalettes().stream()
|
|
354
|
+
.filter(p -> p.name.equalsIgnoreCase(paletteToApply))
|
|
355
|
+
.findFirst()
|
|
356
|
+
.orElse(null);
|
|
357
|
+
if (palette != null) {
|
|
358
|
+
thermalImage.setPalette(palette);
|
|
359
|
+
}
|
|
346
360
|
}
|
|
347
|
-
|
|
361
|
+
|
|
362
|
+
// 2. Save Radiometric Snapshot if requested
|
|
363
|
+
if (snapshotPath != null) {
|
|
364
|
+
try {
|
|
365
|
+
thermalImage.saveAs(snapshotPath);
|
|
366
|
+
Log.i(TAG, "Radiometric snapshot saved to: " + snapshotPath);
|
|
367
|
+
} catch (java.io.IOException e) {
|
|
368
|
+
Log.e(TAG, "Failed to save radiometric snapshot", e);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// 3. Generate Bitmap for display
|
|
373
|
+
Bitmap bitmap = BitmapAndroid.createBitmap(thermalImage.getImage()).getBitMap();
|
|
374
|
+
if (bitmap != null) {
|
|
375
|
+
latestBitmap = bitmap;
|
|
376
|
+
if (listener != null) {
|
|
377
|
+
listener.onFrame(bitmap);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
});
|
|
348
381
|
}
|
|
349
382
|
} catch (Exception e) {
|
|
350
383
|
Log.e(TAG, "Frame processing error", e);
|
|
@@ -423,6 +456,16 @@ public class FlirSdkManager {
|
|
|
423
456
|
}
|
|
424
457
|
|
|
425
458
|
// ==================== LISTENERS ====================
|
|
459
|
+
|
|
460
|
+
public void setPalette(String paletteName) {
|
|
461
|
+
this.currentPaletteName = paletteName;
|
|
462
|
+
Log.d(TAG, "Requested palette: " + paletteName);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
public void captureRadiometricSnapshot(String path) {
|
|
466
|
+
this.pendingSnapshotPath = path;
|
|
467
|
+
Log.d(TAG, "Pending radiometric snapshot: " + path);
|
|
468
|
+
}
|
|
426
469
|
|
|
427
470
|
private final DiscoveryEventListener discoveryListener = new DiscoveryEventListener() {
|
|
428
471
|
@Override
|
|
@@ -66,6 +66,10 @@ import ThermalSDK
|
|
|
66
66
|
// Internal synchronization
|
|
67
67
|
private let stateLock = NSObject()
|
|
68
68
|
|
|
69
|
+
// Palette and Snapshot state
|
|
70
|
+
private var currentPaletteName: String = "iron"
|
|
71
|
+
private var pendingSnapshotPath: String?
|
|
72
|
+
|
|
69
73
|
// Dedicated render queue for frame processing (matches sample app pattern)
|
|
70
74
|
private let renderQueue = DispatchQueue(label: "com.flir.render")
|
|
71
75
|
|
|
@@ -506,11 +510,22 @@ import ThermalSDK
|
|
|
506
510
|
}
|
|
507
511
|
|
|
508
512
|
@objc public func setPalette(_ name: String) {
|
|
509
|
-
|
|
513
|
+
self.currentPaletteName = name
|
|
514
|
+
NSLog("[FlirManager] Requested palette: \(name)")
|
|
510
515
|
}
|
|
511
516
|
|
|
512
517
|
@objc public func setPaletteFromAcol(_ acol: Float) {
|
|
513
|
-
//
|
|
518
|
+
// Map acol (0..7) to palette names
|
|
519
|
+
let palettes = ["iron", "rainbow", "grayscale", "arctic", "lava", "contrast", "hotcold", "medical"]
|
|
520
|
+
let idx = Int(acol)
|
|
521
|
+
if idx >= 0 && idx < palettes.count {
|
|
522
|
+
setPalette(palettes[idx])
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
@objc public func captureRadiometricSnapshot(_ path: String) {
|
|
527
|
+
self.pendingSnapshotPath = path
|
|
528
|
+
NSLog("[FlirManager] Pending radiometric snapshot: \(path)")
|
|
514
529
|
}
|
|
515
530
|
|
|
516
531
|
@objc public func retainClient(_ clientId: String) {
|
|
@@ -684,8 +699,30 @@ extension FlirManager: FLIRStreamDelegate {
|
|
|
684
699
|
return
|
|
685
700
|
}
|
|
686
701
|
|
|
702
|
+
let paletteToApply = self.currentPaletteName
|
|
703
|
+
let snapshotPath = self.pendingSnapshotPath
|
|
704
|
+
self.pendingSnapshotPath = nil
|
|
705
|
+
|
|
687
706
|
do {
|
|
688
707
|
try streamer.update()
|
|
708
|
+
|
|
709
|
+
streamer.withThermalImage { thermalImage in
|
|
710
|
+
// 1. Apply Palette
|
|
711
|
+
if let palette = thermalImage.paletteManager.getDefaultPalettes().first(where: { $0.name.lowercased() == paletteToApply.lowercased() }) {
|
|
712
|
+
thermalImage.palette = palette
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// 2. Save Radiometric Snapshot if requested
|
|
716
|
+
if let path = snapshotPath {
|
|
717
|
+
do {
|
|
718
|
+
try thermalImage.save(to: path)
|
|
719
|
+
NSLog("[FlirManager] Radiometric snapshot saved to: \(path)")
|
|
720
|
+
} catch {
|
|
721
|
+
NSLog("[FlirManager] Failed to save radiometric snapshot: \(error)")
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
689
726
|
NSLog("[FLIR-TRACE 3️⃣] Streamer updated successfully")
|
|
690
727
|
} catch {
|
|
691
728
|
NSLog("[FLIR-TRACE ❌] Streamer update failed: \(error)")
|
|
@@ -479,6 +479,34 @@ RCT_EXPORT_METHOD(setPreferSdkRotation : (BOOL)prefer resolver : (
|
|
|
479
479
|
});
|
|
480
480
|
}
|
|
481
481
|
|
|
482
|
+
RCT_EXPORT_METHOD(setPalette : (NSString *)name resolver : (RCTPromiseResolveBlock)
|
|
483
|
+
resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
484
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
485
|
+
id manager = flir_manager_shared();
|
|
486
|
+
if (manager &&
|
|
487
|
+
[manager respondsToSelector:sel_registerName("setPalette:")]) {
|
|
488
|
+
((void (*)(id, SEL, id))objc_msgSend)(manager,
|
|
489
|
+
sel_registerName("setPalette:"),
|
|
490
|
+
name);
|
|
491
|
+
}
|
|
492
|
+
if (resolve) resolve(@(YES));
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
RCT_EXPORT_METHOD(captureRadiometricSnapshot : (NSString *)path resolver : (RCTPromiseResolveBlock)
|
|
497
|
+
resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
498
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
499
|
+
id manager = flir_manager_shared();
|
|
500
|
+
if (manager &&
|
|
501
|
+
[manager respondsToSelector:sel_registerName("captureRadiometricSnapshot:")]) {
|
|
502
|
+
((void (*)(id, SEL, id))objc_msgSend)(manager,
|
|
503
|
+
sel_registerName("captureRadiometricSnapshot:"),
|
|
504
|
+
path);
|
|
505
|
+
}
|
|
506
|
+
if (resolve) resolve(@(YES));
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
|
|
482
510
|
RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
|
|
483
511
|
resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
484
512
|
dispatch_async(dispatch_get_main_queue(), ^{
|