dynamic_image 1.0.4 → 2.0.0.beta1
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/{LICENSE → MIT-LICENSE} +1 -1
- data/README.md +57 -80
- data/Rakefile +7 -30
- data/lib/dynamic_image/belongs_to.rb +22 -0
- data/lib/dynamic_image/controller.rb +94 -0
- data/lib/dynamic_image/digest_verifier.rb +62 -0
- data/lib/dynamic_image/errors.rb +10 -0
- data/lib/dynamic_image/helper.rb +139 -85
- data/lib/dynamic_image/image_sizing.rb +156 -0
- data/lib/dynamic_image/metadata.rb +84 -0
- data/lib/dynamic_image/model/dimensions.rb +95 -0
- data/lib/dynamic_image/model/validations.rb +94 -0
- data/lib/dynamic_image/model.rb +130 -0
- data/lib/dynamic_image/processed_image.rb +119 -0
- data/lib/dynamic_image/railtie.rb +18 -0
- data/lib/dynamic_image/routing.rb +24 -0
- data/lib/dynamic_image/version.rb +5 -0
- data/lib/dynamic_image.rb +14 -71
- data/lib/rails/generators/dynamic_image/resource/resource_generator.rb +74 -0
- metadata +130 -97
- data/VERSION +0 -1
- data/app/controllers/images_controller.rb +0 -79
- data/app/models/image.rb +0 -188
- data/config/routes.rb +0 -16
- data/dynamic_image.gemspec +0 -62
- data/dynamic_image.sublime-project +0 -9
- data/dynamic_image.sublime-workspace +0 -1599
- data/init.rb +0 -1
- data/install.rb +0 -1
- data/lib/binary_storage/active_record_extensions.rb +0 -144
- data/lib/binary_storage/blob.rb +0 -104
- data/lib/binary_storage.rb +0 -28
- data/lib/dynamic_image/active_record_extensions.rb +0 -60
- data/lib/dynamic_image/engine.rb +0 -6
- data/lib/dynamic_image/filterset.rb +0 -79
- data/lib/generators/dynamic_image/USAGE +0 -5
- data/lib/generators/dynamic_image/dynamic_image_generator.rb +0 -38
- data/lib/generators/dynamic_image/templates/migrations/create_images.rb +0 -21
- data/uninstall.rb +0 -1
data/app/models/image.rb
DELETED
@@ -1,188 +0,0 @@
|
|
1
|
-
class Image < ActiveRecord::Base
|
2
|
-
unloadable
|
3
|
-
|
4
|
-
binary_storage :data, :sha1_hash
|
5
|
-
|
6
|
-
validates_format_of :content_type,
|
7
|
-
:with => /\Aimage/,
|
8
|
-
:message => "you can only upload pictures"
|
9
|
-
|
10
|
-
attr_accessor :filterset, :data_checked, :skip_maxsize
|
11
|
-
|
12
|
-
# Sanitize the filename and set the name to the filename if omitted
|
13
|
-
validate do |image|
|
14
|
-
image.name = File.basename(image.filename, ".*") if !image.name || image.name.strip == ""
|
15
|
-
image.filename = image.friendly_file_name(image.filename)
|
16
|
-
if image.cropped?
|
17
|
-
image.errors.add(:crop_start, "must be a vector") unless image.crop_start =~ /^[\d]+x[\d]+$/
|
18
|
-
image.errors.add(:crop_size, "must be a vector") unless image.crop_size =~ /^[\d]+x[\d]+$/
|
19
|
-
else
|
20
|
-
image.crop_size = image.original_size
|
21
|
-
image.crop_start = "0x0"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# Create the binary from an image file.
|
26
|
-
def imagefile=(image_file)
|
27
|
-
if image_file.kind_of?(String) && image_file =~ /^(ht|f)tps?:\/\//
|
28
|
-
self.filename = File.basename(image_file)
|
29
|
-
image_file = open(image_file)
|
30
|
-
else
|
31
|
-
self.filename = image_file.original_filename rescue File.basename(image_file.path)
|
32
|
-
end
|
33
|
-
self.content_type = image_file.content_type.chomp rescue "image/"+image_file.path.split(/\./).last.downcase.gsub(/jpg/,"jpeg") # ugly hack
|
34
|
-
set_image_data(image_file.read)
|
35
|
-
end
|
36
|
-
|
37
|
-
# Return the image hotspot
|
38
|
-
def hotspot
|
39
|
-
(self.hotspot?) ? self.hotspot : (Vector2d.new(self.size) * 0.5).round.to_s
|
40
|
-
end
|
41
|
-
|
42
|
-
# Check the image data
|
43
|
-
def set_image_data(data)
|
44
|
-
self.data = data
|
45
|
-
if self.data
|
46
|
-
image = Magick::ImageList.new.from_blob(self.data)
|
47
|
-
size = Vector2d.new(image.columns, image.rows)
|
48
|
-
if DynamicImage.crash_size
|
49
|
-
crashsize = Vector2d.new(DynamicImage.crash_size)
|
50
|
-
if (size.x > crashsize.x || size.y > crashsize.y)
|
51
|
-
raise "Image too large!"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
if DynamicImage.max_size && !self.skip_maxsize
|
55
|
-
maxsize = Vector2d.new(DynamicImage.max_size)
|
56
|
-
if (size.x > maxsize.x || size.y > maxsize.y)
|
57
|
-
size = size.constrain_both(maxsize).round
|
58
|
-
image.resize!(size.x, size.y)
|
59
|
-
self.data = image.to_blob
|
60
|
-
end
|
61
|
-
end
|
62
|
-
# Convert image to a proper format
|
63
|
-
unless image.format =~ /(JPEG|PNG|GIF)/
|
64
|
-
self.data = image.to_blob{self.format = 'JPEG'; self.quality = 90}
|
65
|
-
self.filename += ".jpg"
|
66
|
-
self.content_type = "image/jpeg"
|
67
|
-
end
|
68
|
-
self.original_size = size.round.to_s
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# Returns the image width
|
73
|
-
def original_width
|
74
|
-
Vector2d.new(self.original_size).x.to_i
|
75
|
-
end
|
76
|
-
|
77
|
-
# Returns the image height
|
78
|
-
def original_height
|
79
|
-
Vector2d.new(self.original_size).y.to_i
|
80
|
-
end
|
81
|
-
|
82
|
-
def crop_start_x
|
83
|
-
Vector2d.new(self.crop_start).x.to_i
|
84
|
-
end
|
85
|
-
def crop_start_y
|
86
|
-
Vector2d.new(self.crop_start).y.to_i
|
87
|
-
end
|
88
|
-
def crop_width
|
89
|
-
Vector2d.new(self.crop_size).x.to_i
|
90
|
-
end
|
91
|
-
def crop_height
|
92
|
-
Vector2d.new(self.crop_size).y.to_i
|
93
|
-
end
|
94
|
-
|
95
|
-
# Returns original or cropped size
|
96
|
-
def size
|
97
|
-
(self.cropped?) ? self.crop_size : self.original_size
|
98
|
-
end
|
99
|
-
|
100
|
-
def size=(new_size)
|
101
|
-
self.original_size = new_size
|
102
|
-
end
|
103
|
-
|
104
|
-
# Convert file name to a more file system friendly one.
|
105
|
-
# TODO: international chars
|
106
|
-
def friendly_file_name( file_name )
|
107
|
-
[["æ","ae"], ["ø","oe"], ["å","aa"]].each do |int|
|
108
|
-
file_name = file_name.gsub(int[0], int[1])
|
109
|
-
end
|
110
|
-
File.basename(file_name).gsub(/[^\w\d\.-]/, "_")
|
111
|
-
end
|
112
|
-
|
113
|
-
# Get the base part of a filename
|
114
|
-
def base_part_of(file_name)
|
115
|
-
name = File.basename(file_name)
|
116
|
-
name.gsub(/[ˆ\w._-]/, '')
|
117
|
-
end
|
118
|
-
|
119
|
-
# Rescale and crop the image, and return it as a blob.
|
120
|
-
def rescaled_and_cropped_data(*args)
|
121
|
-
DynamicImage.dirty_memory = true # Flag to perform GC
|
122
|
-
image_data = Magick::ImageList.new.from_blob(self.data)
|
123
|
-
|
124
|
-
if self.cropped?
|
125
|
-
cropped_start = Vector2d.new(self.crop_start).round
|
126
|
-
cropped_size = Vector2d.new(self.crop_size).round
|
127
|
-
image_data = image_data.crop(cropped_start.x, cropped_start.y, cropped_size.x, cropped_size.y, true)
|
128
|
-
end
|
129
|
-
|
130
|
-
size = Vector2d.new(self.size)
|
131
|
-
rescale_size = size.dup.constrain_one(args).round # Rescale dimensions
|
132
|
-
crop_to_size = Vector2d.new(args).round # Crop size
|
133
|
-
new_hotspot = Vector2d.new(hotspot) * (rescale_size / size) # Recalculated hotspot
|
134
|
-
rect = [(new_hotspot-(crop_to_size/2)).round, (new_hotspot+(crop_to_size/2)).round] # Array containing crop coords
|
135
|
-
|
136
|
-
# Adjustments
|
137
|
-
x = rect[0].x; rect.each{|r| r.x += (x.abs)} if x < 0
|
138
|
-
y = rect[0].y; rect.each{|r| r.y += (y.abs)} if y < 0
|
139
|
-
x = rect[1].x; rect.each{|r| r.x -= (x-rescale_size.x)} if x > rescale_size.x
|
140
|
-
y = rect[1].y; rect.each{|r| r.y -= (y-rescale_size.y)} if y > rescale_size.y
|
141
|
-
|
142
|
-
rect[0].round!
|
143
|
-
rect[1].round!
|
144
|
-
|
145
|
-
image_data = image_data.resize(rescale_size.x, rescale_size.y)
|
146
|
-
image_data = image_data.crop(rect[0].x, rect[0].y, crop_to_size.x, crop_to_size.y)
|
147
|
-
image_data.to_blob{self.quality = 90}
|
148
|
-
end
|
149
|
-
|
150
|
-
def constrain_size(*max_size)
|
151
|
-
Vector2d.new(self.size).constrain_both(max_size.flatten).round.to_s
|
152
|
-
end
|
153
|
-
|
154
|
-
# Get a duplicate image with resizing and filters applied.
|
155
|
-
def get_processed(size, filterset=nil)
|
156
|
-
size = Vector2d.new(size).round.to_s
|
157
|
-
processed_image = Image.new
|
158
|
-
processed_image.filterset = filterset || 'default'
|
159
|
-
processed_image.data = self.rescaled_and_cropped_data(size)
|
160
|
-
processed_image.size = size
|
161
|
-
processed_image.apply_filters
|
162
|
-
processed_image
|
163
|
-
end
|
164
|
-
|
165
|
-
# Apply filters to image data
|
166
|
-
def apply_filters
|
167
|
-
filterset_name = self.filterset || 'default'
|
168
|
-
filterset = DynamicImage::Filterset[filterset_name]
|
169
|
-
if filterset
|
170
|
-
DynamicImage.dirty_memory = true # Flag for GC
|
171
|
-
data = Magick::ImageList.new.from_blob(self.data)
|
172
|
-
data = filterset.process(data)
|
173
|
-
self.data = data.to_blob
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
# Decorates to_json with additional attributes
|
178
|
-
def to_json
|
179
|
-
attributes.merge({
|
180
|
-
:original_width => self.original_width,
|
181
|
-
:original_height => self.original_height,
|
182
|
-
:crop_width => self.crop_width,
|
183
|
-
:crop_height => self.crop_height,
|
184
|
-
:crop_start_x => self.crop_start_x,
|
185
|
-
:crop_start_y => self.crop_start_y
|
186
|
-
}).to_json
|
187
|
-
end
|
188
|
-
end
|
data/config/routes.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# Rails 3 routes
|
2
|
-
Rails.application.routes.draw do
|
3
|
-
get "dynamic_images/:id/:original(/:size(/:filterset))/*filename" => "images#render_dynamic_image", :size => /\d*x\d*/, :original => /original/
|
4
|
-
get "dynamic_images/:id(/:size(/:filterset))/*filename" => "images#render_dynamic_image", :size => /\d*x\d*/
|
5
|
-
# Legacy
|
6
|
-
get "dynamic_image/:id/:original(/:size(/:filterset))/*filename" => "images#render_dynamic_image", :size => /\d*x\d*/, :original => /original/
|
7
|
-
get "dynamic_image/:id(/:size(/:filterset))/*filename" => "images#render_dynamic_image", :size => /\d*x\d*/
|
8
|
-
end
|
9
|
-
|
10
|
-
# Rails 2 routes
|
11
|
-
#@set.add_route('dynamic_image/:id/:original/:size/:filterset/*filename', {:controller => 'images', :action => 'render_dynamic_image', :requirements => { :size => /[\d]*x[\d]*/, :original => /original/ }})
|
12
|
-
#@set.add_route('dynamic_image/:id/:original/:size/*filename', {:controller => 'images', :action => 'render_dynamic_image', :requirements => { :size => /[\d]*x[\d]*/, :original => /original/ }})
|
13
|
-
#@set.add_route('dynamic_image/:id/:original/*filename', {:controller => 'images', :action => 'render_dynamic_image', :requirements => { :original => /original/ }})
|
14
|
-
#@set.add_route('dynamic_image/:id/:size/:filterset/*filename', {:controller => 'images', :action => 'render_dynamic_image', :requirements => { :size => /[\d]*x[\d]*/ }})
|
15
|
-
#@set.add_route('dynamic_image/:id/:size/*filename', {:controller => 'images', :action => 'render_dynamic_image', :requirements => { :size => /[\d]*x[\d]*/ }})
|
16
|
-
#@set.add_route('dynamic_image/:id/*filename', {:controller => 'images', :action => 'render_dynamic_image'})
|
data/dynamic_image.gemspec
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
-
# -*- encoding: utf-8 -*-
|
5
|
-
|
6
|
-
Gem::Specification.new do |s|
|
7
|
-
s.name = "dynamic_image"
|
8
|
-
s.version = "1.0.4"
|
9
|
-
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["Inge J\303\270rgensen"]
|
12
|
-
s.date = "2014-06-12"
|
13
|
-
s.email = "inge@elektronaut.no"
|
14
|
-
s.extra_rdoc_files = [
|
15
|
-
"LICENSE",
|
16
|
-
"README.md"
|
17
|
-
]
|
18
|
-
s.files = [
|
19
|
-
"LICENSE",
|
20
|
-
"README.md",
|
21
|
-
"Rakefile",
|
22
|
-
"VERSION",
|
23
|
-
"app/controllers/images_controller.rb",
|
24
|
-
"app/models/image.rb",
|
25
|
-
"config/routes.rb",
|
26
|
-
"dynamic_image.gemspec",
|
27
|
-
"init.rb",
|
28
|
-
"install.rb",
|
29
|
-
"lib/binary_storage.rb",
|
30
|
-
"lib/binary_storage/active_record_extensions.rb",
|
31
|
-
"lib/binary_storage/blob.rb",
|
32
|
-
"lib/dynamic_image.rb",
|
33
|
-
"lib/dynamic_image/active_record_extensions.rb",
|
34
|
-
"lib/dynamic_image/engine.rb",
|
35
|
-
"lib/dynamic_image/filterset.rb",
|
36
|
-
"lib/dynamic_image/helper.rb",
|
37
|
-
"lib/generators/dynamic_image/USAGE",
|
38
|
-
"lib/generators/dynamic_image/dynamic_image_generator.rb",
|
39
|
-
"lib/generators/dynamic_image/templates/migrations/create_images.rb",
|
40
|
-
"uninstall.rb"
|
41
|
-
]
|
42
|
-
s.homepage = "http://github.com/elektronaut/dynamic_image"
|
43
|
-
s.require_paths = ["lib"]
|
44
|
-
s.rubygems_version = "1.8.24"
|
45
|
-
s.summary = "DynamicImage is a rails plugin providing transparent uploading and processing of image files."
|
46
|
-
|
47
|
-
if s.respond_to? :specification_version then
|
48
|
-
s.specification_version = 3
|
49
|
-
|
50
|
-
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
51
|
-
s.add_runtime_dependency(%q<rmagick>, ["~> 2.13.2"])
|
52
|
-
s.add_runtime_dependency(%q<vector2d>, ["~> 1.0.0"])
|
53
|
-
else
|
54
|
-
s.add_dependency(%q<rmagick>, ["~> 2.13.2"])
|
55
|
-
s.add_dependency(%q<vector2d>, ["~> 1.0.0"])
|
56
|
-
end
|
57
|
-
else
|
58
|
-
s.add_dependency(%q<rmagick>, ["~> 2.13.2"])
|
59
|
-
s.add_dependency(%q<vector2d>, ["~> 1.0.0"])
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|