@capacitor-community/camera-preview 2.0.0 → 3.1.0
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 +27 -8
- package/android/build.gradle +2 -4
- package/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java +3 -3
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +835 -799
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +184 -173
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomSurfaceView.java +12 -14
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomTextureView.java +16 -18
- package/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java +327 -323
- package/android/src/main/java/com/ahm/capacitor/camera/preview/TapGestureDetector.java +15 -14
- package/android/src/test/java/com/getcapacitor/ExampleUnitTest.java +4 -3
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +2 -2
- package/dist/esm/web.js +24 -23
- package/dist/esm/web.js.map +1 -1
- package/ios/Plugin/CameraController.swift +173 -114
- package/ios/Plugin/Plugin.swift +79 -88
- package/ios/PluginTests/PluginTests.swift +8 -8
- package/package.json +27 -2
package/ios/Plugin/Plugin.swift
CHANGED
|
@@ -8,7 +8,7 @@ import AVFoundation
|
|
|
8
8
|
@objc(CameraPreview)
|
|
9
9
|
public class CameraPreview: CAPPlugin {
|
|
10
10
|
|
|
11
|
-
var previewView:UIView!
|
|
11
|
+
var previewView: UIView!
|
|
12
12
|
var cameraPosition = String()
|
|
13
13
|
let cameraController = CameraController()
|
|
14
14
|
var x: CGFloat?
|
|
@@ -19,34 +19,21 @@ public class CameraPreview: CAPPlugin {
|
|
|
19
19
|
var rotateWhenOrientationChanged: Bool?
|
|
20
20
|
var toBack: Bool?
|
|
21
21
|
var storeToFile: Bool?
|
|
22
|
+
var enableZoom: Bool?
|
|
22
23
|
var highResolutionOutput: Bool = false
|
|
24
|
+
var disableAudio: Bool = false
|
|
23
25
|
|
|
24
26
|
@objc func rotated() {
|
|
27
|
+
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height!;
|
|
25
28
|
|
|
26
|
-
if
|
|
27
|
-
|
|
28
|
-
// we started in landscape
|
|
29
|
-
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height!;
|
|
30
|
-
self.previewView.frame = CGRect(x: self.x!, y: self.y!, width: self.width!, height: height)
|
|
31
|
-
} else {
|
|
32
|
-
// we started in portrait
|
|
33
|
-
let width = self.paddingBottom != nil ? self.width! - self.paddingBottom!: self.width!;
|
|
34
|
-
self.previewView.frame = CGRect(x: self.y!, y: self.x!, width: self.height!, height: width)
|
|
35
|
-
}
|
|
29
|
+
if UIApplication.shared.statusBarOrientation.isLandscape {
|
|
30
|
+
self.previewView.frame = CGRect(x: self.y!, y: self.x!, width: max(height, self.width!), height: min(height, self.width!))
|
|
36
31
|
self.cameraController.previewLayer?.frame = self.previewView.frame
|
|
37
32
|
}
|
|
38
33
|
|
|
39
|
-
if
|
|
34
|
+
if UIApplication.shared.statusBarOrientation.isPortrait {
|
|
40
35
|
if (self.previewView != nil && self.x != nil && self.y != nil && self.width != nil && self.height != nil) {
|
|
41
|
-
|
|
42
|
-
// we started in portrait
|
|
43
|
-
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height!;
|
|
44
|
-
self.previewView.frame = CGRect(x: self.x!, y: self.y!, width: self.width!, height: height)
|
|
45
|
-
} else {
|
|
46
|
-
// we started in landscape
|
|
47
|
-
let width = self.paddingBottom != nil ? self.width! - self.paddingBottom!: self.width!;
|
|
48
|
-
self.previewView.frame = CGRect(x: self.y!, y: self.x!, width: self.height!, height: width)
|
|
49
|
-
}
|
|
36
|
+
self.previewView.frame = CGRect(x: self.x!, y: self.y!, width: min(height, self.width!), height: max(height, self.width!))
|
|
50
37
|
}
|
|
51
38
|
self.cameraController.previewLayer?.frame = self.previewView.frame
|
|
52
39
|
}
|
|
@@ -57,7 +44,7 @@ public class CameraPreview: CAPPlugin {
|
|
|
57
44
|
@objc func start(_ call: CAPPluginCall) {
|
|
58
45
|
self.cameraPosition = call.getString("position") ?? "rear"
|
|
59
46
|
self.highResolutionOutput = call.getBool("enableHighResolution") ?? false
|
|
60
|
-
self.cameraController.highResolutionOutput = self.highResolutionOutput
|
|
47
|
+
self.cameraController.highResolutionOutput = self.highResolutionOutput
|
|
61
48
|
|
|
62
49
|
if call.getInt("width") != nil {
|
|
63
50
|
self.width = CGFloat(call.getInt("width")!)
|
|
@@ -78,45 +65,50 @@ public class CameraPreview: CAPPlugin {
|
|
|
78
65
|
self.rotateWhenOrientationChanged = call.getBool("rotateWhenOrientationChanged") ?? true
|
|
79
66
|
self.toBack = call.getBool("toBack") ?? false
|
|
80
67
|
self.storeToFile = call.getBool("storeToFile") ?? false
|
|
81
|
-
|
|
68
|
+
self.enableZoom = call.getBool("enableZoom") ?? false
|
|
69
|
+
self.disableAudio = call.getBool("disableAudio") ?? false
|
|
70
|
+
|
|
82
71
|
AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) in
|
|
83
72
|
guard granted else {
|
|
84
|
-
call.reject("permission failed")
|
|
73
|
+
call.reject("permission failed")
|
|
85
74
|
return
|
|
86
75
|
}
|
|
87
|
-
|
|
76
|
+
|
|
88
77
|
DispatchQueue.main.async {
|
|
89
|
-
if
|
|
78
|
+
if self.cameraController.captureSession?.isRunning ?? false {
|
|
90
79
|
call.reject("camera already started")
|
|
91
80
|
} else {
|
|
92
|
-
self.cameraController.prepare(cameraPosition: self.cameraPosition){error in
|
|
81
|
+
self.cameraController.prepare(cameraPosition: self.cameraPosition, disableAudio: self.disableAudio){error in
|
|
93
82
|
if let error = error {
|
|
94
83
|
print(error)
|
|
95
84
|
call.reject(error.localizedDescription)
|
|
96
85
|
return
|
|
97
86
|
}
|
|
98
|
-
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height
|
|
87
|
+
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height!
|
|
99
88
|
self.previewView = UIView(frame: CGRect(x: self.x ?? 0, y: self.y ?? 0, width: self.width!, height: height))
|
|
100
89
|
self.webView?.isOpaque = false
|
|
101
90
|
self.webView?.backgroundColor = UIColor.clear
|
|
102
91
|
self.webView?.scrollView.backgroundColor = UIColor.clear
|
|
103
92
|
self.webView?.superview?.addSubview(self.previewView)
|
|
104
|
-
if
|
|
93
|
+
if self.toBack! {
|
|
105
94
|
self.webView?.superview?.bringSubviewToFront(self.webView!)
|
|
106
95
|
}
|
|
107
96
|
try? self.cameraController.displayPreview(on: self.previewView)
|
|
108
|
-
|
|
109
|
-
|
|
97
|
+
|
|
98
|
+
let frontView = self.toBack! ? self.webView : self.previewView
|
|
99
|
+
self.cameraController.setupGestures(target: frontView ?? self.previewView, enableZoom: self.enableZoom!)
|
|
100
|
+
|
|
101
|
+
if self.rotateWhenOrientationChanged == true {
|
|
110
102
|
NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
|
|
111
103
|
}
|
|
112
|
-
|
|
104
|
+
|
|
113
105
|
call.resolve()
|
|
114
106
|
|
|
115
107
|
}
|
|
116
108
|
}
|
|
117
109
|
}
|
|
118
|
-
})
|
|
119
|
-
|
|
110
|
+
})
|
|
111
|
+
|
|
120
112
|
}
|
|
121
113
|
|
|
122
114
|
@objc func flip(_ call: CAPPluginCall) {
|
|
@@ -130,7 +122,7 @@ public class CameraPreview: CAPPlugin {
|
|
|
130
122
|
|
|
131
123
|
@objc func stop(_ call: CAPPluginCall) {
|
|
132
124
|
DispatchQueue.main.async {
|
|
133
|
-
if
|
|
125
|
+
if self.cameraController.captureSession?.isRunning ?? false {
|
|
134
126
|
self.cameraController.captureSession?.stopRunning()
|
|
135
127
|
self.previewView.removeFromSuperview()
|
|
136
128
|
self.webView?.isOpaque = true
|
|
@@ -150,45 +142,45 @@ public class CameraPreview: CAPPlugin {
|
|
|
150
142
|
let fileUrl=path.appendingPathComponent(fileName)
|
|
151
143
|
return fileUrl
|
|
152
144
|
}
|
|
153
|
-
|
|
145
|
+
|
|
154
146
|
@objc func capture(_ call: CAPPluginCall) {
|
|
155
147
|
DispatchQueue.main.async {
|
|
156
148
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
149
|
+
let quality: Int? = call.getInt("quality", 85)
|
|
150
|
+
|
|
151
|
+
self.cameraController.captureImage { (image, error) in
|
|
160
152
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
153
|
+
guard let image = image else {
|
|
154
|
+
print(error ?? "Image capture error")
|
|
155
|
+
guard let error = error else {
|
|
156
|
+
call.reject("Image capture error")
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
call.reject(error.localizedDescription)
|
|
165
160
|
return
|
|
166
161
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
} else {
|
|
175
|
-
imageData = image.jpegData(compressionQuality: CGFloat(quality!/100))
|
|
176
|
-
}
|
|
162
|
+
let imageData: Data?
|
|
163
|
+
if self.cameraController.currentCameraPosition == .front {
|
|
164
|
+
let flippedImage = image.withHorizontallyFlippedOrientation()
|
|
165
|
+
imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality!/100))
|
|
166
|
+
} else {
|
|
167
|
+
imageData = image.jpegData(compressionQuality: CGFloat(quality!/100))
|
|
168
|
+
}
|
|
177
169
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
170
|
+
if self.storeToFile == false {
|
|
171
|
+
let imageBase64 = imageData?.base64EncodedString()
|
|
172
|
+
call.resolve(["value": imageBase64!])
|
|
173
|
+
} else {
|
|
174
|
+
do {
|
|
175
|
+
let fileUrl=self.getTempFilePath()
|
|
176
|
+
try imageData?.write(to: fileUrl)
|
|
177
|
+
call.resolve(["value": fileUrl.absoluteString])
|
|
178
|
+
} catch {
|
|
179
|
+
call.reject("error writing image to file")
|
|
180
|
+
}
|
|
188
181
|
}
|
|
189
182
|
}
|
|
190
183
|
}
|
|
191
|
-
}
|
|
192
184
|
}
|
|
193
185
|
|
|
194
186
|
@objc func captureSample(_ call: CAPPluginCall) {
|
|
@@ -203,20 +195,20 @@ public class CameraPreview: CAPPlugin {
|
|
|
203
195
|
}
|
|
204
196
|
|
|
205
197
|
let imageData: Data?
|
|
206
|
-
if
|
|
198
|
+
if self.cameraPosition == "front" {
|
|
207
199
|
let flippedImage = image.withHorizontallyFlippedOrientation()
|
|
208
200
|
imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality!/100))
|
|
209
201
|
} else {
|
|
210
202
|
imageData = image.jpegData(compressionQuality: CGFloat(quality!/100))
|
|
211
203
|
}
|
|
212
204
|
|
|
213
|
-
if
|
|
205
|
+
if self.storeToFile == false {
|
|
214
206
|
let imageBase64 = imageData?.base64EncodedString()
|
|
215
207
|
call.resolve(["value": imageBase64!])
|
|
216
208
|
} else {
|
|
217
209
|
do {
|
|
218
210
|
let fileUrl = self.getTempFilePath()
|
|
219
|
-
try imageData?.write(to:fileUrl)
|
|
211
|
+
try imageData?.write(to: fileUrl)
|
|
220
212
|
call.resolve(["value": fileUrl.absoluteString])
|
|
221
213
|
} catch {
|
|
222
214
|
call.reject("Error writing image to file")
|
|
@@ -225,7 +217,7 @@ public class CameraPreview: CAPPlugin {
|
|
|
225
217
|
}
|
|
226
218
|
}
|
|
227
219
|
}
|
|
228
|
-
|
|
220
|
+
|
|
229
221
|
@objc func getSupportedFlashModes(_ call: CAPPluginCall) {
|
|
230
222
|
do {
|
|
231
223
|
let supportedFlashModes = try self.cameraController.getSupportedFlashModes()
|
|
@@ -234,7 +226,7 @@ public class CameraPreview: CAPPlugin {
|
|
|
234
226
|
call.reject("failed to get supported flash modes")
|
|
235
227
|
}
|
|
236
228
|
}
|
|
237
|
-
|
|
229
|
+
|
|
238
230
|
@objc func setFlashMode(_ call: CAPPluginCall) {
|
|
239
231
|
guard let flashMode = call.getString("flashMode") else {
|
|
240
232
|
call.reject("failed to set flash mode. required parameter flashMode is missing")
|
|
@@ -243,17 +235,17 @@ public class CameraPreview: CAPPlugin {
|
|
|
243
235
|
do {
|
|
244
236
|
var flashModeAsEnum: AVCaptureDevice.FlashMode?
|
|
245
237
|
switch flashMode {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
238
|
+
case "off" :
|
|
239
|
+
flashModeAsEnum = AVCaptureDevice.FlashMode.off
|
|
240
|
+
case "on":
|
|
241
|
+
flashModeAsEnum = AVCaptureDevice.FlashMode.on
|
|
242
|
+
case "auto":
|
|
243
|
+
flashModeAsEnum = AVCaptureDevice.FlashMode.auto
|
|
244
|
+
default: break
|
|
253
245
|
}
|
|
254
246
|
if flashModeAsEnum != nil {
|
|
255
247
|
try self.cameraController.setFlashMode(flashMode: flashModeAsEnum!)
|
|
256
|
-
} else if
|
|
248
|
+
} else if flashMode == "torch" {
|
|
257
249
|
try self.cameraController.setTorchMode()
|
|
258
250
|
} else {
|
|
259
251
|
call.reject("Flash Mode not supported")
|
|
@@ -265,11 +257,11 @@ public class CameraPreview: CAPPlugin {
|
|
|
265
257
|
}
|
|
266
258
|
}
|
|
267
259
|
|
|
268
|
-
|
|
269
|
-
|
|
260
|
+
@objc func startRecordVideo(_ call: CAPPluginCall) {
|
|
261
|
+
DispatchQueue.main.async {
|
|
270
262
|
|
|
271
263
|
let quality: Int? = call.getInt("quality", 85)
|
|
272
|
-
|
|
264
|
+
|
|
273
265
|
self.cameraController.captureVideo { (image, error) in
|
|
274
266
|
|
|
275
267
|
guard let image = image else {
|
|
@@ -282,19 +274,18 @@ public class CameraPreview: CAPPlugin {
|
|
|
282
274
|
return
|
|
283
275
|
}
|
|
284
276
|
|
|
285
|
-
|
|
277
|
+
// self.videoUrl = image
|
|
286
278
|
|
|
287
|
-
|
|
288
|
-
}
|
|
279
|
+
call.resolve(["value": image.absoluteString])
|
|
289
280
|
}
|
|
290
281
|
}
|
|
282
|
+
}
|
|
291
283
|
|
|
284
|
+
@objc func stopRecordVideo(_ call: CAPPluginCall) {
|
|
292
285
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
self.cameraController.stopRecording { (error) in
|
|
286
|
+
self.cameraController.stopRecording { (_) in
|
|
296
287
|
|
|
297
|
-
}
|
|
298
288
|
}
|
|
299
|
-
|
|
289
|
+
}
|
|
290
|
+
|
|
300
291
|
}
|
|
@@ -3,33 +3,33 @@ import Capacitor
|
|
|
3
3
|
@testable import Plugin
|
|
4
4
|
|
|
5
5
|
class PluginTests: XCTestCase {
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
override func setUp() {
|
|
8
8
|
super.setUp()
|
|
9
9
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
override func tearDown() {
|
|
13
13
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
|
14
14
|
super.tearDown()
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
func testEcho() {
|
|
18
18
|
// This is an example of a functional test case for a plugin.
|
|
19
19
|
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
let value = "Hello, World!"
|
|
22
22
|
let plugin = MyPlugin()
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
let call = CAPPluginCall(callbackId: "test", options: [
|
|
25
25
|
"value": value
|
|
26
|
-
], success: { (result,
|
|
26
|
+
], success: { (result, _) in
|
|
27
27
|
let resultValue = result!.data["value"] as? String
|
|
28
28
|
XCTAssertEqual(value, resultValue)
|
|
29
|
-
}, error: { (
|
|
29
|
+
}, error: { (_) in
|
|
30
30
|
XCTFail("Error shouldn't have been called")
|
|
31
31
|
})
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
plugin.echo(call!)
|
|
34
34
|
}
|
|
35
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor-community/camera-preview",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Camera preview",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"types": "dist/esm/index.d.ts",
|
|
@@ -8,8 +8,13 @@
|
|
|
8
8
|
"build": "npm run clean && tsc",
|
|
9
9
|
"clean": "rimraf './dist'",
|
|
10
10
|
"watch": "tsc --watch",
|
|
11
|
+
"lint": "concurrently -g \"npm:eslint\" \"npm:prettier -- --check\" \"npm run swiftlint -- lint ios\"",
|
|
12
|
+
"fmt": "concurrently -g \"npm:eslint -- --fix\" \"npm:prettier -- --write\" \"npm:swiftlint -- lint --fix --format ios\"",
|
|
13
|
+
"eslint": "eslint . --ext ts",
|
|
14
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
|
|
15
|
+
"swiftlint": "node-swiftlint",
|
|
11
16
|
"prepublishOnly": "npm run build",
|
|
12
|
-
"prepare": "npm run build"
|
|
17
|
+
"prepare": "husky install && npm run build"
|
|
13
18
|
},
|
|
14
19
|
"author": "Ariel Hernandez Musa",
|
|
15
20
|
"license": "MIT",
|
|
@@ -19,9 +24,24 @@
|
|
|
19
24
|
"devDependencies": {
|
|
20
25
|
"@capacitor/android": "latest",
|
|
21
26
|
"@capacitor/ios": "latest",
|
|
27
|
+
"@ionic/eslint-config": "^0.3.0",
|
|
28
|
+
"@ionic/prettier-config": "^2.0.0",
|
|
29
|
+
"@ionic/swiftlint-config": "^1.1.2",
|
|
30
|
+
"concurrently": "^7.0.0",
|
|
31
|
+
"eslint": "^7.32.0",
|
|
32
|
+
"husky": "^7.0.4",
|
|
33
|
+
"prettier": "^2.5.1",
|
|
34
|
+
"prettier-plugin-java": "^1.6.1",
|
|
35
|
+
"pretty-quick": "^3.1.3",
|
|
22
36
|
"rimraf": "^3.0.2",
|
|
37
|
+
"swiftlint": "^1.0.1",
|
|
23
38
|
"typescript": "^4.3.2"
|
|
24
39
|
},
|
|
40
|
+
"husky": {
|
|
41
|
+
"hooks": {
|
|
42
|
+
"pre-commit": "pretty-quick --staged"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
25
45
|
"files": [
|
|
26
46
|
"dist/",
|
|
27
47
|
"ios/",
|
|
@@ -41,6 +61,11 @@
|
|
|
41
61
|
"src": "android"
|
|
42
62
|
}
|
|
43
63
|
},
|
|
64
|
+
"prettier": "@ionic/prettier-config",
|
|
65
|
+
"swiftlint": "@ionic/swiftlint-config",
|
|
66
|
+
"eslintConfig": {
|
|
67
|
+
"extends": "@ionic/eslint-config/recommended"
|
|
68
|
+
},
|
|
44
69
|
"repository": {
|
|
45
70
|
"type": "git",
|
|
46
71
|
"url": "https://github.com/capacitor-community/camera-preview.git"
|