remove_bg 1.3.0 → 1.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85d740935b627c71987091c6b9476d49a17fa2a63cea2844f53a3bb0e7d9621b
4
- data.tar.gz: d9ff54349e69003ecea536d4b669ca4479d4a7cd1c0e2a8577e0b8467cbbcdb2
3
+ metadata.gz: c58154a3e3edc19ed8562c66f603a4965512814787e6b3d62907f7c931fec111
4
+ data.tar.gz: b2c773dc3f11983a95b510b7a65ce8060d318d37b30e0fec4aeaf73552cbdfa0
5
5
  SHA512:
6
- metadata.gz: 18b21fbf48e49447b44eb950b5846e3de1e3ebf52c49aae4ae207870a8367aad61d7eded97709e371c06538830c9a73e86f4af7d7106c62c66d938a86a525bae
7
- data.tar.gz: '079fb2498670102258b88d47d93a665ee47b318b8b307316b8c093f3e47572ec975c814c9d4f237d48dc38e5a196ade29eaa4452db976ed7a238487a3ec6878c'
6
+ metadata.gz: f3ec05a4b3e9f55676d1dd50da5e5f148a532e15c7fce09aa65429df243769e9de47271c31567f1e90f4b16c20bbc653618dbd2b9dffe7bd6b8500dc421eb1ef
7
+ data.tar.gz: 3c2fbb46e300903114df2b0fcca3b6fecdeb0dd3844aace5d60de88cf88794167531456455c52b935f9626f21b1e8cf2476cf4454f95bf6d56c702cc0f49fdd7
@@ -13,6 +13,12 @@ base_job: &base_job
13
13
  name: install dependencies
14
14
  command: bundle install --jobs=4 --retry=3 --path vendor/bundle
15
15
 
16
+ - run:
17
+ name: install image processsing dependencies
18
+ command: |
19
+ sudo apt-get update
20
+ sudo apt install imagemagick libvips
21
+
16
22
  - save_cache:
17
23
  paths:
18
24
  - ./vendor/bundle
data/Appraisals CHANGED
@@ -3,9 +3,12 @@ appraise "faraday-0-15" do
3
3
  gem "faraday", "~> 0.15.0"
4
4
  end
5
5
 
6
- # Latest in Faraday 0.x series
7
- appraise "faraday-0-x" do
8
- gem "faraday", ">= 0.15", "<= 1.0"
6
+ appraise "faraday-0-16" do
7
+ gem "faraday", "~> 0.16.0"
8
+ end
9
+
10
+ appraise "faraday-0-17" do
11
+ gem "faraday", "~> 0.17.0"
9
12
  end
10
13
 
11
14
  # Latest in Faraday 1.x series
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.4.0
4
+
5
+ - Adds support for images up to 25 megapixels ([documentation](https://github.com/remove-bg/ruby#processing-images-over-10-megapixels))
6
+ - Requires an image processing library to be configured (ImageMagick, GraphicsMagick or libvips)
7
+
3
8
  ## 1.3.0
4
9
 
5
10
  - Add `RemoveBg.account_info` which includes available credits - via [#9](https://github.com/remove-bg/ruby/pull/9)
@@ -1,14 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- remove_bg (1.3.0)
4
+ remove_bg (1.4.0)
5
5
  faraday (>= 0.15, < 2)
6
+ image_processing (>= 1.9, < 2)
7
+ rubyzip (>= 2.0, < 3)
6
8
 
7
9
  GEM
8
10
  remote: https://rubygems.org/
9
11
  specs:
10
- addressable (2.6.0)
11
- public_suffix (>= 2.0.2, < 4.0)
12
+ addressable (2.7.0)
13
+ public_suffix (>= 2.0.2, < 5.0)
12
14
  appraisal (2.2.0)
13
15
  bundler
14
16
  rake
@@ -17,41 +19,49 @@ GEM
17
19
  crack (0.4.3)
18
20
  safe_yaml (~> 1.0.0)
19
21
  diff-lcs (1.3)
20
- dotenv (2.7.1)
22
+ dotenv (2.7.5)
21
23
  faraday (1.0.1)
22
24
  multipart-post (>= 1.2, < 3)
23
- hashdiff (0.3.8)
24
- method_source (0.9.2)
25
+ ffi (1.12.2)
26
+ hashdiff (1.0.1)
27
+ image_processing (1.11.0)
28
+ mini_magick (>= 4.9.5, < 5)
29
+ ruby-vips (>= 2.0.17, < 3)
30
+ method_source (1.0.0)
31
+ mini_magick (4.10.1)
25
32
  multipart-post (2.1.1)
26
- pry (0.12.2)
27
- coderay (~> 1.1.0)
28
- method_source (~> 0.9.0)
29
- public_suffix (3.0.3)
30
- rake (12.3.2)
31
- rspec (3.8.0)
32
- rspec-core (~> 3.8.0)
33
- rspec-expectations (~> 3.8.0)
34
- rspec-mocks (~> 3.8.0)
35
- rspec-core (3.8.0)
36
- rspec-support (~> 3.8.0)
37
- rspec-expectations (3.8.2)
33
+ pry (0.13.1)
34
+ coderay (~> 1.1)
35
+ method_source (~> 1.0)
36
+ public_suffix (4.0.4)
37
+ rake (13.0.1)
38
+ rspec (3.9.0)
39
+ rspec-core (~> 3.9.0)
40
+ rspec-expectations (~> 3.9.0)
41
+ rspec-mocks (~> 3.9.0)
42
+ rspec-core (3.9.2)
43
+ rspec-support (~> 3.9.3)
44
+ rspec-expectations (3.9.1)
38
45
  diff-lcs (>= 1.2.0, < 2.0)
39
- rspec-support (~> 3.8.0)
40
- rspec-mocks (3.8.0)
46
+ rspec-support (~> 3.9.0)
47
+ rspec-mocks (3.9.1)
41
48
  diff-lcs (>= 1.2.0, < 2.0)
42
- rspec-support (~> 3.8.0)
43
- rspec-support (3.8.0)
49
+ rspec-support (~> 3.9.0)
50
+ rspec-support (3.9.3)
44
51
  rspec-with_params (0.2.0)
45
52
  rspec (~> 3.0)
46
53
  rspec_junit_formatter (0.4.1)
47
54
  rspec-core (>= 2, < 4, != 2.12.0)
55
+ ruby-vips (2.0.17)
56
+ ffi (~> 1.9)
57
+ rubyzip (2.3.0)
48
58
  safe_yaml (1.0.5)
49
- thor (0.20.3)
50
- vcr (4.0.0)
51
- webmock (3.5.1)
59
+ thor (1.0.1)
60
+ vcr (5.1.0)
61
+ webmock (3.8.3)
52
62
  addressable (>= 2.3.6)
53
63
  crack (>= 0.3.2)
54
- hashdiff
64
+ hashdiff (>= 0.4.0, < 2.0.0)
55
65
 
56
66
  PLATFORMS
57
67
  ruby
@@ -61,7 +71,7 @@ DEPENDENCIES
61
71
  bundler (~> 1.17)
62
72
  dotenv
63
73
  pry
64
- rake (~> 12.0)
74
+ rake
65
75
  remove_bg!
66
76
  rspec (~> 3.8)
67
77
  rspec-with_params
data/README.md CHANGED
@@ -69,6 +69,39 @@ result.save("processed/image.png")
69
69
  result.save("image.png", overwrite: true) # Careful!
70
70
  ```
71
71
 
72
+ #### Processing images over 10 megapixels
73
+
74
+ The Remove.bg API provides a [ZIP format](https://www.remove.bg/api#zip-format)
75
+ which includes all the information required to efficiently composite a large
76
+ image with transparency.
77
+
78
+ The gem can handle this composition for you, but you'll need
79
+ [ImageMagick]/[GraphicsMagick] or [libvips] available on your computer.
80
+
81
+ [ImageMagick]: https://www.imagemagick.org
82
+ [GraphicsMagick]: http://www.graphicsmagick.org
83
+ [libvips]: http://libvips.github.io/libvips/
84
+
85
+ Please configure the image processing library you'd like to use:
86
+
87
+ ```ruby
88
+ RemoveBg.configure do |config|
89
+ config.image_processor = :minimagick # For ImageMagick or GraphicsMagick
90
+ # or
91
+ config.image_processor = :vips
92
+ end
93
+ ```
94
+
95
+ Then process images specifying the `zip` format:
96
+
97
+ ```ruby
98
+ result = RemoveBg.from_file("large-image.jpg", format: "zip")
99
+
100
+ result.save("result-with-transparency.png")
101
+ # or
102
+ result.save_zip("result.zip") # If you want to handle composition yourself
103
+ ```
104
+
72
105
  ### Fetching account information
73
106
 
74
107
  To display the [account information][account-info] for the currently configured
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "faraday", ">= 0.15", "<= 1.0"
5
+ gem "faraday", "~> 0.16.0"
6
6
 
7
7
  gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "faraday", "~> 0.17.0"
6
+
7
+ gemspec path: "../"
@@ -1,6 +1,9 @@
1
1
  require "json"
2
+ require "tempfile"
3
+
2
4
  require_relative "account_info"
3
5
  require_relative "api"
6
+ require_relative "composite_result"
4
7
  require_relative "error"
5
8
  require_relative "http_connection"
6
9
  require_relative "result"
@@ -35,14 +38,35 @@ module RemoveBg
35
38
  attr_reader :connection
36
39
 
37
40
  def request_remove_bg(data, api_key)
41
+ download = Tempfile.new("remove-bg-download")
42
+ streaming = false
43
+
38
44
  response = connection.post(V1_REMOVE_BG, data) do |req|
39
45
  req.headers[HEADER_API_KEY] = api_key
46
+
47
+ # Faraday v0.16 & v1.0+ support streaming, v0.17 did not (rollback release)
48
+ if req.options.respond_to?(:on_data)
49
+ streaming = true
50
+ req.options.on_data = Proc.new do |chunk, _|
51
+ download.write(chunk)
52
+ end
53
+ end
54
+ end
55
+
56
+ # Faraday v0.15 / v0.17
57
+ if !streaming
58
+ download.write(response.body)
40
59
  end
41
60
 
61
+ download.rewind
62
+
42
63
  if response.status == 200
43
- parse_image_result(response)
64
+ parse_image_result(headers: response.headers, download: download)
44
65
  else
45
- handle_http_error(response)
66
+ response_body = download.read
67
+ download.close
68
+ download.unlink
69
+ handle_http_error(response: response, body: response_body)
46
70
  end
47
71
  end
48
72
 
@@ -54,33 +78,41 @@ module RemoveBg
54
78
  if response.status == 200
55
79
  parse_account_result(response)
56
80
  else
57
- handle_http_error(response)
81
+ handle_http_error(response: response, body: response.body)
58
82
  end
59
83
  end
60
84
 
61
- def handle_http_error(response)
85
+ def handle_http_error(response:, body:)
62
86
  case response.status
63
87
  when 400..499
64
- error_message = parse_error_message(response)
65
- raise RemoveBg::ClientHttpError.new(error_message, response)
88
+ error_message = parse_error_message(body)
89
+ raise RemoveBg::ClientHttpError.new(error_message, response, body)
66
90
  when 500..599
67
- error_message = parse_error_message(response)
68
- raise RemoveBg::ServerHttpError.new(error_message, response)
91
+ error_message = parse_error_message(body)
92
+ raise RemoveBg::ServerHttpError.new(error_message, response, body)
69
93
  else
70
- raise RemoveBg::HttpError.new("An unknown error occurred", response)
94
+ raise RemoveBg::HttpError.new("An unknown error occurred", response, body)
71
95
  end
72
96
  end
73
97
 
74
- def parse_image_result(response)
75
- RemoveBg::Result.new(
76
- data: response.body,
77
- type: response.headers[HEADER_TYPE],
78
- width: response.headers[HEADER_WIDTH]&.to_i,
79
- height: response.headers[HEADER_HEIGHT]&.to_i,
80
- credits_charged: response.headers[HEADER_CREDITS_CHARGED]&.to_f,
98
+ def parse_image_result(headers:, download:)
99
+ result_for_content_type(headers["Content-Type"]).new(
100
+ download: download,
101
+ type: headers[HEADER_TYPE],
102
+ width: headers[HEADER_WIDTH]&.to_i,
103
+ height: headers[HEADER_HEIGHT]&.to_i,
104
+ credits_charged: headers[HEADER_CREDITS_CHARGED]&.to_f,
81
105
  )
82
106
  end
83
107
 
108
+ def result_for_content_type(content_type)
109
+ if content_type&.include?("application/zip")
110
+ CompositeResult
111
+ else
112
+ Result
113
+ end
114
+ end
115
+
84
116
  def parse_account_result(response)
85
117
  attributes = JSON.parse(response.body, symbolize_names: true)
86
118
  .fetch(:data)
@@ -89,12 +121,12 @@ module RemoveBg
89
121
  RemoveBg::AccountInfo.new(attributes)
90
122
  end
91
123
 
92
- def parse_error_message(response)
93
- parse_errors(response).first["title"]
124
+ def parse_error_message(response_body)
125
+ parse_errors(response_body).first["title"]
94
126
  end
95
127
 
96
- def parse_errors(response)
97
- JSON.parse(response.body)["errors"] || []
128
+ def parse_errors(response_body)
129
+ JSON.parse(response_body)["errors"] || []
98
130
  rescue JSON::ParserError
99
131
  [{ "title" => "Unable to parse response" }]
100
132
  end
@@ -0,0 +1,52 @@
1
+ require_relative "result"
2
+
3
+ module RemoveBg
4
+ class CompositeResult < Result
5
+ def save_zip(file_path, overwrite: false)
6
+ if File.exist?(file_path) && !overwrite
7
+ raise FileOverwriteError.new(file_path)
8
+ end
9
+
10
+ FileUtils.cp(download, file_path)
11
+ end
12
+
13
+ private
14
+
15
+ def image_file
16
+ composite_file
17
+ end
18
+
19
+ def composite_file
20
+ @composite_file ||= begin
21
+ Tempfile.new(["composed", ".png"]).tap do |file|
22
+ compose_to_file(file)
23
+ end
24
+ end
25
+ end
26
+
27
+ def color_file
28
+ @color_file ||= Tempfile.new(["color", ".jpg"])
29
+ end
30
+
31
+ def alpha_file
32
+ @alpha_file ||= Tempfile.new(["alpha", ".png"])
33
+ end
34
+
35
+ def compose_to_file(destination)
36
+ extract_parts
37
+
38
+ ImageComposer.new.compose(
39
+ color_file: color_file,
40
+ alpha_file: alpha_file,
41
+ destination_path: destination.path
42
+ )
43
+ end
44
+
45
+ def extract_parts
46
+ Zip::File.open(download) do |zf|
47
+ zf.find_entry("color.jpg").extract(color_file.path) { true }
48
+ zf.find_entry("alpha.png").extract(alpha_file.path) { true }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,6 +1,6 @@
1
1
  module RemoveBg
2
2
  class Configuration
3
- attr_accessor :api_key
3
+ attr_accessor :api_key, :image_processor
4
4
 
5
5
  def self.configuration
6
6
  @configuration ||= Configuration.new
@@ -2,10 +2,11 @@ module RemoveBg
2
2
  class Error < StandardError; end
3
3
 
4
4
  class HttpError < Error
5
- attr_reader :http_response
5
+ attr_reader :http_response, :http_response_body
6
6
 
7
- def initialize(message, http_response)
7
+ def initialize(message, http_response, http_response_body)
8
8
  @http_response = http_response
9
+ @http_response_body = http_response_body
9
10
  super(message)
10
11
  end
11
12
  end
@@ -0,0 +1,42 @@
1
+ require_relative "error"
2
+
3
+ module RemoveBg
4
+ class ImageComposer
5
+ def compose(color_file:, alpha_file:, destination_path:)
6
+ image = case configured_image_processor
7
+ when :vips
8
+ then vips_compose(color_file: color_file, alpha_file: alpha_file)
9
+ when :minimagick
10
+ then minimagick_compose(color_file: color_file, alpha_file: alpha_file)
11
+ when nil
12
+ raise RemoveBg::Error, "Please configure an image processor to use image composition"
13
+ else
14
+ raise RemoveBg::Error, "Unsupported image processor: #{configured_image_processor.inspect}"
15
+ end
16
+
17
+ image.call(destination: destination_path)
18
+ end
19
+
20
+ private
21
+
22
+ def configured_image_processor
23
+ RemoveBg::Configuration.configuration.image_processor
24
+ end
25
+
26
+ def minimagick_compose(color_file:, alpha_file:)
27
+ require "image_processing/mini_magick"
28
+
29
+ ImageProcessing::MiniMagick
30
+ .source(color_file)
31
+ .composite(alpha_file, mode: "copy-opacity")
32
+ end
33
+
34
+ def vips_compose(color_file:, alpha_file:)
35
+ require "image_processing/vips"
36
+
37
+ ImageProcessing::Vips
38
+ .source(color_file)
39
+ .custom { |image| image.bandjoin(Vips::Image.new_from_file(alpha_file.path)) }
40
+ end
41
+ end
42
+ end
@@ -1,11 +1,14 @@
1
+ require "fileutils"
2
+ require "zip"
1
3
  require_relative "error"
4
+ require_relative "image_composer"
2
5
 
3
6
  module RemoveBg
4
7
  class Result
5
- attr_reader :data, :type, :width, :height, :credits_charged
8
+ attr_reader :type, :width, :height, :credits_charged
6
9
 
7
- def initialize(data:, type:, width:, height:, credits_charged:)
8
- @data = data
10
+ def initialize(download:, type:, width:, height:, credits_charged:)
11
+ @download = download
9
12
  @type = type
10
13
  @width = width
11
14
  @height = height
@@ -17,7 +20,20 @@ module RemoveBg
17
20
  raise FileOverwriteError.new(file_path)
18
21
  end
19
22
 
20
- File.write(file_path, data)
23
+ FileUtils.cp(image_file, file_path)
24
+ end
25
+
26
+ def data
27
+ image_file.rewind
28
+ image_file.read
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :download
34
+
35
+ def image_file
36
+ download
21
37
  end
22
38
  end
23
39
  end
@@ -1,3 +1,3 @@
1
1
  module RemoveBg
2
- VERSION = "1.3.0"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -24,12 +24,14 @@ Gem::Specification.new do |spec|
24
24
  spec.require_paths = ["lib"]
25
25
 
26
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
30
  spec.add_development_dependency "appraisal"
29
31
  spec.add_development_dependency "bundler", "~> 1.17"
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"
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.3.0
4
+ version: 1.4.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: 2020-05-07 00:00:00.000000000 Z
11
+ date: 2020-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -30,6 +30,46 @@ dependencies:
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: image_processing
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '1.9'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '2'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
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'
33
73
  - !ruby/object:Gem::Dependency
34
74
  name: appraisal
35
75
  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
@@ -191,16 +231,19 @@ files:
191
231
  - bin/console
192
232
  - bin/setup
193
233
  - gemfiles/faraday_0_15.gemfile
194
- - gemfiles/faraday_0_x.gemfile
234
+ - gemfiles/faraday_0_16.gemfile
235
+ - gemfiles/faraday_0_17.gemfile
195
236
  - gemfiles/faraday_1_x.gemfile
196
237
  - lib/remove_bg.rb
197
238
  - lib/remove_bg/account_info.rb
198
239
  - lib/remove_bg/api.rb
199
240
  - lib/remove_bg/api_client.rb
200
241
  - lib/remove_bg/base_request_options.rb
242
+ - lib/remove_bg/composite_result.rb
201
243
  - lib/remove_bg/configuration.rb
202
244
  - lib/remove_bg/error.rb
203
245
  - lib/remove_bg/http_connection.rb
246
+ - lib/remove_bg/image_composer.rb
204
247
  - lib/remove_bg/request_options.rb
205
248
  - lib/remove_bg/result.rb
206
249
  - lib/remove_bg/upload.rb