rack_resize 0.1.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 +7 -0
- data/.gitignore +3 -0
- data/Gemfile +7 -0
- data/README.md +6 -0
- data/config.ru +10 -0
- data/lib/rack_resize/configuration.rb +47 -0
- data/lib/rack_resize/input_parsers/cloudflare.rb +4 -0
- data/lib/rack_resize/processing.rb +49 -0
- data/lib/rack_resize/processors/imlib2.rb +20 -0
- data/lib/rack_resize/processors/mini_magick.rb +53 -0
- data/lib/rack_resize/processors/sips.rb +37 -0
- data/lib/rack_resize/processors/vips.rb +27 -0
- data/lib/rack_resize/rack_app.rb +74 -0
- data/lib/rack_resize/rails_autoload.rb +10 -0
- data/lib/rack_resize.rb +27 -0
- data/rack_resize.gemspec +17 -0
- metadata +74 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 89ff24cb927e939e377fa9de0e4af8d736e026d2536a5721a94c8884c745de16
|
|
4
|
+
data.tar.gz: 13e4ca927f5ef1f058a528ded9158cd324e2eaf0e34c2797b21e1791028a31fc
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 58f951cd5354359a5a6261a739ded0e7136d346a91572c4bc8ba856530feb57644b1825959acc4ecdc79f91a15ab93e1e38c58d3578d82bd4c803a70ac015fdc
|
|
7
|
+
data.tar.gz: 462e57a07904d0e4c845b40611a2d7bc601e4c2fb207b8b7f2cccac9de934d6471bc222550e770ba19e0e58235d977d86b4ed8df0771761ac4b09a884495f106
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
data/config.ru
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
require_relative "lib/rack_resize"
|
|
2
|
+
require "rack/static"
|
|
3
|
+
|
|
4
|
+
use RackResize::RackApp, processor: :imlib2, assets_folder: "samples" # save_resized: false,
|
|
5
|
+
|
|
6
|
+
use Rack::Static, urls: [""], root: "samples", index: "index.html"
|
|
7
|
+
|
|
8
|
+
run lambda { |env|
|
|
9
|
+
[200, {'Content-Type' => 'text/html'}, ['Hello from Rack!']]
|
|
10
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
3
|
+
class RackResize::Configuration
|
|
4
|
+
PROCESSORS = %i[sips vips mini_magick imlib2].freeze
|
|
5
|
+
|
|
6
|
+
attr_reader :processor
|
|
7
|
+
attr_accessor :save_resized, :default_quality, :cache_folder, :assets_folder
|
|
8
|
+
|
|
9
|
+
alias_method :save_resized?, :save_resized
|
|
10
|
+
|
|
11
|
+
def initialize(options = {})
|
|
12
|
+
@processor = options[:processor] || RUBY_PLATFORM.include?('darwin') ? :sips : :mini_magick
|
|
13
|
+
@save_resized = options.key?(:save_resized) ? options[:save_resized] : true
|
|
14
|
+
@default_quality = options[:default_quality] || 95
|
|
15
|
+
@cache_folder = options[:cache_folder]
|
|
16
|
+
@assets_folder = options[:assets_folder] ? Pathname.new(options[:assets_folder]) : nil
|
|
17
|
+
|
|
18
|
+
if defined?(Rails)
|
|
19
|
+
@cache_folder ||= Rails.root.join('tmp', 'rack_resize_cache')
|
|
20
|
+
@assets_folder ||= Rails.root.join('app', 'assets', 'images')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if options[:processor]
|
|
24
|
+
self.processor = options[:processor]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def processor=(value)
|
|
29
|
+
value = value.to_sym
|
|
30
|
+
unless PROCESSORS.include?(value)
|
|
31
|
+
raise ArgumentError, "Unknown processor #{value.inspect}. Must be one of: #{PROCESSORS.join(', ')}"
|
|
32
|
+
end
|
|
33
|
+
@processor = value
|
|
34
|
+
@processor_instance = nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def processor_instance
|
|
38
|
+
@processor_instance ||= case @processor
|
|
39
|
+
when :mini_magick then RackResize::MiniMagick.new
|
|
40
|
+
when :vips then RackResize::Processors::Vips.new
|
|
41
|
+
when :sips then RackResize::Processors::Sips.new
|
|
42
|
+
when :imlib2 then RackResize::Processors::Imlib2.new
|
|
43
|
+
else
|
|
44
|
+
raise "RackResize - Unknow image processor #{@processor.inspect}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
class RackResize::Processing
|
|
2
|
+
attr_reader :config
|
|
3
|
+
|
|
4
|
+
def initialize(config:)
|
|
5
|
+
@config = config
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def process!(source_file:, req_params:)
|
|
9
|
+
if config.save_resized?
|
|
10
|
+
tmp_file_name = config.cache_folder.join(Digest::MD5.hexdigest(source_file.to_s) + File.extname(source_file))
|
|
11
|
+
FileUtils.mkdir_p(tmp_file_name.dirname)
|
|
12
|
+
|
|
13
|
+
unless tmp_file_name.exist?
|
|
14
|
+
process_file(req_params:, source_file:, target_file: tmp_file_name.to_s)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
logger.info("Serving cached file #{tmp_file_name}")
|
|
18
|
+
return StringIO.new(File.open(tmp_file_name.to_s, "rb", &:read))
|
|
19
|
+
else
|
|
20
|
+
file_content = process_file(req_params:, source_file:, target_file: nil)
|
|
21
|
+
return StringIO.new(file_content)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def process_file(source_file:, req_params:, target_file: nil)
|
|
26
|
+
dpr = req_params[:dpr]&.to_f || 1.0
|
|
27
|
+
target_width = (req_params[:w]&.to_i || req_params[:width]&.to_i)&.*(dpr)
|
|
28
|
+
target_height = (req_params[:h]&.to_i || req_params[:height]&.to_i)&.*(dpr)
|
|
29
|
+
|
|
30
|
+
start_time = Time.now
|
|
31
|
+
begin
|
|
32
|
+
return config.processor_instance.resize(source_file:, target_file:, target_width:, target_height:)
|
|
33
|
+
ensure
|
|
34
|
+
processing_time = (Time.now.to_f - start_time.to_f).round(3)
|
|
35
|
+
logger.info("RESIZE IMAGE #{config.processor} #{source_file} - #{req_params} - #{processing_time}s")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def logger
|
|
40
|
+
@logger ||= begin
|
|
41
|
+
if defined?(Rails) && Rails.logger
|
|
42
|
+
Rails.logger
|
|
43
|
+
else
|
|
44
|
+
require 'logger'
|
|
45
|
+
Logger.new(STDOUT)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require "rszr"
|
|
3
|
+
rescue LoadError
|
|
4
|
+
raise LoadError, "RackResize::Processors::Imlib2 requires the rszr gem. Please add `gem \"rszr\"` to your Gemfile."
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class RackResize::Processors::Imlib2
|
|
8
|
+
|
|
9
|
+
def resize(source_file:, target_file:, target_width:, target_height:)
|
|
10
|
+
image = Rszr::Image.load(source_file)
|
|
11
|
+
image.resize!(target_width || :auto, target_height || :auto) if target_width || target_height
|
|
12
|
+
|
|
13
|
+
if target_file
|
|
14
|
+
image.call(destination: target_file)
|
|
15
|
+
image.save(target_file)
|
|
16
|
+
else
|
|
17
|
+
image.save_data(format: source_file.to_s =~ /\.png$/ ? :png : :jpeg)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require "image_processing"
|
|
3
|
+
rescue LoadError
|
|
4
|
+
raise LoadError, "RackResize::Processors::MiniMagick requires the image_processing gem. Please add `gem \"image_processing\"` to your Gemfile."
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# require 'mini_magick'
|
|
8
|
+
# MiniMagick.logger.level = :debug
|
|
9
|
+
|
|
10
|
+
class RackResize::Processors::MiniMagick
|
|
11
|
+
|
|
12
|
+
def resize(source_file:, target_width:, target_height:, target_file: nil)
|
|
13
|
+
image = ImageProcessing::MiniMagick.source(source_file)
|
|
14
|
+
image = image.resize_to_limit(target_width, target_height) if target_width || target_height
|
|
15
|
+
image = image.saver(quality: RackResize.config.default_quality)
|
|
16
|
+
|
|
17
|
+
if target_file
|
|
18
|
+
image.call(destination: target_file)
|
|
19
|
+
else
|
|
20
|
+
begin
|
|
21
|
+
tmp_file = image.call
|
|
22
|
+
return tmp_file.read
|
|
23
|
+
ensure
|
|
24
|
+
tmp_file.unlink
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def resize_mm(source_file:, target_width:, target_height:, target_file: nil)
|
|
30
|
+
image = MiniMagick::Image.open(source_file)
|
|
31
|
+
image.combine_options do |img|
|
|
32
|
+
img.resize("#{target_width}x#{target_height}>") if target_width || target_height
|
|
33
|
+
img.quality(RackResize.config.default_quality)
|
|
34
|
+
|
|
35
|
+
if target_file
|
|
36
|
+
img.write(target_file)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
unless target_file
|
|
41
|
+
return File.open(image.path, 'rb', &:read)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
ensure
|
|
45
|
+
image&.destroy!
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# magick /Users/pavel/Work/resume-io/app/assets/images/templates/vancouver.jpg -auto-orient -resize 426.0x> -quality 95 /Users/pavel/Work/resume-io/tmp/cdn_cgi_cache/60f2727cce350874040b321219f05766.jpg
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# magick mogrify -resize 426.0x> /var/folders/n9/b__lxh7j1_xcwg4k_8j2_39m0000gp/T/mini_magick20260709-58478-qowydk.jpg
|
|
53
|
+
# magick mogrify -quality 95 /var/folders/n9/b__lxh7j1_xcwg4k_8j2_39m0000gp/T/mini_magick20260709-58478-qowydk.jpg
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require "shellwords"
|
|
2
|
+
|
|
3
|
+
class RackResize::Processors::Sips
|
|
4
|
+
|
|
5
|
+
def resize(source_file:, target_width:, target_height:, target_file: nil)
|
|
6
|
+
# args = ["sips", "--deleteColorManagementProperties", "--optimizeColorForSharing"]
|
|
7
|
+
args = ["sips", "--deleteColorManagementProperties", "--debug"]
|
|
8
|
+
args += ["-s formatOptions", RackResize.config.default_quality]
|
|
9
|
+
args << "--resampleWidth" << target_width.to_i if target_width
|
|
10
|
+
args << "--resampleHeight" << target_height.to_i if target_height
|
|
11
|
+
|
|
12
|
+
if target_file
|
|
13
|
+
args << "-o" << Shellwords.escape(target_file)
|
|
14
|
+
else
|
|
15
|
+
tmp_file = Tempfile.new(["result", File.extname(source_file)])
|
|
16
|
+
args << "-o" << tmp_file.path
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
args << Shellwords.escape(source_file)
|
|
20
|
+
|
|
21
|
+
pp [:args, args, args.join(" ")]
|
|
22
|
+
|
|
23
|
+
result = `#{args.join(" ")}`
|
|
24
|
+
|
|
25
|
+
puts "sips command result: #{result}"
|
|
26
|
+
|
|
27
|
+
unless target_file
|
|
28
|
+
begin
|
|
29
|
+
return File.open(tmp_file.path, 'rb', &:read)
|
|
30
|
+
ensure
|
|
31
|
+
tmp_file.unlink
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require "image_processing"
|
|
3
|
+
rescue LoadError
|
|
4
|
+
raise LoadError, "RackResize::Processors::Vips requires the image_processing gem. Please add `gem \"image_processing\"` to your Gemfile."
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class RackResize::Processors::Vips
|
|
8
|
+
|
|
9
|
+
def resize(source_file:, target_file:, target_width:, target_height:)
|
|
10
|
+
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)
|
|
13
|
+
|
|
14
|
+
# image.call(destination: target_file)
|
|
15
|
+
|
|
16
|
+
if target_file
|
|
17
|
+
image.call(destination: target_file)
|
|
18
|
+
else
|
|
19
|
+
begin
|
|
20
|
+
tmp_file = image.call
|
|
21
|
+
return tmp_file.read
|
|
22
|
+
ensure
|
|
23
|
+
tmp_file.unlink
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack'
|
|
4
|
+
|
|
5
|
+
class RackResize::RackApp
|
|
6
|
+
|
|
7
|
+
attr_reader :config
|
|
8
|
+
|
|
9
|
+
def initialize(*args, **options)
|
|
10
|
+
if args.first
|
|
11
|
+
@app = args.first
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
@config = options == {} ? RackResize.config : RackResize::Configuration.new(options)
|
|
15
|
+
@processing = RackResize::Processing.new(config: @config)
|
|
16
|
+
@path_prefix = options[:path_prefix] || "/cdn-cgi/image"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call(env)
|
|
20
|
+
# process string like this
|
|
21
|
+
# /cdn-cgi/image/width=426,format=auto/assets/templates/vancouver-27c47f55.jpg
|
|
22
|
+
|
|
23
|
+
request = Rack::Request.new(env)
|
|
24
|
+
fullpath = request.path_info
|
|
25
|
+
|
|
26
|
+
unless fullpath.start_with?(@path_prefix)
|
|
27
|
+
return @app.call(env)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
fullpath = fullpath.delete_prefix("/cdn-cgi").delete_prefix("/image").delete_prefix("/")
|
|
31
|
+
file_path_match = fullpath.match(%r{(?<params>[^\/]+)(?<file>\/.+?)(-[\da-f]{8})?(?<ext>\.\w{2,})$})
|
|
32
|
+
|
|
33
|
+
return error_resp("can't parse file path") unless file_path_match
|
|
34
|
+
|
|
35
|
+
req_params = file_path_match[:params].split(",").map {|s| s.split("=") }.to_h.transform_keys(&:to_sym)
|
|
36
|
+
asset_path = "#{file_path_match[:file]}#{file_path_match[:ext]}"
|
|
37
|
+
|
|
38
|
+
if defined?(Rails)
|
|
39
|
+
asset_path = asset_path.delete_prefix("/assets/")
|
|
40
|
+
else
|
|
41
|
+
asset_path = asset_path.delete_prefix("/#{config.assets_folder}/")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
asset_file = config.assets_folder.join(asset_path.sub(%r{^/assets/}, ''))
|
|
45
|
+
|
|
46
|
+
return error_resp(".. is not allowed in image path") if asset_path.include?("..")
|
|
47
|
+
|
|
48
|
+
return error_resp("invalid file path") unless asset_file.to_s.start_with?(config.assets_folder.to_s)
|
|
49
|
+
return error_resp("file not exists on a server") unless asset_file.exist?
|
|
50
|
+
|
|
51
|
+
file_content = @processing.process!(source_file: asset_file, req_params:)
|
|
52
|
+
return send_file(asset_file:, file_content:)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def error_resp(message, http_code: 404)
|
|
56
|
+
[http_code, {}, [message]]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def send_file(asset_file:, file_content: nil)
|
|
60
|
+
content_type = Rack::Mime.mime_type(File.extname(asset_file), "application/octet-stream")
|
|
61
|
+
# file = file_path ? File.open(file_path, "rb") : StringIO.new(file_content)
|
|
62
|
+
|
|
63
|
+
[
|
|
64
|
+
200,
|
|
65
|
+
{
|
|
66
|
+
"content-type" => content_type,
|
|
67
|
+
"content-length" => file_content.size.to_s,
|
|
68
|
+
"content-disposition" => "inline",
|
|
69
|
+
"cache-control" => "max-age=86400" # 1 day
|
|
70
|
+
},
|
|
71
|
+
file_content
|
|
72
|
+
]
|
|
73
|
+
end
|
|
74
|
+
end
|
data/lib/rack_resize.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module RackResize
|
|
2
|
+
autoload :Configuration, "#{__dir__}/rack_resize/configuration"
|
|
3
|
+
autoload :RackApp, "#{__dir__}/rack_resize/rack_app"
|
|
4
|
+
autoload :Processing, "#{__dir__}/rack_resize/processing"
|
|
5
|
+
# autoload :ImageController, "#{__dir__}/rack_resize/image_controller"
|
|
6
|
+
|
|
7
|
+
module Processors
|
|
8
|
+
autoload :Sips, "#{__dir__}/rack_resize/processors/sips"
|
|
9
|
+
autoload :Vips, "#{__dir__}/rack_resize/processors/vips"
|
|
10
|
+
autoload :MiniMagic, "#{__dir__}/rack_resize/processors/mini_magic"
|
|
11
|
+
autoload :Imlib2, "#{__dir__}/rack_resize/processors/imlib2"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def configuration
|
|
16
|
+
@configuration ||= Configuration.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def config
|
|
20
|
+
configuration
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def configure
|
|
24
|
+
yield configuration
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/rack_resize.gemspec
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = "rack_resize"
|
|
3
|
+
s.version = "0.1.0"
|
|
4
|
+
s.author = ["Pavel Evstigneev"]
|
|
5
|
+
s.email = ["pavel.evst@gmail.com"]
|
|
6
|
+
s.homepage = "https://github.com/paxa/rack_resize"
|
|
7
|
+
s.summary = %q{Image resizing on a fly}
|
|
8
|
+
s.license = 'MIT'
|
|
9
|
+
s.required_ruby_version = ['>= 3.0']
|
|
10
|
+
|
|
11
|
+
s.files = `git ls-files`.split("\n")
|
|
12
|
+
s.test_files = []
|
|
13
|
+
|
|
14
|
+
s.require_paths = ["lib"]
|
|
15
|
+
|
|
16
|
+
s.add_runtime_dependency "rack", ["> 2.0", "< 4.0"]
|
|
17
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rack_resize
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Pavel Evstigneev
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-07-15 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rack
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '2.0'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '4.0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">"
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '2.0'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '4.0'
|
|
32
|
+
email:
|
|
33
|
+
- pavel.evst@gmail.com
|
|
34
|
+
executables: []
|
|
35
|
+
extensions: []
|
|
36
|
+
extra_rdoc_files: []
|
|
37
|
+
files:
|
|
38
|
+
- ".gitignore"
|
|
39
|
+
- Gemfile
|
|
40
|
+
- README.md
|
|
41
|
+
- config.ru
|
|
42
|
+
- lib/rack_resize.rb
|
|
43
|
+
- lib/rack_resize/configuration.rb
|
|
44
|
+
- lib/rack_resize/input_parsers/cloudflare.rb
|
|
45
|
+
- lib/rack_resize/processing.rb
|
|
46
|
+
- lib/rack_resize/processors/imlib2.rb
|
|
47
|
+
- lib/rack_resize/processors/mini_magick.rb
|
|
48
|
+
- lib/rack_resize/processors/sips.rb
|
|
49
|
+
- lib/rack_resize/processors/vips.rb
|
|
50
|
+
- lib/rack_resize/rack_app.rb
|
|
51
|
+
- lib/rack_resize/rails_autoload.rb
|
|
52
|
+
- rack_resize.gemspec
|
|
53
|
+
homepage: https://github.com/paxa/rack_resize
|
|
54
|
+
licenses:
|
|
55
|
+
- MIT
|
|
56
|
+
metadata: {}
|
|
57
|
+
rdoc_options: []
|
|
58
|
+
require_paths:
|
|
59
|
+
- lib
|
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
61
|
+
requirements:
|
|
62
|
+
- - ">="
|
|
63
|
+
- !ruby/object:Gem::Version
|
|
64
|
+
version: '3.0'
|
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - ">="
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '0'
|
|
70
|
+
requirements: []
|
|
71
|
+
rubygems_version: 3.6.5
|
|
72
|
+
specification_version: 4
|
|
73
|
+
summary: Image resizing on a fly
|
|
74
|
+
test_files: []
|