@succinctlabs/react-native-zcam1 0.2.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/README.md +61 -0
- package/Zcam1Sdk.podspec +157 -0
- package/app.plugin.js +11 -0
- package/cpp/generated/zcam1_c2pa_utils.cpp +4091 -0
- package/cpp/generated/zcam1_c2pa_utils.hpp +367 -0
- package/cpp/generated/zcam1_certs_utils.cpp +1799 -0
- package/cpp/generated/zcam1_certs_utils.hpp +72 -0
- package/cpp/generated/zcam1_verify_utils.cpp +1857 -0
- package/cpp/generated/zcam1_verify_utils.hpp +79 -0
- package/cpp/proving/generated/zcam1_proving_utils.cpp +3661 -0
- package/cpp/proving/generated/zcam1_proving_utils.hpp +275 -0
- package/cpp/proving/zcam1-proving.cpp +16 -0
- package/cpp/proving/zcam1-proving.h +15 -0
- package/cpp/zcam1-sdk.cpp +20 -0
- package/cpp/zcam1-sdk.h +15 -0
- package/ios/Zcam1Camera.swift +2945 -0
- package/ios/Zcam1CameraFilmStyle.swift +191 -0
- package/ios/Zcam1CameraViewManager.m +86 -0
- package/ios/Zcam1Capture.h +13 -0
- package/ios/Zcam1Capture.mm +500 -0
- package/ios/Zcam1DepthData.swift +417 -0
- package/ios/Zcam1Sdk.h +16 -0
- package/ios/Zcam1Sdk.mm +66 -0
- package/ios/proving/Zcam1Proving.h +16 -0
- package/ios/proving/Zcam1Proving.mm +66 -0
- package/lib/module/NativeZcam1Capture.js +12 -0
- package/lib/module/NativeZcam1Capture.js.map +1 -0
- package/lib/module/NativeZcam1Sdk.js +7 -0
- package/lib/module/NativeZcam1Sdk.js.map +1 -0
- package/lib/module/bindings.js +51 -0
- package/lib/module/bindings.js.map +1 -0
- package/lib/module/camera.js +522 -0
- package/lib/module/camera.js.map +1 -0
- package/lib/module/capture.js +120 -0
- package/lib/module/capture.js.map +1 -0
- package/lib/module/common.js +35 -0
- package/lib/module/common.js.map +1 -0
- package/lib/module/generated/zcam1_c2pa_utils-ffi.js +43 -0
- package/lib/module/generated/zcam1_c2pa_utils-ffi.js.map +1 -0
- package/lib/module/generated/zcam1_c2pa_utils.js +1202 -0
- package/lib/module/generated/zcam1_c2pa_utils.js.map +1 -0
- package/lib/module/generated/zcam1_certs_utils-ffi.js +43 -0
- package/lib/module/generated/zcam1_certs_utils-ffi.js.map +1 -0
- package/lib/module/generated/zcam1_certs_utils.js +399 -0
- package/lib/module/generated/zcam1_certs_utils.js.map +1 -0
- package/lib/module/generated/zcam1_proving_utils-ffi.js +43 -0
- package/lib/module/generated/zcam1_proving_utils-ffi.js.map +1 -0
- package/lib/module/generated/zcam1_proving_utils.js +515 -0
- package/lib/module/generated/zcam1_proving_utils.js.map +1 -0
- package/lib/module/generated/zcam1_verify_utils-ffi.js +43 -0
- package/lib/module/generated/zcam1_verify_utils-ffi.js.map +1 -0
- package/lib/module/generated/zcam1_verify_utils.js +252 -0
- package/lib/module/generated/zcam1_verify_utils.js.map +1 -0
- package/lib/module/index.js +31 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/picker.js +222 -0
- package/lib/module/picker.js.map +1 -0
- package/lib/module/proving/NativeZcam1Proving.js +7 -0
- package/lib/module/proving/NativeZcam1Proving.js.map +1 -0
- package/lib/module/proving/bindings.js +46 -0
- package/lib/module/proving/bindings.js.map +1 -0
- package/lib/module/proving/index.js +5 -0
- package/lib/module/proving/index.js.map +1 -0
- package/lib/module/proving/prove.js +346 -0
- package/lib/module/proving/prove.js.map +1 -0
- package/lib/module/utils.js +27 -0
- package/lib/module/utils.js.map +1 -0
- package/lib/module/verify.js +82 -0
- package/lib/module/verify.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeZcam1Capture.d.ts +280 -0
- package/lib/typescript/src/NativeZcam1Capture.d.ts.map +1 -0
- package/lib/typescript/src/NativeZcam1Sdk.d.ts +8 -0
- package/lib/typescript/src/NativeZcam1Sdk.d.ts.map +1 -0
- package/lib/typescript/src/bindings.d.ts +14 -0
- package/lib/typescript/src/bindings.d.ts.map +1 -0
- package/lib/typescript/src/camera.d.ts +300 -0
- package/lib/typescript/src/camera.d.ts.map +1 -0
- package/lib/typescript/src/capture.d.ts +59 -0
- package/lib/typescript/src/capture.d.ts.map +1 -0
- package/lib/typescript/src/common.d.ts +10 -0
- package/lib/typescript/src/common.d.ts.map +1 -0
- package/lib/typescript/src/generated/zcam1_c2pa_utils-ffi.d.ts +175 -0
- package/lib/typescript/src/generated/zcam1_c2pa_utils-ffi.d.ts.map +1 -0
- package/lib/typescript/src/generated/zcam1_c2pa_utils.d.ts +811 -0
- package/lib/typescript/src/generated/zcam1_c2pa_utils.d.ts.map +1 -0
- package/lib/typescript/src/generated/zcam1_certs_utils-ffi.d.ts +82 -0
- package/lib/typescript/src/generated/zcam1_certs_utils-ffi.d.ts.map +1 -0
- package/lib/typescript/src/generated/zcam1_certs_utils.d.ts +413 -0
- package/lib/typescript/src/generated/zcam1_certs_utils.d.ts.map +1 -0
- package/lib/typescript/src/generated/zcam1_proving_utils-ffi.d.ts +153 -0
- package/lib/typescript/src/generated/zcam1_proving_utils-ffi.d.ts.map +1 -0
- package/lib/typescript/src/generated/zcam1_proving_utils.d.ts +321 -0
- package/lib/typescript/src/generated/zcam1_proving_utils.d.ts.map +1 -0
- package/lib/typescript/src/generated/zcam1_verify_utils-ffi.d.ts +84 -0
- package/lib/typescript/src/generated/zcam1_verify_utils-ffi.d.ts.map +1 -0
- package/lib/typescript/src/generated/zcam1_verify_utils.d.ts +286 -0
- package/lib/typescript/src/generated/zcam1_verify_utils.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +29 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/picker.d.ts +103 -0
- package/lib/typescript/src/picker.d.ts.map +1 -0
- package/lib/typescript/src/proving/NativeZcam1Proving.d.ts +8 -0
- package/lib/typescript/src/proving/NativeZcam1Proving.d.ts.map +1 -0
- package/lib/typescript/src/proving/bindings.d.ts +8 -0
- package/lib/typescript/src/proving/bindings.d.ts.map +1 -0
- package/lib/typescript/src/proving/index.d.ts +3 -0
- package/lib/typescript/src/proving/index.d.ts.map +1 -0
- package/lib/typescript/src/proving/prove.d.ts +74 -0
- package/lib/typescript/src/proving/prove.d.ts.map +1 -0
- package/lib/typescript/src/utils.d.ts +2 -0
- package/lib/typescript/src/utils.d.ts.map +1 -0
- package/lib/typescript/src/verify.d.ts +45 -0
- package/lib/typescript/src/verify.d.ts.map +1 -0
- package/package.json +118 -0
- package/src/NativeZcam1Capture.ts +335 -0
- package/src/NativeZcam1Sdk.ts +10 -0
- package/src/bindings.tsx +49 -0
- package/src/camera.tsx +705 -0
- package/src/capture.tsx +165 -0
- package/src/common.tsx +46 -0
- package/src/generated/zcam1_c2pa_utils-ffi.ts +456 -0
- package/src/generated/zcam1_c2pa_utils.ts +1866 -0
- package/src/generated/zcam1_certs_utils-ffi.ts +187 -0
- package/src/generated/zcam1_certs_utils.ts +549 -0
- package/src/generated/zcam1_proving_utils-ffi.ts +374 -0
- package/src/generated/zcam1_proving_utils.ts +804 -0
- package/src/generated/zcam1_verify_utils-ffi.ts +196 -0
- package/src/generated/zcam1_verify_utils.ts +372 -0
- package/src/index.ts +73 -0
- package/src/picker.tsx +342 -0
- package/src/proving/NativeZcam1Proving.ts +10 -0
- package/src/proving/bindings.tsx +50 -0
- package/src/proving/index.ts +8 -0
- package/src/proving/prove.tsx +492 -0
- package/src/utils.ts +38 -0
- package/src/verify.tsx +119 -0
- package/turbo.json +27 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Zcam1DepthData.swift
|
|
3
|
+
// react-native-zcam1-sdk
|
|
4
|
+
//
|
|
5
|
+
// Depth data extraction and processing using AVDepthData.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import AVFoundation
|
|
9
|
+
import Foundation
|
|
10
|
+
import ImageIO
|
|
11
|
+
import UIKit
|
|
12
|
+
|
|
13
|
+
// MARK: - Depth Data Processor
|
|
14
|
+
|
|
15
|
+
/// Handles extraction, conversion, and serialization of depth data from AVDepthData.
|
|
16
|
+
public class Zcam1DepthDataProcessor {
|
|
17
|
+
|
|
18
|
+
/// Extract depth data from an AVCapturePhoto if available.
|
|
19
|
+
/// Returns a dictionary containing depth information or nil if not available.
|
|
20
|
+
public static func extractDepthData(from photo: AVCapturePhoto) -> [String: Any]? {
|
|
21
|
+
guard let depthData = photo.depthData else {
|
|
22
|
+
return nil
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return processDepthData(depthData)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// Process AVDepthData and return a dictionary with depth information.
|
|
29
|
+
public static func processDepthData(_ depthData: AVDepthData) -> [String: Any] {
|
|
30
|
+
let depthDataMap = depthData.depthDataMap
|
|
31
|
+
|
|
32
|
+
// Get depth data dimensions
|
|
33
|
+
let width = CVPixelBufferGetWidth(depthDataMap)
|
|
34
|
+
let height = CVPixelBufferGetHeight(depthDataMap)
|
|
35
|
+
|
|
36
|
+
// Get pixel format type
|
|
37
|
+
let pixelFormatType = CVPixelBufferGetPixelFormatType(depthDataMap)
|
|
38
|
+
let pixelFormatString = pixelFormatTypeToString(pixelFormatType)
|
|
39
|
+
|
|
40
|
+
// Extract depth statistics
|
|
41
|
+
let statistics = extractDepthStatistics(from: depthDataMap)
|
|
42
|
+
|
|
43
|
+
// Get accuracy if available (iOS 14.1+)
|
|
44
|
+
var accuracyString = "relative"
|
|
45
|
+
if #available(iOS 14.1, *) {
|
|
46
|
+
switch depthData.depthDataAccuracy {
|
|
47
|
+
case .relative:
|
|
48
|
+
accuracyString = "relative"
|
|
49
|
+
case .absolute:
|
|
50
|
+
accuracyString = "absolute"
|
|
51
|
+
@unknown default:
|
|
52
|
+
accuracyString = "unknown"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
var result: [String: Any] = [
|
|
57
|
+
"width": width,
|
|
58
|
+
"height": height,
|
|
59
|
+
"pixelFormat": pixelFormatString,
|
|
60
|
+
"statistics": statistics,
|
|
61
|
+
"accuracy": accuracyString,
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
return result
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// Extract statistics (min, max, mean, stddev) from depth data.
|
|
68
|
+
///
|
|
69
|
+
/// Computing stats over every pixel can be expensive and can delay photo capture completion,
|
|
70
|
+
/// especially when depth delivery is enabled. To keep capture responsive, this uses:
|
|
71
|
+
/// - adaptive sampling (caps work to ~65k pixels)
|
|
72
|
+
/// - a single-pass (Welford) accumulator (avoids large allocations)
|
|
73
|
+
private static func extractDepthStatistics(from depthDataMap: CVPixelBuffer) -> [String: Any] {
|
|
74
|
+
let width = CVPixelBufferGetWidth(depthDataMap)
|
|
75
|
+
let height = CVPixelBufferGetHeight(depthDataMap)
|
|
76
|
+
let pixelFormatType = CVPixelBufferGetPixelFormatType(depthDataMap)
|
|
77
|
+
|
|
78
|
+
// Cap work by sampling at most ~65k pixels.
|
|
79
|
+
let totalPixels = max(1, width * height)
|
|
80
|
+
let maxSamples = 65_536
|
|
81
|
+
let stride: Int = {
|
|
82
|
+
if totalPixels <= maxSamples { return 1 }
|
|
83
|
+
// Choose a stride so that (w/stride)*(h/stride) ~= maxSamples.
|
|
84
|
+
let scale = sqrt(Double(totalPixels) / Double(maxSamples))
|
|
85
|
+
return max(1, Int(scale.rounded(.up)))
|
|
86
|
+
}()
|
|
87
|
+
|
|
88
|
+
CVPixelBufferLockBaseAddress(depthDataMap, .readOnly)
|
|
89
|
+
defer { CVPixelBufferUnlockBaseAddress(depthDataMap, .readOnly) }
|
|
90
|
+
|
|
91
|
+
guard let baseAddress = CVPixelBufferGetBaseAddress(depthDataMap) else {
|
|
92
|
+
return [:]
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let bytesPerRow = CVPixelBufferGetBytesPerRow(depthDataMap)
|
|
96
|
+
|
|
97
|
+
var count: Int = 0
|
|
98
|
+
var mean: Double = 0
|
|
99
|
+
var m2: Double = 0
|
|
100
|
+
var minValue: Float = .infinity
|
|
101
|
+
var maxValue: Float = -.infinity
|
|
102
|
+
|
|
103
|
+
func accumulate(_ v: Float) {
|
|
104
|
+
guard v.isFinite else { return }
|
|
105
|
+
count += 1
|
|
106
|
+
minValue = min(minValue, v)
|
|
107
|
+
maxValue = max(maxValue, v)
|
|
108
|
+
|
|
109
|
+
let x = Double(v)
|
|
110
|
+
let delta = x - mean
|
|
111
|
+
mean += delta / Double(count)
|
|
112
|
+
let delta2 = x - mean
|
|
113
|
+
m2 += delta * delta2
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Extract depth values based on pixel format (sampled).
|
|
117
|
+
switch pixelFormatType {
|
|
118
|
+
case kCVPixelFormatType_DepthFloat32, kCVPixelFormatType_DisparityFloat32:
|
|
119
|
+
let floatBuffer = baseAddress.assumingMemoryBound(to: Float32.self)
|
|
120
|
+
let rowStride = bytesPerRow / MemoryLayout<Float32>.stride
|
|
121
|
+
var y = 0
|
|
122
|
+
while y < height {
|
|
123
|
+
let rowBase = y * rowStride
|
|
124
|
+
var x = 0
|
|
125
|
+
while x < width {
|
|
126
|
+
accumulate(floatBuffer[rowBase + x])
|
|
127
|
+
x += stride
|
|
128
|
+
}
|
|
129
|
+
y += stride
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
case kCVPixelFormatType_DepthFloat16, kCVPixelFormatType_DisparityFloat16:
|
|
133
|
+
let float16Buffer = baseAddress.assumingMemoryBound(to: Float16.self)
|
|
134
|
+
let rowStride = bytesPerRow / MemoryLayout<Float16>.stride
|
|
135
|
+
var y = 0
|
|
136
|
+
while y < height {
|
|
137
|
+
let rowBase = y * rowStride
|
|
138
|
+
var x = 0
|
|
139
|
+
while x < width {
|
|
140
|
+
accumulate(Float(float16Buffer[rowBase + x]))
|
|
141
|
+
x += stride
|
|
142
|
+
}
|
|
143
|
+
y += stride
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
default:
|
|
147
|
+
break
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Calculate statistics
|
|
151
|
+
guard count > 0 else {
|
|
152
|
+
return [
|
|
153
|
+
"min": "",
|
|
154
|
+
"max": "",
|
|
155
|
+
"mean": "",
|
|
156
|
+
"stdDev": "",
|
|
157
|
+
"validPixelCount": 0,
|
|
158
|
+
"sampleStride": stride,
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let variance = m2 / Double(count)
|
|
163
|
+
let stdDev = sqrt(max(0, variance))
|
|
164
|
+
|
|
165
|
+
return [
|
|
166
|
+
"min": String(
|
|
167
|
+
format: "%.6f", locale: Locale(identifier: "en_US_POSIX"), Double(minValue)),
|
|
168
|
+
"max": String(
|
|
169
|
+
format: "%.6f", locale: Locale(identifier: "en_US_POSIX"), Double(maxValue)),
|
|
170
|
+
"mean": String(format: "%.6f", locale: Locale(identifier: "en_US_POSIX"), mean),
|
|
171
|
+
"stdDev": String(format: "%.6f", locale: Locale(identifier: "en_US_POSIX"), stdDev),
|
|
172
|
+
"validPixelCount": count,
|
|
173
|
+
"sampleStride": stride,
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/// Extract camera calibration data.
|
|
178
|
+
private static func extractCalibrationData(_ calibration: AVCameraCalibrationData) -> [String:
|
|
179
|
+
Any]
|
|
180
|
+
{
|
|
181
|
+
var result: [String: Any] = [:]
|
|
182
|
+
|
|
183
|
+
// Intrinsic matrix (3x3) - camera intrinsic parameters
|
|
184
|
+
// Intrinsic matrix (3x3)
|
|
185
|
+
let intrinsicMatrix = calibration.intrinsicMatrix
|
|
186
|
+
result["intrinsicMatrix"] = [
|
|
187
|
+
[intrinsicMatrix[0, 0], intrinsicMatrix[0, 1], intrinsicMatrix[0, 2]],
|
|
188
|
+
[intrinsicMatrix[1, 0], intrinsicMatrix[1, 1], intrinsicMatrix[1, 2]],
|
|
189
|
+
[intrinsicMatrix[2, 0], intrinsicMatrix[2, 1], intrinsicMatrix[2, 2]],
|
|
190
|
+
]
|
|
191
|
+
|
|
192
|
+
// Extrinsic matrix (4x3)
|
|
193
|
+
let extrinsicMatrix = calibration.extrinsicMatrix
|
|
194
|
+
result["extrinsicMatrix"] = [
|
|
195
|
+
[extrinsicMatrix[0, 0], extrinsicMatrix[0, 1], extrinsicMatrix[0, 2]],
|
|
196
|
+
[extrinsicMatrix[1, 0], extrinsicMatrix[1, 1], extrinsicMatrix[1, 2]],
|
|
197
|
+
[extrinsicMatrix[2, 0], extrinsicMatrix[2, 1], extrinsicMatrix[2, 2]],
|
|
198
|
+
[extrinsicMatrix[3, 0], extrinsicMatrix[3, 1], extrinsicMatrix[3, 2]],
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
// Lens distortion center
|
|
202
|
+
let lensDistortionCenter = calibration.lensDistortionCenter
|
|
203
|
+
result["lensDistortionCenter"] = [
|
|
204
|
+
"x": lensDistortionCenter.x,
|
|
205
|
+
"y": lensDistortionCenter.y,
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
return result
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/// Convert pixel format type to a human-readable string.
|
|
212
|
+
private static func pixelFormatTypeToString(_ pixelFormatType: OSType) -> String {
|
|
213
|
+
switch pixelFormatType {
|
|
214
|
+
case kCVPixelFormatType_DepthFloat32:
|
|
215
|
+
return "depthFloat32"
|
|
216
|
+
case kCVPixelFormatType_DepthFloat16:
|
|
217
|
+
return "depthFloat16"
|
|
218
|
+
case kCVPixelFormatType_DisparityFloat32:
|
|
219
|
+
return "disparityFloat32"
|
|
220
|
+
case kCVPixelFormatType_DisparityFloat16:
|
|
221
|
+
return "disparityFloat16"
|
|
222
|
+
default:
|
|
223
|
+
return "unknown"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/// Encode depth data as a grayscale image for visualization.
|
|
228
|
+
///
|
|
229
|
+
/// The output is encoded to match Google's GDepth `RangeInverse` convention:
|
|
230
|
+
/// values are higher (brighter) for nearer pixels and lower (darker) for farther pixels.
|
|
231
|
+
public static func encodeDepthDataAsImage(
|
|
232
|
+
depthData: AVDepthData
|
|
233
|
+
) -> UIImage? {
|
|
234
|
+
let depthDataMap = depthData.depthDataMap
|
|
235
|
+
let width = CVPixelBufferGetWidth(depthDataMap)
|
|
236
|
+
let height = CVPixelBufferGetHeight(depthDataMap)
|
|
237
|
+
|
|
238
|
+
CVPixelBufferLockBaseAddress(depthDataMap, .readOnly)
|
|
239
|
+
defer { CVPixelBufferUnlockBaseAddress(depthDataMap, .readOnly) }
|
|
240
|
+
|
|
241
|
+
guard let baseAddress = CVPixelBufferGetBaseAddress(depthDataMap) else {
|
|
242
|
+
return nil
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
let pixelFormatType = CVPixelBufferGetPixelFormatType(depthDataMap)
|
|
246
|
+
let bytesPerRow = CVPixelBufferGetBytesPerRow(depthDataMap)
|
|
247
|
+
|
|
248
|
+
// Extract depth values and find their range
|
|
249
|
+
var depthValues: [Float] = []
|
|
250
|
+
depthValues.reserveCapacity(width * height)
|
|
251
|
+
var minDepth: Float = .infinity
|
|
252
|
+
var maxDepth: Float = -.infinity
|
|
253
|
+
|
|
254
|
+
switch pixelFormatType {
|
|
255
|
+
case kCVPixelFormatType_DepthFloat32, kCVPixelFormatType_DisparityFloat32:
|
|
256
|
+
let floatBuffer = baseAddress.assumingMemoryBound(to: Float32.self)
|
|
257
|
+
for y in 0..<height {
|
|
258
|
+
for x in 0..<width {
|
|
259
|
+
let offset = y * (bytesPerRow / MemoryLayout<Float32>.stride) + x
|
|
260
|
+
let value = floatBuffer[offset]
|
|
261
|
+
if !value.isNaN && !value.isInfinite {
|
|
262
|
+
depthValues.append(value)
|
|
263
|
+
// Ignore non-positive values when establishing near/far planes,
|
|
264
|
+
// since RangeInverse uses 1/depth.
|
|
265
|
+
if value > 0 {
|
|
266
|
+
minDepth = min(minDepth, value)
|
|
267
|
+
maxDepth = max(maxDepth, value)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
case kCVPixelFormatType_DepthFloat16, kCVPixelFormatType_DisparityFloat16:
|
|
274
|
+
let float16Buffer = baseAddress.assumingMemoryBound(to: Float16.self)
|
|
275
|
+
for y in 0..<height {
|
|
276
|
+
for x in 0..<width {
|
|
277
|
+
let offset = y * (bytesPerRow / MemoryLayout<Float16>.stride) + x
|
|
278
|
+
let value = Float(float16Buffer[offset])
|
|
279
|
+
if !value.isNaN && !value.isInfinite {
|
|
280
|
+
depthValues.append(value)
|
|
281
|
+
// Ignore non-positive values when establishing near/far planes,
|
|
282
|
+
// since RangeInverse uses 1/depth.
|
|
283
|
+
if value > 0 {
|
|
284
|
+
minDepth = min(minDepth, value)
|
|
285
|
+
maxDepth = max(maxDepth, value)
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
default:
|
|
292
|
+
return nil
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Create grayscale image from normalized depth data
|
|
296
|
+
guard !depthValues.isEmpty else { return nil }
|
|
297
|
+
|
|
298
|
+
// If we never saw any positive finite values, near/far planes are not usable.
|
|
299
|
+
if !minDepth.isFinite || !maxDepth.isFinite || minDepth <= 0 || maxDepth <= 0 {
|
|
300
|
+
minDepth = 0
|
|
301
|
+
maxDepth = 0
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
let depthRange = maxDepth - minDepth
|
|
305
|
+
var pixelData = [UInt8]()
|
|
306
|
+
pixelData.reserveCapacity(width * height)
|
|
307
|
+
|
|
308
|
+
switch pixelFormatType {
|
|
309
|
+
case kCVPixelFormatType_DepthFloat32, kCVPixelFormatType_DisparityFloat32:
|
|
310
|
+
let floatBuffer = baseAddress.assumingMemoryBound(to: Float32.self)
|
|
311
|
+
for y in 0..<height {
|
|
312
|
+
for x in 0..<width {
|
|
313
|
+
let offset = y * (bytesPerRow / MemoryLayout<Float32>.stride) + x
|
|
314
|
+
let value = floatBuffer[offset]
|
|
315
|
+
if value.isNaN || value.isInfinite || value <= 0 {
|
|
316
|
+
pixelData.append(0)
|
|
317
|
+
continue
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// RangeInverse: normalize in inverse-depth space (1/z), so nearer pixels are brighter.
|
|
321
|
+
let normalized: Float
|
|
322
|
+
if depthRange > 0, minDepth > 0, maxDepth > 0 {
|
|
323
|
+
let inv = 1.0 / value
|
|
324
|
+
let invNear = 1.0 / minDepth
|
|
325
|
+
let invFar = 1.0 / maxDepth
|
|
326
|
+
let invRange = invNear - invFar
|
|
327
|
+
|
|
328
|
+
if inv.isFinite, invNear.isFinite, invFar.isFinite, invRange != 0 {
|
|
329
|
+
normalized = (inv - invFar) / invRange
|
|
330
|
+
} else {
|
|
331
|
+
normalized = 0
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
normalized = 0
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if !normalized.isFinite {
|
|
338
|
+
pixelData.append(0)
|
|
339
|
+
} else {
|
|
340
|
+
let clamped = max(0, min(1, normalized))
|
|
341
|
+
pixelData.append(UInt8(max(0, min(255, clamped * 255))))
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
case kCVPixelFormatType_DepthFloat16, kCVPixelFormatType_DisparityFloat16:
|
|
347
|
+
let float16Buffer = baseAddress.assumingMemoryBound(to: Float16.self)
|
|
348
|
+
for y in 0..<height {
|
|
349
|
+
for x in 0..<width {
|
|
350
|
+
let offset = y * (bytesPerRow / MemoryLayout<Float16>.stride) + x
|
|
351
|
+
let value = Float(float16Buffer[offset])
|
|
352
|
+
if value.isNaN || value.isInfinite || value <= 0 {
|
|
353
|
+
pixelData.append(0)
|
|
354
|
+
continue
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// RangeInverse: normalize in inverse-depth space (1/z), so nearer pixels are brighter.
|
|
358
|
+
let normalized: Float
|
|
359
|
+
if depthRange > 0, minDepth > 0, maxDepth > 0 {
|
|
360
|
+
let inv = 1.0 / value
|
|
361
|
+
let invNear = 1.0 / minDepth
|
|
362
|
+
let invFar = 1.0 / maxDepth
|
|
363
|
+
let invRange = invNear - invFar
|
|
364
|
+
|
|
365
|
+
if inv.isFinite, invNear.isFinite, invFar.isFinite, invRange != 0 {
|
|
366
|
+
normalized = (inv - invFar) / invRange
|
|
367
|
+
} else {
|
|
368
|
+
normalized = 0
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
normalized = 0
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if !normalized.isFinite {
|
|
375
|
+
pixelData.append(0)
|
|
376
|
+
} else {
|
|
377
|
+
let clamped = max(0, min(1, normalized))
|
|
378
|
+
pixelData.append(UInt8(max(0, min(255, clamped * 255))))
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
default:
|
|
384
|
+
return nil
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Create CGImage from pixel data
|
|
388
|
+
guard
|
|
389
|
+
let provider = CGDataProvider(
|
|
390
|
+
data: NSData(bytes: pixelData, length: pixelData.count))
|
|
391
|
+
else {
|
|
392
|
+
return nil
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
let colorSpace = CGColorSpaceCreateDeviceGray()
|
|
396
|
+
guard
|
|
397
|
+
let cgImage = CGImage(
|
|
398
|
+
width: width,
|
|
399
|
+
height: height,
|
|
400
|
+
bitsPerComponent: 8,
|
|
401
|
+
bitsPerPixel: 8,
|
|
402
|
+
bytesPerRow: width,
|
|
403
|
+
space: colorSpace,
|
|
404
|
+
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
|
|
405
|
+
provider: provider,
|
|
406
|
+
decode: nil,
|
|
407
|
+
shouldInterpolate: false,
|
|
408
|
+
intent: .defaultIntent
|
|
409
|
+
)
|
|
410
|
+
else {
|
|
411
|
+
return nil
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return UIImage(cgImage: cgImage)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
}
|
package/ios/Zcam1Sdk.h
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Generated by uniffi-bindgen-react-native
|
|
2
|
+
#ifdef __cplusplus
|
|
3
|
+
#import "zcam1-sdk.h"
|
|
4
|
+
#endif
|
|
5
|
+
|
|
6
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
7
|
+
#import "Zcam1SdkSpec.h"
|
|
8
|
+
|
|
9
|
+
@interface Zcam1Sdk : NSObject <NativeZcam1SdkSpec>
|
|
10
|
+
#else
|
|
11
|
+
#import <React/RCTBridgeModule.h>
|
|
12
|
+
|
|
13
|
+
@interface Zcam1Sdk : NSObject <RCTBridgeModule>
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
@end
|
package/ios/Zcam1Sdk.mm
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Generated by uniffi-bindgen-react-native
|
|
2
|
+
#import "Zcam1Sdk.h"
|
|
3
|
+
|
|
4
|
+
namespace uniffi_generated {
|
|
5
|
+
using namespace facebook::react;
|
|
6
|
+
/**
|
|
7
|
+
* ObjC++ class for module 'NativeZcam1Sdk'
|
|
8
|
+
*/
|
|
9
|
+
class JSI_EXPORT NativeZcam1SdkSpecJSI : public ObjCTurboModule {
|
|
10
|
+
public:
|
|
11
|
+
NativeZcam1SdkSpecJSI(const ObjCTurboModule::InitParams ¶ms);
|
|
12
|
+
std::shared_ptr<CallInvoker> callInvoker;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
static facebook::jsi::Value __hostFunction_Zcam1Sdk_installRustCrate(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
16
|
+
auto& tm = static_cast<NativeZcam1SdkSpecJSI&>(turboModule);
|
|
17
|
+
auto jsInvoker = tm.callInvoker;
|
|
18
|
+
uint8_t result = zcam1sdk::installRustCrate(rt, jsInvoker);
|
|
19
|
+
return facebook::jsi::Value(rt, result);
|
|
20
|
+
}
|
|
21
|
+
static facebook::jsi::Value __hostFunction_Zcam1Sdk_cleanupRustCrate(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
22
|
+
uint8_t result = zcam1sdk::cleanupRustCrate(rt);
|
|
23
|
+
return facebook::jsi::Value(rt, result);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
NativeZcam1SdkSpecJSI::NativeZcam1SdkSpecJSI(const ObjCTurboModule::InitParams ¶ms)
|
|
27
|
+
: ObjCTurboModule(params), callInvoker(params.jsInvoker) {
|
|
28
|
+
this->methodMap_["installRustCrate"] = MethodMetadata {1, __hostFunction_Zcam1Sdk_installRustCrate};
|
|
29
|
+
this->methodMap_["cleanupRustCrate"] = MethodMetadata {1, __hostFunction_Zcam1Sdk_cleanupRustCrate};
|
|
30
|
+
}
|
|
31
|
+
} // namespace uniffi_generated
|
|
32
|
+
|
|
33
|
+
@implementation Zcam1Sdk
|
|
34
|
+
RCT_EXPORT_MODULE()
|
|
35
|
+
|
|
36
|
+
// Don't compile this code when we build for the old architecture.
|
|
37
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
38
|
+
|
|
39
|
+
// Automated testing checks zcam1sdk
|
|
40
|
+
// by comparing the whole line here.
|
|
41
|
+
/*
|
|
42
|
+
- (NSNumber *)multiply:(double)a b:(double)b {
|
|
43
|
+
NSNumber *result = @(zcam1sdk::multiply(a, b));
|
|
44
|
+
}
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
- (NSNumber *)installRustCrate {
|
|
48
|
+
@throw [NSException exceptionWithName:@"UnreachableException"
|
|
49
|
+
reason:@"This method should never be called."
|
|
50
|
+
userInfo:nil];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
- (NSNumber *)cleanupRustCrate {
|
|
54
|
+
@throw [NSException exceptionWithName:@"UnreachableException"
|
|
55
|
+
reason:@"This method should never be called."
|
|
56
|
+
userInfo:nil];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
60
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
61
|
+
{
|
|
62
|
+
return std::make_shared<uniffi_generated::NativeZcam1SdkSpecJSI>(params);
|
|
63
|
+
}
|
|
64
|
+
#endif
|
|
65
|
+
|
|
66
|
+
@end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Generated by uniffi-bindgen-react-native
|
|
2
|
+
#ifdef __cplusplus
|
|
3
|
+
#import "zcam1-proving.h"
|
|
4
|
+
#endif
|
|
5
|
+
|
|
6
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
7
|
+
#import "Zcam1SdkSpec.h"
|
|
8
|
+
|
|
9
|
+
@interface Zcam1Proving : NSObject <NativeZcam1ProvingSpec>
|
|
10
|
+
#else
|
|
11
|
+
#import <React/RCTBridgeModule.h>
|
|
12
|
+
|
|
13
|
+
@interface Zcam1Proving : NSObject <RCTBridgeModule>
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
@end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Generated by uniffi-bindgen-react-native
|
|
2
|
+
#import "Zcam1Proving.h"
|
|
3
|
+
|
|
4
|
+
namespace uniffi_generated {
|
|
5
|
+
using namespace facebook::react;
|
|
6
|
+
/**
|
|
7
|
+
* ObjC++ class for module 'NativeZcam1Proving'
|
|
8
|
+
*/
|
|
9
|
+
class JSI_EXPORT NativeZcam1ProvingSpecJSI : public ObjCTurboModule {
|
|
10
|
+
public:
|
|
11
|
+
NativeZcam1ProvingSpecJSI(const ObjCTurboModule::InitParams ¶ms);
|
|
12
|
+
std::shared_ptr<CallInvoker> callInvoker;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
static facebook::jsi::Value __hostFunction_Zcam1Proving_installRustCrate(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
16
|
+
auto& tm = static_cast<NativeZcam1ProvingSpecJSI&>(turboModule);
|
|
17
|
+
auto jsInvoker = tm.callInvoker;
|
|
18
|
+
uint8_t result = zcam1proving::installRustCrate(rt, jsInvoker);
|
|
19
|
+
return facebook::jsi::Value(rt, result);
|
|
20
|
+
}
|
|
21
|
+
static facebook::jsi::Value __hostFunction_Zcam1Proving_cleanupRustCrate(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
22
|
+
uint8_t result = zcam1proving::cleanupRustCrate(rt);
|
|
23
|
+
return facebook::jsi::Value(rt, result);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
NativeZcam1ProvingSpecJSI::NativeZcam1ProvingSpecJSI(const ObjCTurboModule::InitParams ¶ms)
|
|
27
|
+
: ObjCTurboModule(params), callInvoker(params.jsInvoker) {
|
|
28
|
+
this->methodMap_["installRustCrate"] = MethodMetadata {1, __hostFunction_Zcam1Proving_installRustCrate};
|
|
29
|
+
this->methodMap_["cleanupRustCrate"] = MethodMetadata {1, __hostFunction_Zcam1Proving_cleanupRustCrate};
|
|
30
|
+
}
|
|
31
|
+
} // namespace uniffi_generated
|
|
32
|
+
|
|
33
|
+
@implementation Zcam1Proving
|
|
34
|
+
RCT_EXPORT_MODULE()
|
|
35
|
+
|
|
36
|
+
// Don't compile this code when we build for the old architecture.
|
|
37
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
38
|
+
|
|
39
|
+
// Automated testing checks zcam1proving
|
|
40
|
+
// by comparing the whole line here.
|
|
41
|
+
/*
|
|
42
|
+
- (NSNumber *)multiply:(double)a b:(double)b {
|
|
43
|
+
NSNumber *result = @(zcam1proving::multiply(a, b));
|
|
44
|
+
}
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
- (NSNumber *)installRustCrate {
|
|
48
|
+
@throw [NSException exceptionWithName:@"UnreachableException"
|
|
49
|
+
reason:@"This method should never be called."
|
|
50
|
+
userInfo:nil];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
- (NSNumber *)cleanupRustCrate {
|
|
54
|
+
@throw [NSException exceptionWithName:@"UnreachableException"
|
|
55
|
+
reason:@"This method should never be called."
|
|
56
|
+
userInfo:nil];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
60
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
61
|
+
{
|
|
62
|
+
return std::make_shared<uniffi_generated::NativeZcam1ProvingSpecJSI>(params);
|
|
63
|
+
}
|
|
64
|
+
#endif
|
|
65
|
+
|
|
66
|
+
@end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { TurboModuleRegistry } from "react-native";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Physical device orientation as reported by the accelerometer.
|
|
7
|
+
* Unlike Orientation (which is a capture setting), this reflects the
|
|
8
|
+
* actual device position and is emitted via onOrientationChange events.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export default TurboModuleRegistry.getEnforcing("Zcam1Capture");
|
|
12
|
+
//# sourceMappingURL=NativeZcam1Capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeZcam1Capture.ts"],"mappings":";;AAAA,SAA2BA,mBAAmB,QAAQ,cAAc;;AA8JpE;AACA;AACA;AACA;AACA;;AA4KA,eAAeA,mBAAmB,CAACC,YAAY,CAAO,cAAc,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeZcam1Sdk.ts"],"mappings":";;AAAA;;AAEA,SAASA,mBAAmB,QAAQ,cAAc;AAOlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,UAAU,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Generated by uniffi-bindgen-react-native
|
|
4
|
+
import installer from "./NativeZcam1Sdk.js";
|
|
5
|
+
|
|
6
|
+
// Register the rust crate with Hermes
|
|
7
|
+
// - the boolean flag ensures this loads exactly once, even if the JS
|
|
8
|
+
// code is reloaded (e.g. during development with metro).
|
|
9
|
+
let rustInstalled = false;
|
|
10
|
+
if (!rustInstalled) {
|
|
11
|
+
installer.installRustCrate();
|
|
12
|
+
rustInstalled = true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Export the generated bindings to the app.
|
|
16
|
+
export * from "./generated/zcam1_c2pa_utils.js";
|
|
17
|
+
export * from "./generated/zcam1_certs_utils.js";
|
|
18
|
+
export * from "./generated/zcam1_verify_utils.js";
|
|
19
|
+
|
|
20
|
+
// Now import the bindings so we can:
|
|
21
|
+
// - intialize them
|
|
22
|
+
// - export them as namespaced objects as the default export.
|
|
23
|
+
import * as zcam1_c2pa_utils from "./generated/zcam1_c2pa_utils.js";
|
|
24
|
+
import * as zcam1_certs_utils from "./generated/zcam1_certs_utils.js";
|
|
25
|
+
import * as zcam1_verify_utils from "./generated/zcam1_verify_utils.js";
|
|
26
|
+
|
|
27
|
+
// Initialize the generated bindings: mostly checksums, but also callbacks.
|
|
28
|
+
// - the boolean flag ensures this loads exactly once, even if the JS code
|
|
29
|
+
// is reloaded (e.g. during development with metro).
|
|
30
|
+
let initialized = false;
|
|
31
|
+
if (!initialized) {
|
|
32
|
+
zcam1_c2pa_utils.default.initialize();
|
|
33
|
+
zcam1_certs_utils.default.initialize();
|
|
34
|
+
zcam1_verify_utils.default.initialize();
|
|
35
|
+
initialized = true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// This provides parity with the index.web.ts version of this file.
|
|
39
|
+
// The web version relies on an asynchronous fetch, which this doesn't
|
|
40
|
+
// need, so we just no-op.
|
|
41
|
+
export async function uniffiInitAsync() {
|
|
42
|
+
// NOOP.
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Export the crates as individually namespaced objects.
|
|
46
|
+
export default {
|
|
47
|
+
zcam1_c2pa_utils,
|
|
48
|
+
zcam1_certs_utils,
|
|
49
|
+
zcam1_verify_utils
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=bindings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["installer","rustInstalled","installRustCrate","zcam1_c2pa_utils","zcam1_certs_utils","zcam1_verify_utils","initialized","default","initialize","uniffiInitAsync"],"sourceRoot":"../../src","sources":["bindings.tsx"],"mappings":";;AAAA;AACA,OAAOA,SAAS,MAAM,qBAAkB;;AAExC;AACA;AACA;AACA,IAAIC,aAAa,GAAG,KAAK;AACzB,IAAI,CAACA,aAAa,EAAE;EAClBD,SAAS,CAACE,gBAAgB,CAAC,CAAC;EAC5BD,aAAa,GAAG,IAAI;AACtB;;AAEA;AACA,cAAc,iCAA8B;AAC5C,cAAc,kCAA+B;AAC7C,cAAc,mCAAgC;;AAE9C;AACA;AACA;AACA,OAAO,KAAKE,gBAAgB,MAAM,iCAA8B;AAChE,OAAO,KAAKC,iBAAiB,MAAM,kCAA+B;AAClE,OAAO,KAAKC,kBAAkB,MAAM,mCAAgC;;AAEpE;AACA;AACA;AACA,IAAIC,WAAW,GAAG,KAAK;AACvB,IAAI,CAACA,WAAW,EAAE;EAChBH,gBAAgB,CAACI,OAAO,CAACC,UAAU,CAAC,CAAC;EACrCJ,iBAAiB,CAACG,OAAO,CAACC,UAAU,CAAC,CAAC;EACtCH,kBAAkB,CAACE,OAAO,CAACC,UAAU,CAAC,CAAC;EACvCF,WAAW,GAAG,IAAI;AACpB;;AAEA;AACA;AACA;AACA,OAAO,eAAeG,eAAeA,CAAA,EAAG;EACtC;AAAA;;AAGF;AACA,eAAe;EACbN,gBAAgB;EAChBC,iBAAiB;EACjBC;AACF,CAAC","ignoreList":[]}
|