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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +17 -6
- data/.gitignore +2 -0
- data/Appraisals +12 -6
- data/CHANGELOG.md +26 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +70 -36
- data/README.md +112 -11
- data/gemfiles/faraday_0_15.gemfile +5 -1
- data/gemfiles/faraday_0_16.gemfile +11 -0
- data/gemfiles/faraday_0_17.gemfile +11 -0
- data/gemfiles/faraday_1_x.gemfile +11 -0
- data/lib/remove_bg.rb +22 -0
- data/lib/remove_bg/account_info.rb +34 -0
- data/lib/remove_bg/api.rb +3 -9
- data/lib/remove_bg/api_client.rb +105 -17
- data/lib/remove_bg/base_request_options.rb +32 -0
- data/lib/remove_bg/composite_result.rb +65 -0
- data/lib/remove_bg/configuration.rb +14 -3
- data/lib/remove_bg/error.rb +19 -1
- data/lib/remove_bg/http_connection.rb +2 -0
- data/lib/remove_bg/image_composer.rb +60 -0
- data/lib/remove_bg/rate_limit_info.rb +34 -0
- data/lib/remove_bg/request_options.rb +25 -15
- data/lib/remove_bg/result.rb +42 -7
- data/lib/remove_bg/result_metadata.rb +14 -0
- data/lib/remove_bg/upload.rb +6 -2
- data/lib/remove_bg/version.rb +1 -1
- data/remove_bg.gemspec +9 -4
- metadata +106 -17
- data/gemfiles/faraday_0_14.gemfile +0 -7
- data/gemfiles/faraday_1rc1.gemfile +0 -7
@@ -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 "
|
1
|
+
require_relative "base_request_options"
|
2
2
|
|
3
3
|
module RemoveBg
|
4
|
-
|
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
|
-
|
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
|
-
|
24
|
-
|
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
|
-
|
30
|
-
|
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
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
48
|
+
def can_process_images?
|
49
|
+
RemoveBg::Configuration.configuration.can_process_images?
|
40
50
|
end
|
41
51
|
|
42
|
-
def
|
43
|
-
RemoveBg::Configuration.configuration.
|
52
|
+
def optimization_enabled?
|
53
|
+
RemoveBg::Configuration.configuration.auto_upgrade_png_to_zip
|
44
54
|
end
|
45
55
|
end
|
46
56
|
end
|
data/lib/remove_bg/result.rb
CHANGED
@@ -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
|
-
|
12
|
+
extend ::Forwardable
|
6
13
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
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
|
data/lib/remove_bg/upload.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "faraday
|
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
|
-
|
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
|
data/lib/remove_bg/version.rb
CHANGED
data/remove_bg.gemspec
CHANGED
@@ -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.
|
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 "
|
29
|
-
spec.add_development_dependency "
|
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"
|
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.
|
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:
|
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.
|
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.
|
29
|
+
version: '0.15'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '2'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
34
|
+
name: image_processing
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
40
|
-
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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/
|
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.
|
319
|
+
rubygems_version: 3.1.2
|
231
320
|
signing_key:
|
232
321
|
specification_version: 4
|
233
322
|
summary: Remove image background - 100% automatically
|