motion-capture 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|