@arfuhad/react-native-smart-camera 0.1.1 → 0.1.5
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/CHANGELOG.md +130 -0
- package/README.md +259 -206
- package/android/build.gradle +15 -33
- package/android/src/main/java/com/smartcamera/FaceDetectorFrameProcessorPlugin.kt +324 -0
- package/android/src/main/java/com/smartcamera/SmartCameraPackage.kt +28 -0
- package/build/detection/blinkProcessor.js +2 -1
- package/build/detection/blinkProcessor.js.map +1 -1
- package/build/detection/faceDetector.d.ts +4 -4
- package/build/detection/faceDetector.d.ts.map +1 -1
- package/build/detection/faceDetector.js +31 -11
- package/build/detection/faceDetector.js.map +1 -1
- package/build/detection/index.d.ts +1 -1
- package/build/detection/index.d.ts.map +1 -1
- package/build/detection/index.js +1 -1
- package/build/detection/index.js.map +1 -1
- package/build/detection/staticImageDetector.d.ts +11 -11
- package/build/detection/staticImageDetector.d.ts.map +1 -1
- package/build/detection/staticImageDetector.js +19 -23
- package/build/detection/staticImageDetector.js.map +1 -1
- package/build/hooks/index.d.ts +6 -0
- package/build/hooks/index.d.ts.map +1 -1
- package/build/hooks/index.js +8 -0
- package/build/hooks/index.js.map +1 -1
- package/build/hooks/useBlinkDetection.d.ts +27 -16
- package/build/hooks/useBlinkDetection.d.ts.map +1 -1
- package/build/hooks/useBlinkDetection.js +63 -37
- package/build/hooks/useBlinkDetection.js.map +1 -1
- package/build/hooks/useFaceDetection.js +3 -2
- package/build/hooks/useFaceDetection.js.map +1 -1
- package/build/hooks/useFaceDetector.d.ts +123 -0
- package/build/hooks/useFaceDetector.d.ts.map +1 -0
- package/build/hooks/useFaceDetector.js +133 -0
- package/build/hooks/useFaceDetector.js.map +1 -0
- package/build/hooks/useSmartCamera.js.map +1 -1
- package/build/hooks/useSmartCameraWebRTC.d.ts +3 -5
- package/build/hooks/useSmartCameraWebRTC.d.ts.map +1 -1
- package/build/hooks/useSmartCameraWebRTC.js +19 -87
- package/build/hooks/useSmartCameraWebRTC.js.map +1 -1
- package/build/hooks/useWebRTC.d.ts +88 -0
- package/build/hooks/useWebRTC.d.ts.map +1 -0
- package/build/hooks/useWebRTC.js +394 -0
- package/build/hooks/useWebRTC.js.map +1 -0
- package/build/hooks/useWebRTCWithDetection.d.ts +89 -0
- package/build/hooks/useWebRTCWithDetection.d.ts.map +1 -0
- package/build/hooks/useWebRTCWithDetection.js +131 -0
- package/build/hooks/useWebRTCWithDetection.js.map +1 -0
- package/build/index.d.ts +24 -10
- package/build/index.d.ts.map +1 -1
- package/build/index.js +38 -13
- package/build/index.js.map +1 -1
- package/build/types.d.ts +28 -12
- package/build/types.d.ts.map +1 -1
- package/build/types.js.map +1 -1
- package/build/utils/index.js.map +1 -1
- package/build/webrtc/WebRTCBridge.d.ts +3 -0
- package/build/webrtc/WebRTCBridge.d.ts.map +1 -1
- package/build/webrtc/WebRTCBridge.js +12 -15
- package/build/webrtc/WebRTCBridge.js.map +1 -1
- package/build/webrtc/WebRTCManager.d.ts +148 -0
- package/build/webrtc/WebRTCManager.d.ts.map +1 -0
- package/build/webrtc/WebRTCManager.js +383 -0
- package/build/webrtc/WebRTCManager.js.map +1 -0
- package/build/webrtc/index.d.ts +3 -1
- package/build/webrtc/index.d.ts.map +1 -1
- package/build/webrtc/index.js +5 -0
- package/build/webrtc/index.js.map +1 -1
- package/build/webrtc/types.d.ts +212 -4
- package/build/webrtc/types.d.ts.map +1 -1
- package/build/webrtc/types.js +34 -1
- package/build/webrtc/types.js.map +1 -1
- package/ios/FaceDetectorFrameProcessorPlugin.m +11 -0
- package/ios/FaceDetectorFrameProcessorPlugin.swift +304 -0
- package/package.json +13 -12
- package/react-native-smart-camera.podspec +32 -0
- package/src/detection/blinkProcessor.ts +127 -0
- package/src/detection/faceDetector.ts +78 -0
- package/src/detection/index.ts +3 -0
- package/src/detection/staticImageDetector.ts +53 -0
- package/src/hooks/index.ts +26 -0
- package/src/hooks/useBlinkDetection.ts +127 -0
- package/src/hooks/useFaceDetection.ts +105 -0
- package/src/hooks/useFaceDetector.ts +191 -0
- package/src/hooks/useSmartCamera.ts +83 -0
- package/src/hooks/useSmartCameraWebRTC.ts +120 -0
- package/src/hooks/useWebRTC.ts +453 -0
- package/src/hooks/useWebRTCWithDetection.ts +181 -0
- package/src/index.ts +170 -0
- package/src/types.ts +636 -0
- package/src/utils/index.ts +355 -0
- package/src/webrtc/WebRTCBridge.ts +127 -0
- package/src/webrtc/WebRTCManager.ts +453 -0
- package/src/webrtc/index.ts +50 -0
- package/src/webrtc/types.ts +361 -0
- package/android/src/main/java/expo/modules/smartcamera/ImageLoader.kt +0 -106
- package/android/src/main/java/expo/modules/smartcamera/MLKitFaceDetector.kt +0 -273
- package/android/src/main/java/expo/modules/smartcamera/SmartCameraModule.kt +0 -205
- package/android/src/main/java/expo/modules/smartcamera/SmartCameraView.kt +0 -153
- package/android/src/main/java/expo/modules/smartcamera/WebRTCFrameBridge.kt +0 -184
- package/build/SmartCamera.d.ts +0 -17
- package/build/SmartCamera.d.ts.map +0 -1
- package/build/SmartCamera.js +0 -270
- package/build/SmartCamera.js.map +0 -1
- package/build/SmartCameraModule.d.ts +0 -112
- package/build/SmartCameraModule.d.ts.map +0 -1
- package/build/SmartCameraModule.js +0 -121
- package/build/SmartCameraModule.js.map +0 -1
- package/build/SmartCameraView.d.ts +0 -8
- package/build/SmartCameraView.d.ts.map +0 -1
- package/build/SmartCameraView.js +0 -7
- package/build/SmartCameraView.js.map +0 -1
- package/expo-module.config.json +0 -9
- package/ios/MLKitFaceDetector.swift +0 -310
- package/ios/SmartCamera.podspec +0 -33
- package/ios/SmartCameraModule.swift +0 -225
- package/ios/SmartCameraView.swift +0 -146
- package/ios/WebRTCFrameBridge.swift +0 -150
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebRTC-related types for the SmartCamera module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// Core WebRTC Types
|
|
7
|
+
// =============================================================================
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* ICE server configuration for STUN/TURN servers
|
|
11
|
+
*/
|
|
12
|
+
export interface ICEServer {
|
|
13
|
+
/** STUN/TURN server URLs */
|
|
14
|
+
urls: string | string[];
|
|
15
|
+
/** Username for TURN authentication */
|
|
16
|
+
username?: string;
|
|
17
|
+
/** Credential for TURN authentication */
|
|
18
|
+
credential?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Peer connection configuration
|
|
23
|
+
*/
|
|
24
|
+
export interface PeerConnectionConfig {
|
|
25
|
+
/** ICE servers (STUN/TURN) */
|
|
26
|
+
iceServers?: ICEServer[];
|
|
27
|
+
/** ICE transport policy */
|
|
28
|
+
iceTransportPolicy?: 'all' | 'relay';
|
|
29
|
+
/** Bundle policy */
|
|
30
|
+
bundlePolicy?: 'balanced' | 'max-bundle' | 'max-compat';
|
|
31
|
+
/** RTCP mux policy */
|
|
32
|
+
rtcpMuxPolicy?: 'require';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Video constraints for getUserMedia
|
|
37
|
+
*/
|
|
38
|
+
export interface VideoConstraints {
|
|
39
|
+
/** Frame width in pixels */
|
|
40
|
+
width?: number | { min?: number; ideal?: number; max?: number };
|
|
41
|
+
/** Frame height in pixels */
|
|
42
|
+
height?: number | { min?: number; ideal?: number; max?: number };
|
|
43
|
+
/** Target frame rate */
|
|
44
|
+
frameRate?: number | { min?: number; ideal?: number; max?: number };
|
|
45
|
+
/** Camera facing mode */
|
|
46
|
+
facingMode?: 'user' | 'environment';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Audio constraints for getUserMedia
|
|
51
|
+
*/
|
|
52
|
+
export interface AudioConstraints {
|
|
53
|
+
/** Enable echo cancellation */
|
|
54
|
+
echoCancellation?: boolean;
|
|
55
|
+
/** Enable noise suppression */
|
|
56
|
+
noiseSuppression?: boolean;
|
|
57
|
+
/** Enable auto gain control */
|
|
58
|
+
autoGainControl?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Media stream constraints
|
|
63
|
+
*/
|
|
64
|
+
export interface MediaConstraints {
|
|
65
|
+
/** Video constraints (false to disable video) */
|
|
66
|
+
video?: boolean | VideoConstraints;
|
|
67
|
+
/** Audio constraints (false to disable audio) */
|
|
68
|
+
audio?: boolean | AudioConstraints;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// =============================================================================
|
|
72
|
+
// Call State Types
|
|
73
|
+
// =============================================================================
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* WebRTC call state
|
|
77
|
+
*/
|
|
78
|
+
export type CallState =
|
|
79
|
+
| 'idle' // No active call
|
|
80
|
+
| 'connecting' // Call is being established
|
|
81
|
+
| 'connected' // Call is active
|
|
82
|
+
| 'reconnecting'// Connection lost, attempting to reconnect
|
|
83
|
+
| 'disconnected'// Call ended or failed
|
|
84
|
+
| 'failed'; // Call failed to establish
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* WebRTC connection state (maps to RTCPeerConnectionState)
|
|
88
|
+
*/
|
|
89
|
+
export type WebRTCConnectionState =
|
|
90
|
+
| 'new'
|
|
91
|
+
| 'connecting'
|
|
92
|
+
| 'connected'
|
|
93
|
+
| 'disconnected'
|
|
94
|
+
| 'failed'
|
|
95
|
+
| 'closed';
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* ICE connection state
|
|
99
|
+
*/
|
|
100
|
+
export type ICEConnectionState =
|
|
101
|
+
| 'new'
|
|
102
|
+
| 'checking'
|
|
103
|
+
| 'connected'
|
|
104
|
+
| 'completed'
|
|
105
|
+
| 'failed'
|
|
106
|
+
| 'disconnected'
|
|
107
|
+
| 'closed';
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* ICE gathering state
|
|
111
|
+
*/
|
|
112
|
+
export type ICEGatheringState = 'new' | 'gathering' | 'complete';
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Signaling state
|
|
116
|
+
*/
|
|
117
|
+
export type SignalingState =
|
|
118
|
+
| 'stable'
|
|
119
|
+
| 'have-local-offer'
|
|
120
|
+
| 'have-remote-offer'
|
|
121
|
+
| 'have-local-pranswer'
|
|
122
|
+
| 'have-remote-pranswer'
|
|
123
|
+
| 'closed';
|
|
124
|
+
|
|
125
|
+
// =============================================================================
|
|
126
|
+
// Stream and Track Types
|
|
127
|
+
// =============================================================================
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Video frame format for WebRTC
|
|
131
|
+
*/
|
|
132
|
+
export type VideoFrameFormat = 'I420' | 'NV12' | 'NV21' | 'BGRA';
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Configuration for the WebRTC video source
|
|
136
|
+
*/
|
|
137
|
+
export interface WebRTCVideoSourceConfig {
|
|
138
|
+
/** Frame width in pixels */
|
|
139
|
+
width: number;
|
|
140
|
+
/** Frame height in pixels */
|
|
141
|
+
height: number;
|
|
142
|
+
/** Target frame rate */
|
|
143
|
+
frameRate: number;
|
|
144
|
+
/** Video frame format. Default: 'I420' */
|
|
145
|
+
format?: VideoFrameFormat;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* WebRTC stream statistics
|
|
150
|
+
*/
|
|
151
|
+
export interface WebRTCStreamStats {
|
|
152
|
+
/** Current frame rate */
|
|
153
|
+
frameRate: number;
|
|
154
|
+
/** Frames sent */
|
|
155
|
+
framesSent: number;
|
|
156
|
+
/** Frames dropped */
|
|
157
|
+
framesDropped: number;
|
|
158
|
+
/** Bytes sent */
|
|
159
|
+
bytesSent: number;
|
|
160
|
+
/** Current bitrate in bps */
|
|
161
|
+
bitrate: number;
|
|
162
|
+
/** Round-trip time in ms */
|
|
163
|
+
rtt?: number;
|
|
164
|
+
/** Packets lost */
|
|
165
|
+
packetsLost?: number;
|
|
166
|
+
/** Jitter in ms */
|
|
167
|
+
jitter?: number;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* WebRTC stream quality settings
|
|
172
|
+
*/
|
|
173
|
+
export interface WebRTCQualitySettings {
|
|
174
|
+
/** Maximum bitrate in bps */
|
|
175
|
+
maxBitrate?: number;
|
|
176
|
+
/** Minimum bitrate in bps */
|
|
177
|
+
minBitrate?: number;
|
|
178
|
+
/** Target frame rate */
|
|
179
|
+
targetFrameRate?: number;
|
|
180
|
+
/** Resolution scale (0.0 - 1.0) */
|
|
181
|
+
resolutionScale?: number;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// =============================================================================
|
|
185
|
+
// Event Types
|
|
186
|
+
// =============================================================================
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Event emitted when WebRTC stream state changes
|
|
190
|
+
*/
|
|
191
|
+
export interface WebRTCStreamEvent {
|
|
192
|
+
type: 'started' | 'stopped' | 'error' | 'stats';
|
|
193
|
+
timestamp: number;
|
|
194
|
+
error?: Error;
|
|
195
|
+
stats?: WebRTCStreamStats;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* ICE candidate event data
|
|
200
|
+
*/
|
|
201
|
+
export interface ICECandidateEvent {
|
|
202
|
+
/** The ICE candidate */
|
|
203
|
+
candidate: RTCIceCandidate | null;
|
|
204
|
+
/** SDP mid */
|
|
205
|
+
sdpMid?: string | null;
|
|
206
|
+
/** SDP m-line index */
|
|
207
|
+
sdpMLineIndex?: number | null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Session description for signaling
|
|
212
|
+
*/
|
|
213
|
+
export interface SessionDescription {
|
|
214
|
+
/** Type of description (offer/answer) */
|
|
215
|
+
type: 'offer' | 'answer';
|
|
216
|
+
/** SDP string */
|
|
217
|
+
sdp: string;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// =============================================================================
|
|
221
|
+
// Hook Options and Results
|
|
222
|
+
// =============================================================================
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Options for useWebRTC hook
|
|
226
|
+
*/
|
|
227
|
+
export interface UseWebRTCOptions {
|
|
228
|
+
/** Peer connection configuration */
|
|
229
|
+
config?: PeerConnectionConfig;
|
|
230
|
+
/** Media constraints for local stream */
|
|
231
|
+
mediaConstraints?: MediaConstraints;
|
|
232
|
+
/** Initial camera facing mode */
|
|
233
|
+
initialCamera?: 'front' | 'back';
|
|
234
|
+
/** Auto-start local stream when hook mounts */
|
|
235
|
+
autoStartLocalStream?: boolean;
|
|
236
|
+
/** Callback when call state changes */
|
|
237
|
+
onCallStateChange?: (state: CallState) => void;
|
|
238
|
+
/** Callback when connection state changes */
|
|
239
|
+
onConnectionStateChange?: (state: WebRTCConnectionState) => void;
|
|
240
|
+
/** Callback when ICE connection state changes */
|
|
241
|
+
onIceConnectionStateChange?: (state: ICEConnectionState) => void;
|
|
242
|
+
/** Callback when remote stream is received */
|
|
243
|
+
onRemoteStream?: (stream: MediaStream) => void;
|
|
244
|
+
/** Callback when remote stream is removed */
|
|
245
|
+
onRemoteStreamRemoved?: () => void;
|
|
246
|
+
/** Callback when an error occurs */
|
|
247
|
+
onError?: (error: Error) => void;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Result type for useWebRTC hook
|
|
252
|
+
*/
|
|
253
|
+
export interface UseWebRTCResult {
|
|
254
|
+
// Streams
|
|
255
|
+
/** Local media stream (camera + microphone) */
|
|
256
|
+
localStream: MediaStream | null;
|
|
257
|
+
/** Remote media stream from peer */
|
|
258
|
+
remoteStream: MediaStream | null;
|
|
259
|
+
|
|
260
|
+
// State
|
|
261
|
+
/** Current call state */
|
|
262
|
+
callState: CallState;
|
|
263
|
+
/** Whether local audio is enabled */
|
|
264
|
+
isAudioEnabled: boolean;
|
|
265
|
+
/** Whether local video is enabled */
|
|
266
|
+
isVideoEnabled: boolean;
|
|
267
|
+
/** Current camera facing mode */
|
|
268
|
+
currentCamera: 'front' | 'back';
|
|
269
|
+
/** Peer connection instance */
|
|
270
|
+
peerConnection: RTCPeerConnection | null;
|
|
271
|
+
|
|
272
|
+
// Local stream controls
|
|
273
|
+
/** Start local camera/microphone stream */
|
|
274
|
+
startLocalStream: () => Promise<void>;
|
|
275
|
+
/** Stop local stream */
|
|
276
|
+
stopLocalStream: () => void;
|
|
277
|
+
/** Switch between front and back camera */
|
|
278
|
+
switchCamera: () => Promise<void>;
|
|
279
|
+
/** Toggle local audio on/off */
|
|
280
|
+
toggleAudio: () => void;
|
|
281
|
+
/** Toggle local video on/off */
|
|
282
|
+
toggleVideo: () => void;
|
|
283
|
+
|
|
284
|
+
// Peer connection management
|
|
285
|
+
/** Create a new peer connection */
|
|
286
|
+
createPeerConnection: (config?: PeerConnectionConfig) => RTCPeerConnection;
|
|
287
|
+
/** Close the peer connection */
|
|
288
|
+
closePeerConnection: () => void;
|
|
289
|
+
|
|
290
|
+
// Signaling helpers (user integrates with their signaling server)
|
|
291
|
+
/** Create an SDP offer */
|
|
292
|
+
createOffer: () => Promise<SessionDescription>;
|
|
293
|
+
/** Create an SDP answer */
|
|
294
|
+
createAnswer: () => Promise<SessionDescription>;
|
|
295
|
+
/** Set the remote SDP description */
|
|
296
|
+
setRemoteDescription: (description: SessionDescription) => Promise<void>;
|
|
297
|
+
/** Add an ICE candidate from remote peer */
|
|
298
|
+
addIceCandidate: (candidate: RTCIceCandidate) => Promise<void>;
|
|
299
|
+
/** Register callback for ICE candidates to send to remote peer */
|
|
300
|
+
onIceCandidate: (callback: (candidate: ICECandidateEvent) => void) => void;
|
|
301
|
+
|
|
302
|
+
// Cleanup
|
|
303
|
+
/** Clean up all resources */
|
|
304
|
+
cleanup: () => void;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Options for useWebRTCWithDetection hook
|
|
309
|
+
*/
|
|
310
|
+
export interface UseWebRTCWithDetectionOptions extends UseWebRTCOptions {
|
|
311
|
+
/** Face detection options */
|
|
312
|
+
faceDetection?: {
|
|
313
|
+
enabled?: boolean;
|
|
314
|
+
performanceMode?: 'fast' | 'accurate';
|
|
315
|
+
landmarkMode?: 'none' | 'all';
|
|
316
|
+
classificationMode?: 'none' | 'all';
|
|
317
|
+
};
|
|
318
|
+
/** Eye tracking options */
|
|
319
|
+
eyeTracking?: {
|
|
320
|
+
enabled?: boolean;
|
|
321
|
+
eyeClosedThreshold?: number;
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// =============================================================================
|
|
326
|
+
// Default Configurations
|
|
327
|
+
// =============================================================================
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Default ICE servers (Google STUN servers)
|
|
331
|
+
*/
|
|
332
|
+
export const DEFAULT_ICE_SERVERS: ICEServer[] = [
|
|
333
|
+
{ urls: 'stun:stun.l.google.com:19302' },
|
|
334
|
+
{ urls: 'stun:stun1.l.google.com:19302' },
|
|
335
|
+
];
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Default peer connection configuration
|
|
339
|
+
*/
|
|
340
|
+
export const DEFAULT_PEER_CONNECTION_CONFIG: PeerConnectionConfig = {
|
|
341
|
+
iceServers: DEFAULT_ICE_SERVERS,
|
|
342
|
+
iceTransportPolicy: 'all',
|
|
343
|
+
bundlePolicy: 'balanced',
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Default media constraints
|
|
348
|
+
*/
|
|
349
|
+
export const DEFAULT_MEDIA_CONSTRAINTS: MediaConstraints = {
|
|
350
|
+
video: {
|
|
351
|
+
width: { ideal: 1280 },
|
|
352
|
+
height: { ideal: 720 },
|
|
353
|
+
frameRate: { ideal: 30 },
|
|
354
|
+
facingMode: 'user',
|
|
355
|
+
},
|
|
356
|
+
audio: {
|
|
357
|
+
echoCancellation: true,
|
|
358
|
+
noiseSuppression: true,
|
|
359
|
+
autoGainControl: true,
|
|
360
|
+
},
|
|
361
|
+
};
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
package expo.modules.smartcamera
|
|
2
|
-
|
|
3
|
-
import android.graphics.Bitmap
|
|
4
|
-
import android.graphics.BitmapFactory
|
|
5
|
-
import android.net.Uri
|
|
6
|
-
import android.util.Base64
|
|
7
|
-
import android.util.Log
|
|
8
|
-
import kotlinx.coroutines.Dispatchers
|
|
9
|
-
import kotlinx.coroutines.withContext
|
|
10
|
-
import java.io.File
|
|
11
|
-
import java.net.URL
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Utility class for loading images from various sources
|
|
15
|
-
*/
|
|
16
|
-
class ImageLoader {
|
|
17
|
-
companion object {
|
|
18
|
-
private const val TAG = "ImageLoader"
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Load an image from various sources (suspending function for async loading)
|
|
23
|
-
*
|
|
24
|
-
* @param source Image source - can be String URI, Map with "uri" key, or resource ID
|
|
25
|
-
* @return Bitmap
|
|
26
|
-
* @throws IllegalArgumentException if the source is invalid
|
|
27
|
-
*/
|
|
28
|
-
suspend fun loadImage(source: Any): Bitmap = withContext(Dispatchers.IO) {
|
|
29
|
-
when (source) {
|
|
30
|
-
is String -> loadFromString(source)
|
|
31
|
-
is Map<*, *> -> {
|
|
32
|
-
val uri = source["uri"] as? String
|
|
33
|
-
val base64 = source["base64"] as? String
|
|
34
|
-
|
|
35
|
-
when {
|
|
36
|
-
uri != null -> loadFromString(uri)
|
|
37
|
-
base64 != null -> loadFromBase64(base64)
|
|
38
|
-
else -> throw IllegalArgumentException("Invalid image source map - must contain 'uri' or 'base64'")
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
is Number -> throw IllegalArgumentException("Loading from resource ID not supported. Use a URI instead.")
|
|
42
|
-
else -> throw IllegalArgumentException("Unsupported image source type: ${source::class.java.simpleName}")
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
private fun loadFromString(source: String): Bitmap {
|
|
47
|
-
return when {
|
|
48
|
-
source.startsWith("data:image") -> {
|
|
49
|
-
// Base64 data URI
|
|
50
|
-
val base64Data = source.substringAfter("base64,")
|
|
51
|
-
loadFromBase64(base64Data)
|
|
52
|
-
}
|
|
53
|
-
source.startsWith("http://") || source.startsWith("https://") -> {
|
|
54
|
-
loadFromUrl(source)
|
|
55
|
-
}
|
|
56
|
-
source.startsWith("file://") -> {
|
|
57
|
-
loadFromFile(source.removePrefix("file://"))
|
|
58
|
-
}
|
|
59
|
-
else -> {
|
|
60
|
-
// Try as file path
|
|
61
|
-
loadFromFile(source)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
private fun loadFromBase64(base64: String): Bitmap {
|
|
67
|
-
return try {
|
|
68
|
-
val decodedBytes = Base64.decode(base64, Base64.DEFAULT)
|
|
69
|
-
BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size)
|
|
70
|
-
?: throw IllegalStateException("Failed to decode base64 image data")
|
|
71
|
-
} catch (e: Exception) {
|
|
72
|
-
Log.e(TAG, "Failed to decode base64 image", e)
|
|
73
|
-
throw IllegalArgumentException("Failed to decode base64 image: ${e.message}", e)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
private fun loadFromUrl(url: String): Bitmap {
|
|
78
|
-
return try {
|
|
79
|
-
val connection = URL(url).openConnection()
|
|
80
|
-
connection.connectTimeout = 10000
|
|
81
|
-
connection.readTimeout = 30000
|
|
82
|
-
connection.doInput = true
|
|
83
|
-
connection.connect()
|
|
84
|
-
val inputStream = connection.getInputStream()
|
|
85
|
-
BitmapFactory.decodeStream(inputStream)
|
|
86
|
-
?: throw IllegalStateException("Failed to decode image from URL")
|
|
87
|
-
} catch (e: Exception) {
|
|
88
|
-
Log.e(TAG, "Failed to load image from URL: $url", e)
|
|
89
|
-
throw IllegalArgumentException("Failed to load image from URL: ${e.message}", e)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private fun loadFromFile(path: String): Bitmap {
|
|
94
|
-
return try {
|
|
95
|
-
val file = File(path)
|
|
96
|
-
if (!file.exists()) {
|
|
97
|
-
throw IllegalArgumentException("File not found: $path")
|
|
98
|
-
}
|
|
99
|
-
BitmapFactory.decodeFile(path)
|
|
100
|
-
?: throw IllegalStateException("Failed to decode image from file")
|
|
101
|
-
} catch (e: Exception) {
|
|
102
|
-
Log.e(TAG, "Failed to load image from file: $path", e)
|
|
103
|
-
throw IllegalArgumentException("Failed to load image from file: ${e.message}", e)
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|