minimage 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ doc/
5
+ pkg/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in minimage.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Damian Caruso
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
File without changes
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new do |t|
6
+ t.libs = ["lib","test"]
7
+ t.verbose = true
8
+ t.test_files = FileList['test/**/test_*.rb']
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,39 @@
1
+ require 'minimage/processor/mini_magick'
2
+ require 'minimage/storage/file'
3
+ require 'nesty'
4
+
5
+ module Minimage
6
+ extend self
7
+
8
+ Error = Class.new(Nesty::NestedStandardError)
9
+
10
+ attr_accessor :storage, :processor
11
+
12
+ def storage
13
+ @storage ||= Minimage::Storage::File.new
14
+ end
15
+
16
+ def processor
17
+ @processor ||= Minimage::Processor::MiniMagick.public_method(:new)
18
+ end
19
+
20
+ def configure
21
+ yield self
22
+ end
23
+
24
+ def process(stream, format = nil, &block)
25
+ p = processor.call(stream, format)
26
+ block.call(p)
27
+ p.stream
28
+ end
29
+
30
+ def store(path)
31
+ storage.store!(path)
32
+ rescue => e
33
+ raise Error.new
34
+ end
35
+
36
+ def fetch(uid)
37
+ storage.fetch!(uid)
38
+ end
39
+ end
@@ -0,0 +1,32 @@
1
+ module Minimage
2
+ module Processor
3
+ class Base
4
+ attr_reader :stream
5
+
6
+ def initialize(stream, format = nil)
7
+ @format = format
8
+ @stream = stream
9
+ end
10
+
11
+ def format(format)
12
+ raise NotImplementedError.new
13
+ end
14
+
15
+ def limit(width, height = nil, gravity = nil)
16
+ raise NotImplementedError.new
17
+ end
18
+
19
+ def fill(width, height = nil, gravity = nil)
20
+ raise NotImplementedError.new
21
+ end
22
+
23
+ def fit(width, height = nil, gravity = nil)
24
+ raise NotImplementedError.new
25
+ end
26
+
27
+ def scale(width, height = nil, gravity = nil)
28
+ raise NotImplementedError.new
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,88 @@
1
+ require 'minimage/processor'
2
+ require 'mini_magick'
3
+
4
+ module Minimage
5
+ module Processor
6
+ class MiniMagick < Base
7
+
8
+ def format(format)
9
+ manipulate! do |img|
10
+ img.format format.to_s.downcase
11
+ img
12
+ end
13
+ end
14
+
15
+ def limit(width, height = nil, gravity = nil)
16
+ manipulate! do |img|
17
+ img.resize "#{width}x#{height}>" if width && height
18
+ img.resize "#{width}" if width
19
+ img.resize "x#{height}" if height
20
+ img
21
+ end
22
+ end
23
+
24
+ def fill(width, height, gravity = :center)
25
+ manipulate! do |img|
26
+ if width && height
27
+ width = width.to_i
28
+ height = height.to_i
29
+ gravity = :center unless gravity
30
+ gravity = gravity.to_s.capitalize.gsub(/(?:_)([a-z\d]*)/i) { $1.capitalize }
31
+ cols, rows = img[:dimensions]
32
+ img.combine_options do |c|
33
+ if width != cols || height != rows
34
+ scale_x = width/cols.to_f
35
+ scale_y = height/rows.to_f
36
+ if scale_x >= scale_y
37
+ cols = (scale_x * (cols + 0.5)).round
38
+ rows = (scale_x * (rows + 0.5)).round
39
+ c.resize "#{cols}"
40
+ else
41
+ cols = (scale_y * (cols + 0.5)).round
42
+ rows = (scale_y * (rows + 0.5)).round
43
+ c.resize "x#{rows}"
44
+ end
45
+ end
46
+ c.gravity gravity
47
+ c.background "rgba(255,255,255,0.0)"
48
+ c.extent "#{width}x#{height}" if cols != width || rows != height
49
+ end
50
+ else
51
+ img.resize "#{width}" if width
52
+ img.resize "x#{height}" if height
53
+ end
54
+ img
55
+ end
56
+ end
57
+
58
+ def fit(width, height = nil, gravity = nil)
59
+ manipulate! do |img|
60
+ img.resize "#{width}x#{height}" if width && height
61
+ img.resize "#{width}" if width
62
+ img.resize "x#{height}" if height
63
+ img
64
+ end
65
+ end
66
+
67
+ def scale(width, height = nil, gravity = nil)
68
+ manipulate! do |img|
69
+ img.resize "#{width}x#{height}!" if width && height
70
+ img.resize "#{width}" if width
71
+ img.resize "x#{height}" if height
72
+ img
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def manipulate!
79
+ image = ::MiniMagick::Image.read(stream)
80
+ image.format(@format.to_s.downcase) if @format
81
+ image = yield(image)
82
+ @stream = image.to_blob
83
+ rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
84
+ raise Minimage::Error.new
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,48 @@
1
+ require 'minimage'
2
+ require 'cuba'
3
+
4
+ module Minimage
5
+ class Server < Cuba
6
+ def not_found
7
+ res.status = 404
8
+ halt(res.finish)
9
+ end
10
+
11
+ def content_type(stream)
12
+ case stream.byteslice(0, 10)
13
+ when /^GIF8/ then 'image/gif'
14
+ when /^\x89PNG/ then 'image/png'
15
+ when /^\xff\xd8\xff\xe0\x00\x10JFIF/ then 'image/jpg'
16
+ when /^\xff\xd8\xff\xe1(.*){2}Exif/ then 'image/jpg'
17
+ else 'application/octet-stream'
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ Minimage::Server.settings[:cache_expiration] = 3600*24*365
24
+
25
+ Minimage::Server.define do
26
+ on get, %r{(?:(?:c_(fit|fill|limit)(?:,|\/)|w_(\d+)(?:,|\z)|h_(\d+)(?:,|\/)|g_(north_west|north|north_east|west|center|east|south_west|south|south_east)(?:,|\/))+)([^\\/]+)\.([a-z]{3,})} do |crop_mode, width, height, gravity, uid, format|
27
+ stream = Minimage.fetch(uid)
28
+ not_found unless stream
29
+ stream = Minimage.process(stream, format) do |processor|
30
+ crop_mode = crop_mode.nil? ? :scale : crop_mode.to_sym
31
+ processor.send(crop_mode, width, height, gravity)
32
+ end
33
+ res['Content-Type'] = content_type(stream)
34
+ res['Cache-Control'] = "public, max-age=#{settings[:cache_expiration]}"
35
+ res.write stream
36
+ end
37
+
38
+ on get, ':uid\.:format' do |uid, format|
39
+ stream = Minimage.fetch(uid)
40
+ not_found unless stream
41
+ stream = Minimage.process(stream) do |processor|
42
+ processor.format(format)
43
+ end
44
+ res['Content-Type'] = content_type(stream)
45
+ res['Cache-Control'] = "public, max-age=#{settings[:cache_expiration]}"
46
+ res.write stream
47
+ end
48
+ end
@@ -0,0 +1,17 @@
1
+ module Minimage
2
+ module Storage
3
+ class Base
4
+ def configure
5
+ yield self
6
+ end
7
+
8
+ def store!(file)
9
+ raise NotImplementedError.new
10
+ end
11
+
12
+ def fetch!(uid)
13
+ raise NotImplementedError.new
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ require 'minimage/storage'
2
+ require 'fileutils'
3
+
4
+ module Minimage
5
+ module Storage
6
+ class File < Base
7
+ attr_accessor :root_path
8
+
9
+ def store!(pathname)
10
+ atime = pathname.mtime
11
+ rnd = '%05d' % (rand(99999) + 1)
12
+ uid = "#{atime.to_i}_#{rnd}"
13
+
14
+ path = pathname.to_path
15
+ new_path = ::File.expand_path(::File.join(root_path, atime.strftime('%Y/%m/%d/%H/%M'), uid))
16
+
17
+ FileUtils.mkdir_p(::File.dirname(new_path)) unless ::File.exists?(::File.dirname(new_path))
18
+ FileUtils.copy(path, new_path) unless new_path == path
19
+ uid
20
+ rescue Errno::EACCES => e
21
+ raise Minimage::Storage::Error.new
22
+ end
23
+
24
+ def fetch!(uid)
25
+ matchdata = uid.match(/^(\d+)_\d{5}$/)
26
+ raise Minimage::Storage::NotFound.new unless matchdata
27
+
28
+ atime = Time.at(matchdata.captures.shift.to_i)
29
+ path = ::File.expand_path(::File.join(root_path, atime.strftime('%Y/%m/%d/%H/%M'), uid))
30
+ ::File.open(path, "rb") { |f| f.read }
31
+ rescue Errno::ENOENT => e
32
+ raise Minimage::Storage::NotFound.new
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module Minimage
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "minimage/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "minimage"
7
+ s.version = Minimage::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Damian Caruso"]
10
+ s.email = ["damian.caruso@gmail.com"]
11
+ s.homepage = "http://github.com/cdamian/minimage"
12
+ s.summary = %q{}
13
+ s.description = %q{}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency "cuba", "~> 3.1"
21
+ s.add_dependency "mini_magick", "~> 3.6"
22
+ s.add_dependency "nesty", "~> 1.0"
23
+ s.add_development_dependency "minitest", "~> 5.0"
24
+ s.add_development_dependency "rake"
25
+ end
@@ -0,0 +1,3 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/pride'
3
+ require 'minimage'
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestMinimage < Minitest::Test
4
+ def test_module_defined
5
+ assert defined?(Minimage)
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: minimage
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Damian Caruso
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cuba
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
30
+ - !ruby/object:Gem::Dependency
31
+ name: mini_magick
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3.6'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3.6'
46
+ - !ruby/object:Gem::Dependency
47
+ name: nesty
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: minitest
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '5.0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '5.0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: ''
95
+ email:
96
+ - damian.caruso@gmail.com
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitignore
102
+ - Gemfile
103
+ - LICENSE
104
+ - README.md
105
+ - Rakefile
106
+ - lib/minimage.rb
107
+ - lib/minimage/processor.rb
108
+ - lib/minimage/processor/mini_magick.rb
109
+ - lib/minimage/server.rb
110
+ - lib/minimage/storage.rb
111
+ - lib/minimage/storage/file.rb
112
+ - lib/minimage/version.rb
113
+ - minimage.gemspec
114
+ - test/helper.rb
115
+ - test/test_minimage.rb
116
+ homepage: http://github.com/cdamian/minimage
117
+ licenses: []
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 1.8.24
137
+ signing_key:
138
+ specification_version: 3
139
+ summary: ''
140
+ test_files: []
141
+ has_rdoc: