motion-capture 1.3.1 → 1.4.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.
- checksums.yaml +5 -5
- data/README.md +37 -4
- data/lib/project/motion-capture.rb +140 -22
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ee51432dacdc318b8b687203b598709f6d69e549709f43390628e6ab6b4f6b7b
|
4
|
+
data.tar.gz: 7df7fe7e9d0fc9fa21cf315edd714213991e75e4ba34cbc0f27d0a83e983ec79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89a3887fa974c95d0e2d37a3c36b90f842bc8d52d0f5e3a504df3e307759ca7bd2a62b7c7115305bc55b36d084955ce4a481cbc3292d0dc8bc47bcf5de22ef1c
|
7
|
+
data.tar.gz: 61c711ba4823f72564e0d21f86d21f4a8fc73f5846f0ffa9f6a9c0eb8c7b9aacbb11c2b1cdd2442b47f6a4a64f8b92353453ac180f4881d437eecf024f878da5
|
data/README.md
CHANGED
@@ -7,9 +7,9 @@ Camera support for custom camera controllers
|
|
7
7
|
``` ruby
|
8
8
|
motion_capture = Motion::Capture.new
|
9
9
|
motion_capture = Motion::Capture.new(device: :front) # specify camera
|
10
|
+
motion_capture = Motion::Capture.new(preset: AVCaptureSessionPreset640x480) # specify a different preset (defaults to high resolution photo)
|
10
11
|
|
11
|
-
|
12
|
-
view.addSubview(preview) # UIView containing AVCaptureVideoPreviewLayer
|
12
|
+
motion_capture.attach(view) # apply a AVCaptureVideoPreviewLayer to the specified view
|
13
13
|
|
14
14
|
motion_capture.toggle_camera # Switch between front/rear cameras
|
15
15
|
motion_capture.toggle_flash # Switch bettwen flash on/off
|
@@ -21,15 +21,34 @@ motion_capture.use_camera(:default)
|
|
21
21
|
motion_capture.use_camera(:front)
|
22
22
|
motion_capture.use_camera(:rear)
|
23
23
|
|
24
|
+
# When you're ready to start the capture session:
|
25
|
+
motion_capture.start!
|
26
|
+
|
27
|
+
# Capturing Single Photos
|
28
|
+
|
24
29
|
motion_capture.capture do |image_data|
|
25
30
|
# Use NSData
|
26
31
|
end
|
27
32
|
|
28
|
-
motion_capture.
|
29
|
-
# Use
|
33
|
+
motion_capture.capture_image do |image|
|
34
|
+
# Use UIImage
|
35
|
+
end
|
36
|
+
|
37
|
+
# Saving captured images to the Photos library
|
38
|
+
|
39
|
+
motion_capture.capture_and_save do |image_data, asset_url|
|
40
|
+
# Use NSData and NSURL
|
41
|
+
end
|
42
|
+
|
43
|
+
motion_capture.capture_image_and_save do |image, asset_url|
|
44
|
+
# Use UIImage and NSURL
|
30
45
|
end
|
46
|
+
|
47
|
+
# When you're done using the camera and are ready to stop the capture session:
|
48
|
+
motion_capture.stop!
|
31
49
|
```
|
32
50
|
|
51
|
+
|
33
52
|
## Setup
|
34
53
|
|
35
54
|
Add this line to your application's Gemfile:
|
@@ -44,6 +63,20 @@ Or install it yourself as:
|
|
44
63
|
|
45
64
|
$ gem install motion-capture
|
46
65
|
|
66
|
+
Add the necessary frameworks to your app configuration in your Rakefile:
|
67
|
+
|
68
|
+
app.frameworks << 'AVFoundation'
|
69
|
+
app.frameworks << 'Photos' # if you will be saving to the Photo library and targeting iOS 8+
|
70
|
+
app.frameworks << 'AssetsLibrary' # if you will be targeting iOS 4-7
|
71
|
+
|
72
|
+
Then update your app configuration in your Rakefile to specify the message that will be displayed when asking the user for permission to use the camera:
|
73
|
+
|
74
|
+
app.info_plist['NSCameraUsageDescription'] = 'Camera will be used for taking your profile photo.'
|
75
|
+
|
76
|
+
If you will be saving photos to the Photo Library, you will also need to specify the message that will be displayed to the user:
|
77
|
+
|
78
|
+
app.info_plist['NSPhotoLibraryUsageDescription'] = 'Photos taken will be saved to your library.'
|
79
|
+
|
47
80
|
## Contributing
|
48
81
|
|
49
82
|
1. Fork it
|
@@ -8,18 +8,55 @@ module Motion; class Capture
|
|
8
8
|
@options = options
|
9
9
|
end
|
10
10
|
|
11
|
-
def on_error(block)
|
11
|
+
def on_error(&block)
|
12
12
|
@error_callback = block
|
13
13
|
end
|
14
14
|
|
15
|
-
def start!
|
15
|
+
def start!
|
16
|
+
return if session.running?
|
17
|
+
if defined?(AVCapturePhotoOutput) # iOS 10+
|
18
|
+
@starting = true
|
19
|
+
authorize_camera do |success|
|
20
|
+
if success
|
21
|
+
Dispatch::Queue.new('motion-capture').async do
|
22
|
+
configure_session
|
23
|
+
session.startRunning
|
24
|
+
@starting = false
|
25
|
+
end
|
26
|
+
else
|
27
|
+
@starting = false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
else # iOS 4-9
|
31
|
+
configure_session
|
32
|
+
session.startRunning
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def authorize_camera(&block)
|
37
|
+
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: -> (success) {
|
38
|
+
block.call(success)
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
def configure_session
|
43
|
+
session.beginConfiguration
|
44
|
+
|
45
|
+
set_preset(options.fetch(:preset, AVCaptureSessionPresetPhoto))
|
46
|
+
|
16
47
|
use_camera(options.fetch(:device, :default))
|
17
48
|
|
18
|
-
|
49
|
+
if defined?(AVCapturePhotoOutput) # iOS 10+
|
50
|
+
add_output(photo_output)
|
51
|
+
else # iOS 4-9
|
52
|
+
add_output(still_image_output)
|
53
|
+
end
|
19
54
|
|
20
|
-
|
55
|
+
session.commitConfiguration
|
56
|
+
end
|
21
57
|
|
22
|
-
|
58
|
+
def running?
|
59
|
+
@session && session.running?
|
23
60
|
end
|
24
61
|
|
25
62
|
def stop!
|
@@ -31,30 +68,66 @@ module Motion; class Capture
|
|
31
68
|
preview_layer.removeFromSuperlayer if preview_layer && preview_layer.superlayer
|
32
69
|
|
33
70
|
@still_image_output = nil
|
71
|
+
@photo_output = nil
|
34
72
|
@session = nil
|
35
73
|
@preview_layer = nil
|
36
74
|
end
|
37
75
|
|
38
|
-
def
|
39
|
-
|
76
|
+
def capture(&block)
|
77
|
+
if defined?(AVCapturePhotoOutput) # iOS 10+
|
78
|
+
Dispatch::Queue.new('motion-capture').async do
|
79
|
+
ensure_running_session do
|
80
|
+
update_video_orientation!
|
81
|
+
@capture_callback = block
|
82
|
+
capture_settings = AVCapturePhotoSettings.photoSettingsWithFormat(AVVideoCodecKey => AVVideoCodecJPEG)
|
83
|
+
photo_output.capturePhotoWithSettings(capture_settings, delegate: self)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
else # iOS 4-9
|
87
|
+
still_image_output.captureStillImageAsynchronouslyFromConnection(still_image_connection, completionHandler: -> (buffer, error) {
|
88
|
+
if error
|
89
|
+
error_callback.call(error)
|
90
|
+
else
|
91
|
+
image_data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
|
92
|
+
block.call(image_data)
|
93
|
+
end
|
94
|
+
})
|
95
|
+
end
|
40
96
|
end
|
41
97
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
98
|
+
def ensure_running_session(&block)
|
99
|
+
start! unless @starting || session.running?
|
100
|
+
while @starting || !session.running?
|
101
|
+
# wait for session to start...
|
102
|
+
end
|
103
|
+
block.call
|
104
|
+
end
|
48
105
|
|
49
|
-
|
50
|
-
|
51
|
-
|
106
|
+
# iOS 11+ AVCapturePhotoCaptureDelegate method
|
107
|
+
def captureOutput(output, didFinishProcessingPhoto: photo, error: error)
|
108
|
+
if error
|
109
|
+
error_callback.call(error)
|
110
|
+
else
|
111
|
+
@capture_callback.call(photo.fileDataRepresentation)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# iOS 10 AVCapturePhotoCaptureDelegate method
|
116
|
+
def captureOutput(output, didFinishProcessingPhotoSampleBuffer: photo_sample_buffer, previewPhotoSampleBuffer: preview_photo_sample_buffer, resolvedSettings: resolved_settings, bracketSettings: bracket_settings, error: error)
|
117
|
+
if error
|
118
|
+
error_callback.call(error)
|
119
|
+
else
|
120
|
+
jpeg_data = AVCapturePhotoOutput.jpegPhotoDataRepresentation(
|
121
|
+
forJPEGSampleBuffer: photo_sample_buffer,
|
122
|
+
previewPhotoSampleBuffer: preview_photo_sample_buffer
|
123
|
+
)
|
124
|
+
@capture_callback.call(jpeg_data)
|
125
|
+
end
|
52
126
|
end
|
53
127
|
|
54
128
|
def capture_image(&block)
|
55
129
|
capture do |jpeg_data|
|
56
130
|
image = UIImage.imageWithData(jpeg_data)
|
57
|
-
|
58
131
|
block.call(image)
|
59
132
|
end
|
60
133
|
end
|
@@ -71,18 +144,40 @@ module Motion; class Capture
|
|
71
144
|
capture do |jpeg_data|
|
72
145
|
save_data(jpeg_data) do |asset_url|
|
73
146
|
image = UIImage.imageWithData(jpeg_data)
|
74
|
-
|
75
147
|
block.call(image, asset_url)
|
76
148
|
end
|
77
149
|
end
|
78
150
|
end
|
79
151
|
|
80
152
|
def save_data(jpeg_data, &block)
|
153
|
+
if defined?(PHPhotoLibrary) # iOS 8+
|
154
|
+
save_to_photo_library(jpeg_data, &block)
|
155
|
+
else # iOS 4-8
|
156
|
+
save_to_assets_library(jpeg_data, &block)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# iOS 4-8
|
161
|
+
def save_to_assets_library(jpeg_data, &block)
|
81
162
|
assets_library.writeImageDataToSavedPhotosAlbum(jpeg_data, metadata: nil, completionBlock: -> (asset_url, error) {
|
82
163
|
error ? error_callback.call(error) : block.call(asset_url)
|
83
164
|
})
|
84
165
|
end
|
85
166
|
|
167
|
+
# iOS 8+
|
168
|
+
def save_to_photo_library(jpeg_data, &block)
|
169
|
+
photo_library.performChanges(-> {
|
170
|
+
image = UIImage.imageWithData(jpeg_data)
|
171
|
+
PHAssetChangeRequest.creationRequestForAssetFromImage(image)
|
172
|
+
}, completionHandler: -> (success, error) {
|
173
|
+
if error
|
174
|
+
error_callback.call(error)
|
175
|
+
else
|
176
|
+
block.call(nil) # asset url is not returned in completion block
|
177
|
+
end
|
178
|
+
})
|
179
|
+
end
|
180
|
+
|
86
181
|
def attach(view, options = {})
|
87
182
|
@preview_layer = preview_layer_for_view(view, options)
|
88
183
|
|
@@ -124,13 +219,14 @@ module Motion; class Capture
|
|
124
219
|
end
|
125
220
|
|
126
221
|
def preset
|
127
|
-
session.
|
222
|
+
session.sessionPreset if @session
|
128
223
|
end
|
129
224
|
|
130
225
|
def flash
|
131
226
|
device.flashMode if @device
|
132
227
|
end
|
133
228
|
|
229
|
+
# iOS 4-9
|
134
230
|
def set_flash(mode = :auto)
|
135
231
|
configure_with_lock { device.flashMode = FLASH_MODES[mode] } if flash_mode_available?(mode)
|
136
232
|
end
|
@@ -145,6 +241,7 @@ module Motion; class Capture
|
|
145
241
|
@error_callback ||= -> (error) { p "An error occurred: #{error.localizedDescription}." }
|
146
242
|
end
|
147
243
|
|
244
|
+
# iOS 4-9
|
148
245
|
def still_image_connection
|
149
246
|
still_image_output.connectionWithMediaType(AVMediaTypeVideo).tap do |connection|
|
150
247
|
device_orientation = UIDevice.currentDevice.orientation
|
@@ -154,6 +251,16 @@ module Motion; class Capture
|
|
154
251
|
end
|
155
252
|
end
|
156
253
|
|
254
|
+
# iOS 10+
|
255
|
+
def update_video_orientation!
|
256
|
+
photo_output.connectionWithMediaType(AVMediaTypeVideo).tap do |connection|
|
257
|
+
device_orientation = UIDevice.currentDevice.orientation
|
258
|
+
video_orientation = orientation_mapping.fetch(device_orientation, AVCaptureVideoOrientationPortrait)
|
259
|
+
|
260
|
+
connection.setVideoOrientation(video_orientation) if connection.videoOrientationSupported?
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
157
264
|
def orientation_mapping
|
158
265
|
{ UIDeviceOrientationPortrait => AVCaptureVideoOrientationPortrait,
|
159
266
|
UIDeviceOrientationPortraitUpsideDown => AVCaptureVideoOrientationPortraitUpsideDown,
|
@@ -161,10 +268,16 @@ module Motion; class Capture
|
|
161
268
|
UIDeviceOrientationLandscapeLeft => AVCaptureVideoOrientationLandscapeRight }
|
162
269
|
end
|
163
270
|
|
271
|
+
# iOS 4-8
|
164
272
|
def assets_library
|
165
273
|
@assets_library ||= ALAssetsLibrary.alloc.init
|
166
274
|
end
|
167
275
|
|
276
|
+
# iOS 8+
|
277
|
+
def photo_library
|
278
|
+
@photo_library ||= PHPhotoLibrary.sharedPhotoLibrary
|
279
|
+
end
|
280
|
+
|
168
281
|
def configure_with_lock(&block)
|
169
282
|
error_pointer = Pointer.new(:object)
|
170
283
|
|
@@ -213,7 +326,7 @@ module Motion; class Capture
|
|
213
326
|
session.addInput(input) if session.canAddInput(input)
|
214
327
|
end
|
215
328
|
|
216
|
-
def
|
329
|
+
def add_output(output)
|
217
330
|
session.addOutput(output) if session.canAddOutput(output)
|
218
331
|
end
|
219
332
|
|
@@ -260,11 +373,16 @@ module Motion; class Capture
|
|
260
373
|
@session ||= AVCaptureSession.alloc.init
|
261
374
|
end
|
262
375
|
|
376
|
+
# iOS 4-9
|
263
377
|
def still_image_output
|
264
378
|
@still_image_output ||= AVCaptureStillImageOutput.alloc.init.tap do |output|
|
265
|
-
settings = { '
|
266
|
-
|
379
|
+
settings = { 'AVVideoCodecKey' => AVVideoCodecJPEG }
|
267
380
|
output.setOutputSettings(settings)
|
268
381
|
end
|
269
382
|
end
|
383
|
+
|
384
|
+
# iOS 10+
|
385
|
+
def photo_output
|
386
|
+
@photo_output ||= AVCapturePhotoOutput.alloc.init
|
387
|
+
end
|
270
388
|
end; end
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motion-capture
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Devon Blandin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-05-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
description: Easily create custom camera controllers
|
@@ -44,17 +44,17 @@ require_paths:
|
|
44
44
|
- lib
|
45
45
|
required_ruby_version: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
|
-
- -
|
47
|
+
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: '0'
|
50
50
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
requirements: []
|
56
56
|
rubyforge_project:
|
57
|
-
rubygems_version: 2.
|
57
|
+
rubygems_version: 2.7.6
|
58
58
|
signing_key:
|
59
59
|
specification_version: 4
|
60
60
|
summary: RubyMotion AVFoundation wrapper
|