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.
Files changed (4) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +37 -4
  3. data/lib/project/motion-capture.rb +140 -22
  4. metadata +7 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a40129aa5ea8c985e6089e6db40906b56f00bb3c
4
- data.tar.gz: 5b4726c722107daad383f37b2e520418beb3a5fa
2
+ SHA256:
3
+ metadata.gz: ee51432dacdc318b8b687203b598709f6d69e549709f43390628e6ab6b4f6b7b
4
+ data.tar.gz: 7df7fe7e9d0fc9fa21cf315edd714213991e75e4ba34cbc0f27d0a83e983ec79
5
5
  SHA512:
6
- metadata.gz: 473b932901836198ddc185c257435834fccfd9a709e3d6d47a5fc048ac18c725812da2b5d4df88d142263787be86fcd29f54bf50f1700b507eb4b918f53d211f
7
- data.tar.gz: 988ce6e872578fe0df289dd76543a3bfb87de881d36e0c7a31b2481aad65a6f6ad29facc9c30f4487ba2c1e84a892abd8e0bb4f16998af41fd0fd314de64219b
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
- preview = motion_capture.capture_preview_view(frame: view.bounds)
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.capture_and_save do |asset_url|
29
- # Use NSURL
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!(preset = AVCaptureSessionPresetPhoto)
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
- set_preset(preset)
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
- add_ouput(still_image_output)
55
+ session.commitConfiguration
56
+ end
21
57
 
22
- session.startRunning
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 running?
39
- @session && session.running?
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 capture(&block)
43
- still_image_output.captureStillImageAsynchronouslyFromConnection(still_image_connection, completionHandler: -> (buffer, error) {
44
- if error
45
- error_callback.call(error)
46
- else
47
- image_data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
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
- block.call(image_data)
50
- end
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.captureSession if @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 add_ouput(output)
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 = { 'AVVideoCodeKey' => AVVideoCodecJPEG }
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.3.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: 2014-01-29 00:00:00.000000000 Z
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.0.3
57
+ rubygems_version: 2.7.6
58
58
  signing_key:
59
59
  specification_version: 4
60
60
  summary: RubyMotion AVFoundation wrapper