@capacitor-community/camera-preview 3.0.0 → 3.1.2
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 +11 -2
- package/android/build.gradle +14 -7
- package/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java +3 -3
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +869 -798
- 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/definitions.d.ts +10 -8
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +3 -3
- package/dist/esm/web.js +36 -25
- package/dist/esm/web.js.map +1 -1
- package/ios/Plugin/CameraController.swift +107 -129
- package/ios/Plugin/Plugin.swift +76 -90
- 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?
|
|
@@ -21,33 +21,19 @@ public class CameraPreview: CAPPlugin {
|
|
|
21
21
|
var storeToFile: Bool?
|
|
22
22
|
var enableZoom: Bool?
|
|
23
23
|
var highResolutionOutput: Bool = false
|
|
24
|
+
var disableAudio: Bool = false
|
|
24
25
|
|
|
25
26
|
@objc func rotated() {
|
|
27
|
+
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height!;
|
|
26
28
|
|
|
27
|
-
if
|
|
28
|
-
|
|
29
|
-
// we started in landscape
|
|
30
|
-
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height!;
|
|
31
|
-
self.previewView.frame = CGRect(x: self.x!, y: self.y!, width: self.width!, height: height)
|
|
32
|
-
} else {
|
|
33
|
-
// we started in portrait
|
|
34
|
-
let width = self.paddingBottom != nil ? self.width! - self.paddingBottom!: self.width!;
|
|
35
|
-
self.previewView.frame = CGRect(x: self.y!, y: self.x!, width: self.height!, height: width)
|
|
36
|
-
}
|
|
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!))
|
|
37
31
|
self.cameraController.previewLayer?.frame = self.previewView.frame
|
|
38
32
|
}
|
|
39
33
|
|
|
40
|
-
if
|
|
34
|
+
if UIApplication.shared.statusBarOrientation.isPortrait {
|
|
41
35
|
if (self.previewView != nil && self.x != nil && self.y != nil && self.width != nil && self.height != nil) {
|
|
42
|
-
|
|
43
|
-
// we started in portrait
|
|
44
|
-
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height!;
|
|
45
|
-
self.previewView.frame = CGRect(x: self.x!, y: self.y!, width: self.width!, height: height)
|
|
46
|
-
} else {
|
|
47
|
-
// we started in landscape
|
|
48
|
-
let width = self.paddingBottom != nil ? self.width! - self.paddingBottom!: self.width!;
|
|
49
|
-
self.previewView.frame = CGRect(x: self.y!, y: self.x!, width: self.height!, height: width)
|
|
50
|
-
}
|
|
36
|
+
self.previewView.frame = CGRect(x: self.x!, y: self.y!, width: min(height, self.width!), height: max(height, self.width!))
|
|
51
37
|
}
|
|
52
38
|
self.cameraController.previewLayer?.frame = self.previewView.frame
|
|
53
39
|
}
|
|
@@ -58,7 +44,7 @@ public class CameraPreview: CAPPlugin {
|
|
|
58
44
|
@objc func start(_ call: CAPPluginCall) {
|
|
59
45
|
self.cameraPosition = call.getString("position") ?? "rear"
|
|
60
46
|
self.highResolutionOutput = call.getBool("enableHighResolution") ?? false
|
|
61
|
-
self.cameraController.highResolutionOutput = self.highResolutionOutput
|
|
47
|
+
self.cameraController.highResolutionOutput = self.highResolutionOutput
|
|
62
48
|
|
|
63
49
|
if call.getInt("width") != nil {
|
|
64
50
|
self.width = CGFloat(call.getInt("width")!)
|
|
@@ -80,48 +66,49 @@ public class CameraPreview: CAPPlugin {
|
|
|
80
66
|
self.toBack = call.getBool("toBack") ?? false
|
|
81
67
|
self.storeToFile = call.getBool("storeToFile") ?? false
|
|
82
68
|
self.enableZoom = call.getBool("enableZoom") ?? false
|
|
83
|
-
|
|
69
|
+
self.disableAudio = call.getBool("disableAudio") ?? false
|
|
70
|
+
|
|
84
71
|
AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) in
|
|
85
72
|
guard granted else {
|
|
86
|
-
call.reject("permission failed")
|
|
73
|
+
call.reject("permission failed")
|
|
87
74
|
return
|
|
88
75
|
}
|
|
89
|
-
|
|
76
|
+
|
|
90
77
|
DispatchQueue.main.async {
|
|
91
|
-
if
|
|
78
|
+
if self.cameraController.captureSession?.isRunning ?? false {
|
|
92
79
|
call.reject("camera already started")
|
|
93
80
|
} else {
|
|
94
|
-
self.cameraController.prepare(cameraPosition: self.cameraPosition){error in
|
|
81
|
+
self.cameraController.prepare(cameraPosition: self.cameraPosition, disableAudio: self.disableAudio){error in
|
|
95
82
|
if let error = error {
|
|
96
83
|
print(error)
|
|
97
84
|
call.reject(error.localizedDescription)
|
|
98
85
|
return
|
|
99
86
|
}
|
|
100
|
-
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height
|
|
87
|
+
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height!
|
|
101
88
|
self.previewView = UIView(frame: CGRect(x: self.x ?? 0, y: self.y ?? 0, width: self.width!, height: height))
|
|
102
89
|
self.webView?.isOpaque = false
|
|
103
90
|
self.webView?.backgroundColor = UIColor.clear
|
|
104
91
|
self.webView?.scrollView.backgroundColor = UIColor.clear
|
|
105
92
|
self.webView?.superview?.addSubview(self.previewView)
|
|
106
|
-
if
|
|
93
|
+
if self.toBack! {
|
|
107
94
|
self.webView?.superview?.bringSubviewToFront(self.webView!)
|
|
108
95
|
}
|
|
109
96
|
try? self.cameraController.displayPreview(on: self.previewView)
|
|
110
|
-
|
|
111
|
-
let frontView = self.toBack! ? self.webView : self.previewView
|
|
97
|
+
|
|
98
|
+
let frontView = self.toBack! ? self.webView : self.previewView
|
|
112
99
|
self.cameraController.setupGestures(target: frontView ?? self.previewView, enableZoom: self.enableZoom!)
|
|
113
|
-
|
|
114
|
-
if
|
|
100
|
+
|
|
101
|
+
if self.rotateWhenOrientationChanged == true {
|
|
115
102
|
NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
|
|
116
103
|
}
|
|
117
|
-
|
|
104
|
+
|
|
118
105
|
call.resolve()
|
|
119
106
|
|
|
120
107
|
}
|
|
121
108
|
}
|
|
122
109
|
}
|
|
123
|
-
})
|
|
124
|
-
|
|
110
|
+
})
|
|
111
|
+
|
|
125
112
|
}
|
|
126
113
|
|
|
127
114
|
@objc func flip(_ call: CAPPluginCall) {
|
|
@@ -135,7 +122,7 @@ public class CameraPreview: CAPPlugin {
|
|
|
135
122
|
|
|
136
123
|
@objc func stop(_ call: CAPPluginCall) {
|
|
137
124
|
DispatchQueue.main.async {
|
|
138
|
-
if
|
|
125
|
+
if self.cameraController.captureSession?.isRunning ?? false {
|
|
139
126
|
self.cameraController.captureSession?.stopRunning()
|
|
140
127
|
self.previewView.removeFromSuperview()
|
|
141
128
|
self.webView?.isOpaque = true
|
|
@@ -155,45 +142,45 @@ public class CameraPreview: CAPPlugin {
|
|
|
155
142
|
let fileUrl=path.appendingPathComponent(fileName)
|
|
156
143
|
return fileUrl
|
|
157
144
|
}
|
|
158
|
-
|
|
145
|
+
|
|
159
146
|
@objc func capture(_ call: CAPPluginCall) {
|
|
160
147
|
DispatchQueue.main.async {
|
|
161
148
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
149
|
+
let quality: Int? = call.getInt("quality", 85)
|
|
150
|
+
|
|
151
|
+
self.cameraController.captureImage { (image, error) in
|
|
165
152
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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)
|
|
170
160
|
return
|
|
171
161
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
} else {
|
|
180
|
-
imageData = image.jpegData(compressionQuality: CGFloat(quality!/100))
|
|
181
|
-
}
|
|
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
|
+
}
|
|
182
169
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
+
}
|
|
193
181
|
}
|
|
194
182
|
}
|
|
195
183
|
}
|
|
196
|
-
}
|
|
197
184
|
}
|
|
198
185
|
|
|
199
186
|
@objc func captureSample(_ call: CAPPluginCall) {
|
|
@@ -208,20 +195,20 @@ public class CameraPreview: CAPPlugin {
|
|
|
208
195
|
}
|
|
209
196
|
|
|
210
197
|
let imageData: Data?
|
|
211
|
-
if
|
|
198
|
+
if self.cameraPosition == "front" {
|
|
212
199
|
let flippedImage = image.withHorizontallyFlippedOrientation()
|
|
213
200
|
imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality!/100))
|
|
214
201
|
} else {
|
|
215
202
|
imageData = image.jpegData(compressionQuality: CGFloat(quality!/100))
|
|
216
203
|
}
|
|
217
204
|
|
|
218
|
-
if
|
|
205
|
+
if self.storeToFile == false {
|
|
219
206
|
let imageBase64 = imageData?.base64EncodedString()
|
|
220
207
|
call.resolve(["value": imageBase64!])
|
|
221
208
|
} else {
|
|
222
209
|
do {
|
|
223
210
|
let fileUrl = self.getTempFilePath()
|
|
224
|
-
try imageData?.write(to:fileUrl)
|
|
211
|
+
try imageData?.write(to: fileUrl)
|
|
225
212
|
call.resolve(["value": fileUrl.absoluteString])
|
|
226
213
|
} catch {
|
|
227
214
|
call.reject("Error writing image to file")
|
|
@@ -230,7 +217,7 @@ public class CameraPreview: CAPPlugin {
|
|
|
230
217
|
}
|
|
231
218
|
}
|
|
232
219
|
}
|
|
233
|
-
|
|
220
|
+
|
|
234
221
|
@objc func getSupportedFlashModes(_ call: CAPPluginCall) {
|
|
235
222
|
do {
|
|
236
223
|
let supportedFlashModes = try self.cameraController.getSupportedFlashModes()
|
|
@@ -239,7 +226,7 @@ public class CameraPreview: CAPPlugin {
|
|
|
239
226
|
call.reject("failed to get supported flash modes")
|
|
240
227
|
}
|
|
241
228
|
}
|
|
242
|
-
|
|
229
|
+
|
|
243
230
|
@objc func setFlashMode(_ call: CAPPluginCall) {
|
|
244
231
|
guard let flashMode = call.getString("flashMode") else {
|
|
245
232
|
call.reject("failed to set flash mode. required parameter flashMode is missing")
|
|
@@ -248,17 +235,17 @@ public class CameraPreview: CAPPlugin {
|
|
|
248
235
|
do {
|
|
249
236
|
var flashModeAsEnum: AVCaptureDevice.FlashMode?
|
|
250
237
|
switch flashMode {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
|
258
245
|
}
|
|
259
246
|
if flashModeAsEnum != nil {
|
|
260
247
|
try self.cameraController.setFlashMode(flashMode: flashModeAsEnum!)
|
|
261
|
-
} else if
|
|
248
|
+
} else if flashMode == "torch" {
|
|
262
249
|
try self.cameraController.setTorchMode()
|
|
263
250
|
} else {
|
|
264
251
|
call.reject("Flash Mode not supported")
|
|
@@ -270,11 +257,11 @@ public class CameraPreview: CAPPlugin {
|
|
|
270
257
|
}
|
|
271
258
|
}
|
|
272
259
|
|
|
273
|
-
|
|
274
|
-
|
|
260
|
+
@objc func startRecordVideo(_ call: CAPPluginCall) {
|
|
261
|
+
DispatchQueue.main.async {
|
|
275
262
|
|
|
276
263
|
let quality: Int? = call.getInt("quality", 85)
|
|
277
|
-
|
|
264
|
+
|
|
278
265
|
self.cameraController.captureVideo { (image, error) in
|
|
279
266
|
|
|
280
267
|
guard let image = image else {
|
|
@@ -287,19 +274,18 @@ public class CameraPreview: CAPPlugin {
|
|
|
287
274
|
return
|
|
288
275
|
}
|
|
289
276
|
|
|
290
|
-
|
|
277
|
+
// self.videoUrl = image
|
|
291
278
|
|
|
292
|
-
|
|
293
|
-
}
|
|
279
|
+
call.resolve(["value": image.absoluteString])
|
|
294
280
|
}
|
|
295
281
|
}
|
|
282
|
+
}
|
|
296
283
|
|
|
284
|
+
@objc func stopRecordVideo(_ call: CAPPluginCall) {
|
|
297
285
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
self.cameraController.stopRecording { (error) in
|
|
286
|
+
self.cameraController.stopRecording { (_) in
|
|
301
287
|
|
|
302
|
-
}
|
|
303
288
|
}
|
|
304
|
-
|
|
289
|
+
}
|
|
290
|
+
|
|
305
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.
|
|
3
|
+
"version": "3.1.2",
|
|
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"
|