imagga 0.0.3 → 0.0.5
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 +15 -0
- data/README.md +28 -1
- data/imagga.gemspec +1 -0
- data/lib/imagga.rb +8 -3
- data/lib/imagga/client.rb +12 -34
- data/lib/imagga/commands.rb +42 -0
- data/lib/imagga/core_client.rb +25 -0
- data/lib/imagga/exceptions.rb +3 -0
- data/lib/imagga/image.rb +59 -2
- data/lib/imagga/image_or_url_parametizer.rb +21 -0
- data/lib/imagga/options.rb +74 -0
- data/lib/imagga/parametizer.rb +18 -0
- data/lib/imagga/rank_color_parametizer.rb +17 -0
- data/lib/imagga/resolution_parametizer.rb +17 -0
- data/lib/imagga/result_builder.rb +27 -0
- data/lib/imagga/version.rb +1 -1
- data/spec/fixtures/crop_response.txt +62 -0
- data/spec/fixtures/extract_response.txt +253 -0
- data/spec/fixtures/rank_response.txt +12 -0
- data/spec/integration/crop_spec.rb +60 -0
- data/spec/integration/extract_spec.rb +51 -0
- data/spec/integration/rank_spec.rb +103 -0
- data/spec/lib/commands_spec.rb +70 -0
- data/spec/lib/core_client_spec.rb +43 -0
- data/spec/lib/crop_info_spec.rb +15 -0
- data/spec/lib/crop_options_spec.rb +24 -0
- data/spec/lib/crop_result_builder_spec.rb +4 -0
- data/spec/lib/extraction_options_spec.rb +16 -51
- data/spec/lib/image_crop_spec.rb +34 -0
- data/spec/lib/image_or_url_parametizer_spec.rb +65 -0
- data/spec/lib/parametizer_spec.rb +42 -0
- data/spec/lib/rank_color_parametizer_spec.rb +27 -0
- data/spec/lib/rank_color_spec.rb +51 -0
- data/spec/lib/rank_options_spec.rb +28 -0
- data/spec/lib/rank_result_builder_spec.rb +1 -12
- data/spec/lib/resolution_parametizer_spec.rb +60 -0
- metadata +63 -28
- data/lib/imagga/extract_options.rb +0 -74
- data/lib/imagga/extract_result_builder.rb +0 -11
- data/lib/imagga/rank_result_builder.rb +0 -9
- data/spec/lib/client_spec.rb +0 -352
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
N2ViMjRjNTFlZmE3YTNmYzc4ZTEwMjlmZDg5NjJiNzRkNGRjOGViNg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NGMyOTRhMzEzMTkzZmQ5MjJmMTkxZGJiOTBiYzViM2IwZTE0Njk1Mg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZDc1MWI4N2NmOGQ0N2FlZTQ2NjJjZDRkMzA0ZDhiYzAyNjcwMmNlNmI0OGY3
|
10
|
+
MjY2ZjVlOTcwMzhiZWRmMmI0N2YyYjU1MDQxYWU4MWI3YjM5ZjM2MzU2NjI4
|
11
|
+
MDAwNTQ5NGUxMDRmZWE4MmRjNTkzMGE2OTljZGIwM2ZiZWQ2MTg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YTc1ODMzZGVlOTgyZDAwM2JlMmZiNjNiMzNlMWZkMWYyNDdmNGY2MGY4NTJh
|
14
|
+
MjE4ZDI2M2FiNzRhOTNmMWY0N2FjYTQ0YWJmNTFlMWQ0ZTNmNjY3YzMxZWNh
|
15
|
+
MzlhYTkwMmQ5NTgwZTJiZjRhNWUzNDBiNTRhZjZmM2U5YTJkNTM=
|
data/README.md
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
[](https://codeclimate.com/github/martkaru/imagga)
|
1
2
|
[](https://travis-ci.org/martkaru/imagga)
|
2
3
|
|
3
4
|
# Imagga
|
@@ -56,7 +57,10 @@ Check the results, for example:
|
|
56
57
|
Multi-color search:
|
57
58
|
|
58
59
|
client.rank(
|
59
|
-
|
60
|
+
colors: [
|
61
|
+
Imagga::RankColor.new(percent: 100, r: 82, g: 37, b: 43) # use r g b values
|
62
|
+
Imagga::RankColor.new(percent: 100, hex: '#336699') # or use hex
|
63
|
+
],
|
60
64
|
type: 'object',
|
61
65
|
dist: 6000,
|
62
66
|
count: 10
|
@@ -64,6 +68,29 @@ Multi-color search:
|
|
64
68
|
puts "Distance of #%i is %.4f" % [similarity.id, similarity.dist] # Distance of #333 is 3581.5500
|
65
69
|
end
|
66
70
|
|
71
|
+
Image crop suggestions:
|
72
|
+
|
73
|
+
client.crop(
|
74
|
+
[
|
75
|
+
'http://image1', # Use urls
|
76
|
+
Imagga::Image.new(url: 'http://image2') # or image object
|
77
|
+
],
|
78
|
+
resolutions: ['100x40','50x100'], # '100,40,50,100' or '100x40,50x100' instead of array would work also
|
79
|
+
no_scaling: true
|
80
|
+
).each do |crop_info|
|
81
|
+
puts crop_info.url
|
82
|
+
crop_info.croppings.each do |cropping|
|
83
|
+
puts cropping.info
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
## Contributors
|
88
|
+
|
89
|
+
martkaru
|
90
|
+
|
91
|
+
jprosevear
|
92
|
+
|
93
|
+
|
67
94
|
## Contributing
|
68
95
|
|
69
96
|
1. Fork it
|
data/imagga.gemspec
CHANGED
data/lib/imagga.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
require "imagga/version"
|
2
2
|
require "imagga/exceptions"
|
3
|
-
require "imagga/extract_result_builder"
|
4
|
-
require "imagga/rank_result_builder"
|
5
3
|
require "imagga/image"
|
6
|
-
require "imagga/
|
4
|
+
require "imagga/result_builder"
|
5
|
+
require "imagga/parametizer"
|
6
|
+
require "imagga/image_or_url_parametizer"
|
7
|
+
require "imagga/rank_color_parametizer"
|
8
|
+
require "imagga/resolution_parametizer"
|
9
|
+
require "imagga/commands"
|
10
|
+
require "imagga/core_client"
|
11
|
+
require "imagga/options"
|
7
12
|
require "imagga/client"
|
data/lib/imagga/client.rb
CHANGED
@@ -1,42 +1,20 @@
|
|
1
|
-
require "httparty"
|
2
|
-
require "json"
|
3
|
-
|
4
1
|
module Imagga
|
5
|
-
class Client
|
6
|
-
|
7
|
-
|
8
|
-
|
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)
|
2
|
+
class Client < CoreClient
|
3
|
+
def extract(urls_or_images, options={})
|
4
|
+
options.merge!(ImageOrUrlParametizer.new.parametrize(urls_or_images))
|
5
|
+
ExtractResultBuilder.new.build_from(super(options))
|
30
6
|
end
|
31
7
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
8
|
+
def rank(options={})
|
9
|
+
colors = options.delete(:colors) { raise_missing('colors') }
|
10
|
+
options.merge!(RankColorParametizer.new.parametrize(colors))
|
11
|
+
RankResultBuilder.new.build_from(super(options))
|
36
12
|
end
|
37
13
|
|
38
|
-
def
|
39
|
-
|
14
|
+
def crop(urls_or_images, options={})
|
15
|
+
options.merge!(ImageOrUrlParametizer.new.build_urls(urls_or_images))
|
16
|
+
options.merge!(ResolutionParametizer.new.parametrize(options.fetch(:resolutions)))
|
17
|
+
CropResultBuilder.new.build_from(super(options))
|
40
18
|
end
|
41
19
|
end
|
42
20
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "httparty"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Imagga
|
5
|
+
class BaseCommand
|
6
|
+
include HTTParty
|
7
|
+
include Imagga::Exceptions
|
8
|
+
|
9
|
+
attr_reader :api_key, :api_secret, :base_uri
|
10
|
+
|
11
|
+
def initialize(api_key, api_secret, base_uri)
|
12
|
+
@api_key, @api_secret, @base_uri = api_key, api_secret, base_uri
|
13
|
+
self.class.base_uri @base_uri
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(options)
|
17
|
+
JSON.parse(self.class.post(service_path, body: args(options))).tap do |result|
|
18
|
+
raise_if_request_failed!(result)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def args(options)
|
23
|
+
options_class.new(api_key, api_secret).options(options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def options_class; BaseOptions; end
|
27
|
+
end
|
28
|
+
|
29
|
+
class ExtractCommand < BaseCommand
|
30
|
+
def service_path; '/colorsearchserver.php'; end
|
31
|
+
def options_class; ExtractOptions; end
|
32
|
+
end
|
33
|
+
|
34
|
+
class RankCommand < ExtractCommand
|
35
|
+
def options_class; RankOptions; end
|
36
|
+
end
|
37
|
+
|
38
|
+
class CropCommand < BaseCommand
|
39
|
+
def service_path; '/extractionrestserver.php'; end
|
40
|
+
def options_class; CropOptions; end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Imagga
|
2
|
+
class CoreClient
|
3
|
+
include Imagga::Exceptions
|
4
|
+
attr_reader :api_key, :api_secret, :base_uri
|
5
|
+
|
6
|
+
def initialize(opts={})
|
7
|
+
@api_key = opts[:api_key] || raise_missing(:api_key)
|
8
|
+
@api_secret = opts[:api_secret] || raise_missing(:api_secret)
|
9
|
+
@base_uri = opts[:base_uri] || raise_missing(:base_uri)
|
10
|
+
end
|
11
|
+
|
12
|
+
def extract(options={})
|
13
|
+
ExtractCommand.new(api_key, api_secret, base_uri).execute(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def rank(options={})
|
17
|
+
RankCommand.new(api_key, api_secret, base_uri).execute(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def crop(options={})
|
21
|
+
CropCommand.new(api_key, api_secret, base_uri).execute(options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
data/lib/imagga/exceptions.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module Imagga
|
2
2
|
module Exceptions
|
3
|
+
|
3
4
|
def raise_missing(attribute)
|
4
5
|
raise ArgumentError, "%s is missing" % attribute.to_s
|
5
6
|
end
|
@@ -9,10 +10,12 @@ module Imagga
|
|
9
10
|
raise Imagga::ClientException.new(result['error_code'].to_i), result['error_message'], caller[0..-1]
|
10
11
|
end
|
11
12
|
end
|
13
|
+
|
12
14
|
end
|
13
15
|
|
14
16
|
class ClientException < StandardError
|
15
17
|
attr_accessor :error_code
|
18
|
+
|
16
19
|
def initialize(error_code)
|
17
20
|
@error_code = error_code
|
18
21
|
super
|
data/lib/imagga/image.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
require 'color'
|
2
|
+
|
1
3
|
module Imagga
|
2
4
|
class Image
|
3
5
|
include Imagga::Exceptions
|
4
6
|
attr_accessor :url, :id
|
5
7
|
|
6
8
|
def initialize(opts)
|
7
|
-
@url
|
8
|
-
@id
|
9
|
+
@url = opts[:url] || raise_missing(:url)
|
10
|
+
@id = opts[:id] || 0
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
@@ -64,6 +66,20 @@ module Imagga
|
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
69
|
+
class RankColor
|
70
|
+
attr_accessor :percent, :r, :g, :b, :hex
|
71
|
+
def initialize(opts)
|
72
|
+
@percent = opts.fetch(:percent)
|
73
|
+
if @hex = opts[:hex]
|
74
|
+
color = Color::RGB.from_html(@hex)
|
75
|
+
@r, @g, @b = color.red, color.green, color.blue
|
76
|
+
else
|
77
|
+
@r, @g, @b = opts[:r], opts[:g], opts[:b]
|
78
|
+
@hex = Color::RGB.new(r, g, b).html
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
67
83
|
class RankSimilarity < ImageInfoBase
|
68
84
|
def self.fields
|
69
85
|
%w(id dist)
|
@@ -71,4 +87,45 @@ module Imagga
|
|
71
87
|
|
72
88
|
attr_accessor *fields
|
73
89
|
end
|
90
|
+
|
91
|
+
class CropInfo < ImageInfoBase
|
92
|
+
def self.fields
|
93
|
+
%w(url)
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.crop_fields
|
97
|
+
%w(croppings)
|
98
|
+
end
|
99
|
+
|
100
|
+
def initialize(opts={})
|
101
|
+
super({'url' => opts['url']})
|
102
|
+
self.class.crop_fields.each do |field|
|
103
|
+
send("#{field}=", build_image_crops(opts[field]))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def build_image_crops(image_crop_nodes)
|
108
|
+
image_crop_nodes && image_crop_nodes.map { |crop_node| ImageCrop.new(crop_node) }
|
109
|
+
end
|
110
|
+
|
111
|
+
attr_accessor *(fields + crop_fields)
|
112
|
+
end
|
113
|
+
|
114
|
+
class ImageCrop < ImageInfoBase
|
115
|
+
def self.fields
|
116
|
+
%w(target_width target_height x1 y1 x2 y2)
|
117
|
+
end
|
118
|
+
|
119
|
+
attr_accessor *fields
|
120
|
+
|
121
|
+
%w(target_width target_height x1 y1 x2 y2).each do |field|
|
122
|
+
define_method("#{field}=") do |value|
|
123
|
+
instance_variable_set("@#{field}", value.to_i)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def info
|
128
|
+
"target: (%i,%i), crop: (%i, %i) to (%i, %i)" % [target_width, target_height, x1, y1, x2, y2]
|
129
|
+
end
|
130
|
+
end
|
74
131
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Imagga
|
2
|
+
class ImageOrUrlParametizer
|
3
|
+
include Parametizer
|
4
|
+
|
5
|
+
def parametrize(urls_or_images)
|
6
|
+
options = build_urls(urls_or_images)
|
7
|
+
if (ids = build_ids(urls_or_images))[:ids]
|
8
|
+
options.merge!(ids)
|
9
|
+
end
|
10
|
+
options
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_urls(urls_or_images)
|
14
|
+
{ urls: [urls_or_images].flatten.map{ |o| o.url rescue o }.join(',') }
|
15
|
+
end
|
16
|
+
|
17
|
+
def build_ids(urls_or_images)
|
18
|
+
{ ids: build_comma_separated_string(urls_or_images, :id, 0) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Imagga
|
2
|
+
class BaseOptions
|
3
|
+
include Parametizer
|
4
|
+
attr_accessor :api_key, :api_secret, :version
|
5
|
+
|
6
|
+
def initialize(api_key, api_secret)
|
7
|
+
@version = '1.0'
|
8
|
+
@api_key = api_key || raise_missing(:api_key)
|
9
|
+
@api_secret = api_secret || raise_missing(:api_secret)
|
10
|
+
end
|
11
|
+
|
12
|
+
def base_options
|
13
|
+
{ v: version, api_key: api_key }
|
14
|
+
end
|
15
|
+
|
16
|
+
def sign(options)
|
17
|
+
sorted_options_string = options.keys.sort.map do |key|
|
18
|
+
"%s=%s" % [key.to_s, options[key]]
|
19
|
+
end.join('') << api_secret
|
20
|
+
Digest::MD5.hexdigest(sorted_options_string)
|
21
|
+
end
|
22
|
+
|
23
|
+
def options(opts={})
|
24
|
+
{}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ExtractOptions < BaseOptions
|
29
|
+
def options(opts={})
|
30
|
+
opts.merge!(base_options).merge!(method: method)
|
31
|
+
opts.merge!(build_boolean_options(opts, boolean_fields))
|
32
|
+
opts.merge!(sig: sign(opts))
|
33
|
+
end
|
34
|
+
|
35
|
+
def method
|
36
|
+
'imagga.colorsearch.extract'
|
37
|
+
end
|
38
|
+
|
39
|
+
def boolean_fields
|
40
|
+
[:extract_overall_colors, :extract_object_colors]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class RankOptions < BaseOptions
|
45
|
+
include Imagga::Exceptions
|
46
|
+
|
47
|
+
def options(opts={})
|
48
|
+
opts.merge!(base_options).merge!(
|
49
|
+
method: method,
|
50
|
+
color_vector: opts.delete(:color_vector),
|
51
|
+
type: (opts.delete(:type) { raise_missing('type') }).to_s,
|
52
|
+
dist: (opts.delete(:dist) { raise_missing('dist') }).to_s,
|
53
|
+
count: (opts.delete(:count) { raise_missing('count') }).to_s
|
54
|
+
)
|
55
|
+
opts.merge!(sig: sign(opts))
|
56
|
+
end
|
57
|
+
|
58
|
+
def method
|
59
|
+
'imagga.colorsearch.rank'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class CropOptions < BaseOptions
|
64
|
+
def options(opts={})
|
65
|
+
options = base_options.merge(opts).merge(method: method)
|
66
|
+
options.merge!(build_boolean_options(opts, :no_scaling))
|
67
|
+
options.merge!(sig: sign(options))
|
68
|
+
end
|
69
|
+
|
70
|
+
def method
|
71
|
+
'imagga.process.crop'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Imagga
|
2
|
+
module Parametizer
|
3
|
+
def build_comma_separated_string(objects, field, default_to=nil)
|
4
|
+
field_values = [objects].flatten.map{ |o| o.send(field) rescue default_to }
|
5
|
+
return if field_values.uniq == [default_to]
|
6
|
+
field_values.join(',')
|
7
|
+
end
|
8
|
+
|
9
|
+
def build_boolean_options(options, keys)
|
10
|
+
[keys].flatten.inject({}) do |result, key|
|
11
|
+
if options.keys.include?(key) && (value = [true, '1', 1].include?(options[key]) ? 1 : 0)
|
12
|
+
result[key] = value
|
13
|
+
end
|
14
|
+
result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Imagga
|
2
|
+
class RankColorParametizer
|
3
|
+
include Parametizer
|
4
|
+
|
5
|
+
def parametrize(rank_color_or_colors)
|
6
|
+
{ color_vector: build_vector(rank_color_or_colors) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def build_vector(rank_color_or_colors)
|
10
|
+
[rank_color_or_colors].flatten.map{ |o| build_rank_color_string(o) rescue o }.join(',')
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_rank_color_string(rank_color)
|
14
|
+
"%i,%i,%i,%i" % [rank_color.percent, rank_color.r, rank_color.g, rank_color.b]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|