@regulaforensics/face-sdk 8.2.806-nightly → 8.2.812-beta
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/RNFaceSDK.podspec +4 -4
- package/android/{CVDFaceSDK.kt → CDVFaceSDK.kt} +1 -1
- package/android/build.gradle +2 -2
- package/android/cordova.gradle +2 -2
- package/android/src/main/java/com/regula/plugin/facesdk/JSONConstructor.kt +12 -7
- package/examples/capacitor/package.json +2 -2
- package/examples/ionic/images/icon.png +0 -0
- package/examples/ionic/package.json +15 -13
- package/examples/ionic/patches/cordova-plugin-ionic-webview+5.0.1.patch +23 -0
- package/examples/ionic/scripts/ios.sh +1 -1
- package/examples/react_native/package.json +2 -2
- package/ios/CDVFaceSDK.swift +43 -0
- package/ios/Config.swift +242 -0
- package/ios/Decoder.swift +934 -0
- package/ios/Main.swift +191 -0
- package/ios/RNFaceSDK.m +7 -39
- package/ios/RNFaceSDK.swift +42 -0
- package/ios/Utils.swift +82 -0
- package/package.json +1 -1
- package/plugin.xml +11 -13
- package/test/package-lock.json +1 -1
- package/ios/CVDFaceSDK.h +0 -7
- package/ios/CVDFaceSDK.m +0 -43
- package/ios/RFSWConfig.h +0 -27
- package/ios/RFSWConfig.m +0 -199
- package/ios/RFSWJSONConstructor.h +0 -135
- package/ios/RFSWJSONConstructor.m +0 -985
- package/ios/RFSWMain.h +0 -24
- package/ios/RFSWMain.m +0 -381
- package/ios/RNFaceSDK.h +0 -8
package/RNFaceSDK.podspec
CHANGED
|
@@ -5,7 +5,7 @@ source = File.join(__dir__, 'ios')
|
|
|
5
5
|
|
|
6
6
|
Pod::Spec.new do |s|
|
|
7
7
|
s.name = 'RNFaceSDK'
|
|
8
|
-
s.version = '8.2.
|
|
8
|
+
s.version = '8.2.812-beta'
|
|
9
9
|
s.summary = package['description']
|
|
10
10
|
s.license = package['license']
|
|
11
11
|
|
|
@@ -14,8 +14,8 @@ Pod::Spec.new do |s|
|
|
|
14
14
|
|
|
15
15
|
s.source = { http: "file:#{source}" }
|
|
16
16
|
s.ios.deployment_target = '13.0'
|
|
17
|
-
s.source_files = 'ios/**/*.
|
|
18
|
-
s.exclude_files = [ 'ios/
|
|
19
|
-
s.dependency '
|
|
17
|
+
s.source_files = [ 'ios/**/*.swift', 'ios/**/RN*.m' ]
|
|
18
|
+
s.exclude_files = [ 'ios/CDVFaceSDK.swift' ]
|
|
19
|
+
s.dependency 'FaceSDK', '8.1.3731'
|
|
20
20
|
s.dependency 'React'
|
|
21
21
|
end
|
package/android/build.gradle
CHANGED
|
@@ -20,7 +20,7 @@ android {
|
|
|
20
20
|
rootProject.allprojects {
|
|
21
21
|
repositories {
|
|
22
22
|
maven {
|
|
23
|
-
url "https://maven.regulaforensics.com/RegulaDocumentReader
|
|
23
|
+
url "https://maven.regulaforensics.com/RegulaDocumentReader"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -29,7 +29,7 @@ dependencies {
|
|
|
29
29
|
//noinspection GradleDynamicVersion
|
|
30
30
|
implementation 'com.facebook.react:react-native:+'
|
|
31
31
|
//noinspection GradleDependency
|
|
32
|
-
implementation('com.regula.face:api:8.
|
|
32
|
+
implementation('com.regula.face:api:8.1.4455'){
|
|
33
33
|
transitive = true
|
|
34
34
|
}
|
|
35
35
|
}
|
package/android/cordova.gradle
CHANGED
|
@@ -6,13 +6,13 @@ android {
|
|
|
6
6
|
|
|
7
7
|
repositories {
|
|
8
8
|
maven {
|
|
9
|
-
url "https://maven.regulaforensics.com/RegulaDocumentReader
|
|
9
|
+
url "https://maven.regulaforensics.com/RegulaDocumentReader"
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
dependencies {
|
|
14
14
|
//noinspection GradleDependency
|
|
15
|
-
implementation('com.regula.face:api:8.
|
|
15
|
+
implementation('com.regula.face:api:8.1.4455'){
|
|
16
16
|
transitive = true
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -636,13 +636,18 @@ fun generateDetectFacesConfig(input: DetectFacesConfiguration?) = input?.let {
|
|
|
636
636
|
|
|
637
637
|
fun detectFacesRequestFromJSON(input: JSONObject) = input.let {
|
|
638
638
|
val image = it.getString("image").toBitmap()!!
|
|
639
|
-
it.getStringOrNull("scenario")
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
639
|
+
val scenario = it.getStringOrNull("scenario")
|
|
640
|
+
val config = detectFacesConfigFromJSON(it.getJSONObjectOrNull("configuration"))
|
|
641
|
+
val tag = it.getStringOrNull("tag")
|
|
642
|
+
|
|
643
|
+
scenario?.let { scenario ->
|
|
644
|
+
DetectFacesRequest::class.java.getDeclaredConstructor(
|
|
645
|
+
Bitmap::class.java,
|
|
646
|
+
String::class.java,
|
|
647
|
+
DetectFacesConfiguration::class.java,
|
|
648
|
+
String::class.java
|
|
649
|
+
).instantiate(image, scenario, null, tag)
|
|
650
|
+
} ?: DetectFacesRequest(image, config, tag)
|
|
646
651
|
}
|
|
647
652
|
|
|
648
653
|
fun generateDetectFacesRequest(it: DetectFacesRequest) = mapOf(
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
"android": "scripts/android.sh"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@regulaforensics/face-sdk": "8.2.
|
|
10
|
-
"@regulaforensics/face-core-basic": "8.
|
|
9
|
+
"@regulaforensics/face-sdk": "8.2.812-beta",
|
|
10
|
+
"@regulaforensics/face-core-basic": "8.1.422",
|
|
11
11
|
"@awesome-cordova-plugins/file": "^8.1.0",
|
|
12
12
|
"@awesome-cordova-plugins/camera": "^8.1.0",
|
|
13
13
|
"cordova-plugin-file": "^8.1.3",
|
|
Binary file
|
|
@@ -3,30 +3,32 @@
|
|
|
3
3
|
"scripts": {
|
|
4
4
|
"setup": "scripts/setup.sh",
|
|
5
5
|
"ios": "scripts/ios.sh",
|
|
6
|
-
"android": "scripts/android.sh"
|
|
6
|
+
"android": "scripts/android.sh",
|
|
7
|
+
"postinstall": "patch-package"
|
|
7
8
|
},
|
|
8
9
|
"dependencies": {
|
|
9
|
-
"@angular-devkit/build-angular": "^21.1.
|
|
10
|
-
"@angular/cli": "^21.1.
|
|
11
|
-
"@angular/common": "^21.1.
|
|
12
|
-
"@angular/compiler-cli": "^21.1.
|
|
13
|
-
"@angular/core": "^21.1.
|
|
14
|
-
"@angular/forms": "^21.1.
|
|
15
|
-
"@angular/platform-browser-dynamic": "^21.1.
|
|
16
|
-
"@angular/router": "^21.1.
|
|
10
|
+
"@angular-devkit/build-angular": "^21.1.4",
|
|
11
|
+
"@angular/cli": "^21.1.4",
|
|
12
|
+
"@angular/common": "^21.1.5",
|
|
13
|
+
"@angular/compiler-cli": "^21.1.5",
|
|
14
|
+
"@angular/core": "^21.1.5",
|
|
15
|
+
"@angular/forms": "^21.1.5",
|
|
16
|
+
"@angular/platform-browser-dynamic": "^21.1.5",
|
|
17
|
+
"@angular/router": "^21.1.5",
|
|
17
18
|
"@ionic/angular": "^8.7.17",
|
|
18
19
|
"@ionic/cordova-builders": "^12.3.0",
|
|
19
20
|
"@awesome-cordova-plugins/camera": "^8.1.0",
|
|
20
21
|
"@awesome-cordova-plugins/dialogs": "^8.1.0",
|
|
21
22
|
"@awesome-cordova-plugins/file": "^8.1.0",
|
|
22
|
-
"@regulaforensics/face-sdk": "8.2.
|
|
23
|
-
"@regulaforensics/face-core-basic": "8.
|
|
23
|
+
"@regulaforensics/face-sdk": "8.2.812-beta",
|
|
24
|
+
"@regulaforensics/face-core-basic": "8.1.422",
|
|
24
25
|
"cordova-android": "^14.0.1",
|
|
25
|
-
"cordova-ios": "^
|
|
26
|
+
"cordova-ios": "^8.0.0",
|
|
26
27
|
"cordova-plugin-camera": "^8.0.0",
|
|
27
28
|
"cordova-plugin-dialogs": "^2.0.2",
|
|
28
29
|
"cordova-plugin-file": "^8.1.3",
|
|
29
|
-
"cordova-plugin-ionic-webview": "^5.0.1"
|
|
30
|
+
"cordova-plugin-ionic-webview": "^5.0.1",
|
|
31
|
+
"patch-package": "^8.0.1"
|
|
30
32
|
},
|
|
31
33
|
"cordova": {
|
|
32
34
|
"plugins": {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
diff --git a/node_modules/cordova-plugin-ionic-webview/src/ios/CDVWKWebViewEngine.m b/node_modules/cordova-plugin-ionic-webview/src/ios/CDVWKWebViewEngine.m
|
|
2
|
+
index 2acb99b..900a04c 100644
|
|
3
|
+
--- a/node_modules/cordova-plugin-ionic-webview/src/ios/CDVWKWebViewEngine.m
|
|
4
|
+
+++ b/node_modules/cordova-plugin-ionic-webview/src/ios/CDVWKWebViewEngine.m
|
|
5
|
+
@@ -731,6 +731,18 @@ - (BOOL)defaultResourcePolicyForURL:(NSURL*)url
|
|
6
|
+
return YES;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
+ // Allow internal local-server navigation even when no plugin overrides the request.
|
|
10
|
+
+ NSURL *localServerUrl = [NSURL URLWithString:self.CDV_LOCAL_SERVER];
|
|
11
|
+
+ if (localServerUrl != nil && url != nil) {
|
|
12
|
+
+ NSString *localScheme = localServerUrl.scheme.lowercaseString;
|
|
13
|
+
+ NSString *localHost = localServerUrl.host.lowercaseString;
|
|
14
|
+
+ NSString *urlScheme = url.scheme.lowercaseString;
|
|
15
|
+
+ NSString *urlHost = url.host.lowercaseString;
|
|
16
|
+
+ if ([localScheme isEqualToString:urlScheme] && [localHost isEqualToString:urlHost]) {
|
|
17
|
+
+ return YES;
|
|
18
|
+
+ }
|
|
19
|
+
+ }
|
|
20
|
+
+
|
|
21
|
+
return NO;
|
|
22
|
+
}
|
|
23
|
+
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"start": "expo start"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@regulaforensics/face-sdk": "8.2.
|
|
12
|
-
"@regulaforensics/face-core-basic": "8.
|
|
11
|
+
"@regulaforensics/face-sdk": "8.2.812-beta",
|
|
12
|
+
"@regulaforensics/face-core-basic": "8.1.422",
|
|
13
13
|
"react-native": "^0.81.4",
|
|
14
14
|
"react-native-fs": "^2.20.0",
|
|
15
15
|
"react-native-image-picker": "^8.2.1",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
var eventCallbackIds: [String: String] = [:]
|
|
2
|
+
private var this: CDVFaceSDK?
|
|
3
|
+
|
|
4
|
+
func sendEvent(_ event: String, _ data: Any? = "") {
|
|
5
|
+
var callbackId = event
|
|
6
|
+
let eventId = eventCallbackIds[event]
|
|
7
|
+
if eventId != nil { callbackId = eventId! }
|
|
8
|
+
|
|
9
|
+
// In this section unreasonable casts and optionals are made to
|
|
10
|
+
// ensure that this code works with both cordova-ios@7 and cordova-ios@8.
|
|
11
|
+
var sendable = data.toSendable()
|
|
12
|
+
if sendable is NSNull { sendable = "" }
|
|
13
|
+
let message = sendable as! String
|
|
14
|
+
let result: CDVPluginResult? = CDVPluginResult(status: CDVCommandStatus.ok, messageAs: message)
|
|
15
|
+
result!.setKeepCallbackAs(true)
|
|
16
|
+
|
|
17
|
+
this!.commandDelegate.send(result!, callbackId: callbackId)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@objc(CDVFaceSDK)
|
|
21
|
+
class CDVFaceSDK: CDVPlugin {
|
|
22
|
+
@objc(exec:)
|
|
23
|
+
func exec(_ command: CDVInvokedUrlCommand) {
|
|
24
|
+
this = self
|
|
25
|
+
let method = command.arguments.first as! String
|
|
26
|
+
args = Array(command.arguments.dropFirst())
|
|
27
|
+
|
|
28
|
+
if method == "setEvent" {
|
|
29
|
+
eventCallbackIds[args.first as! String] = command.callbackId
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
methodCall(method, { data in sendEvent(command.callbackId, data) })
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let rootViewController: () -> UIViewController? = {
|
|
38
|
+
return UIApplication.shared.connectedScenes
|
|
39
|
+
.compactMap { $0 as? UIWindowScene }
|
|
40
|
+
.flatMap { $0.windows }
|
|
41
|
+
.first { $0.isKeyWindow }?
|
|
42
|
+
.rootViewController
|
|
43
|
+
}
|
package/ios/Config.swift
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import FaceSDK
|
|
3
|
+
|
|
4
|
+
func setCustomization(_ it: [String: [String: Any]]) {
|
|
5
|
+
for (key, value) in it {
|
|
6
|
+
if key == "uiCustomizationLayer" {
|
|
7
|
+
face.customization.customUILayerJSON = value as [AnyHashable : Any]
|
|
8
|
+
continue
|
|
9
|
+
}
|
|
10
|
+
let dict = (face.customization.configuration!.value(forKey: key) as! NSMutableDictionary)
|
|
11
|
+
for (k, v) in value {
|
|
12
|
+
let k = Int(k)!
|
|
13
|
+
switch key {
|
|
14
|
+
case("colors"): dict[k] = UIColor.decode(v)
|
|
15
|
+
case("fonts"): dict[k] = UIFont.decode(v)
|
|
16
|
+
case("images"): dict[k] = UIImage.decode(v)
|
|
17
|
+
default: break
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public extension FaceCaptureConfiguration {
|
|
24
|
+
static func decode(_ it: Any?) -> Self? {
|
|
25
|
+
guard let it = it as? [String: Any] else { return nil }
|
|
26
|
+
return Self(builder: { builder in
|
|
27
|
+
for (k, v) in it {
|
|
28
|
+
switch k {
|
|
29
|
+
case("copyright"): builder.isCopyright = v as! Bool
|
|
30
|
+
case("cameraSwitchEnabled"): builder.isCameraSwitchButtonEnabled = v as! Bool
|
|
31
|
+
case("closeButtonEnabled"): builder.isCloseButtonEnabled = v as! Bool
|
|
32
|
+
case("torchButtonEnabled"): builder.isTorchButtonEnabled = v as! Bool
|
|
33
|
+
case("vibrateOnSteps"): builder.vibrateOnSteps = v as! Bool
|
|
34
|
+
case("detectOcclusion"): builder.detectOcclusion = v as! Bool
|
|
35
|
+
case("showFaceAnimation"): builder.showFaceAnimation = v as! Bool
|
|
36
|
+
case("cameraPositionIOS"): builder.cameraPosition = CameraPosition(rawValue: v as! Int)!
|
|
37
|
+
case("screenOrientation"): builder.screenOrientation = RFSScreenOrientation.decode(v)
|
|
38
|
+
case("timeout"): builder.timeoutInterval = v as? NSNumber
|
|
39
|
+
case("holdStillDuration"): builder.holdStillDuration = v as? NSNumber
|
|
40
|
+
default: break
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
func encode() -> [String: Any?] {
|
|
46
|
+
return [
|
|
47
|
+
"copyright": self.isCopyright,
|
|
48
|
+
"cameraSwitchEnabled": self.isCameraSwitchButtonEnabled,
|
|
49
|
+
"closeButtonEnabled": self.isCloseButtonEnabled,
|
|
50
|
+
"torchButtonEnabled": self.isTorchButtonEnabled,
|
|
51
|
+
"vibrateOnSteps": self.vibrateOnSteps,
|
|
52
|
+
"detectOcclusion": self.detectOcclusion,
|
|
53
|
+
"showFaceAnimation": self.showFaceAnimation,
|
|
54
|
+
"cameraPositionIOS": self.cameraPosition.rawValue,
|
|
55
|
+
"screenOrientation": self.screenOrientation.encode(),
|
|
56
|
+
"timeout": self.timeoutInterval,
|
|
57
|
+
"holdStillDuration": self.holdStillDuration,
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public extension LivenessConfiguration {
|
|
63
|
+
static func decode(_ it: Any?) -> Self? {
|
|
64
|
+
guard let it = it as? [String: Any] else { return nil }
|
|
65
|
+
return Self(builder: { builder in
|
|
66
|
+
for (k, v) in it {
|
|
67
|
+
switch k {
|
|
68
|
+
case("copyright"): builder.isCopyright = v as! Bool
|
|
69
|
+
case("cameraSwitchEnabled"): builder.isCameraSwitchButtonEnabled = v as! Bool
|
|
70
|
+
case("closeButtonEnabled"): builder.isCloseButtonEnabled = v as! Bool
|
|
71
|
+
case("torchButtonEnabled"): builder.isTorchButtonEnabled = v as! Bool
|
|
72
|
+
case("vibrateOnSteps"): builder.vibrateOnSteps = v as! Bool
|
|
73
|
+
case("cameraPositionIOS"): builder.cameraPosition = CameraPosition(rawValue: v as! Int)!
|
|
74
|
+
case("attemptsCount"): builder.attemptsCount = v as! Int
|
|
75
|
+
case("locationTrackingEnabled"): builder.isLocationTrackingEnabled = v as! Bool
|
|
76
|
+
case("recordingProcess"): builder.recordingProcess = RecordingProcess(rawValue: v as! Int)!
|
|
77
|
+
case("livenessType"): builder.livenessType = LivenessType(rawValue: v as! Int)!
|
|
78
|
+
case("screenOrientation"): builder.screenOrientation = RFSScreenOrientation.decode(v)
|
|
79
|
+
case("tag"): builder.tag = v as? String
|
|
80
|
+
case("skipStep"): builder.stepSkippingMask = RFSLivenessStepSkip.decode(v)
|
|
81
|
+
case("metadata"): builder.metadata = v as! [String: Any]
|
|
82
|
+
default: break
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
func encode() -> [String: Any?] {
|
|
88
|
+
return [
|
|
89
|
+
"copyright": self.isCopyright,
|
|
90
|
+
"cameraSwitchEnabled": self.isCameraSwitchButtonEnabled,
|
|
91
|
+
"closeButtonEnabled": self.isCloseButtonEnabled,
|
|
92
|
+
"torchButtonEnabled": self.isTorchButtonEnabled,
|
|
93
|
+
"vibrateOnSteps": self.vibrateOnSteps,
|
|
94
|
+
"cameraPositionIOS": self.cameraPosition.rawValue,
|
|
95
|
+
"attemptsCount": self.attemptsCount,
|
|
96
|
+
"locationTrackingEnabled": self.isLocationTrackingEnabled,
|
|
97
|
+
"recordingProcess": self.recordingProcess.rawValue,
|
|
98
|
+
"livenessType": self.livenessType.rawValue,
|
|
99
|
+
"screenOrientation": self.screenOrientation.encode(),
|
|
100
|
+
"tag": self.tag,
|
|
101
|
+
"skipStep": self.stepSkippingMask.encode(),
|
|
102
|
+
"metadata": self.metadata,
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public extension MatchFacesConfiguration {
|
|
108
|
+
static func decode(_ it: Any?) -> Self? {
|
|
109
|
+
guard let it = it as? [String: Any] else { return nil }
|
|
110
|
+
return Self(builder: { builder in
|
|
111
|
+
for (k, v) in it {
|
|
112
|
+
switch k {
|
|
113
|
+
case("processingMode"): builder.processingMode = FaceSDK.ProcessingMode(rawValue: v as! Int)!
|
|
114
|
+
case("locationTrackingEnabled"): builder.isLocationTrackingEnabled = v as! Bool
|
|
115
|
+
default: break
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
func encode() -> [String: Any?] {
|
|
121
|
+
return [
|
|
122
|
+
"processingMode": self.processingMode.rawValue,
|
|
123
|
+
"locationTrackingEnabled": self.isLocationTrackingEnabled,
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// MARK: - Convetring
|
|
129
|
+
|
|
130
|
+
extension UIColor {
|
|
131
|
+
// Create from a hex integer; supports #RGB, #ARGB, #RRGGBB, #AARRGGBB semantics
|
|
132
|
+
static func decode(_ it: Any?) -> Self? {
|
|
133
|
+
guard let it = it as? Int else { return nil }
|
|
134
|
+
// Build hex string manually to preserve leading zeros when derived from integers
|
|
135
|
+
var value = UInt32(truncatingIfNeeded: it)
|
|
136
|
+
let digits = Array("0123456789ABCDEF")
|
|
137
|
+
var hex = ""
|
|
138
|
+
while value > 0 {
|
|
139
|
+
let d = Int(value % 16)
|
|
140
|
+
hex.insert(digits[d], at: hex.startIndex)
|
|
141
|
+
value /= 16
|
|
142
|
+
}
|
|
143
|
+
if hex.isEmpty { hex = "0" }
|
|
144
|
+
// If length is 5 or 7, pad a leading 0 to restore a lost leading nibble
|
|
145
|
+
if hex.count == 5 || hex.count == 7 { hex = "0" + hex }
|
|
146
|
+
let s = hex.uppercased()
|
|
147
|
+
|
|
148
|
+
let a, r, g, b: CGFloat
|
|
149
|
+
switch s.count {
|
|
150
|
+
case 3: // RGB
|
|
151
|
+
a = 1.0
|
|
152
|
+
r = Self.component(from: s, start: 0, length: 1)
|
|
153
|
+
g = Self.component(from: s, start: 1, length: 1)
|
|
154
|
+
b = Self.component(from: s, start: 2, length: 1)
|
|
155
|
+
case 4: // ARGB
|
|
156
|
+
a = Self.component(from: s, start: 0, length: 1)
|
|
157
|
+
r = Self.component(from: s, start: 1, length: 1)
|
|
158
|
+
g = Self.component(from: s, start: 2, length: 1)
|
|
159
|
+
b = Self.component(from: s, start: 3, length: 1)
|
|
160
|
+
case 6: // RRGGBB
|
|
161
|
+
a = 1.0
|
|
162
|
+
r = Self.component(from: s, start: 0, length: 2)
|
|
163
|
+
g = Self.component(from: s, start: 2, length: 2)
|
|
164
|
+
b = Self.component(from: s, start: 4, length: 2)
|
|
165
|
+
case 8: // AARRGGBB
|
|
166
|
+
a = Self.component(from: s, start: 0, length: 2)
|
|
167
|
+
r = Self.component(from: s, start: 2, length: 2)
|
|
168
|
+
g = Self.component(from: s, start: 4, length: 2)
|
|
169
|
+
b = Self.component(from: s, start: 6, length: 2)
|
|
170
|
+
default:
|
|
171
|
+
assertionFailure("Invalid color value: #\(s). Expected #RGB, #ARGB, #RRGGBB, or #AARRGGBB")
|
|
172
|
+
return nil
|
|
173
|
+
}
|
|
174
|
+
return Self(red: r, green: g, blue: b, alpha: a)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// AARRGGBB integer representation as Int
|
|
178
|
+
func encode() -> Int {
|
|
179
|
+
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
|
|
180
|
+
if !getRed(&r, green: &g, blue: &b, alpha: &a) {
|
|
181
|
+
if let comps = cgColor.components {
|
|
182
|
+
if comps.count == 2 { r = comps[0]; g = comps[0]; b = comps[0]; a = comps[1] }
|
|
183
|
+
else if comps.count >= 4 { r = comps[0]; g = comps[1]; b = comps[2]; a = comps[3] }
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
let aa = UInt32(lroundf(Float(a * 255)))
|
|
187
|
+
let rr = UInt32(lroundf(Float(r * 255)))
|
|
188
|
+
let gg = UInt32(lroundf(Float(g * 255)))
|
|
189
|
+
let bb = UInt32(lroundf(Float(b * 255)))
|
|
190
|
+
let composed: UInt32 = (aa << 24) | (rr << 16) | (gg << 8) | bb
|
|
191
|
+
return Int(truncatingIfNeeded: composed)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private static func component(from hex: String, start: Int, length: Int) -> CGFloat {
|
|
195
|
+
let startIdx = hex.index(hex.startIndex, offsetBy: start)
|
|
196
|
+
let endIdx = hex.index(startIdx, offsetBy: length)
|
|
197
|
+
let substr = String(hex[startIdx..<endIdx])
|
|
198
|
+
let full = (length == 2) ? substr : substr + substr
|
|
199
|
+
let value = UInt32(full, radix: 16) ?? 0
|
|
200
|
+
return CGFloat(value) / 255.0
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
extension UIFont {
|
|
205
|
+
static func decode(_ it: Any?) -> Self? {
|
|
206
|
+
guard let it = it as? [String: Any] else { return nil }
|
|
207
|
+
return Self(name: it["name"] as! String,
|
|
208
|
+
size: it["size"] as! CGFloat)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
extension RFSScreenOrientation {
|
|
213
|
+
static func decode(_ it: Any?) -> Self {
|
|
214
|
+
let it = it as! [Int]
|
|
215
|
+
if it.contains(0) && it.contains(1) { return Self(arrayLiteral: .portrait, .landscape) }
|
|
216
|
+
if it.contains(0) { return Self(arrayLiteral: .portrait) }
|
|
217
|
+
if it.contains(1) { return Self(arrayLiteral: .landscape) }
|
|
218
|
+
return Self(arrayLiteral: [])
|
|
219
|
+
}
|
|
220
|
+
func encode() -> [Int] {
|
|
221
|
+
if self == .portrait { return [0] }
|
|
222
|
+
if self == .landscape { return [1] }
|
|
223
|
+
if self == [.portrait, .landscape] { return [0, 1] }
|
|
224
|
+
return []
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
extension RFSLivenessStepSkip {
|
|
229
|
+
static func decode(_ it: Any?) -> Self {
|
|
230
|
+
let it = it as! [Int]
|
|
231
|
+
if it.contains(0) && it.contains(1) { return Self(arrayLiteral: .onboarding, .success) }
|
|
232
|
+
if it.contains(0) { return Self(arrayLiteral: .onboarding) }
|
|
233
|
+
if it.contains(1) { return Self(arrayLiteral: .success) }
|
|
234
|
+
return Self(arrayLiteral: [])
|
|
235
|
+
}
|
|
236
|
+
func encode() -> [Int] {
|
|
237
|
+
if self == .onboarding { return [0] }
|
|
238
|
+
if self == .success { return [1] }
|
|
239
|
+
if self == [.onboarding, .success] { return [0, 1] }
|
|
240
|
+
return []
|
|
241
|
+
}
|
|
242
|
+
}
|