rack_resize 0.1.3 → 0.1.6

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.
@@ -1,20 +1,32 @@
1
1
  require "open3"
2
+ require "tempfile"
2
3
 
3
4
  class RackResize::Processors::Sips
4
5
 
5
- def resize(source_file:, target_width:, target_height:, target_file: nil)
6
+ def resize(source_file:, target_width:, target_height:, target_file: nil, fit: nil, format: nil, quality: nil, bg_color: nil)
7
+ quality ||= RackResize.config.default_quality
8
+ cover = (fit == 'cover' || fit == 'crop') && target_width && target_height
9
+
6
10
  args = %w[sips --deleteColorManagementProperties]
7
- args += ["-s", "formatOptions", RackResize.config.default_quality.to_s]
11
+ args += ["-s", "format", sips_format(format)] if format
12
+ args += ["-s", "formatOptions", quality.to_s]
8
13
 
9
14
  if target_width && target_height
10
- info, status = Open3.capture2("sips", "-g", "pixelWidth", "-g", "pixelHeight", source_file.to_s)
11
- raise "sips failed to read dimensions for #{source_file}" unless status.success?
12
- src_w = info[/pixelWidth: (\d+)/, 1]&.to_f
13
- src_h = info[/pixelHeight: (\d+)/, 1]&.to_f
14
- if src_w && src_h && (target_width.to_f / src_w) <= (target_height.to_f / src_h)
15
- args += ["--resampleWidth", target_width.to_i.to_s]
16
- else
17
- args += ["--resampleHeight", target_height.to_i.to_s]
15
+ src_w, src_h = sips_dimensions(source_file)
16
+ if cover
17
+ if src_w.nil? || src_h.nil?
18
+ args += ["--resampleWidth", target_width.to_i.to_s]
19
+ elsif target_width.to_f / src_w >= target_height.to_f / src_h
20
+ args += ["--resampleWidth", target_width.to_i.to_s]
21
+ else
22
+ args += ["--resampleHeight", target_height.to_i.to_s]
23
+ end
24
+ elsif src_w && src_h
25
+ if (target_width.to_f / src_w) <= (target_height.to_f / src_h)
26
+ args += ["--resampleWidth", target_width.to_i.to_s]
27
+ else
28
+ args += ["--resampleHeight", target_height.to_i.to_s]
29
+ end
18
30
  end
19
31
  else
20
32
  args += ["--resampleWidth", target_width.to_i.to_s] if target_width
@@ -22,20 +34,40 @@ class RackResize::Processors::Sips
22
34
  end
23
35
 
24
36
  if target_file
25
- _, status = Open3.capture2(*args, "-o", target_file.to_s, source_file.to_s)
26
- raise "sips failed (exit #{status.exitstatus}) for #{source_file}" unless status.success?
27
- return nil
37
+ run_sips(*args, "-o", target_file.to_s, source_file.to_s)
38
+ sips_crop!(target_file.to_s, target_width, target_height) if cover
39
+ nil
40
+ else
41
+ tmp = Tempfile.new(["result", File.extname(source_file)])
42
+ begin
43
+ run_sips(*args, "-o", tmp.path, source_file.to_s)
44
+ sips_crop!(tmp.path, target_width, target_height) if cover
45
+ File.binread(tmp.path)
46
+ ensure
47
+ tmp.close
48
+ tmp.unlink
49
+ end
28
50
  end
51
+ end
29
52
 
30
- tmp = Tempfile.new(["result", File.extname(source_file)])
31
- tmp_path = tmp.path || raise("tempfile has no path")
32
- begin
33
- _, status = Open3.capture2(*args, "-o", tmp_path, source_file.to_s)
34
- raise "sips failed (exit #{status.exitstatus}) for #{source_file}" unless status.success?
35
- File.binread(tmp_path)
36
- ensure
37
- tmp.close
38
- tmp.unlink
39
- end
53
+ private
54
+
55
+ def sips_dimensions(source_file)
56
+ info, status = Open3.capture2("sips", "-g", "pixelWidth", "-g", "pixelHeight", source_file.to_s)
57
+ raise "sips failed to read dimensions for #{source_file}" unless status.success?
58
+ [info[/pixelWidth: (\d+)/, 1]&.to_f, info[/pixelHeight: (\d+)/, 1]&.to_f]
59
+ end
60
+
61
+ def run_sips(*args)
62
+ _, status = Open3.capture2(*args)
63
+ raise "sips failed (exit #{status.exitstatus}): #{args.join(' ')}" unless status.success?
64
+ end
65
+
66
+ def sips_crop!(path, width, height)
67
+ run_sips("sips", "--cropToHeightWidth", height.to_i.to_s, width.to_i.to_s, path)
68
+ end
69
+
70
+ def sips_format(format)
71
+ format.to_s.downcase == 'jpg' ? 'jpeg' : format.to_s.downcase
40
72
  end
41
73
  end
@@ -6,13 +6,28 @@ end
6
6
 
7
7
  class RackResize::Processors::Vips
8
8
 
9
- def resize(source_file:, target_file:, target_width:, target_height:)
9
+ def resize(source_file:, target_file:, target_width:, target_height:, fit: nil, format: nil, quality: nil, bg_color: nil)
10
+ quality ||= RackResize.config.default_quality
11
+ cover = (fit == 'cover' || fit == 'crop') && target_width && target_height
12
+
10
13
  image = ImageProcessing::Vips.source(source_file)
11
- image = image.resize_to_limit(target_width, target_height) if target_width || target_height
12
- image = image.saver(quality: RackResize.config.default_quality)
14
+ image = image.convert(format) if format
15
+
16
+ if target_width || target_height
17
+ image = cover ? image.resize_to_fill(target_width, target_height)
18
+ : image.resize_to_limit(target_width, target_height)
19
+ end
20
+
21
+ if bg_color
22
+ r, g, b, _a = bg_color
23
+ image = image.flatten(background: [r, g, b])
24
+ end
25
+
26
+ image = image.saver(quality: quality)
13
27
 
14
28
  if target_file
15
29
  image.call(destination: target_file)
30
+ nil
16
31
  else
17
32
  begin
18
33
  tmp_file = image.call
@@ -18,8 +18,10 @@ class RackResize::RackApp
18
18
  request = Rack::Request.new(env)
19
19
  fullpath = request.path_info
20
20
 
21
- RackResize::InputParsers::Cloudflare.parse_input(fullpath, cf_path_prefix: @cf_path_prefix) =>
22
- {route_matched:, req_params:, asset_path:}
21
+ result = RackResize::InputParsers::Cloudflare.parse_input(fullpath, cf_path_prefix: @cf_path_prefix)
22
+ result = RackResize::InputParsers::QueryString.parse_input(fullpath, request.query_string) unless result[:route_matched]
23
+ result = RackResize::InputParsers::Imgproxy.parse_input(fullpath) unless result[:route_matched]
24
+ result => {route_matched:, req_params:, asset_path:}
23
25
 
24
26
  return @app.call(env) unless route_matched
25
27
  return error_resp("can't parse file path") unless asset_path
@@ -31,7 +33,7 @@ class RackResize::RackApp
31
33
  config.assets_folders.each do |prefix, folder|
32
34
  if asset_path.start_with?(prefix)
33
35
  asset_file = folder.join(asset_path.delete_prefix(prefix + (prefix.end_with?("/") ? "" : "/")))
34
- if asset_file.expand_path.to_s.start_with?(folder.to_s)
36
+ if asset_file.expand_path.to_s.start_with?(folder.expand_path.to_s)
35
37
  has_matched = true
36
38
  end
37
39
  break
@@ -47,20 +49,22 @@ class RackResize::RackApp
47
49
  return error_resp("invalid file path")
48
50
  end
49
51
  unless asset_file.exist?
50
- @processing.logger.info("RackResize::RackApp - File path fond #{asset_path} => #{asset_file}")
52
+ @processing.logger.info("RackResize::RackApp - File path not found #{asset_path} => #{asset_file}")
51
53
  return error_resp("file not exists on a server")
52
54
  end
53
55
 
54
56
  file_content = @processing.process!(source_file: asset_file, req_params:)
55
- return send_file(asset_file:, file_content:)
57
+ output_format = req_params[:format].then { |f| (f && f != 'auto') ? f : nil }
58
+ return send_file(asset_file:, file_content:, output_format:)
56
59
  end
57
60
 
58
61
  def error_resp(message, http_code: 404)
59
62
  [http_code, {}, [message]]
60
63
  end
61
64
 
62
- def send_file(asset_file:, file_content: nil)
63
- content_type = Rack::Mime.mime_type(File.extname(asset_file), "application/octet-stream")
65
+ def send_file(asset_file:, file_content: nil, output_format: nil)
66
+ ext = (output_format && output_format != 'auto') ? ".#{output_format}" : File.extname(asset_file)
67
+ content_type = Rack::Mime.mime_type(ext, "application/octet-stream")
64
68
 
65
69
  [
66
70
  200,
data/lib/rack_resize.rb CHANGED
@@ -2,17 +2,20 @@ module RackResize
2
2
  autoload :Configuration, "#{__dir__}/rack_resize/configuration"
3
3
  autoload :RackApp, "#{__dir__}/rack_resize/rack_app"
4
4
  autoload :Processing, "#{__dir__}/rack_resize/processing"
5
- # autoload :ImageController, "#{__dir__}/rack_resize/image_controller"
5
+ autoload :ColorUtils, "#{__dir__}/rack_resize/color_utils"
6
6
 
7
7
  module Processors
8
- autoload :Sips, "#{__dir__}/rack_resize/processors/sips"
9
- autoload :Vips, "#{__dir__}/rack_resize/processors/vips"
8
+ autoload :Sips, "#{__dir__}/rack_resize/processors/sips"
9
+ autoload :Vips, "#{__dir__}/rack_resize/processors/vips"
10
10
  autoload :MiniMagick, "#{__dir__}/rack_resize/processors/mini_magick"
11
- autoload :Imlib2, "#{__dir__}/rack_resize/processors/imlib2"
11
+ autoload :Imlib2, "#{__dir__}/rack_resize/processors/imlib2"
12
+ autoload :BunImage, "#{__dir__}/rack_resize/processors/bun_image"
12
13
  end
13
14
 
14
15
  module InputParsers
15
- autoload :Cloudflare, "#{__dir__}/rack_resize/input_parsers/cloudflare"
16
+ autoload :Cloudflare, "#{__dir__}/rack_resize/input_parsers/cloudflare"
17
+ autoload :QueryString, "#{__dir__}/rack_resize/input_parsers/query_string"
18
+ autoload :Imgproxy, "#{__dir__}/rack_resize/input_parsers/imgproxy"
16
19
  end
17
20
 
18
21
  class << self
data/rack_resize.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rack_resize"
3
- s.version = "0.1.3"
3
+ s.version = "0.1.6"
4
4
  s.author = ["Pavel Evstigneev"]
5
5
  s.email = ["pavel.evst@gmail.com"]
6
6
  s.homepage = "https://github.com/paxa/rack_resize"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack_resize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Evstigneev
@@ -41,11 +41,18 @@ files:
41
41
  - Gemfile
42
42
  - README.md
43
43
  - Rakefile
44
+ - benchmark/http_benchmark.rb
45
+ - benchmark/processor_benchmark.rb
44
46
  - config.ru
45
47
  - lib/rack_resize.rb
48
+ - lib/rack_resize/color_utils.rb
46
49
  - lib/rack_resize/configuration.rb
47
50
  - lib/rack_resize/input_parsers/cloudflare.rb
51
+ - lib/rack_resize/input_parsers/imgproxy.rb
52
+ - lib/rack_resize/input_parsers/query_string.rb
48
53
  - lib/rack_resize/processing.rb
54
+ - lib/rack_resize/processors/bun_image.js
55
+ - lib/rack_resize/processors/bun_image.rb
49
56
  - lib/rack_resize/processors/imlib2.rb
50
57
  - lib/rack_resize/processors/mini_magick.rb
51
58
  - lib/rack_resize/processors/sips.rb
@@ -71,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
78
  - !ruby/object:Gem::Version
72
79
  version: '0'
73
80
  requirements: []
74
- rubygems_version: 4.0.10
81
+ rubygems_version: 4.0.16
75
82
  specification_version: 4
76
83
  summary: Image resizing on a fly
77
84
  test_files: []