remove_bg 1.2.0 → 1.5.0

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.
@@ -8,6 +8,8 @@ module RemoveBg
8
8
  HTTP_BASE_TIMEOUT = 10
9
9
  HTTP_WRITE_TIMEOUT = 120
10
10
 
11
+ # @return [Faraday::Connection]
12
+ #
11
13
  def self.build(api_url = RemoveBg::Api::URL)
12
14
  retry_options = {
13
15
  max: 2,
@@ -0,0 +1,60 @@
1
+ require_relative "error"
2
+
3
+ module RemoveBg
4
+ # Combines alpha.png and color.jpg files to produce a full-sized transparent PNG.
5
+ # An image processing library (ImageMagick, GraphicsMagick, or libvips) must
6
+ # be available on the system.
7
+ # @see RemoveBg::CompositeResult
8
+ #
9
+ class ImageComposer
10
+ DEFAULT_BINARY_DETECTOR = lambda do |binary_name|
11
+ system("which", binary_name, out: File::NULL)
12
+ end
13
+
14
+ def self.detect_image_processor(detector: DEFAULT_BINARY_DETECTOR)
15
+ case
16
+ when detector.call("magick"), detector.call("convert"), detector.call("gm")
17
+ :minimagick
18
+ when detector.call("vips")
19
+ :vips
20
+ end
21
+ end
22
+
23
+ def compose(color_file:, alpha_file:, destination_path:)
24
+ image = case configured_image_processor
25
+ when :vips
26
+ then vips_compose(color_file: color_file, alpha_file: alpha_file)
27
+ when :minimagick
28
+ then minimagick_compose(color_file: color_file, alpha_file: alpha_file)
29
+ when nil
30
+ raise RemoveBg::Error, "Please configure an image processor to use image composition"
31
+ else
32
+ raise RemoveBg::Error, "Unsupported image processor: #{configured_image_processor.inspect}"
33
+ end
34
+
35
+ image.call(destination: destination_path)
36
+ end
37
+
38
+ private
39
+
40
+ def configured_image_processor
41
+ RemoveBg::Configuration.configuration.image_processor
42
+ end
43
+
44
+ def minimagick_compose(color_file:, alpha_file:)
45
+ require "image_processing/mini_magick"
46
+
47
+ ImageProcessing::MiniMagick
48
+ .source(color_file)
49
+ .composite(alpha_file, mode: "copy-opacity")
50
+ end
51
+
52
+ def vips_compose(color_file:, alpha_file:)
53
+ require "image_processing/vips"
54
+
55
+ ImageProcessing::Vips
56
+ .source(color_file)
57
+ .custom { |image| image.bandjoin(Vips::Image.new_from_file(alpha_file.path)) }
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,34 @@
1
+ require "time"
2
+
3
+ module RemoveBg
4
+ class RateLimitInfo
5
+ attr_reader :total, :remaining, :retry_after_seconds
6
+
7
+ def initialize(headers)
8
+ @total = headers["X-RateLimit-Limit"]&.to_i
9
+ @remaining = headers["X-RateLimit-Remaining"]&.to_i
10
+ @reset_timestamp = headers["X-RateLimit-Reset"]&.to_i
11
+
12
+ # Only present if rate limit exceeded
13
+ @retry_after_seconds = headers["Retry-After"]&.to_i
14
+ end
15
+
16
+ def reset_at
17
+ return if reset_timestamp.nil?
18
+ Time.at(reset_timestamp).utc
19
+ end
20
+
21
+ def to_s
22
+ "<RateLimit"\
23
+ " reset_at='#{reset_at.iso8601}'"\
24
+ " retry_after_seconds=#{retry_after_seconds}"\
25
+ " total=#{total}"\
26
+ " remaining=#{remaining}"\
27
+ ">"
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :reset_timestamp
33
+ end
34
+ end
@@ -1,7 +1,9 @@
1
- require_relative "error"
1
+ require_relative "base_request_options"
2
2
 
3
3
  module RemoveBg
4
- class RequestOptions
4
+ # Options for image processing requests. Arbitary options are passed directly to the API.
5
+ #
6
+ class RequestOptions < BaseRequestOptions
5
7
  SIZE_REGULAR = "regular"
6
8
  SIZE_MEDIUM = "medium"
7
9
  SIZE_HD = "hd"
@@ -15,32 +17,40 @@ module RemoveBg
15
17
  CHANNELS_RGBA = "rgba"
16
18
  CHANNELS_ALPHA = "alpha"
17
19
 
18
- attr_reader :api_key, :data
20
+ FORMAT_PNG = "png"
21
+ FORMAT_ZIP = "zip"
22
+ FORMAT_JPG = "jpg"
19
23
 
20
24
  def initialize(raw_options = {})
21
25
  options = raw_options.dup
22
26
  options[:size] ||= SIZE_AUTO
23
- @api_key = resolve_api_key(options.delete(:api_key))
24
- @data = options
27
+
28
+ if options.key?(:format)
29
+ options[:format] = optimize_format(options[:format])
30
+ end
31
+
32
+ super(options)
25
33
  end
26
34
 
27
35
  private
28
36
 
29
- def resolve_api_key(request_api_key)
30
- api_key = request_api_key || global_api_key
37
+ # Save bandwidth where possible
38
+ def optimize_format(requested_format)
39
+ requested_png = requested_format.to_s.casecmp?(FORMAT_PNG)
31
40
 
32
- if api_key.nil? || api_key.empty?
33
- raise RemoveBg::Error, <<~MSG
34
- Please configure an API key or specify one per request. API key was:
35
- #{api_key.inspect}
36
- MSG
41
+ if requested_png && optimization_enabled? && can_process_images?
42
+ FORMAT_ZIP
43
+ else
44
+ requested_format
37
45
  end
46
+ end
38
47
 
39
- api_key
48
+ def can_process_images?
49
+ RemoveBg::Configuration.configuration.can_process_images?
40
50
  end
41
51
 
42
- def global_api_key
43
- RemoveBg::Configuration.configuration.api_key
52
+ def optimization_enabled?
53
+ RemoveBg::Configuration.configuration.auto_upgrade_png_to_zip
44
54
  end
45
55
  end
46
56
  end
@@ -1,22 +1,57 @@
1
+ require "fileutils"
2
+ require "forwardable"
3
+ require "zip"
1
4
  require_relative "error"
5
+ require_relative "image_composer"
2
6
 
3
7
  module RemoveBg
8
+ # Provides convenience methods to save the processed image, read the image data,
9
+ # and access metadata such as the image height/width and credits charged.
10
+ #
4
11
  class Result
5
- attr_reader :data, :width, :height, :credits_charged
12
+ extend ::Forwardable
6
13
 
7
- def initialize(data:, width:, height:, credits_charged:)
8
- @data = data
9
- @width = width
10
- @height = height
11
- @credits_charged = credits_charged
14
+ # @return [RemoveBg::ResultMetadata]
15
+ attr_reader :metadata
16
+
17
+ # @return [RemoveBg::RateLimitInfo]
18
+ attr_reader :rate_limit
19
+
20
+ def_delegators :metadata, :type, :width, :height, :credits_charged
21
+
22
+ def initialize(download:, metadata:, rate_limit:)
23
+ @download = download
24
+ @metadata = metadata
25
+ @rate_limit = rate_limit
12
26
  end
13
27
 
28
+ # Saves the processed image to the path specified
29
+ # @param file_path [string]
30
+ # @param overwrite [boolean] Overwrite any existing file at the specified path
31
+ # @return [nil]
32
+ #
14
33
  def save(file_path, overwrite: false)
15
34
  if File.exist?(file_path) && !overwrite
16
35
  raise FileOverwriteError.new(file_path)
17
36
  end
18
37
 
19
- File.write(file_path, data)
38
+ FileUtils.cp(image_file, file_path)
39
+ end
40
+
41
+ # Returns the binary data of the processed image
42
+ # @return [String]
43
+ #
44
+ def data
45
+ image_file.rewind
46
+ image_file.read
47
+ end
48
+
49
+ private
50
+
51
+ attr_reader :download
52
+
53
+ def image_file
54
+ download
20
55
  end
21
56
  end
22
57
  end
@@ -0,0 +1,14 @@
1
+ require_relative "api"
2
+
3
+ module RemoveBg
4
+ class ResultMetadata
5
+ attr_reader :type, :width, :height, :credits_charged
6
+
7
+ def initialize(headers)
8
+ @type = headers["X-Type"]
9
+ @width = headers["X-Width"]&.to_i
10
+ @height = headers["X-Height"]&.to_i
11
+ @credits_charged = headers["X-Credits-Charged"]&.to_f
12
+ end
13
+ end
14
+ end
@@ -1,4 +1,4 @@
1
- require "faraday/upload_io"
1
+ require "faraday"
2
2
  require_relative "error"
3
3
 
4
4
  module RemoveBg
@@ -9,7 +9,7 @@ module RemoveBg
9
9
  end
10
10
 
11
11
  content_type = determine_content_type(file_path)
12
- Faraday::UploadIO.new(file_path, content_type)
12
+ FARADAY_FILE.new(file_path, content_type)
13
13
  end
14
14
 
15
15
  def self.determine_content_type(file_path)
@@ -22,5 +22,9 @@ module RemoveBg
22
22
  end
23
23
 
24
24
  private_class_method :determine_content_type
25
+
26
+ # UploadIO for Faraday < 0.16.0
27
+ FARADAY_FILE = defined?(Faraday::FilePart) ? Faraday::FilePart : Faraday::UploadIO
28
+ private_constant :FARADAY_FILE
25
29
  end
26
30
  end
@@ -1,3 +1,3 @@
1
1
  module RemoveBg
2
- VERSION = "1.2.0"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -23,16 +23,21 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ["lib"]
25
25
 
26
- spec.add_dependency "faraday", ">= 0.14", "< 2"
26
+ spec.add_dependency "faraday", ">= 0.15", "< 2"
27
+ spec.add_dependency "image_processing", ">= 1.9", "< 2"
28
+ spec.add_dependency "rubyzip", ">= 2.0", "< 3"
27
29
 
28
- spec.add_development_dependency "appraisal"
29
- spec.add_development_dependency "bundler", "~> 1.17"
30
+ spec.add_development_dependency "bundler", "~> 2.0"
31
+ spec.add_development_dependency "codecov"
30
32
  spec.add_development_dependency "dotenv"
31
33
  spec.add_development_dependency "pry"
32
- spec.add_development_dependency "rake", "~> 12.0"
34
+ spec.add_development_dependency "rake"
33
35
  spec.add_development_dependency "rspec_junit_formatter"
34
36
  spec.add_development_dependency "rspec-with_params"
35
37
  spec.add_development_dependency "rspec", "~> 3.8"
38
+ spec.add_development_dependency "simplecov"
39
+ spec.add_development_dependency "vcr_better_binary"
36
40
  spec.add_development_dependency "vcr"
37
41
  spec.add_development_dependency "webmock"
42
+ spec.add_development_dependency "yard"
38
43
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remove_bg
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Peate
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-12 00:00:00.000000000 Z
11
+ date: 2020-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0.14'
19
+ version: '0.15'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '2'
@@ -26,38 +26,78 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '0.14'
29
+ version: '0.15'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '2'
33
33
  - !ruby/object:Gem::Dependency
34
- name: appraisal
34
+ name: image_processing
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '0'
40
- type: :development
39
+ version: '1.9'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '2'
43
+ type: :runtime
41
44
  prerelease: false
42
45
  version_requirements: !ruby/object:Gem::Requirement
43
46
  requirements:
44
47
  - - ">="
45
48
  - !ruby/object:Gem::Version
46
- version: '0'
49
+ version: '1.9'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '2'
53
+ - !ruby/object:Gem::Dependency
54
+ name: rubyzip
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '2.0'
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: '3'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '2.0'
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: '3'
47
73
  - !ruby/object:Gem::Dependency
48
74
  name: bundler
49
75
  requirement: !ruby/object:Gem::Requirement
50
76
  requirements:
51
77
  - - "~>"
52
78
  - !ruby/object:Gem::Version
53
- version: '1.17'
79
+ version: '2.0'
54
80
  type: :development
55
81
  prerelease: false
56
82
  version_requirements: !ruby/object:Gem::Requirement
57
83
  requirements:
58
84
  - - "~>"
59
85
  - !ruby/object:Gem::Version
60
- version: '1.17'
86
+ version: '2.0'
87
+ - !ruby/object:Gem::Dependency
88
+ name: codecov
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ type: :development
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
61
101
  - !ruby/object:Gem::Dependency
62
102
  name: dotenv
63
103
  requirement: !ruby/object:Gem::Requirement
@@ -90,16 +130,16 @@ dependencies:
90
130
  name: rake
91
131
  requirement: !ruby/object:Gem::Requirement
92
132
  requirements:
93
- - - "~>"
133
+ - - ">="
94
134
  - !ruby/object:Gem::Version
95
- version: '12.0'
135
+ version: '0'
96
136
  type: :development
97
137
  prerelease: false
98
138
  version_requirements: !ruby/object:Gem::Requirement
99
139
  requirements:
100
- - - "~>"
140
+ - - ">="
101
141
  - !ruby/object:Gem::Version
102
- version: '12.0'
142
+ version: '0'
103
143
  - !ruby/object:Gem::Dependency
104
144
  name: rspec_junit_formatter
105
145
  requirement: !ruby/object:Gem::Requirement
@@ -142,6 +182,34 @@ dependencies:
142
182
  - - "~>"
143
183
  - !ruby/object:Gem::Version
144
184
  version: '3.8'
185
+ - !ruby/object:Gem::Dependency
186
+ name: simplecov
187
+ requirement: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ type: :development
193
+ prerelease: false
194
+ version_requirements: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ - !ruby/object:Gem::Dependency
200
+ name: vcr_better_binary
201
+ requirement: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - ">="
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
206
+ type: :development
207
+ prerelease: false
208
+ version_requirements: !ruby/object:Gem::Requirement
209
+ requirements:
210
+ - - ">="
211
+ - !ruby/object:Gem::Version
212
+ version: '0'
145
213
  - !ruby/object:Gem::Dependency
146
214
  name: vcr
147
215
  requirement: !ruby/object:Gem::Requirement
@@ -170,6 +238,20 @@ dependencies:
170
238
  - - ">="
171
239
  - !ruby/object:Gem::Version
172
240
  version: '0'
241
+ - !ruby/object:Gem::Dependency
242
+ name: yard
243
+ requirement: !ruby/object:Gem::Requirement
244
+ requirements:
245
+ - - ">="
246
+ - !ruby/object:Gem::Version
247
+ version: '0'
248
+ type: :development
249
+ prerelease: false
250
+ version_requirements: !ruby/object:Gem::Requirement
251
+ requirements:
252
+ - - ">="
253
+ - !ruby/object:Gem::Version
254
+ version: '0'
173
255
  description:
174
256
  email:
175
257
  - team@remove.bg
@@ -190,17 +272,24 @@ files:
190
272
  - Rakefile
191
273
  - bin/console
192
274
  - bin/setup
193
- - gemfiles/faraday_0_14.gemfile
194
275
  - gemfiles/faraday_0_15.gemfile
195
- - gemfiles/faraday_1rc1.gemfile
276
+ - gemfiles/faraday_0_16.gemfile
277
+ - gemfiles/faraday_0_17.gemfile
278
+ - gemfiles/faraday_1_x.gemfile
196
279
  - lib/remove_bg.rb
280
+ - lib/remove_bg/account_info.rb
197
281
  - lib/remove_bg/api.rb
198
282
  - lib/remove_bg/api_client.rb
283
+ - lib/remove_bg/base_request_options.rb
284
+ - lib/remove_bg/composite_result.rb
199
285
  - lib/remove_bg/configuration.rb
200
286
  - lib/remove_bg/error.rb
201
287
  - lib/remove_bg/http_connection.rb
288
+ - lib/remove_bg/image_composer.rb
289
+ - lib/remove_bg/rate_limit_info.rb
202
290
  - lib/remove_bg/request_options.rb
203
291
  - lib/remove_bg/result.rb
292
+ - lib/remove_bg/result_metadata.rb
204
293
  - lib/remove_bg/upload.rb
205
294
  - lib/remove_bg/url_validator.rb
206
295
  - lib/remove_bg/version.rb
@@ -227,7 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
316
  - !ruby/object:Gem::Version
228
317
  version: '0'
229
318
  requirements: []
230
- rubygems_version: 3.0.4
319
+ rubygems_version: 3.1.2
231
320
  signing_key:
232
321
  specification_version: 4
233
322
  summary: Remove image background - 100% automatically