@simasfin/smmf-sdk 0.0.0-stage → 0.2.3
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 +84 -2
- package/android/build.gradle +51 -0
- package/android/maven/id/co/onepass/onepass-sdk/0.2.3/onepass-sdk-0.2.3.aar +0 -0
- package/android/maven/id/co/onepass/onepass-sdk/0.2.3/onepass-sdk-0.2.3.pom +52 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/id/co/onepass/expo/OnePassSignatureExpoView.kt +25 -0
- package/android/src/main/java/id/co/onepass/expo/OnepassExpoModule.kt +134 -0
- package/app.plugin.js +1 -0
- package/build/OnePassSignatureView.d.ts +19 -0
- package/build/OnePassSignatureView.d.ts.map +1 -0
- package/build/OnePassSignatureView.js +15 -0
- package/build/OnePassSignatureView.js.map +1 -0
- package/build/index.d.ts +21 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +10 -0
- package/build/index.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/ios/OnePassSDK/DesignSystem.swift +139 -0
- package/ios/OnePassSDK/IconView.swift +54 -0
- package/ios/OnePassSDK/IconsaxPath.swift +216 -0
- package/ios/OnePassSDK/Liveness/FaceAnalyzer.swift +114 -0
- package/ios/OnePassSDK/Liveness/FaceLandmarkMetrics.swift +28 -0
- package/ios/OnePassSDK/Liveness/FaceSnapshotMapper.swift +37 -0
- package/ios/OnePassSDK/Liveness/LivenessGate.swift +155 -0
- package/ios/OnePassSDK/Liveness/LivenessImagePreparer.swift +44 -0
- package/ios/OnePassSDK/Liveness/LivenessViewController.swift +724 -0
- package/ios/OnePassSDK/Ocr/CoverFitCrop.swift +37 -0
- package/ios/OnePassSDK/Ocr/KtpFrameOverlayView.swift +98 -0
- package/ios/OnePassSDK/Ocr/KtpImagePreparer.swift +90 -0
- package/ios/OnePassSDK/Ocr/KtpOcrViewController.swift +703 -0
- package/ios/OnePassSDK/Ocr/KtpPhotoInspector.swift +93 -0
- package/ios/OnePassSDK/Ocr/KtpQualityGate.swift +185 -0
- package/ios/OnePassSDK/OnePass.swift +28 -0
- package/ios/OnePassSDK/Resources/hindari_pemakaian.png +0 -0
- package/ios/OnePassSDK/Resources/inter_bold.ttf +0 -0
- package/ios/OnePassSDK/Resources/inter_medium.ttf +0 -0
- package/ios/OnePassSDK/Resources/inter_regular.ttf +0 -0
- package/ios/OnePassSDK/Resources/inter_semibold.ttf +0 -0
- package/ios/OnePassSDK/Resources/ktp_illustration.webp +0 -0
- package/ios/OnePassSDK/Resources/logo_smmf.png +0 -0
- package/ios/OnePassSDK/Resources/placeholder_head.png +0 -0
- package/ios/OnePassSDK/Signature/SignaturePadView.swift +144 -0
- package/ios/OnePassSignatureExpoView.swift +22 -0
- package/ios/OnepassExpo.podspec +23 -0
- package/ios/OnepassExpoModule.swift +77 -0
- package/licenses/Iconsax-MIT.txt +26 -0
- package/licenses/Inter-OFL-1.1.txt +93 -0
- package/package.json +49 -4
- package/plugin/src/inject.js +31 -0
- package/plugin/withOnePass.js +32 -0
- package/scripts/sync-native.js +84 -0
- package/src/OnePassSignatureView.tsx +34 -0
- package/src/index.ts +44 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import CoreGraphics
|
|
2
|
+
import Foundation
|
|
3
|
+
|
|
4
|
+
public struct CropRegion: Equatable {
|
|
5
|
+
public let left: Int
|
|
6
|
+
public let top: Int
|
|
7
|
+
public let width: Int
|
|
8
|
+
public let height: Int
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public enum CoverFitCrop {
|
|
12
|
+
public static func compute(
|
|
13
|
+
photoWidth: Int,
|
|
14
|
+
photoHeight: Int,
|
|
15
|
+
displayWidth: Int,
|
|
16
|
+
displayHeight: Int,
|
|
17
|
+
frame: CGRect
|
|
18
|
+
) -> CropRegion {
|
|
19
|
+
let displayAspect = Float(displayWidth) / Float(displayHeight)
|
|
20
|
+
let photoAspect = Float(photoWidth) / Float(photoHeight)
|
|
21
|
+
let scale: Float
|
|
22
|
+
var offsetX: Float = 0
|
|
23
|
+
var offsetY: Float = 0
|
|
24
|
+
if photoAspect > displayAspect {
|
|
25
|
+
scale = Float(photoHeight) / Float(displayHeight)
|
|
26
|
+
offsetX = (Float(photoWidth) - Float(displayWidth) * scale) / 2
|
|
27
|
+
} else {
|
|
28
|
+
scale = Float(photoWidth) / Float(displayWidth)
|
|
29
|
+
offsetY = (Float(photoHeight) - Float(displayHeight) * scale) / 2
|
|
30
|
+
}
|
|
31
|
+
let left = max(0, Int((offsetX + Float(frame.minX) * scale).rounded()))
|
|
32
|
+
let top = max(0, Int((offsetY + Float(frame.minY) * scale).rounded()))
|
|
33
|
+
let width = max(1, min(Int((Float(frame.width) * scale).rounded()), photoWidth - left))
|
|
34
|
+
let height = max(1, min(Int((Float(frame.height) * scale).rounded()), photoHeight - top))
|
|
35
|
+
return CropRegion(left: left, top: top, width: width, height: height)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
final class KtpFrameOverlayView: UIView {
|
|
4
|
+
|
|
5
|
+
static let frameRatio: CGFloat = 1.586
|
|
6
|
+
private static let frameWidthFraction: CGFloat = 0.85
|
|
7
|
+
private static let cornerSize: CGFloat = 24
|
|
8
|
+
private static let cornerBorder: CGFloat = 3
|
|
9
|
+
private static let frameRadius: CGFloat = 12
|
|
10
|
+
private static let guideWidthFraction: CGFloat = 0.3
|
|
11
|
+
private static let guideRadius: CGFloat = 4
|
|
12
|
+
|
|
13
|
+
var frameRect: CGRect {
|
|
14
|
+
let width = bounds.width * Self.frameWidthFraction
|
|
15
|
+
let height = width / Self.frameRatio
|
|
16
|
+
return CGRect(
|
|
17
|
+
x: (bounds.width - width) / 2,
|
|
18
|
+
y: (bounds.height - height) / 2,
|
|
19
|
+
width: width,
|
|
20
|
+
height: height
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override init(frame: CGRect) {
|
|
25
|
+
super.init(frame: frame)
|
|
26
|
+
backgroundColor = .clear
|
|
27
|
+
isUserInteractionEnabled = false
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@available(*, unavailable)
|
|
31
|
+
required init?(coder: NSCoder) { fatalError("tidak dipakai") }
|
|
32
|
+
|
|
33
|
+
override func draw(_ rect: CGRect) {
|
|
34
|
+
guard let context = UIGraphicsGetCurrentContext() else { return }
|
|
35
|
+
let frame = frameRect
|
|
36
|
+
|
|
37
|
+
UIColor.black.withAlphaComponent(0.5).setFill()
|
|
38
|
+
context.fill(bounds)
|
|
39
|
+
let hole = UIBezierPath(roundedRect: frame, cornerRadius: Self.frameRadius)
|
|
40
|
+
context.setBlendMode(.clear)
|
|
41
|
+
hole.fill()
|
|
42
|
+
context.setBlendMode(.normal)
|
|
43
|
+
|
|
44
|
+
UIColor.white.withAlphaComponent(0.3).setStroke()
|
|
45
|
+
hole.lineWidth = 1
|
|
46
|
+
hole.stroke()
|
|
47
|
+
|
|
48
|
+
drawCorners(in: frame)
|
|
49
|
+
drawPhotoGuide(in: frame)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private func drawCorners(in frame: CGRect) {
|
|
53
|
+
let path = UIBezierPath()
|
|
54
|
+
let inset = Self.cornerBorder / 2
|
|
55
|
+
let left = frame.minX + inset
|
|
56
|
+
let top = frame.minY + inset
|
|
57
|
+
let right = frame.maxX - inset
|
|
58
|
+
let bottom = frame.maxY - inset
|
|
59
|
+
let size = Self.cornerSize
|
|
60
|
+
|
|
61
|
+
path.move(to: CGPoint(x: left, y: top + size))
|
|
62
|
+
path.addLine(to: CGPoint(x: left, y: top))
|
|
63
|
+
path.addLine(to: CGPoint(x: left + size, y: top))
|
|
64
|
+
|
|
65
|
+
path.move(to: CGPoint(x: right - size, y: top))
|
|
66
|
+
path.addLine(to: CGPoint(x: right, y: top))
|
|
67
|
+
path.addLine(to: CGPoint(x: right, y: top + size))
|
|
68
|
+
|
|
69
|
+
path.move(to: CGPoint(x: left, y: bottom - size))
|
|
70
|
+
path.addLine(to: CGPoint(x: left, y: bottom))
|
|
71
|
+
path.addLine(to: CGPoint(x: left + size, y: bottom))
|
|
72
|
+
|
|
73
|
+
path.move(to: CGPoint(x: right - size, y: bottom))
|
|
74
|
+
path.addLine(to: CGPoint(x: right, y: bottom))
|
|
75
|
+
path.addLine(to: CGPoint(x: right, y: bottom - size))
|
|
76
|
+
|
|
77
|
+
UIColor.white.setStroke()
|
|
78
|
+
path.lineWidth = Self.cornerBorder
|
|
79
|
+
path.stroke()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private func drawPhotoGuide(in frame: CGRect) {
|
|
83
|
+
let width = frame.width * Self.guideWidthFraction
|
|
84
|
+
let height = width * 4 / 3
|
|
85
|
+
let margin: CGFloat = 12
|
|
86
|
+
let guide = CGRect(
|
|
87
|
+
x: frame.maxX - margin - width,
|
|
88
|
+
y: frame.maxY - margin - height,
|
|
89
|
+
width: width,
|
|
90
|
+
height: height
|
|
91
|
+
)
|
|
92
|
+
let path = UIBezierPath(roundedRect: guide, cornerRadius: Self.guideRadius)
|
|
93
|
+
path.setLineDash([6, 4], count: 2, phase: 0)
|
|
94
|
+
path.lineWidth = 1
|
|
95
|
+
UIColor.white.withAlphaComponent(0.25).setStroke()
|
|
96
|
+
path.stroke()
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
enum KtpImagePreparer {
|
|
4
|
+
static let maxUploadDimension: CGFloat = 1600
|
|
5
|
+
static let jpegQuality: CGFloat = 0.9
|
|
6
|
+
|
|
7
|
+
struct Prepared {
|
|
8
|
+
let image: UIImage
|
|
9
|
+
let jpegData: Data
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static func cropToFrame(image: UIImage, displaySize: CGSize, frame: CGRect) -> Prepared {
|
|
13
|
+
let upright = normalizedOrientation(image)
|
|
14
|
+
guard
|
|
15
|
+
let cgImage = upright.cgImage,
|
|
16
|
+
displaySize.width > 0,
|
|
17
|
+
displaySize.height > 0,
|
|
18
|
+
frame.width > 0
|
|
19
|
+
else {
|
|
20
|
+
return Prepared(
|
|
21
|
+
image: upright,
|
|
22
|
+
jpegData: upright.jpegData(compressionQuality: jpegQuality) ?? Data()
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
let region = CoverFitCrop.compute(
|
|
26
|
+
photoWidth: cgImage.width,
|
|
27
|
+
photoHeight: cgImage.height,
|
|
28
|
+
displayWidth: Int(displaySize.width),
|
|
29
|
+
displayHeight: Int(displaySize.height),
|
|
30
|
+
frame: frame
|
|
31
|
+
)
|
|
32
|
+
let cropRect = CGRect(
|
|
33
|
+
x: region.left,
|
|
34
|
+
y: region.top,
|
|
35
|
+
width: region.width,
|
|
36
|
+
height: region.height
|
|
37
|
+
)
|
|
38
|
+
guard let croppedCg = cgImage.cropping(to: cropRect) else {
|
|
39
|
+
return Prepared(
|
|
40
|
+
image: upright,
|
|
41
|
+
jpegData: upright.jpegData(compressionQuality: jpegQuality) ?? Data()
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
let cropped = downscale(UIImage(cgImage: croppedCg))
|
|
45
|
+
return Prepared(
|
|
46
|
+
image: cropped,
|
|
47
|
+
jpegData: cropped.jpegData(compressionQuality: jpegQuality) ?? Data()
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static func cropToDetectedBounds(image: UIImage, bounds: CGRect?) -> UIImage {
|
|
52
|
+
guard let bounds, let cgImage = image.cgImage else { return image }
|
|
53
|
+
let region = KtpAutoCrop.cropTo(
|
|
54
|
+
bounds: bounds,
|
|
55
|
+
imageSize: CGSize(width: cgImage.width, height: cgImage.height),
|
|
56
|
+
targetRatio: KtpFrameOverlayView.frameRatio
|
|
57
|
+
)
|
|
58
|
+
let rect = CGRect(
|
|
59
|
+
x: region.left,
|
|
60
|
+
y: region.top,
|
|
61
|
+
width: region.width,
|
|
62
|
+
height: region.height
|
|
63
|
+
)
|
|
64
|
+
guard let cropped = cgImage.cropping(to: rect) else { return image }
|
|
65
|
+
return downscale(UIImage(cgImage: cropped))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static func downscale(_ image: UIImage) -> UIImage {
|
|
69
|
+
let longestSide = max(image.size.width, image.size.height)
|
|
70
|
+
guard longestSide > maxUploadDimension else { return image }
|
|
71
|
+
let scale = maxUploadDimension / longestSide
|
|
72
|
+
let target = CGSize(width: image.size.width * scale, height: image.size.height * scale)
|
|
73
|
+
let format = UIGraphicsImageRendererFormat.default()
|
|
74
|
+
format.scale = 1
|
|
75
|
+
format.opaque = true
|
|
76
|
+
return UIGraphicsImageRenderer(size: target, format: format).image { _ in
|
|
77
|
+
image.draw(in: CGRect(origin: .zero, size: target))
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static func normalizedOrientation(_ image: UIImage) -> UIImage {
|
|
82
|
+
guard image.imageOrientation != .up else { return image }
|
|
83
|
+
let format = UIGraphicsImageRendererFormat.default()
|
|
84
|
+
format.scale = image.scale
|
|
85
|
+
format.opaque = true
|
|
86
|
+
return UIGraphicsImageRenderer(size: image.size, format: format).image { _ in
|
|
87
|
+
image.draw(in: CGRect(origin: .zero, size: image.size))
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|