imagga 0.0.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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - jruby-19mode # JRuby in 1.9 mode
5
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in imagga.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Mart Karu
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,53 @@
1
+ [![Build Status](https://travis-ci.org/martkaru/imagga.png?branch=master)](https://travis-ci.org/martkaru/imagga)
2
+
3
+ # Imagga
4
+
5
+ Client for Imagga image analytics services API
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'imagga'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install imagga
20
+
21
+ ## Usage
22
+
23
+ Set up a client
24
+
25
+ client = Imagga::Client.new(
26
+ base_uri: '0.0.0.0', # IP of the Imagga server
27
+ api_key: '12345678', # Your api key
28
+ api_secret: '1234567890123456789' # Your api secret
29
+ )
30
+
31
+ Extract image information
32
+
33
+ results = client.extract('http://imagga.com/images/scheme_colors.png')
34
+
35
+ Extract image information with indexing and extraction options:
36
+
37
+ results = client.extract(
38
+ [
39
+ Imagga::Image.new(url: 'http://image1', id: '333'),
40
+ Imagga::Image.new(url: 'http://image2')
41
+ ],
42
+ extract_overall_colors: true,
43
+ extract_object_colors: false
44
+ )
45
+
46
+
47
+ ## Contributing
48
+
49
+ 1. Fork it
50
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
51
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
52
+ 4. Push to the branch (`git push origin my-new-feature`)
53
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
6
+
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'imagga/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "imagga"
8
+ gem.version = Imagga::VERSION
9
+ gem.authors = ["Mart Karu"]
10
+ gem.email = ["karu@metal.ee"]
11
+ gem.description = %q{Ruby client for accessing Imagga API}
12
+ gem.summary = %q{Ruby client for accessing Imagga API}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.add_dependency "httparty", "~> 0.10"
20
+ gem.add_dependency "json", "~> 1.7"
21
+
22
+ gem.add_development_dependency "rspec", "~> 2.12"
23
+ gem.add_development_dependency "rake"
24
+ gem.add_development_dependency "fakeweb"
25
+ end
@@ -0,0 +1,7 @@
1
+ require "imagga/version"
2
+ require "imagga/exceptions"
3
+ require "imagga/extract_result_builder"
4
+ require "imagga/rank_result_builder"
5
+ require "imagga/image"
6
+ require "imagga/extract_options"
7
+ require "imagga/client"
@@ -0,0 +1,42 @@
1
+ require "httparty"
2
+ require "json"
3
+
4
+ module Imagga
5
+ class Client
6
+ include HTTParty
7
+ include Imagga::Exceptions
8
+ attr_reader :api_key, :api_secret, :base_uri, :service_path
9
+
10
+ def initialize(opts={})
11
+ @api_key = opts[:api_key] || raise_missing(:api_key)
12
+ @api_secret = opts[:api_secret] || raise_missing(:api_secret)
13
+ @base_uri = opts[:base_uri] || raise_missing(:base_uri)
14
+ @service_path = '/colorsearchserver.php'
15
+
16
+ Imagga::Client.base_uri @base_uri
17
+ end
18
+
19
+ def extract(urls_or_images, additional_options={})
20
+ options = extract_options(urls_or_images, additional_options)
21
+ result = JSON.parse(self.class.post(service_path, body: options))
22
+ raise_if_request_failed!(result)
23
+ ExtractResultBuilder.new.build_from(result)
24
+ end
25
+
26
+ def rank(opts)
27
+ result = JSON.parse(self.class.post(service_path, body: rank_options(opts)))
28
+ raise_if_request_failed!(result)
29
+ RankResultBuilder.new.build_from(result)
30
+ end
31
+
32
+ private
33
+
34
+ def extract_options(urls_or_images, additional_options)
35
+ ExtractOptions.new(api_key, api_secret).options(urls_or_images, additional_options)
36
+ end
37
+
38
+ def rank_options(opts)
39
+ RankOptions.new(api_key, api_secret).options(opts)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ module Imagga
2
+ module Exceptions
3
+ def raise_missing(attribute)
4
+ raise ArgumentError, "%s is missing" % attribute.to_s
5
+ end
6
+
7
+ def raise_if_request_failed!(result)
8
+ if result.respond_to?(:keys) && result.keys.include?('error_code')
9
+ raise Imagga::ClientException.new(result['error_code'].to_i), result['error_message'], caller[0..-1]
10
+ end
11
+ end
12
+ end
13
+
14
+ class ClientException < StandardError
15
+ attr_accessor :error_code
16
+ def initialize(error_code)
17
+ @error_code = error_code
18
+ super
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,74 @@
1
+ module Imagga
2
+ class BaseOptions
3
+ attr_accessor :api_key, :api_secret
4
+
5
+ def initialize(api_key, api_secret)
6
+ @version = '1.0'
7
+ @api_key = api_key || raise_missing(:api_key)
8
+ @api_secret = api_secret || raise_missing(:api_secret)
9
+ end
10
+
11
+ def base_options
12
+ { v: @version, api_key: @api_key }
13
+ end
14
+
15
+ def sign(options)
16
+ sorted_options_string = options.keys.sort.map do |key|
17
+ "%s=%s" % [key.to_s, options[key]]
18
+ end.join('') << @api_secret
19
+ Digest::MD5.hexdigest(sorted_options_string)
20
+ end
21
+ end
22
+
23
+ class ExtractOptions < BaseOptions
24
+
25
+ def options(urls_or_images, additional_options={})
26
+ options = base_options.merge(
27
+ method: 'imagga.colorsearch.extract',
28
+ urls: build_urls(urls_or_images),
29
+ )
30
+
31
+ if ids = build_ids(urls_or_images)
32
+ options.merge!(ids: ids)
33
+ end
34
+
35
+ [:extract_overall_colors, :extract_object_colors].each do |key|
36
+ if additional_options.keys.include?(key) && (value = additional_options[key] ? 1 : 0)
37
+ options.merge!(key => value)
38
+ end
39
+ end
40
+
41
+ options.merge!(sig: sign(options))
42
+ end
43
+
44
+ def build_urls(urls_or_images)
45
+ [urls_or_images].flatten.map{ |o| o.url rescue o }.join(',')
46
+ end
47
+
48
+ def build_ids(urls_or_images)
49
+ ids = [urls_or_images].flatten.map{ |o| o.id rescue 0 }
50
+ return if ids.uniq == [0]
51
+ ids.join(',')
52
+ end
53
+
54
+ end
55
+
56
+ class RankOptions < BaseOptions
57
+ def options(opts)
58
+ color_vector = opts.fetch(:color_vector)
59
+ type = opts.fetch(:type)
60
+ dist = opts.fetch(:dist)
61
+ count = opts.fetch(:count)
62
+
63
+ options = base_options.merge(
64
+ method: 'imagga.colorsearch.rank',
65
+ color_vector: color_vector,
66
+ type: type,
67
+ dist: dist,
68
+ count: count
69
+ )
70
+
71
+ options.merge!(sig: sign(options))
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,11 @@
1
+ require "json"
2
+
3
+ module Imagga
4
+
5
+ class ExtractResultBuilder
6
+ def build_from(result)
7
+ result['colors'].map { |image_node| ImageInfo.new(image_node) }
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,71 @@
1
+ module Imagga
2
+ class Image
3
+ include Imagga::Exceptions
4
+ attr_accessor :url, :id
5
+
6
+ def initialize(opts)
7
+ @url = opts[:url] || raise_missing(:url)
8
+ @id = opts[:id] || 0
9
+ end
10
+ end
11
+
12
+ class ImageInfoBase
13
+ def initialize(opts={})
14
+ self.class.fields.each { |field| send("#{field}=", opts[field]) }
15
+ end
16
+ end
17
+
18
+ class ImageInfo < ImageInfoBase
19
+ def self.fields
20
+ %w(url object_percentage color_variance image_packed foreground_packed background_packed)
21
+ end
22
+
23
+ def self.color_fields
24
+ %w(image_colors foreground_colors background_colors)
25
+ end
26
+
27
+ def initialize(opts={})
28
+ super(opts['info'].merge('url' => opts['url']))
29
+ self.class.color_fields.each do |field|
30
+ send("#{field}=", build_image_colors(opts['info'][field]))
31
+ end
32
+ end
33
+
34
+ def build_image_colors(image_color_nodes)
35
+ image_color_nodes && image_color_nodes.map { |color_node| ImageColor.new(color_node) }
36
+ end
37
+
38
+ attr_accessor *(fields + color_fields)
39
+
40
+ def color_variance=(value)
41
+ @color_variance = value.to_i
42
+ end
43
+ end
44
+
45
+ class ImageColor < ImageInfoBase
46
+ def self.fields
47
+ %w(percent r g b html_code closest_palette_color closest_palette_color_parent closest_palette_distance)
48
+ end
49
+
50
+ attr_accessor *fields
51
+
52
+ %w(r g b).each do |field|
53
+ define_method("#{field}=") do |value|
54
+ instance_variable_set("@#{field}", value.to_i)
55
+ end
56
+ end
57
+
58
+ def percent=(value)
59
+ @percent = value.to_f
60
+ end
61
+
62
+ end
63
+
64
+ class RankSimilarity < ImageInfoBase
65
+ def self.fields
66
+ %w(id dist)
67
+ end
68
+
69
+ attr_accessor *fields
70
+ end
71
+ end
@@ -0,0 +1,9 @@
1
+ module Imagga
2
+
3
+ class RankResultBuilder
4
+ def build_from(result)
5
+ result['rank_similarity'].map { |rank| RankSimilarity.new(rank) }
6
+ end
7
+ end
8
+
9
+ end
@@ -0,0 +1,3 @@
1
+ module Imagga
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,352 @@
1
+ require 'spec_helper'
2
+ require 'fake_web'
3
+
4
+ describe Imagga::Client do
5
+
6
+ subject { described_class.new(api_key: '1', api_secret: '2', base_uri: 'http://example.com') }
7
+ let(:extract_response) {'{
8
+ "colors":[
9
+ {
10
+ "url":"http:\/\/www.stockpodium.com\/stock-photo-8244245\/smiling-presenting-2-apples-image.jpg",
11
+ "info":{
12
+ "image_colors":[
13
+ {
14
+ "percent":"38.90",
15
+ "r":"247",
16
+ "g":"245",
17
+ "b":"243",
18
+ "html_code":"#f7f5f3",
19
+ "closest_palette_color":"white",
20
+ "closest_palette_color_parent":"white",
21
+ "closest_palette_distance":1.8304102578
22
+ },
23
+ {
24
+ "percent":"35.16",
25
+ "r":"206",
26
+ "g":"167",
27
+ "b":"146",
28
+ "html_code":"#cea792",
29
+ "closest_palette_color":"fresco",
30
+ "closest_palette_color_parent":"beige",
31
+ "closest_palette_distance":4.93287465177
32
+ },
33
+ {
34
+ "percent":"10.41",
35
+ "r":"150",
36
+ "g":"60",
37
+ "b":"45",
38
+ "html_code":"#963c2d",
39
+ "closest_palette_color":"ribbon red",
40
+ "closest_palette_color_parent":"red",
41
+ "closest_palette_distance":5.6423821179
42
+ },
43
+ {
44
+ "percent":"8.38",
45
+ "r":"55",
46
+ "g":"37",
47
+ "b":"31",
48
+ "html_code":"#37251f",
49
+ "closest_palette_color":"espresso",
50
+ "closest_palette_color_parent":"brown",
51
+ "closest_palette_distance":5.91329502182
52
+ },
53
+ {
54
+ "percent":"7.15",
55
+ "r":"168",
56
+ "g":"181",
57
+ "b":"45",
58
+ "html_code":"#a8b52d",
59
+ "closest_palette_color":"mint",
60
+ "closest_palette_color_parent":"olive green",
61
+ "closest_palette_distance":10.7126507469
62
+ }
63
+ ],
64
+ "foreground_colors":[
65
+ {
66
+ "percent":"45.92",
67
+ "r":"200",
68
+ "g":"180",
69
+ "b":"112",
70
+ "html_code":"#c8b470",
71
+ "closest_palette_color":"medium olive",
72
+ "closest_palette_color_parent":"skin",
73
+ "closest_palette_distance":7.22056402093
74
+ },
75
+ {
76
+ "percent":"34.21",
77
+ "r":"162",
78
+ "g":"79",
79
+ "b":"61",
80
+ "html_code":"#a24f3d",
81
+ "closest_palette_color":"fiesta",
82
+ "closest_palette_color_parent":"red",
83
+ "closest_palette_distance":6.29194294147
84
+ },
85
+ {
86
+ "percent":"19.86",
87
+ "r":"52",
88
+ "g":"35",
89
+ "b":"31",
90
+ "html_code":"#34231f",
91
+ "closest_palette_color":"espresso",
92
+ "closest_palette_color_parent":"brown",
93
+ "closest_palette_distance":6.49089812519
94
+ }
95
+ ],
96
+ "background_colors":[
97
+ {
98
+ "percent":"58.05",
99
+ "r":"249",
100
+ "g":"248",
101
+ "b":"247",
102
+ "html_code":"#f9f8f7",
103
+ "closest_palette_color":"white",
104
+ "closest_palette_color_parent":"white",
105
+ "closest_palette_distance":2.48109615666
106
+ },
107
+ {
108
+ "percent":"36.41",
109
+ "r":"206",
110
+ "g":"177",
111
+ "b":"161",
112
+ "html_code":"#ceb1a1",
113
+ "closest_palette_color":"pearl pink",
114
+ "closest_palette_color_parent":"light pink",
115
+ "closest_palette_distance":4.11506425614
116
+ },
117
+ {
118
+ "percent":"5.55",
119
+ "r":"150",
120
+ "g":"100",
121
+ "b":"77",
122
+ "html_code":"#96644d",
123
+ "closest_palette_color":"light bronze",
124
+ "closest_palette_color_parent":"skin",
125
+ "closest_palette_distance":6.37479340147
126
+ }
127
+ ],
128
+ "object_percentage":38.4,
129
+ "color_variance":"33"
130
+ }
131
+ },
132
+ {
133
+ "url":"http:\/\/www.stockpodium.com\/stock-photo-9289532\/car-dirving-very-fast-under-image.jpg",
134
+ "info":{
135
+ "image_colors":[
136
+ {
137
+ "percent":"38.53",
138
+ "r":"103",
139
+ "g":"98",
140
+ "b":"98",
141
+ "html_code":"#676262",
142
+ "closest_palette_color":"blue steel",
143
+ "closest_palette_color_parent":"grey",
144
+ "closest_palette_distance":10.486937593
145
+ },
146
+ {
147
+ "percent":"26.31",
148
+ "r":"42",
149
+ "g":"37",
150
+ "b":"33",
151
+ "html_code":"#2a2521",
152
+ "closest_palette_color":"espresso",
153
+ "closest_palette_color_parent":"brown",
154
+ "closest_palette_distance":8.14492880108
155
+ },
156
+ {
157
+ "percent":"16.19",
158
+ "r":"178",
159
+ "g":"182",
160
+ "b":"190",
161
+ "html_code":"#b2b6be",
162
+ "closest_palette_color":"frost",
163
+ "closest_palette_color_parent":"light grey",
164
+ "closest_palette_distance":2.82095071372
165
+ },
166
+ {
167
+ "percent":"12.06",
168
+ "r":"197",
169
+ "g":"51",
170
+ "b":"45",
171
+ "html_code":"#c5332d",
172
+ "closest_palette_color":"fiesta",
173
+ "closest_palette_color_parent":"red",
174
+ "closest_palette_distance":5.41278686601
175
+ },
176
+ {
177
+ "percent":"6.91",
178
+ "r":"86",
179
+ "g":"97",
180
+ "b":"28",
181
+ "html_code":"#56611c",
182
+ "closest_palette_color":"moss",
183
+ "closest_palette_color_parent":"olive green",
184
+ "closest_palette_distance":9.97695248255
185
+ }
186
+ ],
187
+ "foreground_colors":[
188
+ {
189
+ "percent":"62.98",
190
+ "r":"199",
191
+ "g":"50",
192
+ "b":"43",
193
+ "html_code":"#c7322b",
194
+ "closest_palette_color":"fiesta",
195
+ "closest_palette_color_parent":"red",
196
+ "closest_palette_distance":5.44027296941
197
+ },
198
+ {
199
+ "percent":"22.01",
200
+ "r":"140",
201
+ "g":"132",
202
+ "b":"144",
203
+ "html_code":"#8c8490",
204
+ "closest_palette_color":"shadow",
205
+ "closest_palette_color_parent":"light grey",
206
+ "closest_palette_distance":3.40761167276
207
+ },
208
+ {
209
+ "percent":"15.01",
210
+ "r":"61",
211
+ "g":"38",
212
+ "b":"43",
213
+ "html_code":"#3d262b",
214
+ "closest_palette_color":"espresso",
215
+ "closest_palette_color_parent":"brown",
216
+ "closest_palette_distance":5.85441000013
217
+ }
218
+ ],
219
+ "background_colors":[
220
+ {
221
+ "percent":"41.07",
222
+ "r":"103",
223
+ "g":"97",
224
+ "b":"97",
225
+ "html_code":"#676161",
226
+ "closest_palette_color":"blue steel",
227
+ "closest_palette_color_parent":"grey",
228
+ "closest_palette_distance":10.6345471176
229
+ },
230
+ {
231
+ "percent":"39.63",
232
+ "r":"53",
233
+ "g":"51",
234
+ "b":"34",
235
+ "html_code":"#353322",
236
+ "closest_palette_color":"graphite",
237
+ "closest_palette_color_parent":"black",
238
+ "closest_palette_distance":9.18317865786
239
+ },
240
+ {
241
+ "percent":"19.29",
242
+ "r":"174",
243
+ "g":"180",
244
+ "b":"187",
245
+ "html_code":"#aeb4bb",
246
+ "closest_palette_color":"frost",
247
+ "closest_palette_color_parent":"light grey",
248
+ "closest_palette_distance":2.03931376316
249
+ }
250
+ ],
251
+ "object_percentage":17.99,
252
+ "color_variance":"37",
253
+ "image_packed":null,
254
+ "foreground_packed":null,
255
+ "background_packed":null
256
+ }
257
+ }
258
+ ]
259
+ }'}
260
+
261
+ let(:rank_response) { '{
262
+ "rank_similarity":[
263
+ {
264
+ "id":8774077,
265
+ "dist":2597.38299
266
+ },
267
+ {
268
+ "id":9085916,
269
+ "dist":2681.33259
270
+ }
271
+ ]
272
+ }'}
273
+
274
+ let(:failed_signature_response) { '{"error_code":3,"error_message":"Invalid signature"}' }
275
+
276
+ it "has api_key" do
277
+ subject.api_key.should == '1'
278
+ end
279
+
280
+ it "has api_secret" do
281
+ subject.api_secret.should == '2'
282
+ end
283
+
284
+ it "has base_uri" do
285
+ subject.base_uri.should == 'http://example.com'
286
+ end
287
+
288
+ it "knows service path" do
289
+ subject.service_path.should == '/colorsearchserver.php'
290
+ end
291
+
292
+ describe "#extract" do
293
+ it "extracts image info" do
294
+ FakeWeb.register_uri(:post, 'http://example.com/colorsearchserver.php', body: extract_response)
295
+ subject.extract('http://image').size.should == 2
296
+ end
297
+
298
+ context "with failing request" do
299
+ before :each do
300
+ FakeWeb.register_uri(:post, 'http://example.com/colorsearchserver.php', body: failed_signature_response)
301
+ subject.should_receive(:extract_options).with('http://image', {})
302
+ end
303
+
304
+ it "raises exception" do
305
+ expect { subject.extract('http://image') }.to raise_error(Imagga::ClientException)
306
+ end
307
+
308
+ it "populates exception object with details" do
309
+ begin
310
+ subject.extract('http://image')
311
+ rescue Imagga::ClientException => e
312
+ e.message.should == 'Invalid signature'
313
+ e.error_code.should == 3
314
+ end
315
+ end
316
+ end
317
+ end
318
+
319
+ describe "#rank" do
320
+ let(:rank_arguments) { {
321
+ color_vector: [{percent: 60, r: 255, g: 0, b: 0}],
322
+ type: 'overall',
323
+ dist: 3000,
324
+ count: 200
325
+ } }
326
+
327
+ it "does a rank search" do
328
+ FakeWeb.register_uri(:post, 'http://example.com/colorsearchserver.php', body: rank_response)
329
+ subject.rank(rank_arguments).size.should == 2
330
+ end
331
+
332
+ context "with failing request" do
333
+ before :each do
334
+ FakeWeb.register_uri(:post, 'http://example.com/colorsearchserver.php', body: failed_signature_response)
335
+ subject.should_receive(:rank_options)
336
+ end
337
+
338
+ it "raises exception" do
339
+ expect { subject.rank(rank_arguments) }.to raise_error(Imagga::ClientException)
340
+ end
341
+
342
+ it "populates exception object with details" do
343
+ begin
344
+ subject.rank(rank_arguments)
345
+ rescue Imagga::ClientException => e
346
+ e.message.should == 'Invalid signature'
347
+ e.error_code.should == 3
348
+ end
349
+ end
350
+ end
351
+ end
352
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Imagga::ExtractResultBuilder do
4
+ let(:result) { {
5
+ "colors" => [
6
+ {
7
+ "url" =>"http:\/\/www.stockpodium.com\/stock-photo-8244245\/smiling-presenting-2-apples-image.jpg",
8
+ "info" => {}
9
+ },
10
+ {
11
+ "url" =>"http:\/\/www.stockpodium.com\/stock-photo-9289532\/car-dirving-very-fast-under-image.jpg",
12
+ "info" => {}
13
+ }
14
+ ]
15
+ } }
16
+
17
+ subject { described_class.new }
18
+
19
+ describe '#build' do
20
+ it "builds result" do
21
+ subject.build_from(result).size.should == 2
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe Imagga::ExtractOptions do
4
+ subject { described_class.new('apikey', 'secret') }
5
+
6
+ describe "#options" do
7
+ it "builds simple options" do
8
+ subject.options('http://image').should == {
9
+ urls: 'http://image',
10
+ method: 'imagga.colorsearch.extract',
11
+ sig: '76e667179a6520da86e272a609bc7fab',
12
+ api_key: 'apikey',
13
+ v: '1.0'
14
+ }
15
+ end
16
+
17
+ it "builds complex options" do
18
+ subject.options([
19
+ Imagga::Image.new(url: 'http://image1', id: '333'),
20
+ Imagga::Image.new(url: 'http://image2')
21
+ ], extract_overall_colors: true, extract_object_colors: false).should == {
22
+ urls: 'http://image1,http://image2',
23
+ ids: '333,0',
24
+ method: 'imagga.colorsearch.extract',
25
+ extract_overall_colors: 1,
26
+ extract_object_colors: 0,
27
+ sig: 'd66a0e3409ed08878ce7efae2827de87',
28
+ api_key: 'apikey',
29
+ v: '1.0'
30
+ }
31
+ end
32
+ end
33
+
34
+ describe "#build_urls" do
35
+ it "builds string of urls based on single image url string" do
36
+ subject.build_urls('http://image').should == 'http://image'
37
+ end
38
+
39
+ it "builds string of urls based on image url string arrays" do
40
+ subject.build_urls(['http://image1', 'http://image2']).should == 'http://image1,http://image2'
41
+ end
42
+
43
+ it "builds string of urls based on single image object" do
44
+ subject.build_urls(Imagga::Image.new(url: 'http://image')).should == 'http://image'
45
+ end
46
+
47
+ it "builds string of urls based on image object array" do
48
+ subject.build_urls([
49
+ Imagga::Image.new(url: 'http://image1'),
50
+ Imagga::Image.new(url: 'http://image2')]).should == 'http://image1,http://image2'
51
+ end
52
+ end
53
+
54
+ describe "#build_ids" do
55
+ it "returns 0 based on single image url string" do
56
+ subject.build_ids('http://image').should == nil
57
+ end
58
+
59
+ it "returns array of 0-s given image url string arrays" do
60
+ subject.build_ids(['http://image1', 'http://image2']).should == nil
61
+ end
62
+
63
+ it "builds string of ids based on single image object" do
64
+ subject.build_ids(Imagga::Image.new(url: 'http://image', id: '123')).should == '123'
65
+ end
66
+
67
+ it "builds string of ids based on image object array" do
68
+ subject.build_ids([
69
+ Imagga::Image.new(url: 'http://image1', id: '123'),
70
+ Imagga::Image.new(url: 'http://image2')]).should == '123,0'
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe Imagga::ImageColor do
4
+
5
+ let(:init_hash) { {
6
+ "percent" => '19.29',
7
+ "r" => '174', "g" => '180', "b" => '187',
8
+ "html_code" => "#aeb4bb",
9
+ "closest_palette_color" => "frost",
10
+ "closest_palette_color_parent" => "light grey",
11
+ "closest_palette_distance" => 2.03931376316
12
+ } }
13
+
14
+ describe "initialized by hash" do
15
+ subject { described_class.new(init_hash) }
16
+
17
+ it "has percent" do
18
+ subject.percent.should == 19.29
19
+ end
20
+
21
+ it "has r" do
22
+ subject.r.should == 174
23
+ end
24
+
25
+ it "has g" do
26
+ subject.g.should == 180
27
+ end
28
+
29
+ it "has b" do
30
+ subject.b.should == 187
31
+ end
32
+
33
+ it "has html_code" do
34
+ subject.html_code.should == '#aeb4bb'
35
+ end
36
+
37
+ it "has closest palette color" do
38
+ subject.closest_palette_color.should == 'frost'
39
+ end
40
+
41
+ it "has closest parent palette color" do
42
+ subject.closest_palette_color_parent.should == 'light grey'
43
+ end
44
+
45
+ it "has closest palette distance" do
46
+ subject.closest_palette_distance.should == 2.03931376316
47
+ end
48
+ end
49
+
50
+ describe "initialized by hash with not supported attributes" do
51
+ subject { described_class.new(a: 'b') }
52
+
53
+ it "ignores not supported attributes" do
54
+ expect { subject.a }.to raise_error
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ describe Imagga::ImageInfo do
4
+
5
+ let(:init_hash) { {
6
+ "url" => 'http://image',
7
+ "info" => {
8
+ "image_colors" => [ { "html_code" => "#676262", } ],
9
+ "foreground_colors" => [ { "html_code" => "#c7322b", } ],
10
+ "background_colors" => [ { "html_code" => "#676161", } ],
11
+ "object_percentage" => 17.99,
12
+ "color_variance" => "37",
13
+ "image_packed" => nil,
14
+ "foreground_packed" => nil,
15
+ "background_packed" => nil
16
+ }
17
+ } }
18
+ subject { described_class.new(init_hash) }
19
+
20
+ describe "initialized by hash" do
21
+
22
+ it "has url" do
23
+ subject.url.should == 'http://image'
24
+ end
25
+
26
+ it "has image colors" do
27
+ subject.image_colors.should have(1).items
28
+ subject.image_colors.first.html_code.should == '#676262'
29
+ end
30
+
31
+ it "has foreground colors" do
32
+ subject.foreground_colors.should have(1).items
33
+ subject.foreground_colors.first.html_code.should == '#c7322b'
34
+ end
35
+
36
+ it "has background colors" do
37
+ subject.background_colors.should have(1).items
38
+ subject.background_colors.first.html_code.should == '#676161'
39
+ end
40
+
41
+ it "has object percentage" do
42
+ subject.object_percentage.should == 17.99
43
+ end
44
+
45
+ it "has color variance" do
46
+ subject.color_variance.should == 37
47
+ end
48
+ end
49
+
50
+ describe "initialized by hash with not supported attributes" do
51
+ subject { described_class.new(a: 'b') }
52
+
53
+ it "ignores not supported attributes" do
54
+ expect { subject.a }.to raise_error
55
+ end
56
+ end
57
+
58
+ describe "initialied with empty color info" do
59
+ let(:init_hash) { {
60
+ "url" => 'http://image',
61
+ "info" => {
62
+ "image_colors" => [],
63
+ "foreground_colors" => [],
64
+ "background_colors" => [],
65
+ }
66
+ } }
67
+
68
+ it "initializes color infos as empty arrays" do
69
+ subject.image_colors.should be_empty
70
+ subject.foreground_colors.should be_empty
71
+ subject.background_colors.should be_empty
72
+ end
73
+ end
74
+
75
+ describe "initialied with missing color info" do
76
+ let(:init_hash) { {
77
+ "url" => 'http://image',
78
+ "info" => {}
79
+ } }
80
+
81
+ it "does not initialize color infos" do
82
+ subject.image_colors.should be_nil
83
+ subject.foreground_colors.should be_nil
84
+ subject.background_colors.should be_nil
85
+ end
86
+ end
87
+
88
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Imagga::Image do
4
+ subject { described_class.new(url: 'http://', id: '1234') }
5
+
6
+ it "has id" do
7
+ subject.id.should == '1234'
8
+ end
9
+
10
+ it "has url" do
11
+ subject.url.should == 'http://'
12
+ end
13
+
14
+ context "without url" do
15
+ it "throws ArgumentError" do
16
+ expect{ described_class.new(id: '1234') }.to raise_error(ArgumentError, 'url is missing')
17
+ end
18
+ end
19
+
20
+ context "without id" do
21
+ it "assigns id as 0" do
22
+ described_class.new(url: 'http://').id.should == 0
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Imagga::RankResultBuilder do
4
+ let(:result) { {
5
+ 'rank_similarity' => [
6
+ {
7
+ "id" => 8774077,
8
+ "dist" => 2597.38299
9
+ },
10
+ {
11
+ "id" => 9085916,
12
+ "dist" => 2681.33259
13
+ }
14
+ ]
15
+ } }
16
+
17
+ subject { described_class.new }
18
+
19
+ describe '#build' do
20
+ it "builds result" do
21
+ subject.build_from(result).size.should == 2
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Imagga::RankSimilarity do
4
+
5
+ let(:init_hash) { {
6
+ "id" => 8774077,
7
+ "dist" => 2597.38299
8
+ } }
9
+
10
+ describe "initialized by hash" do
11
+ subject { described_class.new(init_hash) }
12
+
13
+ it "has id" do
14
+ subject.id.should == 8774077
15
+ end
16
+
17
+ it "has dist" do
18
+ subject.dist.should == 2597.38299
19
+ end
20
+ end
21
+
22
+ # todo
23
+ describe "initialized by hash with not supported attributes" do
24
+ subject { described_class.new(a: 'b') }
25
+
26
+ it "ignores not supported attributes" do
27
+ expect { subject.a }.to raise_error
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,11 @@
1
+ require 'rspec/autorun'
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ Bundler.require(:default, :development)
5
+
6
+ # Requires supporting ruby files with custom matchers and macros, etc,
7
+ # in spec/support/ and its subdirectories.
8
+ Dir["spec/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+ end
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: imagga
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mart Karu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: httparty
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.10'
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: '0.10'
30
+ - !ruby/object:Gem::Dependency
31
+ name: json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.7'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.7'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.12'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.12'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: fakeweb
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: Ruby client for accessing Imagga API
95
+ email:
96
+ - karu@metal.ee
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitignore
102
+ - .rspec
103
+ - .travis.yml
104
+ - Gemfile
105
+ - LICENSE.txt
106
+ - README.md
107
+ - Rakefile
108
+ - imagga.gemspec
109
+ - lib/imagga.rb
110
+ - lib/imagga/client.rb
111
+ - lib/imagga/exceptions.rb
112
+ - lib/imagga/extract_options.rb
113
+ - lib/imagga/extract_result_builder.rb
114
+ - lib/imagga/image.rb
115
+ - lib/imagga/rank_result_builder.rb
116
+ - lib/imagga/version.rb
117
+ - spec/lib/client_spec.rb
118
+ - spec/lib/extract_result_builder_spec.rb
119
+ - spec/lib/extraction_options_spec.rb
120
+ - spec/lib/image_color_spec.rb
121
+ - spec/lib/image_info_spec.rb
122
+ - spec/lib/image_spec.rb
123
+ - spec/lib/rank_result_builder_spec.rb
124
+ - spec/lib/rank_similarity_spec.rb
125
+ - spec/spec_helper.rb
126
+ homepage: ''
127
+ licenses: []
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ! '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ segments:
139
+ - 0
140
+ hash: 440675985594337981
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ! '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ segments:
148
+ - 0
149
+ hash: 440675985594337981
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 1.8.25
153
+ signing_key:
154
+ specification_version: 3
155
+ summary: Ruby client for accessing Imagga API
156
+ test_files:
157
+ - spec/lib/client_spec.rb
158
+ - spec/lib/extract_result_builder_spec.rb
159
+ - spec/lib/extraction_options_spec.rb
160
+ - spec/lib/image_color_spec.rb
161
+ - spec/lib/image_info_spec.rb
162
+ - spec/lib/image_spec.rb
163
+ - spec/lib/rank_result_builder_spec.rb
164
+ - spec/lib/rank_similarity_spec.rb
165
+ - spec/spec_helper.rb