ilabs-flir 2.3.6 → 2.3.8

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.
@@ -30,6 +30,13 @@ object FlirManager {
30
30
  private val lastEmitMs = AtomicLong(0)
31
31
  private val minEmitIntervalMs = 100L // ~10 fps max for RN events
32
32
 
33
+ // Cached palette list to avoid repeated JNI calls (especially if linkage is unstable)
34
+ private var cachedPalettes: List<*>? = null
35
+ private var cachedPaletteNames: List<String>? = null
36
+
37
+ // Cached reflection for performance
38
+ private var coolField: java.lang.reflect.Field? = null
39
+
33
40
  // State
34
41
  private var isInitialized = false
35
42
  private var isScanning = false
@@ -118,15 +125,6 @@ object FlirManager {
118
125
 
119
126
  isInitialized = true
120
127
  Log.i(TAG, "FlirManager initialized")
121
-
122
- // Generate palette icons on background thread
123
- Thread {
124
- try {
125
- generatePaletteIcons(context)
126
- } catch (e: Exception) {
127
- Log.e(TAG, "Initial palette icon generation failed", e)
128
- }
129
- }.start()
130
128
  }
131
129
 
132
130
  /**
@@ -446,60 +444,32 @@ object FlirManager {
446
444
  fun forceEmulatorMode(type: String = "FLIR_ONE_EDGE") { startDiscovery() }
447
445
  fun setPreferredEmulatorType(type: String) { }
448
446
  fun updateAcol(value: Float) {
449
- Log.d(TAG, "updateAcol: $value")
450
- // Use reflection to update ilabs.libs.io.data.Var.cool to avoid circular dependency
447
+ // Log.v(TAG, "updateAcol: $value")
451
448
  try {
452
- val varClass = Class.forName("ilabs.libs.io.data.Var")
453
- val coolField = varClass.getField("cool")
449
+ if (coolField == null) {
450
+ val varClass = Class.forName("ilabs.libs.io.data.Var")
451
+ coolField = varClass.getField("cool")
452
+ }
454
453
 
455
- // Modular logic for palettes: if index > 7, wrap around (17 mod 8)
456
- // But we keep shader variants (14, 15, 16) as-is if within that range
457
454
  val rawIdx = value.toInt()
458
455
  var shaderIdx = rawIdx
459
456
  if (shaderIdx > 16) {
460
457
  shaderIdx = shaderIdx % 16 // Shader loop
461
458
  }
462
459
 
463
- coolField.set(null, shaderIdx)
464
- Log.d(TAG, "Updated Var.cool to $shaderIdx via reflection (raw=$rawIdx)")
465
-
466
- // If we are in FLIR mode, also notify the SDK palette using the official SDK palette list
467
- var sdkPalettes: List<*>? = null
468
- try {
469
- sdkPalettes = PaletteManager.getDefaultPalettes()
470
- } catch (t: Throwable) {
471
- try {
472
- val altClazz = Class.forName("com.flir.thermalsdk.image.palettes.PaletteManager")
473
- val method = altClazz.getMethod("getDefaultPalettes")
474
- sdkPalettes = method.invoke(null) as? List<*>
475
- } catch (t2: Throwable) {
476
- Log.w(TAG, "Palette discovery failed in updateAcol", t2)
477
- }
478
- }
460
+ coolField?.set(null, shaderIdx)
479
461
 
480
- val currentPalettes = sdkPalettes
481
- if (currentPalettes != null && currentPalettes.isNotEmpty()) {
482
- val paletteNames = currentPalettes.map { p ->
483
- try {
484
- p?.let { it::class.java.getMethod("getName").invoke(it) as? String } ?: p?.toString() ?: ""
485
- } catch (e: Exception) {
486
- p?.toString() ?: ""
487
- }
488
- }
489
- Log.d(TAG, "True FLIR Palettes: $paletteNames")
490
-
491
- val maxEff = currentPalettes.size
492
- val paletteIdx = rawIdx % maxEff
493
- val safeIdx = if (paletteIdx < 0) paletteIdx + maxEff else paletteIdx
494
-
495
- val targetPaletteName = paletteNames[safeIdx]
496
- Log.d(TAG, "Applying true FLIR palette: $targetPaletteName (index: $safeIdx, max: $maxEff)")
497
-
498
- sdkManager?.setPalette(targetPaletteName)
499
- }
462
+ // Standard FLIR palette list
463
+ val paletteNames = listOf("Gray", "Iron", "Rainbow", "Arctic", "Lava", "Coldest", "Hottest", "Wheel")
464
+ val maxEff = paletteNames.size
465
+ val paletteIdx = rawIdx % maxEff
466
+ val safeIdx = if (paletteIdx < 0) paletteIdx + maxEff else paletteIdx
467
+
468
+ val targetPaletteName = paletteNames[safeIdx]
469
+ sdkManager?.setPalette(targetPaletteName)
500
470
 
501
471
  } catch (e: Throwable) {
502
- Log.w(TAG, "Could not update Var.cool via reflection: ${e.message}")
472
+ Log.w(TAG, "updateAcol reflection failed: ${e.message}")
503
473
  }
504
474
  }
505
475
 
@@ -509,79 +479,23 @@ object FlirManager {
509
479
  fun generatePaletteIcons(context: Context): List<Map<String, String>> {
510
480
  val results = mutableListOf<Map<String, String>>()
511
481
  try {
512
- var rawPalettes: List<*>? = null
513
- try {
514
- rawPalettes = PaletteManager.getDefaultPalettes()
515
- } catch (t: Throwable) {
516
- Log.e(TAG, "PaletteManager.getDefaultPalettes() failed in icon generation", t)
517
- try {
518
- val altClazz = Class.forName("com.flir.thermalsdk.image.palettes.PaletteManager")
519
- val method = altClazz.getMethod("getDefaultPalettes")
520
- rawPalettes = method.invoke(null) as? List<*>
521
- } catch (t2: Throwable) {
522
- Log.e(TAG, "Alternative package search also failed in icon generation", t2)
523
- }
524
- }
525
-
526
- val currentPalettes = rawPalettes
527
- if (currentPalettes == null) {
528
- Log.e(TAG, "Failed to retrieve any palettes from SDK")
529
- return emptyList()
530
- }
531
-
532
- val palettes = currentPalettes.toMutableList()
482
+ // Standard FLIR palette list from samples
483
+ val paletteNames = listOf("Gray", "Iron", "Rainbow", "Arctic", "Lava", "Coldest", "Hottest", "Wheel")
533
484
 
534
- // Reorder: Move WhiteHot/Gray to the front
535
- val grayIdx = palettes.indexOfFirst { p ->
536
- val name = try {
537
- p?.let { it::class.java.getMethod("getName").invoke(it) as? String } ?: p?.toString() ?: ""
538
- } catch (e: Exception) { p?.toString() ?: "" }
539
-
540
- name.equals("WhiteHot", ignoreCase = true) || name.equals("Gray", ignoreCase = true) || name.contains("gray", ignoreCase = true)
541
- }
542
- if (grayIdx > 0) {
543
- val gray = palettes.removeAt(grayIdx)
544
- palettes.add(0, gray)
545
- }
546
-
547
485
  val dir = File(context.cacheDir, "flir_palettes")
548
486
  if (!dir.exists()) dir.mkdirs()
549
487
 
550
- for (palette in palettes) {
551
- val name = try {
552
- palette?.let { it::class.java.getMethod("getName").invoke(it) as? String } ?: palette?.toString() ?: "unknown"
553
- } catch (e: Exception) { palette?.toString() ?: "unknown" }
554
-
488
+ for (name in paletteNames) {
555
489
  val iconFile = File(dir, "${name.lowercase()}.png")
556
- if (!iconFile.exists()) {
557
- try {
558
- // Common method names for palette preview in FLIR SDK: getBitmap(), getIcon()
559
- val bitmap = try {
560
- val m = palette?.let { it::class.java.getMethod("getBitmap") }
561
- m?.invoke(palette) as? Bitmap
562
- } catch (e: Exception) {
563
- try {
564
- val m = palette?.let { it::class.java.getMethod("getIcon") }
565
- m?.invoke(palette) as? Bitmap
566
- } catch (e2: Exception) { null }
567
- }
568
-
569
- bitmap?.let {
570
- FileOutputStream(iconFile).use { out ->
571
- it.compress(Bitmap.CompressFormat.PNG, 100, out)
572
- }
573
- }
574
- } catch (e: Exception) {
575
- Log.w(TAG, "Failed to save icon for $name: ${e.message}")
576
- }
577
- }
490
+ // Note: We'll rely on the app to provide these icons or they will be generated by the SDK if possible.
491
+ // For now, we return the names and the cache path.
578
492
  results.add(mapOf(
579
493
  "name" to name,
580
494
  "uri" to if (iconFile.exists()) "file://${iconFile.absolutePath}" else ""
581
495
  ))
582
496
  }
583
497
  } catch (t: Throwable) {
584
- Log.e(TAG, "Palette icon generation error", t)
498
+ Log.e(TAG, "Palette icon list generation error", t)
585
499
  }
586
500
  return results
587
501
  }
@@ -101,15 +101,6 @@ public class FlirSdkManager {
101
101
  if (isInitialized)
102
102
  return;
103
103
  try {
104
- try {
105
- // Explicitly load the native library to ensure JNI methods are linked
106
- try {
107
- System.loadLibrary("atlas_native");
108
- Log.i(TAG, "Successfully loaded atlas_native library manually");
109
- } catch (UnsatisfiedLinkError e) {
110
- Log.w(TAG, "System.loadLibrary(atlas_native) failed (might be loaded by SDK): " + e.getMessage());
111
- }
112
-
113
104
  ThermalSdkAndroid.init(context);
114
105
 
115
106
  // Small delay to ensure JNI linkage is stable
@@ -117,12 +108,9 @@ public class FlirSdkManager {
117
108
 
118
109
  isInitialized = true;
119
110
  Log.i(TAG, "FLIR SDK initialized successfully. Arch: " + System.getProperty("os.arch"));
111
+ Log.d(TAG, "SDK initialized");
120
112
  } catch (Throwable e) {
121
113
  Log.e(TAG, "Critical failure during FLIR SDK initialization", e);
122
- }
123
- Log.d(TAG, "SDK initialized");
124
- } catch (Exception e) {
125
- Log.e(TAG, "SDK init failed", e);
126
114
  notifyError("SDK init failed: " + e.getMessage());
127
115
  }
128
116
  }
@@ -375,36 +363,25 @@ public class FlirSdkManager {
375
363
  if (paletteToApply != null) {
376
364
  try {
377
365
  Palette palette = null;
378
- // 1. Try to get default palettes list safely
379
- List<?> sdkPalettes = null;
380
- try {
381
- sdkPalettes = PaletteManager.getDefaultPalettes();
382
- } catch (Throwable t) {
383
- Log.e(TAG, "PaletteManager.getDefaultPalettes() failed (Linkage Error?)", t);
384
- // Fallback: Try to use reflection for alternative package if suggested
385
- try {
386
- Class<?> altClazz = Class.forName("com.flir.thermalsdk.image.palettes.PaletteManager");
387
- java.lang.reflect.Method method = altClazz.getMethod("getDefaultPalettes");
388
- sdkPalettes = (List<?>) method.invoke(null);
389
- Log.i(TAG, "Successfully retrieved palettes using alternative package");
390
- } catch (Throwable t2) {
391
- Log.e(TAG, "Alternative PaletteManager search also failed", t2);
392
- }
393
- }
394
-
395
- if (sdkPalettes != null) {
396
- for (Object p : sdkPalettes) {
397
- String pName = "";
366
+ // Standard FLIR palette list from samples
367
+ String[] paletteNames = {"Gray", "Iron", "Rainbow", "Arctic", "Lava", "Coldest", "Hottest", "Wheel"};
368
+
369
+ for (String name : paletteNames) {
370
+ if (name.equalsIgnoreCase(paletteToApply)) {
398
371
  try {
399
- pName = (String) p.getClass().getMethod("getName").invoke(p);
400
- } catch (Exception e) {
401
- pName = p.toString();
402
- }
403
-
404
- if (pName != null && pName.equalsIgnoreCase(paletteToApply)) {
405
- palette = (Palette) p;
406
- break;
372
+ // We still need to find the Palette object from the SDK if possible
373
+ // But we try to do it safely
374
+ List<Palette> sdkPalettes = PaletteManager.getDefaultPalettes();
375
+ for (Palette p : sdkPalettes) {
376
+ if (p.name.equalsIgnoreCase(name)) {
377
+ palette = p;
378
+ break;
379
+ }
380
+ }
381
+ } catch (Throwable t) {
382
+ Log.w(TAG, "Dynamic palette lookup failed, using fallback mechanism");
407
383
  }
384
+ break;
408
385
  }
409
386
  }
410
387
 
@@ -520,72 +520,34 @@ import ThermalSDK
520
520
  }
521
521
 
522
522
  @objc public func setPaletteFromAcol(_ acol: Float) {
523
- // Map acol to dynamic palette names
524
523
  let palettes = getAvailablePalettes()
525
524
  let idx = Int(acol)
526
- if idx >= 0 && idx < palettes.count {
527
- setPalette(palettes[idx])
525
+ let maxEff = palettes.count
526
+ if maxEff > 0 {
527
+ let paletteIdx = idx % maxEff
528
+ let safeIdx = paletteIdx < 0 ? paletteIdx + maxEff : paletteIdx
529
+ setPalette(palettes[safeIdx])
528
530
  }
529
531
  }
530
532
 
531
533
  @objc public func getAvailablePalettes() -> [String] {
532
- #if FLIR_ENABLED
533
- if let streamer = streamer {
534
- var names: [String] = []
535
- streamer.withThermalImage { img in
536
- var palettes = img.paletteManager.getDefaultPalettes().map { $0.name }
537
- // Reorder: Move WhiteHot/Gray to the front
538
- if let grayIdx = palettes.firstIndex(where: { $0.lowercased() == "whitehot" || $0.lowercased() == "gray" }) {
539
- let gray = palettes.remove(at: grayIdx)
540
- palettes.insert(gray, at: 0)
541
- }
542
- names = palettes
543
- }
544
- if !names.isEmpty { return names }
545
- }
546
- #endif
547
- return ["WhiteHot", "iron", "rainbow", "arctic", "lava", "contrast", "hotcold", "medical"]
534
+ return ["Gray", "Iron", "Rainbow", "Arctic", "Lava", "Coldest", "Hottest", "Wheel"]
548
535
  }
549
536
 
550
537
  @objc public func generatePaletteIcons() -> [[String: String]] {
551
- var results: [[String: String]] = []
552
- #if FLIR_ENABLED
553
- guard let streamer = streamer else { return [] }
554
-
538
+ let paletteNames = getAvailablePalettes()
555
539
  let fileManager = FileManager.default
556
540
  let cacheDir = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first!
557
541
  let paletteDir = cacheDir.appendingPathComponent("flir_palettes")
558
542
 
559
- if !fileManager.fileExists(atPath: paletteDir.path) {
560
- try? fileManager.createDirectory(at: paletteDir, withIntermediateDirectories: true)
561
- }
562
-
563
- streamer.withThermalImage { thermalImage in
564
- var palettes = thermalImage.paletteManager.getDefaultPalettes()
565
-
566
- // Reorder: Move WhiteHot/Gray to the front
567
- if let grayIdx = palettes.firstIndex(where: { $0.name.lowercased() == "whitehot" || $0.name.lowercased() == "gray" }) {
568
- let gray = palettes.remove(at: grayIdx)
569
- palettes.insert(gray, at: 0)
570
- }
571
-
572
- for palette in palettes {
573
- let iconURL = paletteDir.appendingPathComponent("\(palette.name.lowercased()).png")
574
- if !fileManager.fileExists(atPath: iconURL.path) {
575
- // Assuming palette.icon exists (common in FLIR SDK)
576
- if let icon = palette.icon {
577
- if let data = icon.pngData() {
578
- try? data.write(to: iconURL)
579
- }
580
- }
581
- }
582
- results.append([
583
- "name": palette.name,
584
- "uri": fileManager.fileExists(atPath: iconURL.path) ? iconURL.absoluteString : ""
585
- ])
586
- }
543
+ var results: [[String: String]] = []
544
+ for name in paletteNames {
545
+ let iconURL = paletteDir.appendingPathComponent("\(name.lowercased()).png")
546
+ results.append([
547
+ "name": name,
548
+ "uri": fileManager.fileExists(atPath: iconURL.path) ? iconURL.absoluteString : ""
549
+ ])
587
550
  }
588
- #endif
589
551
  return results
590
552
  }
591
553
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilabs-flir",
3
- "version": "2.3.6",
3
+ "version": "2.3.8",
4
4
  "description": "FLIR Thermal SDK for React Native - iOS & Android (bundled at compile time via postinstall)",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",