-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathimage_size.rb
164 lines (146 loc) · 4.51 KB
/
image_size.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
module CarrierWave
module ImageSize
# Requirements:
# imagemagick - in particular the "identify" command
#
# Include CarrierWave::ImageSize in your CarrierWave uploader
# to have image sizes and content type automatically stored
# along with the image. For this to work, you must create a
# second column in your database named:
#
# "#{image_name}_information"
#
# For instance, if your image is named "pic", you need to create
# a string or text column named "pic_information".
#
# t.string :pic, :limit => 250
# t.string :pic_information, :limit => 250
#
# In your model, you mount the uploader
#
# mount_uploader :pic, PicUploader
#
# And in the uploader, you include CarrierWave::ImageSize:
#
# class LogoUploader < CarrierWave::Uploader::Base
#
# ...
# include CarrierWave::ImageSize
#
# Note that you might also need to "require" it at the top
# of the file:
#
# require 'carrier_wave/image_size'
#
# You now have three new methods on your uploaded pictures:
#
# image_width, image_height - returns height and width of images
# as integers
#
# content_type - returns the original content type of the image
#
# Note that nested versions are fully supported and you can use
# these methods with any of your versions:
#
# version :thumb do
# process :resize_to_fit => [50, 50]
# version :tiny do
# process :resize_to_fit => [10, 10]
# end
# end
#
# In your code:
#
# artist.pic.thumb.tiny.image_width
#
# Additionally, your form should propogate the _information field
# along with the cache, otherwise the content type will be lost.
#
# <%= f.file_field :pic %>
# <%= f.hidden_field :pic_cache %>
# <%= f.hidden_field :pic_information unless f.object.pic_cache.blank? %>
#
# The only limitation is that you cannot create a version of your
# picture called "base", as I use that for storing the size of the
# base image. If you really badly need to use "base", search for "base"
# below and change it to something else.
#
# Internally, the _information field is simply a string:
#
# "image/png\nbase:200x150\nthumb:20x15\nthumb_tiny:10x7\n"
#
# Where the sizes are simply width x height. The content_type
# is saved across "recreate_versions!".
#
# Improvements (TODO):
#
# 1. This should be turned into a gem
# 2. Could probably better use the image processor (i.e. minimagick)
# to get size information
# 3. Needs some tests
extend ActiveSupport::Concern
include CarrierWave::Uploader::Callbacks
included do
after :cache, :capture_size_after_cache
end
def image_width
info_field(my_version_name).first rescue nil
end
def image_height
info_field(my_version_name).last rescue nil
end
def content_type
info_field('content_type')
end
protected
def my_version_name
(self.version_name || 'base').to_s
end
private
def capture_size_after_cache(new_file)
if has_info_field?
if has_info?
prev_content_type = info_field('content_type')
end
set_info((new_file.content_type.blank? ? prev_content_type : new_file.content_type) + "\n" + drill_for_info(model.send(mounted_as)).collect { |k,v| sprintf("%s:%dx%d\n",k,v[0],v[1]) }.join() )
end
end
def drill_for_info(obj, hash = {})
hash[obj.my_version_name] = do_identify(obj.current_path)
obj.versions.keys.each { |v| drill_for_info(obj.send(v), hash) }
hash
end
def info_field_name
"#{mounted_as}_information"
end
def raw_info_field
model[info_field_name]
end
def info_field(datum)
if datum == 'content_type'
raw_info_field.split(/\r?\n/).first
else
md = /^#{datum}:(\d+)x(\d+)/.match(raw_info_field)
if md
md[1..2]
else
nil
end
end
end
def has_info_field?
model.respond_to?(info_field_name)
end
def has_info?
has_info_field? && raw_info_field.is_a?(String)
end
def set_info(new_info)
model.send("#{info_field_name}=", new_info)
end
def do_identify(filename)
ret = nil
IO.popen(['identify', '-format', '%wx%h', filename]) { |f| ret = f.gets.chomp }
!ret.blank? ? ret.split(/x/).collect { |x| x.to_i } : nil
end
end
end