ilabs-flir 2.4.9 → 2.4.11

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/Flir.podspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'Flir'
3
- s.version = '2.4.9'
3
+ s.version = '2.4.11'
4
4
  s.summary = 'FLIR Thermal SDK React Native - Bundled via postinstall'
5
5
  s.description = <<-DESC
6
6
  A React Native wrapper for the FLIR Thermal SDK, providing thermal imaging
@@ -504,103 +504,105 @@ public class FlirSdkManager {
504
504
  // to ensure the native frame reference remains valid.
505
505
  if (isProcessingFrame.compareAndSet(false, true)) {
506
506
  try {
507
- if (streamer != null && activeStream != null) {
508
- streamer.update();
509
-
510
- final String paletteToApply = currentPaletteName;
511
- final String snapshotPath = pendingSnapshotPath;
512
- pendingSnapshotPath = null;
513
- streamer.withThermalImage(thermalImage -> {
514
- // 1. Apply Palette
515
- if (paletteToApply != null) {
516
- try {
517
- List<Palette> sdkPalettes = cachedSdkPalettes;
518
- if (sdkPalettes == null) {
519
- synchronized (FlirSdkManager.this) {
520
- sdkPalettes = cachedSdkPalettes;
521
- if (sdkPalettes == null) {
522
- try {
523
- sdkPalettes = PaletteManager.getDefaultPalettes();
524
- cachedSdkPalettes = sdkPalettes;
525
- } catch (Throwable t) {
526
- Log.e(TAG, "Failed to get default palettes", t);
507
+ synchronized (FlirSdkManager.this) {
508
+ if (streamer != null && activeStream != null) {
509
+ streamer.update();
510
+
511
+ final String paletteToApply = currentPaletteName;
512
+ final String snapshotPath = pendingSnapshotPath;
513
+ pendingSnapshotPath = null;
514
+ streamer.withThermalImage(thermalImage -> {
515
+ // 1. Apply Palette
516
+ if (paletteToApply != null) {
517
+ try {
518
+ List<Palette> sdkPalettes = cachedSdkPalettes;
519
+ if (sdkPalettes == null) {
520
+ synchronized (FlirSdkManager.this) {
521
+ sdkPalettes = cachedSdkPalettes;
522
+ if (sdkPalettes == null) {
523
+ try {
524
+ sdkPalettes = PaletteManager.getDefaultPalettes();
525
+ cachedSdkPalettes = sdkPalettes;
526
+ } catch (Throwable t) {
527
+ Log.e(TAG, "Failed to get default palettes", t);
528
+ }
527
529
  }
528
530
  }
529
531
  }
530
- }
531
-
532
- if (paletteToApply.equalsIgnoreCase("Gray") || paletteToApply.equalsIgnoreCase("grayscale")) {
533
- // User wants Gray - map to WhiteHot which is the SDK's standard grayscale
534
- for (Palette p : sdkPalettes) {
535
- if (p.name.equalsIgnoreCase("WhiteHot") || p.name.equalsIgnoreCase("White hot")) {
536
- thermalImage.setPalette(p);
537
- break;
538
- }
539
- }
540
- } else {
541
- Palette palette = null;
542
- for (Palette p : sdkPalettes) {
543
- if (p.name.equalsIgnoreCase(paletteToApply)) {
544
- palette = p;
545
- break;
546
- }
547
- }
548
532
 
549
- if (palette != null) {
550
- thermalImage.setPalette(palette);
551
- } else if (paletteToApply.equalsIgnoreCase("Wheel")) {
552
- // Fallback for Wheel if not found - some SDKs use different names
533
+ if (paletteToApply.equalsIgnoreCase("Gray") || paletteToApply.equalsIgnoreCase("grayscale")) {
534
+ // User wants Gray - map to WhiteHot which is the SDK's standard grayscale
553
535
  for (Palette p : sdkPalettes) {
554
- if (p.name.contains("Wheel") || p.name.contains("ColorWheel") || p.name.contains("Rainbow")) {
536
+ if (p.name.equalsIgnoreCase("WhiteHot") || p.name.equalsIgnoreCase("White hot")) {
555
537
  thermalImage.setPalette(p);
556
538
  break;
557
539
  }
558
540
  }
541
+ } else {
542
+ Palette palette = null;
543
+ for (Palette p : sdkPalettes) {
544
+ if (p.name.equalsIgnoreCase(paletteToApply)) {
545
+ palette = p;
546
+ break;
547
+ }
548
+ }
549
+
550
+ if (palette != null) {
551
+ thermalImage.setPalette(palette);
552
+ } else if (paletteToApply.equalsIgnoreCase("Wheel")) {
553
+ // Fallback for Wheel if not found - some SDKs use different names
554
+ for (Palette p : sdkPalettes) {
555
+ if (p.name.contains("Wheel") || p.name.contains("ColorWheel") || p.name.contains("Rainbow")) {
556
+ thermalImage.setPalette(p);
557
+ break;
558
+ }
559
+ }
560
+ }
559
561
  }
562
+ } catch (Throwable t) {
563
+ Log.e(TAG, "Failed to apply palette: " + paletteToApply, t);
560
564
  }
561
- } catch (Throwable t) {
562
- Log.e(TAG, "Failed to apply palette: " + paletteToApply, t);
563
565
  }
564
- }
565
566
 
566
- // 2. Save Radiometric Snapshot if requested
567
- if (snapshotPath != null) {
568
- try {
569
- Log.i(TAG, "[SNAPSHOT] Attempting to save radiometric snapshot: " + snapshotPath);
570
- thermalImage.saveAs(snapshotPath);
571
- Log.i(TAG, "[SNAPSHOT] ✅ Success: Radiometric snapshot saved");
572
- if (snapshotCallback != null) {
573
- snapshotCallback.onSnapshotSaved(snapshotPath);
574
- snapshotCallback = null;
575
- }
576
- } catch (java.io.IOException e) {
577
- Log.e(TAG, "Failed to save radiometric snapshot", e);
578
- if (snapshotCallback != null) {
579
- snapshotCallback.onSnapshotError(e.getMessage());
580
- snapshotCallback = null;
567
+ // 2. Save Radiometric Snapshot if requested
568
+ if (snapshotPath != null) {
569
+ try {
570
+ Log.i(TAG, "[SNAPSHOT] Attempting to save radiometric snapshot: " + snapshotPath);
571
+ thermalImage.saveAs(snapshotPath);
572
+ Log.i(TAG, "[SNAPSHOT] ✅ Success: Radiometric snapshot saved");
573
+ if (snapshotCallback != null) {
574
+ snapshotCallback.onSnapshotSaved(snapshotPath);
575
+ snapshotCallback = null;
576
+ }
577
+ } catch (java.io.IOException e) {
578
+ Log.e(TAG, "Failed to save radiometric snapshot", e);
579
+ if (snapshotCallback != null) {
580
+ snapshotCallback.onSnapshotError(e.getMessage());
581
+ snapshotCallback = null;
582
+ }
581
583
  }
582
584
  }
583
- }
584
-
585
- // 3. Generate Bitmap for display
586
- // We use streamer.getImage() to get the rendered image with palette applied.
587
- try {
588
- Bitmap newBitmap = BitmapAndroid.createBitmap(streamer.getImage()).getBitMap();
589
- if (newBitmap != null) {
590
- Bitmap oldBitmap = latestBitmap;
591
- latestBitmap = newBitmap;
592
- if (listener != null) {
593
- listener.onFrame(newBitmap);
594
- }
595
- // Recycle old bitmap to prevent memory leak
596
- if (oldBitmap != null && oldBitmap != newBitmap) {
597
- oldBitmap.recycle();
585
+
586
+ // 3. Generate Bitmap for display
587
+ // We use streamer.getImage() to get the rendered image with palette applied.
588
+ try {
589
+ Bitmap newBitmap = BitmapAndroid.createBitmap(streamer.getImage()).getBitMap();
590
+ if (newBitmap != null) {
591
+ Bitmap oldBitmap = latestBitmap;
592
+ latestBitmap = newBitmap;
593
+ if (listener != null) {
594
+ listener.onFrame(newBitmap);
595
+ }
596
+ // Recycle old bitmap to prevent memory leak
597
+ if (oldBitmap != null && oldBitmap != newBitmap) {
598
+ oldBitmap.recycle();
599
+ }
598
600
  }
601
+ } catch (Exception e) {
602
+ Log.e(TAG, "Bitmap creation failed", e);
599
603
  }
600
- } catch (Exception e) {
601
- Log.e(TAG, "Bitmap creation failed", e);
602
- }
603
- });
604
+ });
605
+ }
604
606
  }
605
607
  } catch (Exception e) {
606
608
  Log.e(TAG, "Frame processing error", e);
@@ -629,16 +631,18 @@ public class FlirSdkManager {
629
631
  }
630
632
 
631
633
  private void stopStreamInternal() {
632
- if (activeStream != null) {
633
- try {
634
- activeStream.stop();
635
- } catch (Exception e) {
636
- Log.e(TAG, "Stop stream error", e);
634
+ synchronized (this) {
635
+ if (activeStream != null) {
636
+ try {
637
+ activeStream.stop();
638
+ } catch (Exception e) {
639
+ Log.e(TAG, "Stop stream error", e);
640
+ }
641
+ activeStream = null;
637
642
  }
638
- activeStream = null;
643
+ streamer = null;
644
+ latestBitmap = null;
639
645
  }
640
- streamer = null;
641
- latestBitmap = null;
642
646
  Log.d(TAG, "Streaming stopped");
643
647
  }
644
648
 
@@ -643,23 +643,24 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
643
643
  - (void)onFrameReceived:(UIImage *)image
644
644
  width:(NSInteger)width
645
645
  height:(NSInteger)height {
646
+ @autoreleasepool {
647
+ NSLog(@"[FLIR-TRACE 6️⃣] onFrameReceived in FlirModule - _isCapturing=%d image=%@",
648
+ atomic_load(&_isCapturing), image);
646
649
 
647
- NSLog(@"[FLIR-TRACE 6️⃣] onFrameReceived in FlirModule - _isCapturing=%d image=%@",
648
- atomic_load(&_isCapturing), image);
649
-
650
- if (!atomic_load(&_isCapturing)) {
651
- NSLog(@"[FLIR-TRACE ❌] _isCapturing is false - frame DROPPED");
652
- return;
653
- }
650
+ if (!atomic_load(&_isCapturing)) {
651
+ NSLog(@"[FLIR-TRACE ❌] _isCapturing is false - frame DROPPED");
652
+ return;
653
+ }
654
654
 
655
- NSLog(@"[FLIR-TRACE 7️⃣] Calling FlirState.updateFrame with image %ldx%ld",
656
- (long)width, (long)height);
657
-
658
- // CRITICAL: Update shared state so native preview (FlirPreviewView) receives
659
- // the texture
660
- [[FlirState shared] updateFrame:image];
655
+ NSLog(@"[FLIR-TRACE 7️⃣] Calling FlirState.updateFrame with image %ldx%ld",
656
+ (long)width, (long)height);
657
+
658
+ // CRITICAL: Update shared state so native preview (FlirPreviewView) receives
659
+ // the texture
660
+ [[FlirState shared] updateFrame:image];
661
661
 
662
- NSLog(@"[FLIR-TRACE 8️⃣] FlirState.updateFrame completed");
662
+ NSLog(@"[FLIR-TRACE 8️⃣] FlirState.updateFrame completed");
663
+ }
663
664
  }
664
665
 
665
666
  - (void)onFrameReceivedRaw:(NSData *)data
@@ -90,12 +90,14 @@ static FlirState *_sharedState = nil;
90
90
  - (void)updateFrame:(UIImage *)image
91
91
  withTemperatureData:(NSArray<NSNumber *> *)tempData {
92
92
  dispatch_async(_accessQueue, ^{
93
- self.latestImage = image;
93
+ @autoreleasepool {
94
+ self.latestImage = image;
94
95
 
95
- if (tempData != nil) {
96
- self->_temperatureData = [tempData copy];
97
- self->_imageWidth = (int)image.size.width;
98
- self->_imageHeight = (int)image.size.height;
96
+ if (tempData != nil) {
97
+ self->_temperatureData = [tempData copy];
98
+ self->_imageWidth = (int)image.size.width;
99
+ self->_imageHeight = (int)image.size.height;
100
+ }
99
101
  }
100
102
  });
101
103
 
@@ -110,18 +112,20 @@ static FlirState *_sharedState = nil;
110
112
  NSLog(@"[FLIR-TRACE 🔟] Dispatching onTextureUpdate callback to main "
111
113
  @"queue");
112
114
  dispatch_async(dispatch_get_main_queue(), ^{
113
- @try {
114
- if (self.onTextureUpdate) {
115
- NSLog(@"[FLIR-TRACE 1️⃣1️⃣] Invoking onTextureUpdate callback with "
116
- @"image %@",
117
- image);
118
- self.onTextureUpdate(image, 7);
119
- NSLog(@"[FLIR-TRACE 1️⃣2️⃣] onTextureUpdate callback completed");
120
- } else {
121
- NSLog(@"[FLIR-TRACE ❌] onTextureUpdate became nil before invoke");
115
+ @autoreleasepool {
116
+ @try {
117
+ if (self.onTextureUpdate) {
118
+ NSLog(@"[FLIR-TRACE 1️⃣1️⃣] Invoking onTextureUpdate callback with "
119
+ @"image %@",
120
+ image);
121
+ self.onTextureUpdate(image, 7);
122
+ NSLog(@"[FLIR-TRACE 1️⃣2️⃣] onTextureUpdate callback completed");
123
+ } else {
124
+ NSLog(@"[FLIR-TRACE ❌] onTextureUpdate became nil before invoke");
125
+ }
126
+ } @finally {
127
+ atomic_store(&_isTextureBusy, false);
122
128
  }
123
- } @finally {
124
- atomic_store(&_isTextureBusy, false);
125
129
  }
126
130
  });
127
131
  } else {
@@ -140,8 +144,10 @@ static FlirState *_sharedState = nil;
140
144
  double temp = [self getTemperatureAt:centerX y:centerY];
141
145
 
142
146
  dispatch_async(dispatch_get_main_queue(), ^{
143
- if (self.onTemperatureUpdate) {
144
- self.onTemperatureUpdate(temp, centerX, centerY);
147
+ @autoreleasepool {
148
+ if (self.onTemperatureUpdate) {
149
+ self.onTemperatureUpdate(temp, centerX, centerY);
150
+ }
145
151
  }
146
152
  });
147
153
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilabs-flir",
3
- "version": "2.4.9",
3
+ "version": "2.4.11",
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",
@@ -67,4 +67,4 @@
67
67
  "sourceDir": "./android/Flir"
68
68
  }
69
69
  }
70
- }
70
+ }