motionscan 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +23 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/Motionscan.gemspec +18 -0
- data/README.md +174 -0
- data/RakefileExample +20 -0
- data/app/app_delegate.rb +14 -0
- data/app/root_view_controller.rb +57 -0
- data/app/scanner_view_controller.rb +33 -0
- data/lib/motion/project/motionscan.rb +78 -0
- data/lib/motionscan/flash.rb +18 -0
- data/lib/motionscan/result.rb +39 -0
- data/lib/motionscan/scanner.rb +109 -0
- data/lib/motionscan/sync.rb +49 -0
- data/lib/motionscan/version.rb +3 -0
- data/lib/motionscan.rb +13 -0
- metadata +93 -0
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
.repl_history
|
2
|
+
build
|
3
|
+
.build
|
4
|
+
libPods.a
|
5
|
+
vendor/Pods/Pods.xcodeproj
|
6
|
+
tags
|
7
|
+
resources/*.nib
|
8
|
+
resources/*.momd
|
9
|
+
resources/*.storyboardc
|
10
|
+
.DS_Store
|
11
|
+
nbproject
|
12
|
+
.redcar
|
13
|
+
#*#
|
14
|
+
*~
|
15
|
+
*.sw[po]
|
16
|
+
.eprj
|
17
|
+
pkg/*
|
18
|
+
vendor/Pods
|
19
|
+
vendor/Podfile.lock
|
20
|
+
Gemfile.lock
|
21
|
+
wildcard_dev.mobileprovision
|
22
|
+
Rakefile
|
23
|
+
app/motionscan_config.rb
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2012 by Joffrey Jaffeux
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/Motionscan.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/motionscan/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "motionscan"
|
6
|
+
s.version = Motionscan::VERSION
|
7
|
+
s.authors = ["Joffrey Jaffeux"]
|
8
|
+
s.email = ["j.jaffeux@gmail.com"]
|
9
|
+
s.homepage = "https://github.com/jjaffeux/Motionscan"
|
10
|
+
s.summary = "A RubyMotion Moodstocks SDK image recognition wrapper"
|
11
|
+
s.description = "A RubyMotion Moodstocks SDK image recognition wrapper"
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split($\)
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
|
16
|
+
s.add_dependency "motion-cocoapods", ">= 1.2.1"
|
17
|
+
s.add_development_dependency 'rake'
|
18
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
<!>Not production ready<!>
|
2
|
+
|
3
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/jjaffeux/Motionscan)
|
4
|
+
|
5
|
+
|
6
|
+
# Description
|
7
|
+
|
8
|
+
Motionscan is a RubyMotion wrapper for the Moodstocks SDK. Moodstocks provide an incredibly fast and easy tool to add image recognition to your app.
|
9
|
+
|
10
|
+
Watch the video to see what you will be able to build in few minutes : http://cl.ly/0Q3K163y3b12
|
11
|
+
|
12
|
+
|
13
|
+
# Usage
|
14
|
+
- Create an account on moodstocks.com
|
15
|
+
- Use Moodstocks image uploader to add images to your account
|
16
|
+
- Complete your application Rakefile with RakefileExample (most notably pod and credentials)
|
17
|
+
- Look at /app to use it in your application
|
18
|
+
- Not yet pushed to rubygems, you have to build the gem and link to it from your Gemfile
|
19
|
+
|
20
|
+
If you want build this application you need to upload images with json attached to images, for example :
|
21
|
+
http://cl.ly/image/3l331E0K0L2P
|
22
|
+
|
23
|
+
# Documentation
|
24
|
+
## Motionscan::Sync
|
25
|
+
|
26
|
+
Moodstocks is fast because the image processor is fast but also because it allows you to cache image signature, the Sync class allows you to decide when and how you want to sync the device cache.
|
27
|
+
|
28
|
+
-init
|
29
|
+
```ruby
|
30
|
+
sync = Motionscan::Sync.init
|
31
|
+
```
|
32
|
+
|
33
|
+
-startWithStatus(syncStarted, success:syncCompleted, error:syncFailed, progress:syncProgressed)
|
34
|
+
```ruby
|
35
|
+
sync.startWithStatus(
|
36
|
+
lambda {
|
37
|
+
# sync started
|
38
|
+
},
|
39
|
+
success:lambda {|result|
|
40
|
+
# sync finished
|
41
|
+
# Motionscan::Result instance
|
42
|
+
},
|
43
|
+
error:lambda {|error|
|
44
|
+
# an error occured while syncing
|
45
|
+
# NSError
|
46
|
+
},
|
47
|
+
progress:lambda {|progress, total|
|
48
|
+
# progress : current number of cached items
|
49
|
+
# total : number of items to cache
|
50
|
+
}
|
51
|
+
)
|
52
|
+
```
|
53
|
+
|
54
|
+
## Motionscan::Scanner
|
55
|
+
|
56
|
+
|
57
|
+
-initWithFrame(frame)
|
58
|
+
```ruby
|
59
|
+
scanner = Motionscan::Scanner.initWithFrame([[0,0],[320,200]])
|
60
|
+
```
|
61
|
+
|
62
|
+
-frame=(frame)
|
63
|
+
```ruby
|
64
|
+
scanner.frame = [[0,0],[320,200]]
|
65
|
+
```
|
66
|
+
|
67
|
+
-displayScannerInView(view)
|
68
|
+
```ruby
|
69
|
+
scanner.displayScannerInView(self.view)
|
70
|
+
```
|
71
|
+
|
72
|
+
-startWithStatus(scanStarted, success:scanCompleted, error:scanError, notFound:scanNotFound)
|
73
|
+
```ruby
|
74
|
+
scanner.startWithStatus(
|
75
|
+
lambda {
|
76
|
+
# scan started
|
77
|
+
# will fire once at the beginning
|
78
|
+
# from this point everything captured
|
79
|
+
# by the video will be scanned
|
80
|
+
},
|
81
|
+
success:lambda {|result|
|
82
|
+
# scan found and image in the cache
|
83
|
+
# Motionscan::Result instance
|
84
|
+
},
|
85
|
+
error:lambda {|error|
|
86
|
+
# scan error
|
87
|
+
# NSError
|
88
|
+
},
|
89
|
+
notFound:lambda {
|
90
|
+
# scan didn't find the image in the cache
|
91
|
+
# you shouldn't do anything expensive here
|
92
|
+
# as it will fire very frequently
|
93
|
+
}
|
94
|
+
)
|
95
|
+
```
|
96
|
+
|
97
|
+
|
98
|
+
-pause
|
99
|
+
|
100
|
+
If you wish to pause the scanner, and prevent current result to change you can use this method. Use scanner.resume to resume scanning process.
|
101
|
+
```ruby
|
102
|
+
scanner.pause
|
103
|
+
```
|
104
|
+
|
105
|
+
-stop
|
106
|
+
|
107
|
+
Call this method to terminate the scanner, usually in viewWillDisappear(animated). /!\ You have to call it at some point or pushing a new UIViewController and going back to this one, will crash the app.
|
108
|
+
```ruby
|
109
|
+
scanner.stop
|
110
|
+
```
|
111
|
+
|
112
|
+
-resume
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
scanner.resume
|
116
|
+
```
|
117
|
+
|
118
|
+
-searchWithStatus(searchStarted, success:searchCompleted, error:searchError, notFound:searchNotFound)
|
119
|
+
|
120
|
+
If an image is not in the cache, you can trigger an API call to search it on your account.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
scanner.searchWithStatus(
|
124
|
+
lambda {
|
125
|
+
#search in remote started
|
126
|
+
},
|
127
|
+
success:lambda {|result|
|
128
|
+
#search found and image in remote
|
129
|
+
},
|
130
|
+
error:lambda {|error|
|
131
|
+
#search error
|
132
|
+
},
|
133
|
+
notFound:lambda {
|
134
|
+
#search didn't find the image in remote
|
135
|
+
}
|
136
|
+
)
|
137
|
+
```
|
138
|
+
|
139
|
+
## Motionscan::Result
|
140
|
+
|
141
|
+
Result is a simple wrapper arround MSResult, every methods that should return a result will give an instance of Motionscan::Result.
|
142
|
+
|
143
|
+
-imageId
|
144
|
+
|
145
|
+
Returns the imageId of the scanned image.
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
result.imageId
|
149
|
+
```
|
150
|
+
|
151
|
+
-msSDKResult
|
152
|
+
|
153
|
+
Let you access the raw MSResult
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
result.msSDKResult
|
157
|
+
```
|
158
|
+
|
159
|
+
-data
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
result.data
|
163
|
+
```
|
164
|
+
|
165
|
+
Returns the string or the hash (json is converted to a hash) saved with the image. For example if the following json is attached to your image :
|
166
|
+
```ruby
|
167
|
+
{"type":"businessCat", "name":"Carl"}
|
168
|
+
```
|
169
|
+
|
170
|
+
You will get the following ruby hash :
|
171
|
+
```ruby
|
172
|
+
result.data
|
173
|
+
# {type:"businessCat", name:"Carl"}
|
174
|
+
```
|
data/RakefileExample
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
$:.unshift("/Library/RubyMotion/lib")
|
3
|
+
require 'motion/project'
|
4
|
+
require "bundler/gem_tasks"
|
5
|
+
require "bundler/setup"
|
6
|
+
Bundler.require :default
|
7
|
+
|
8
|
+
$:.unshift("./lib/")
|
9
|
+
require './lib/motionscan'
|
10
|
+
|
11
|
+
Motion::Project::App.setup do |app|
|
12
|
+
app.name = 'Motionscan'
|
13
|
+
|
14
|
+
app.motionscan.api_key = "xxx"
|
15
|
+
app.motionscan.api_secret = "xxx"
|
16
|
+
|
17
|
+
app.pods do
|
18
|
+
pod 'Moodstocks-iOS-SDK', '~> 3.5'
|
19
|
+
end
|
20
|
+
end
|
data/app/app_delegate.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class AppDelegate
|
2
|
+
|
3
|
+
attr_accessor :window
|
4
|
+
|
5
|
+
def application(application, didFinishLaunchingWithOptions:launchOptions)
|
6
|
+
controller = RootViewController.alloc.init
|
7
|
+
navigationController = UINavigationController.alloc.initWithRootViewController(controller)
|
8
|
+
self.window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
|
9
|
+
self.window.rootViewController = navigationController
|
10
|
+
self.window.makeKeyAndVisible
|
11
|
+
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class RootViewController < UIViewController
|
2
|
+
|
3
|
+
attr_accessor :counterLabel
|
4
|
+
|
5
|
+
def loadView
|
6
|
+
super
|
7
|
+
self.counterLabel = UILabel.alloc.initWithFrame([[60,80],[200,40]])
|
8
|
+
self.counterLabel.textAlignment = UITextAlignmentCenter
|
9
|
+
self.counterLabel.backgroundColor = UIColor.darkGrayColor
|
10
|
+
self.counterLabel.font = UIFont.boldSystemFontOfSize(20)
|
11
|
+
self.counterLabel.layer.cornerRadius = 5.0
|
12
|
+
self.counterLabel.text = "Sync will start"
|
13
|
+
self.view.addSubview(self.counterLabel)
|
14
|
+
end
|
15
|
+
|
16
|
+
def viewDidLoad
|
17
|
+
super
|
18
|
+
self.title = "Root"
|
19
|
+
self.view.backgroundColor = UIColor.whiteColor
|
20
|
+
|
21
|
+
@sync = Motionscan::Sync.init
|
22
|
+
@sync.startWithStatus(
|
23
|
+
lambda {
|
24
|
+
NSLog("sync started")
|
25
|
+
},
|
26
|
+
success:lambda {|result|
|
27
|
+
self.counterLabel.removeFromSuperview
|
28
|
+
addScannerViewControllerButton
|
29
|
+
},
|
30
|
+
error:lambda {|error|
|
31
|
+
p error
|
32
|
+
},
|
33
|
+
progress:lambda {|progress, total|
|
34
|
+
self.counterLabel.text = "#{progress} / #{total}"
|
35
|
+
}
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def addScannerViewControllerButton
|
42
|
+
scanButton = UIButton.buttonWithType(UIButtonTypeCustom)
|
43
|
+
scanButton.frame = [[40,140],[240,40]]
|
44
|
+
scanButton.setTitle("Launch Scanner", forState:UIControlStateNormal)
|
45
|
+
scanButton.backgroundColor = UIColor.darkGrayColor
|
46
|
+
scanButton.addTarget(self,
|
47
|
+
action: :pushScannerViewController,
|
48
|
+
forControlEvents:UIControlEventTouchUpInside)
|
49
|
+
self.view.addSubview(scanButton)
|
50
|
+
end
|
51
|
+
|
52
|
+
def pushScannerViewController
|
53
|
+
scannerController = ScannerViewController.alloc.init
|
54
|
+
self.navigationController.pushViewController(scannerController, animated:true)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class ScannerViewController < UIViewController
|
2
|
+
|
3
|
+
def init
|
4
|
+
super
|
5
|
+
@overlay = UILabel.alloc.initWithFrame([[10,10],[300,40]])
|
6
|
+
@overlay.textAlignment = UITextAlignmentCenter
|
7
|
+
@overlay.alpha = 0.8
|
8
|
+
@overlay.backgroundColor = UIColor.darkGrayColor
|
9
|
+
@overlay.layer.zPosition = 2
|
10
|
+
self.view.addSubview(@overlay)
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def viewDidAppear(animated)
|
15
|
+
@scanner = Motionscan::Scanner.initWithFrame(self.view.bounds)
|
16
|
+
@scanner.displayScannerInView(self.view)
|
17
|
+
@scanner.startWithStatus(
|
18
|
+
lambda {
|
19
|
+
@overlay.text = "Will start scanning"
|
20
|
+
},
|
21
|
+
success:lambda {|result|
|
22
|
+
@overlay.text = "#{result.data[:type]}"
|
23
|
+
},
|
24
|
+
error:lambda {|error|},
|
25
|
+
notFound:lambda {}
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def viewWillDisappear(animated)
|
30
|
+
@scanner.stop
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
class MotionscanConfig
|
6
|
+
attr_accessor :api_key
|
7
|
+
attr_accessor :api_secret
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def api_secret=(api_secret)
|
14
|
+
@api_secret = api_secret
|
15
|
+
create_code
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def create_code
|
21
|
+
unless @api_key && @api_secret
|
22
|
+
raise "Need to configure `app.motionscan.api_key' and `app.motionscan.api_secret' variables"
|
23
|
+
end
|
24
|
+
|
25
|
+
code = <<EOF
|
26
|
+
# Moodstocks SDK launcher
|
27
|
+
# This file is automatically generated. Do not edit.
|
28
|
+
if MSDeviceCompatibleWithSDK()
|
29
|
+
scanner = MSScanner.sharedInstance
|
30
|
+
error_ptr = Pointer.new(:object)
|
31
|
+
unless scanner.openWithKey("#{@api_key}", secret:"#{@api_secret}", error:error_ptr)
|
32
|
+
errorCode = error_ptr[0].code
|
33
|
+
if errorCode == MS_CREDMISMATCH
|
34
|
+
NSLog("[MOODSTOCKS SDK] There is a problem with your key/secret pair : see https://github.com/Moodstocks/moodstocks-sdk/blob/master/sample/iphone/demo/Demo/MSAppDelegate.m#L65")
|
35
|
+
NSException.exceptionWithName("MSScannerException", reason:"Credentials mismatch", userInfo:nil).raise
|
36
|
+
else
|
37
|
+
errorString = NSString.stringWithCString(ms_errmsg(errorCode), encoding:NSUTF8StringEncoding)
|
38
|
+
NSLog("[MOODSTOCKS SDK] Scanner open error code :" + errorString)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
NSLog("[MOODSTOCKS SDK] Scanner initialized.")
|
42
|
+
else
|
43
|
+
NSLog("[MOODSTOCKS SDK] Your device is not compatible with the Moodstocks SDK.")
|
44
|
+
end
|
45
|
+
EOF
|
46
|
+
|
47
|
+
motionscan_file = './app/motionscan_config.rb'
|
48
|
+
create_stub(motionscan_file, code)
|
49
|
+
add_file(motionscan_file)
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_stub(path, code)
|
53
|
+
if !File.exist?(path) or File.read(path) != code
|
54
|
+
File.open(path, 'w') { |io| io.write(code) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_file(path)
|
59
|
+
files = @config.files.flatten
|
60
|
+
@config.files << path unless files.find { |x| File.expand_path(x) == File.expand_path(path) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module Motion
|
65
|
+
module Project
|
66
|
+
class Config
|
67
|
+
|
68
|
+
variable :motionscan
|
69
|
+
|
70
|
+
def motionscan
|
71
|
+
@motionscan ||= MotionscanConfig.new(self)
|
72
|
+
yield @motionscan if block_given?
|
73
|
+
@motionscan
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Motionscan
|
2
|
+
|
3
|
+
module Flash
|
4
|
+
|
5
|
+
def flash
|
6
|
+
flashView = UIView.alloc.initWithFrame(@view.bounds)
|
7
|
+
flashView.backgroundColor = UIColor.whiteColor
|
8
|
+
@view.addSubview(flashView)
|
9
|
+
|
10
|
+
UIView.animateWithDuration(0.4,
|
11
|
+
animations:lambda { flashView.alpha = 0.0 },
|
12
|
+
completion:lambda { |finished| flashView.removeFromSuperview }
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Motionscan
|
2
|
+
|
3
|
+
class Result
|
4
|
+
|
5
|
+
attr_reader :msSDKResult
|
6
|
+
|
7
|
+
def initialize(msSDKResult)
|
8
|
+
@msSDKResult = msSDKResult
|
9
|
+
end
|
10
|
+
|
11
|
+
def imageId
|
12
|
+
@msSDKResult.getValue
|
13
|
+
end
|
14
|
+
|
15
|
+
def data
|
16
|
+
error_ptr = Pointer.new(:object)
|
17
|
+
|
18
|
+
options = NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves | NSJSONReadingAllowFragments
|
19
|
+
json = NSJSONSerialization.JSONObjectWithData(base64URLString,
|
20
|
+
options:options,
|
21
|
+
error:error_ptr)
|
22
|
+
|
23
|
+
error = error_ptr[0]
|
24
|
+
error.nil? ? json : decodeImageBase64URLString
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def decodeImageBase64URLString
|
30
|
+
NSString.alloc.initWithData(base64URLString, encoding:NSUTF8StringEncoding)
|
31
|
+
end
|
32
|
+
|
33
|
+
def base64URLString
|
34
|
+
MSResult.dataFromBase64URLString(@msSDKResult.getValue)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Motionscan
|
2
|
+
class Scanner
|
3
|
+
include Flash
|
4
|
+
|
5
|
+
attr_accessor :flashEnabled
|
6
|
+
attr_accessor :frame
|
7
|
+
attr_reader :session
|
8
|
+
attr_reader :view
|
9
|
+
|
10
|
+
def self.initWithFrame(frame)
|
11
|
+
instance = allocate
|
12
|
+
instance.scannerInitializer(frame)
|
13
|
+
instance
|
14
|
+
end
|
15
|
+
|
16
|
+
def scannerInitializer(frame)
|
17
|
+
@frame = frame
|
18
|
+
@flashEnabled = true
|
19
|
+
@view = UIView.alloc.initWithFrame(frame)
|
20
|
+
end
|
21
|
+
|
22
|
+
def frame=(frame)
|
23
|
+
@view.frame = frame
|
24
|
+
end
|
25
|
+
|
26
|
+
def displayScannerInView(view)
|
27
|
+
@session = MSScannerSession.alloc.initWithScanner(MSScanner.sharedInstance)
|
28
|
+
@session.scanOptions = MS_RESULT_TYPE_IMAGE
|
29
|
+
@session.delegate = self
|
30
|
+
|
31
|
+
@view.backgroundColor = UIColor.blackColor
|
32
|
+
@view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
|
33
|
+
@view.autoresizesSubviews = true
|
34
|
+
view.addSubview(@view)
|
35
|
+
end
|
36
|
+
|
37
|
+
# scanner session flow
|
38
|
+
def startWithStatus(scanStarted, success:scanCompleted,
|
39
|
+
error:scanError, notFound:scanNotFound)
|
40
|
+
scanStarted.call
|
41
|
+
@scanCompleted = scanCompleted
|
42
|
+
@scanError = scanError
|
43
|
+
@scanNotFound = scanNotFound
|
44
|
+
|
45
|
+
viewLayer = @view.layer
|
46
|
+
viewLayer.setMasksToBounds(true)
|
47
|
+
|
48
|
+
captureLayer = @session.previewLayer
|
49
|
+
captureLayer.setFrame(@view.bounds)
|
50
|
+
|
51
|
+
viewLayer.insertSublayer(captureLayer, below:viewLayer.sublayers)
|
52
|
+
|
53
|
+
@session.startCapture
|
54
|
+
end
|
55
|
+
|
56
|
+
def stop
|
57
|
+
@session.stopCapture
|
58
|
+
@session.cancel
|
59
|
+
@view.removeFromSuperview
|
60
|
+
end
|
61
|
+
|
62
|
+
def resume
|
63
|
+
@session.resume
|
64
|
+
end
|
65
|
+
|
66
|
+
def pause
|
67
|
+
@session.pause
|
68
|
+
end
|
69
|
+
|
70
|
+
def searchWithStatus(searchStarted, success:searchCompleted,error:searchError,notFound:searchNotFound)
|
71
|
+
@searchStarted = searchStarted
|
72
|
+
@searchCompleted = searchCompleted
|
73
|
+
@searchError = searchError
|
74
|
+
@searchNotFound = searchNotFound
|
75
|
+
|
76
|
+
self.flash if @flashEnabled
|
77
|
+
@session.snap
|
78
|
+
@session.pause
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
# delegates
|
84
|
+
def session(session, didScan:result)
|
85
|
+
Dispatch::Queue.main.async {
|
86
|
+
result.nil? ? @scanNotFound.call : @scanCompleted.call(Result.new(result))
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def session(session, failedToScan:error)
|
91
|
+
Dispatch::Queue.main.async { @scanError.call(error) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def scannerWillSearch(scanner)
|
95
|
+
Dispatch::Queue.main.async { @searchStarted.call }
|
96
|
+
end
|
97
|
+
|
98
|
+
def scanner(scanner, didSearchWithResult:result)
|
99
|
+
Dispatch::Queue.main.async {
|
100
|
+
result.nil? ? @searchNotFound.call : @searchCompleted.call(Result.new(result))
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def scanner(scanner, failedToSearchWithError:error)
|
105
|
+
Dispatch::Queue.main.async { @searchError.call(error) }
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Motionscan
|
2
|
+
|
3
|
+
class Sync
|
4
|
+
|
5
|
+
attr_reader :scanner
|
6
|
+
|
7
|
+
def self.init
|
8
|
+
instance = allocate
|
9
|
+
instance
|
10
|
+
end
|
11
|
+
|
12
|
+
def startWithStatus(syncStarted, success:syncCompleted,
|
13
|
+
error:syncFailed, progress:syncProgressed)
|
14
|
+
@syncStarted = syncStarted
|
15
|
+
@syncCompleted = syncCompleted
|
16
|
+
@syncFailed = syncFailed
|
17
|
+
@syncProgressed = syncProgressed
|
18
|
+
|
19
|
+
@scanner = MSScanner.sharedInstance
|
20
|
+
@scanner.syncWithDelegate(self) unless @scanner.isSyncing
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def scannerWillSync(scanner)
|
26
|
+
@syncStarted.call
|
27
|
+
end
|
28
|
+
|
29
|
+
def didSyncWithProgress(progress, total:total)
|
30
|
+
@syncProgressed.call(progress, total)
|
31
|
+
end
|
32
|
+
|
33
|
+
def scannerDidSync(scanner)
|
34
|
+
@lastSync = NSDate.date.timeIntervalSince1970
|
35
|
+
@syncCompleted.call(scanner.count(nil))
|
36
|
+
end
|
37
|
+
|
38
|
+
def scanner(scanner, failedToSyncWithError:error)
|
39
|
+
errorCode = error.code
|
40
|
+
if errorCode >= 0 and errorCode != MS_BUSY
|
41
|
+
errorString = NSString.stringWithCString(ms_errmsg(errorCode), encoding:NSUTF8StringEncoding)
|
42
|
+
NSLog("[MOODSTOCKS SDK] FAILED TO SYNC WITH ERROR : #{errorString}.")
|
43
|
+
end
|
44
|
+
@syncFailed.call(error)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/lib/motionscan.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'motion/project/motionscan'
|
2
|
+
require 'motionscan/version'
|
3
|
+
require 'motion-cocoapods'
|
4
|
+
|
5
|
+
unless defined?(Motion::Project::Config)
|
6
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
7
|
+
end
|
8
|
+
|
9
|
+
Motion::Project::App.setup do |app|
|
10
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'motionscan/*.rb')).each do |file|
|
11
|
+
app.files.unshift(file)
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: motionscan
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joffrey Jaffeux
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: motion-cocoapods
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.2.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.2.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: A RubyMotion Moodstocks SDK image recognition wrapper
|
47
|
+
email:
|
48
|
+
- j.jaffeux@gmail.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
55
|
+
- LICENSE
|
56
|
+
- Motionscan.gemspec
|
57
|
+
- README.md
|
58
|
+
- RakefileExample
|
59
|
+
- app/app_delegate.rb
|
60
|
+
- app/root_view_controller.rb
|
61
|
+
- app/scanner_view_controller.rb
|
62
|
+
- lib/motion/project/motionscan.rb
|
63
|
+
- lib/motionscan.rb
|
64
|
+
- lib/motionscan/flash.rb
|
65
|
+
- lib/motionscan/result.rb
|
66
|
+
- lib/motionscan/scanner.rb
|
67
|
+
- lib/motionscan/sync.rb
|
68
|
+
- lib/motionscan/version.rb
|
69
|
+
homepage: https://github.com/jjaffeux/Motionscan
|
70
|
+
licenses: []
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ! '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 1.8.23
|
90
|
+
signing_key:
|
91
|
+
specification_version: 3
|
92
|
+
summary: A RubyMotion Moodstocks SDK image recognition wrapper
|
93
|
+
test_files: []
|