ilabs-flir 2.1.36 → 2.1.37

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.
@@ -38,7 +38,7 @@ android {
38
38
 
39
39
  dependencies {
40
40
  // React Native
41
- implementation("com.facebook.react:react-native:+")
41
+ implementation("com.facebook.react:react-native:+")66a6f83912ba50ae5553aff1f5b0
42
42
 
43
43
  // Kotlin coroutines
44
44
  implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
@@ -11,16 +11,40 @@
11
11
 
12
12
  // Note: React headers are provided by the app's build system
13
13
  // These imports are for documentation purposes when building within Xcode
14
- #if __has_include(<React/RCTBridgeModule.h>)
14
+ // Prefer React/ headers, but fall back to ReactCore or local headers for different RN layouts
15
15
  #if __has_include(<React/RCTBridgeModule.h>)
16
16
  #import <React/RCTBridgeModule.h>
17
+ #if __has_include(<React/RCTEventEmitter.h>)
17
18
  #import <React/RCTEventEmitter.h>
19
+ #endif
20
+ #if __has_include(<React/RCTLog.h>)
21
+ #import <React/RCTLog.h>
22
+ #endif
23
+ #if __has_include(<React/RCTViewManager.h>)
24
+ #import <React/RCTViewManager.h>
25
+ #endif
18
26
  #elif __has_include(<ReactCore/RCTBridgeModule.h>)
19
27
  #import <ReactCore/RCTBridgeModule.h>
28
+ #if __has_include(<ReactCore/RCTEventEmitter.h>)
29
+ #import <ReactCore/RCTEventEmitter.h>
30
+ #elif __has_include(<React/RCTEventEmitter.h>)
20
31
  #import <React/RCTEventEmitter.h>
32
+ #endif
33
+ #if __has_include(<ReactCore/RCTLog.h>)
34
+ #import <ReactCore/RCTLog.h>
35
+ #elif __has_include(<React/RCTLog.h>)
36
+ #import <React/RCTLog.h>
37
+ #endif
38
+ #if __has_include(<ReactCore/RCTViewManager.h>)
39
+ #import <ReactCore/RCTViewManager.h>
40
+ #elif __has_include(<React/RCTViewManager.h>)
41
+ #import <React/RCTViewManager.h>
42
+ #endif
21
43
  #elif __has_include("RCTBridgeModule.h")
22
44
  #import "RCTBridgeModule.h"
23
45
  #import "RCTEventEmitter.h"
46
+ #import "RCTLog.h"
47
+ #import "RCTViewManager.h"
24
48
  #else
25
49
  #import <Foundation/Foundation.h>
26
50
  @interface RCTEventEmitter : NSObject
@@ -28,9 +52,6 @@
28
52
  @protocol RCTBridgeModule <NSObject>
29
53
  @end
30
54
  #endif
31
- #import <React/RCTLog.h>
32
- #import <React/RCTViewManager.h>
33
- #endif
34
55
 
35
56
  // FLIR module headers (local)
36
57
  #import "FlirEventEmitter.h"
@@ -5,12 +5,19 @@
5
5
  // Event emitter for sending FLIR events to React Native
6
6
  //
7
7
 
8
+ // Prefer React/ headers, but fall back to ReactCore or local headers for different RN layouts
8
9
  #if __has_include(<React/RCTBridgeModule.h>)
9
10
  #import <React/RCTBridgeModule.h>
11
+ #if __has_include(<React/RCTEventEmitter.h>)
10
12
  #import <React/RCTEventEmitter.h>
13
+ #endif
11
14
  #elif __has_include(<ReactCore/RCTBridgeModule.h>)
12
15
  #import <ReactCore/RCTBridgeModule.h>
16
+ #if __has_include(<ReactCore/RCTEventEmitter.h>)
17
+ #import <ReactCore/RCTEventEmitter.h>
18
+ #elif __has_include(<React/RCTEventEmitter.h>)
13
19
  #import <React/RCTEventEmitter.h>
20
+ #endif
14
21
  #elif __has_include("RCTBridgeModule.h")
15
22
  #import "RCTBridgeModule.h"
16
23
  #import "RCTEventEmitter.h"
@@ -43,6 +43,7 @@ import ThermalSDK
43
43
  func onDeviceConnected(_ device: FlirDeviceInfo)
44
44
  func onDeviceDisconnected()
45
45
  func onFrameReceived(_ image: UIImage, width: Int, height: Int)
46
+ @objc optional func onFrameReceivedRaw(_ data: Data, width: Int, height: Int, bytesPerRow: Int, timestamp: Double)
46
47
  func onError(_ message: String)
47
48
  func onStateChanged(_ state: String, isConnected: Bool, isStreaming: Bool, isEmulator: Bool)
48
49
  }
@@ -188,6 +189,35 @@ import ThermalSDK
188
189
  return nil
189
190
  }
190
191
 
192
+ // Returns a NSDictionary with BGRA base64 data for the latest frame.
193
+ // Keys: width (Int), height (Int), bytesPerRow (Int), dataBase64 (String)
194
+ @objc public func latestFrameBitmapBase64() -> NSDictionary? {
195
+ guard let img = latestImage else { return nil }
196
+ guard let bmp = convertUIImageToBGRA(img) else { return nil }
197
+ let b64 = bmp.data.base64EncodedString()
198
+ return ["width": bmp.width, "height": bmp.height, "bytesPerRow": bmp.bytesPerRow, "dataBase64": b64]
199
+ }
200
+
201
+ // Convert a UIImage to BGRA (kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst).
202
+ private func convertUIImageToBGRA(_ image: UIImage) -> (data: Data, width: Int, height: Int, bytesPerRow: Int)? {
203
+ guard let cg = image.cgImage else { return nil }
204
+ let width = cg.width
205
+ let height = cg.height
206
+ let bytesPerRow = width * 4
207
+ let size = height * bytesPerRow
208
+ var data = Data(count: size)
209
+ let colorSpace = CGColorSpaceCreateDeviceRGB()
210
+ let bitmapInfo = CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue
211
+ let success = data.withUnsafeMutableBytes { (ptr: UnsafeMutableRawBufferPointer) -> Bool in
212
+ guard let base = ptr.baseAddress else { return false }
213
+ guard let ctx = CGContext(data: base, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { return false }
214
+ let rect = CGRect(x: 0, y: 0, width: width, height: height)
215
+ ctx.draw(cg, in: rect)
216
+ return true
217
+ }
218
+ return success ? (data, width, height, bytesPerRow) : nil
219
+ }
220
+
191
221
  // Client lifecycle helpers: callers (UI/filters) can retain/release to ensure
192
222
  // discovery runs while any client is active.
193
223
  @objc public func retainClient(_ clientId: String) {
@@ -851,6 +881,23 @@ extension FlirManager: FLIRStreamDelegate {
851
881
  height: Int(image.size.height)
852
882
  )
853
883
  }
884
+
885
+ // Also provide a raw BGRA bitmap callback (optional) to delegates and a
886
+ // queryable base64 bitmap dict for RN consumers. Conversion is done
887
+ // off the main thread to avoid blocking UI.
888
+ DispatchQueue.global(qos: .utility).async { [weak self, weak image] in
889
+ guard let self = self, let image = image else { return }
890
+ if let bmp = self.convertUIImageToBGRA(image) {
891
+ let ts = Date().timeIntervalSince1970 * 1000.0
892
+ DispatchQueue.main.async {
893
+ // Notify the delegate if set (may be FlirModule or another consumer)
894
+ self.delegate?.onFrameReceivedRaw?(bmp.data, width: bmp.width, height: bmp.height, bytesPerRow: bmp.bytesPerRow, timestamp: ts)
895
+
896
+ // Post a system notification so multiple native observers can react
897
+ NotificationCenter.default.post(name: Notification.Name("FlirFrameBitmapAvailableNative"), object: nil, userInfo: ["width": bmp.width, "height": bmp.height, "bytesPerRow": bmp.bytesPerRow, "timestamp": ts])
898
+ }
899
+ }
900
+ }
854
901
  }
855
902
  } catch {
856
903
  NSLog("[FlirManager] Streamer update error: \(error)")
@@ -5,12 +5,19 @@
5
5
  // React Native bridge module for FLIR thermal camera SDK
6
6
  //
7
7
 
8
+ // Prefer React/ headers, but fall back to ReactCore or local headers for different RN layouts
8
9
  #if __has_include(<React/RCTBridgeModule.h>)
9
10
  #import <React/RCTBridgeModule.h>
11
+ #if __has_include(<React/RCTEventEmitter.h>)
10
12
  #import <React/RCTEventEmitter.h>
13
+ #endif
11
14
  #elif __has_include(<ReactCore/RCTBridgeModule.h>)
12
15
  #import <ReactCore/RCTBridgeModule.h>
16
+ #if __has_include(<ReactCore/RCTEventEmitter.h>)
17
+ #import <ReactCore/RCTEventEmitter.h>
18
+ #elif __has_include(<React/RCTEventEmitter.h>)
13
19
  #import <React/RCTEventEmitter.h>
20
+ #endif
14
21
  #elif __has_include("RCTBridgeModule.h")
15
22
  #import "RCTBridgeModule.h"
16
23
  #import "RCTEventEmitter.h"
@@ -121,7 +121,7 @@ RCT_EXPORT_MODULE(FlirModule);
121
121
  - (NSArray<NSString *> *)supportedEvents {
122
122
  return @[
123
123
  @"FlirDeviceConnected", @"FlirDeviceDisconnected", @"FlirDevicesFound",
124
- @"FlirFrameReceived", @"FlirError", @"FlirStateChanged",
124
+ @"FlirFrameReceived", @"FlirFrameBitmapAvailable", @"FlirError", @"FlirStateChanged",
125
125
  @"FlirBatteryUpdated"
126
126
  ];
127
127
  }
@@ -308,6 +308,22 @@ RCT_EXPORT_METHOD(isEmulator : (RCTPromiseResolveBlock)
308
308
  });
309
309
  }
310
310
 
311
+ RCT_EXPORT_METHOD(getLatestFrameBitmap : (RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject) {
312
+ dispatch_async(dispatch_get_main_queue(), ^{
313
+ id manager = flir_manager_shared();
314
+ if (!manager || ![manager respondsToSelector:sel_registerName("latestFrameBitmapBase64")]) {
315
+ resolve([NSNull null]);
316
+ return;
317
+ }
318
+ NSDictionary *dict = ((NSDictionary * (*)(id, SEL)) objc_msgSend)(manager, sel_registerName("latestFrameBitmapBase64"));
319
+ if (!dict) {
320
+ resolve([NSNull null]);
321
+ } else {
322
+ resolve(dict);
323
+ }
324
+ });
325
+ }
326
+
311
327
  RCT_EXPORT_METHOD(isDeviceConnected : (RCTPromiseResolveBlock)
312
328
  resolve rejecter : (RCTPromiseRejectBlock)reject) {
313
329
  dispatch_async(dispatch_get_main_queue(), ^{
@@ -431,6 +447,16 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
431
447
  }];
432
448
  }
433
449
 
450
+ - (void)onFrameReceivedRaw:(NSData *)data width:(NSInteger)width height:(NSInteger)height bytesPerRow:(NSInteger)bytesPerRow timestamp:(double)timestamp {
451
+ // Emit a lightweight event to notify JS that a raw bitmap is available; raw bytes are available via getLatestFrameBitmap()
452
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirFrameBitmapAvailable" body:@{
453
+ @"width": @(width),
454
+ @"height": @(height),
455
+ @"bytesPerRow": @(bytesPerRow),
456
+ @"timestamp": @(timestamp)
457
+ }];
458
+ }
459
+
434
460
  - (void)onError:(NSString *)message {
435
461
  if (self.connectReject) {
436
462
  self.connectReject(@"ERR_FLIR", message, nil);
@@ -0,0 +1,50 @@
1
+ // FlirPublic.h
2
+ // Public C/ObjC API for the Flir library
3
+
4
+ #import <Foundation/Foundation.h>
5
+ #import <UIKit/UIKit.h>
6
+
7
+ NS_ASSUME_NONNULL_BEGIN
8
+
9
+ @interface FlirDeviceInfo : NSObject
10
+ @property (nonatomic, readonly) NSString *deviceId;
11
+ @property (nonatomic, readonly) NSString *name;
12
+ @property (nonatomic, readonly) NSString *communicationType;
13
+ @property (nonatomic, readonly) BOOL isEmulator;
14
+ - (NSDictionary *)toDictionary;
15
+ @end
16
+
17
+ @protocol FlirPublicDelegate <NSObject>
18
+ - (void)onDevicesFound:(NSArray<FlirDeviceInfo *> *)devices;
19
+ - (void)onDeviceConnected:(FlirDeviceInfo *)device;
20
+ - (void)onDeviceDisconnected;
21
+ - (void)onFrameReceived:(UIImage *)image width:(NSInteger)width height:(NSInteger)height;
22
+ @optional
23
+ - (void)onFrameReceivedRaw:(NSData *)data width:(NSInteger)width height:(NSInteger)height bytesPerRow:(NSInteger)bytesPerRow timestamp:(double)timestamp;
24
+ - (void)onError:(NSString *)message;
25
+ - (void)onStateChanged:(NSString *)state isConnected:(BOOL)isConnected isStreaming:(BOOL)isStreaming isEmulator:(BOOL)isEmulator;
26
+ @end
27
+
28
+ @interface FlirManager : NSObject
29
+ + (instancetype)shared NS_SWIFT_NAME(shared);
30
+
31
+ @property (nonatomic, weak, nullable) id<FlirPublicDelegate> delegate;
32
+
33
+ // Lifecycle
34
+ - (void)startDiscovery;
35
+ - (void)stopDiscovery;
36
+ - (void)connectToDevice:(NSString *)deviceId;
37
+ - (void)disconnect;
38
+ - (void)stop;
39
+
40
+ // Frame accessors
41
+ - (nullable NSDictionary *)latestFrameBitmapBase64; // { width, height, bytesPerRow, dataBase64 }
42
+ - (nullable NSString *)latestFrameBase64;
43
+
44
+ // Utilities
45
+ - (NSInteger)getBatteryLevel;
46
+ - (BOOL)isBatteryCharging;
47
+
48
+ @end
49
+
50
+ NS_ASSUME_NONNULL_END
@@ -5,8 +5,13 @@
5
5
  // React Native view manager for FLIR preview
6
6
  //
7
7
 
8
+ // Prefer React/ headers, but support multiple RN header layouts
8
9
  #if __has_include(<React/RCTViewManager.h>)
9
10
  #import <React/RCTViewManager.h>
11
+ #elif __has_include(<ReactCore/RCTViewManager.h>)
12
+ #import <ReactCore/RCTViewManager.h>
13
+ #elif __has_include("RCTViewManager.h")
14
+ #import "RCTViewManager.h"
10
15
  #elif __has_include(<React/RCTUIManager.h>)
11
16
  #import <React/RCTUIManager.h>
12
17
  #else
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilabs-flir",
3
- "version": "2.1.36",
3
+ "version": "2.1.37",
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",