attachment_on_the_fly 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MDIxZWM5YjI4NzY2OGNjYWExOGY1MDAzNDAxMzJiODJkMjM5MThkZg==
5
+ data.tar.gz: !binary |-
6
+ NTliMDE1OTYxOTA1MWM3NmRhNzZjMGMyMzg5MWEwNjM1ODc1ODIzNQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NzYwNDkzNjI3MWE2MTcwY2QyYWYyNGZlNGE4MWMzNzY3NGU2NGVjNWNmNWRl
10
+ M2JiOTlhODZkZWQxNGM5MWRmODRlMzRhNDA1MmE4OWIwMDM0N2E5ZDY2OWJm
11
+ NmMxNGE3MjJlZmRhYWY0NmUyNWMyZDQ3MDRjYjU3NzBmZjU0MjU=
12
+ data.tar.gz: !binary |-
13
+ YzdmY2M1OTRmODEzOGFiOTIxMTgyYWU0MDY3MDkzMjJiNjA1MjBjZGMzNDI5
14
+ YjA4NWJjNDIxNzM3OGFiYjA5YTIxNzIyMTVhNzRmNzdhMWQ4YzgyZjYyZTQz
15
+ MWY3YzVjMjIyNGNlMGU2ZGZjMTFjNWZjMzUzY2E0ZGI0N2FhZDk=
@@ -42,11 +42,25 @@ proportional, and width proportional.
42
42
  my_image_model.attachment.s_640_480 will generate a 640x480 pixel image.
43
43
 
44
44
  my_image_model.attachment.s_640_width will generate an image that is 640 pixels
45
+
45
46
  wide and proportionally high based on the original image dimensions.
46
47
 
47
48
  my_image_model.attachment.s_480_height will generate an image that is 480 pixels
48
49
  high and proportionally wide based on the original image dimensions.
49
50
 
51
+ == Parameters options
52
+ Attachement-on-the-fly uses 'Convert' from image-magick to resize image and
53
+ you can pass any convert options in hash notation.
54
+ my_image_model.attachement.s_800_600 :morph => 15
55
+
56
+ The only exception is :extension parameter
57
+ my_image_model.attachement.s_400_300 :quality => 75,:extension => 'jpg' will generate
58
+ an image that is 400x300 with quality 75% and convert jpg if necessary.
59
+
60
+ link:http://www.imagemagick.org/script/command-line-options.php
61
+
62
+
63
+
50
64
  When an image's instance is first accessed through the s_ method, a new image
51
65
  will be generated according to the image's path interpolation. Then, every time
52
66
  the image is accessed with the same dimensions, the previously generated image
@@ -58,6 +72,8 @@ or any other of convert's command line options, you will need to do so in the
58
72
  final lines of lib/attachment_on_the_fly.rb. We are working on a feature to do
59
73
  this dynamically, but it is not available yet.
60
74
 
75
+ Note that, for now, you need to name your model 'attachment'.
76
+
61
77
  ==Contributing
62
78
 
63
79
  If you find this gem useful, please post your comments, bugs, patches and
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
@@ -2,16 +2,17 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
+ # stub: attachment_on_the_fly 0.1.3 ruby lib
5
6
 
6
7
  Gem::Specification.new do |s|
7
- s.name = %q{attachment_on_the_fly}
8
- s.version = "0.1.1"
8
+ s.name = "attachment_on_the_fly"
9
+ s.version = "0.1.3"
9
10
 
10
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
12
  s.authors = ["Jeff Sutherland"]
12
- s.date = %q{2011-02-18}
13
- s.description = %q{A Paperclip mix-in to allow auto-generation of resized images}
14
- s.email = %q{jefferey.sutherland@gmail.com}
13
+ s.date = "2013-12-04"
14
+ s.description = "A Paperclip mix-in to allow auto-generation of resized images"
15
+ s.email = "jefferey.sutherland@gmail.com"
15
16
  s.extra_rdoc_files = [
16
17
  "README",
17
18
  "README.rdoc"
@@ -23,15 +24,17 @@ Gem::Specification.new do |s|
23
24
  "VERSION",
24
25
  "attachment_on_the_fly.gemspec",
25
26
  "init.rb",
26
- "lib/attachment_on_the_fly.rb"
27
+ "lib/attachment_on_the_fly.rb",
28
+ "spec/attachment_on_the_fly_spec.rb",
29
+ "spec/spec_helper.rb"
27
30
  ]
28
- s.homepage = %q{http://github.com/drpentode/Attachment-on-the-Fly}
31
+ s.homepage = "http://github.com/drpentode/Attachment-on-the-Fly"
29
32
  s.require_paths = ["lib"]
30
- s.rubygems_version = %q{1.5.0}
31
- s.summary = %q{A Paperclip mix-in to allow auto-generation of resized images}
33
+ s.rubygems_version = "2.1.11"
34
+ s.summary = "A Paperclip mix-in to allow auto-generation of resized images"
32
35
 
33
36
  if s.respond_to? :specification_version then
34
- s.specification_version = 3
37
+ s.specification_version = 4
35
38
 
36
39
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
37
40
  s.add_runtime_dependency(%q<paperclip>, [">= 0"])
@@ -9,8 +9,9 @@ Paperclip::Attachment.class_eval do
9
9
 
10
10
  # we respond to s_ and cls_
11
11
  def respond_to?(method,*args, &block)
12
- if method.to_s.match(/^s_[0-9]+_[0-9]+/) || method.to_s.match(/^s_[0-9]+_[a-z]+/) || method.to_s.match(/^s[0-9]+/) ||
13
- method.to_s.match(/^cls_[0-9]+_[0-9]+/) || method.to_s.match(/^cls_[0-9]+_[a-z]+/) || method.to_s.match(/^cls[0-9]+/)
12
+ if method.to_s.match(/^(cls|s)_[0-9]+_[0-9]+$/) ||
13
+ method.to_s.match(/^(cls|s)_[0-9]+_(width|height|both)$/) ||
14
+ method.to_s.match(/^(cls|s)[0-9]+$/)
14
15
  return true
15
16
  end
16
17
  super
@@ -19,24 +20,27 @@ Paperclip::Attachment.class_eval do
19
20
  def method_missing(symbol , *args, &block )
20
21
  # We are looking for methods with S_[number]_[number]_(height | width | proportion)
21
22
  # Height and width
22
- # Check to see if file exist if so return string
23
- # if not generate image and return string to file Fiel is in format S_Height_x_Width_FILE_NAME
23
+ # Check to see if file exists, if so return string
24
+ # if not generate image and return string to file
24
25
  image_name = nil
25
- if symbol.to_s.match(/^s_[0-9]+_[0-9]+/) || symbol.to_s.match(/^cls_[0-9]+_[0-9]+/)
26
+ parameters = args.shift
27
+ parameters ||= {}
28
+
29
+ if symbol.to_s.match(/^(cls|s)_[0-9]+_[0-9]+$/)
26
30
  values = symbol.to_s.split("_")
27
- height = values[1]
28
- width = values[2]
29
- image_name = generate_image("both", height.to_i, width.to_i)
30
- elsif symbol.to_s.match(/^s_[0-9]+_[a-z]+/) || symbol.to_s.match(/^cls_[0-9]+_[a-z]+/)
31
+ height = values[1].to_i
32
+ width = values[2].to_i
33
+ image_name = generate_image("both", height, width, parameters)
34
+ elsif symbol.to_s.match(/^(cls|s)_[0-9]+_(width|height|both)$/)
31
35
  values = symbol.to_s.split("_")
32
- size = values[1]
33
- who = values[2]
34
- image_name = generate_image(who, size.to_i)
35
- elsif symbol.to_s.match(/^s[0-9]+/) || symbol.to_s.match(/^cls[0-9]+/)
36
+ size = values[1].to_i
37
+ kind = values[2]
38
+ image_name = generate_image(kind, size, size, parameters)
39
+ elsif symbol.to_s.match(/^(cls|s)[0-9]+$/)
36
40
  values = symbol.to_s.split("s")
37
- size = values[1]
38
- who = "width"
39
- image_name = generate_image(who, size.to_i)
41
+ size = values[1].to_i
42
+ kind = "width"
43
+ image_name = generate_image(kind, size, size, parameters)
40
44
  else
41
45
  # if our method string does not match, we kick things back up to super ... this keeps ActiveRecord chugging along happily
42
46
  super
@@ -44,9 +48,15 @@ Paperclip::Attachment.class_eval do
44
48
  return image_name
45
49
  end
46
50
 
47
- def generate_image(kind, height = 0, width = 0)
51
+ def generate_image(kind, height = 0, width = 0, parameters = {})
48
52
  convert_command_path = (Paperclip.options[:command_path] ? Paperclip.options[:command_path] + "/" : "")
49
-
53
+ parameters.symbolize_keys!
54
+ [:extension, :quality].each do |opt|
55
+ parameters.reverse_merge!({opt => Paperclip.options[opt]}) if Paperclip.options[opt]
56
+ end
57
+ quality = parameters[:quality] ||= 100
58
+ parameters.delete :quality
59
+
50
60
  prefix = ""
51
61
 
52
62
  if kind == "height"
@@ -55,27 +65,37 @@ Paperclip::Attachment.class_eval do
55
65
  width = height
56
66
  prefix = "S_" + height.to_s + "_WIDTH_"
57
67
  elsif kind == "both"
58
- prefix = "S_" + height.to_s + "_" + height.to_s + "_"
68
+ prefix = "S_" + width.to_s + "_" + height.to_s + "_"
59
69
  end
70
+ presuffix = parameters.map{|k,v| "#{k}_#{v}" }.join('___') + "_q_#{quality}_"
71
+ prefix = "#{prefix}#{presuffix}_"
72
+ prefix = "#{prefix}#{Paperclip.options[:version_prefix]}_" if Paperclip.options[:version_prefix]
60
73
 
61
- path = instance.attachment.path
62
- url = instance.attachment.url
74
+ path = self.path
75
+ url = self.url
63
76
 
64
77
  path_arr = path.split("/")
65
78
  file_name = path_arr.pop
66
79
  path = path_arr.join("/")
67
80
 
81
+ base_arr = file_name.split('.');
82
+ original_extension = extension = base_arr.pop
83
+ base_name = base_arr.join('.')
84
+ extension = parameters[:extension] || extension
85
+ parameters.delete :extension
86
+
68
87
  url_arr = url.split("/")
69
88
  url_file_name = url_arr.pop
70
89
  url_path = url_arr.join("/")
71
90
 
72
- original = path + "/" + instance.attachment.original_filename
73
- newfilename = path + "/" + prefix + file_name
74
- new_path = url_path + "/" + prefix + file_name
75
-
76
- return new_path if File.exist?(newfilename)
91
+ original = path + "/" + self.original_filename
92
+ newfilename = path + "/" + prefix + base_name + '.' + extension
93
+ fallback_newfilename = path + "/" + prefix + base_name + '.' + original_extension
94
+ new_path = url_path + "/" + prefix + base_name + '.' + extension
95
+ fallback_new_path = url_path + "/" + prefix + base_name + '.' + original_extension
96
+ return new_path if File.exist?(newfilename)
77
97
 
78
- if !File.exist?(original)
98
+ if !File.exist?(original)
79
99
  if Paperclip.options[:whiny]
80
100
  raise AttachmentOnTheFlyError.new("Original asset could not be read from disk at #{original}")
81
101
  else
@@ -91,24 +111,49 @@ Paperclip::Attachment.class_eval do
91
111
 
92
112
  command = ""
93
113
 
114
+ options_for_extension = ""
115
+ if original_extension != extension && has_alpha?(original)
116
+ # Converting extension with alpha channel is problematic.
117
+ # Fall back to original extension.
118
+ Paperclip.log("Ignoring extension parameter because original file is transparent")
119
+ newfilename = fallback_newfilename
120
+ new_path = fallback_new_path
121
+ end
122
+
123
+ base_command = "#{convert_command_path}convert -strip -geometry"
124
+
94
125
  if kind == "height"
95
126
  # resize_image infilename, outfilename , 0, height
96
- command = "#{convert_command_path}convert -colorspace RGB -geometry x#{height} -quality 100 -sharpen 1 #{original} #{newfilename} 2>&1 > /dev/null"
127
+ command = "#{base_command} x#{height} -quality #{quality} -sharpen 1 '#{original}' '#{newfilename}' 2>&1 > /dev/null"
97
128
  elsif kind == "width"
98
129
  # resize_image infilename, outfilename, width
99
- command = "#{convert_command_path}convert -colorspace RGB -geometry #{width} -quality 100 -sharpen 1 #{original} #{newfilename} 2>&1 > /dev/null"
130
+ command = "#{base_command} #{width} -quality #{quality} -sharpen 1 '#{original}' '#{newfilename}' 2>&1 > /dev/null"
100
131
  elsif kind == "both"
101
132
  # resize_image infilename, outfilename, height, width
102
- command = "#{convert_command_path}convert -colorspace RGB -geometry #{width}x#{height} -quality 100 -sharpen 1 #{original} #{newfilename} 2>&1 > /dev/null"
133
+ command = "#{base_command} #{width}x#{height} -quality #{quality} -sharpen 1 '#{original}' '#{newfilename}' 2>&1 > /dev/null"
103
134
  end
104
135
 
105
- `#{command}`
136
+ convert_command command
106
137
 
107
- if $? != 0
108
- raise AttachmentOnTheFlyError.new("Execution of convert failed. Please set path in Paperclip.options[:command_path] or ensure that file permissions are correct.")
138
+ return new_path
139
+ end
140
+
141
+ def convert_command command
142
+ `#{command}`
143
+ if ($? != 0)
144
+ raise AttachmentOnTheFlyError.new("Execution of convert failed. Please set path in Paperclip.options[:command_path] or ensure that file permissions are correct. Failed trying to do: #{command}")
109
145
  end
146
+ end
110
147
 
111
- return new_path
148
+ def has_alpha? image
149
+ identify_command_path = (Paperclip.options[:identify_command_path] ? Paperclip.options[:identify_command_path] + "/" : "")
150
+ # http://stackoverflow.com/questions/2581469/detect-alpha-channel-with-imagemagick
151
+ command = "#{identify_command_path}identify -format '%[channels]' '#{image}'"
152
+ result = `#{command}`
153
+ if ($? != 0)
154
+ raise AttachmentOnTheFlyError.new("Execution of identify failed. Please set path in Paperclip.options[:identify_command_path] or ensure that file permissions are correct. Failed trying to do: #{command}")
155
+ end
156
+ result && result.chomp == "rgba"
112
157
  end
113
158
  end
114
159
 
@@ -0,0 +1,99 @@
1
+ require_relative './spec_helper'
2
+
3
+ describe "Attachment on the fly mixin" do
4
+
5
+ subject { Paperclip::Attachment.new }
6
+
7
+ context "#respond_to?" do
8
+ method_names = %w{s125 cls125 s_125_250 cls_125_250
9
+ s_125_width cls_125_width s_125_height cls_125_height
10
+ s_125_both cls_125_both
11
+ }
12
+
13
+ method_names.each do |method_name|
14
+ it { should respond_to(method_name.to_sym) }
15
+ end
16
+
17
+ it { should_not respond_to(:x_125_250) }
18
+ it { should_not respond_to(:s_125_250foo) }
19
+ it { should_not respond_to(:S_125_250) }
20
+ end
21
+
22
+ context "#method_missing" do
23
+
24
+ context "translates method into a generate image call" do
25
+ method_name_to_generate_image_call = {
26
+ :s_125_225 => ["both", 125, 225, {}],
27
+ :s125 => ["width", 125, 125, {}],
28
+ :s_125_height => ["height", 125, 125, {}],
29
+ :s_125_width => ["width", 125, 125, {}],
30
+ :s_125_both => ["both", 125, 125, {}]
31
+ }
32
+
33
+ method_name_to_generate_image_call.each do |method_name, generate_image_args|
34
+ it "#{method_name}" do
35
+ subject.should_receive(:generate_image).with(*generate_image_args)
36
+ subject.send(method_name)
37
+ end
38
+ end
39
+
40
+ it "passes parameters through as well" do
41
+ subject.should_receive(:generate_image).with("width", 125, 125, {:quality => 90, :extension => "jpeg"})
42
+ subject.s_125_width :quality => 90, :extension => "jpeg"
43
+ end
44
+ end
45
+ end
46
+
47
+ context "#generate_image" do
48
+
49
+ context "it should generate a new image" do
50
+ method_name_to_expectations = {
51
+ :s_125_width => {
52
+ :new => "/S_125_WIDTH__q_100__path.png",
53
+ :regex => /-geometry 125 /
54
+ },
55
+ :s_125_height => {
56
+ :new => "/S_125_HEIGHT__q_100__path.png",
57
+ :regex => /-geometry x125 /
58
+ },
59
+ :s_125_both => {
60
+ :new => "/S_125_125__q_100__path.png",
61
+ :regex => /-geometry 125x125 /
62
+ }
63
+ }
64
+ method_name_to_expectations.each do |method_name, expected|
65
+ it "for #{method_name}" do
66
+ File.should_receive(:exist?).with(expected[:new]).and_return(false)
67
+ File.should_receive(:exist?).with("//file.png").and_return(true)
68
+ subject.should_receive(:convert_command).with(expected[:regex])
69
+ subject.send(method_name)
70
+ end
71
+ end
72
+
73
+ it "passes in parameters for quality" do
74
+ File.should_receive(:exist?).with("/S_125_WIDTH__q_75__path.png").and_return(false)
75
+ File.should_receive(:exist?).with("//file.png").and_return(true)
76
+ subject.should_receive(:convert_command).with(/-quality 75/)
77
+ subject.s_125_width :quality => 75
78
+ end
79
+
80
+ it "passes in parameters for extension" do
81
+ File.should_receive(:exist?).with("/S_125_WIDTH_extension_jpeg_q_75__path.jpeg").and_return(false)
82
+ File.should_receive(:exist?).with("//file.png").and_return(true)
83
+ subject.should_receive(:convert_command).with(/-quality 75/)
84
+ subject.should_receive(:has_alpha?).with("//file.png").and_return(false)
85
+ subject.s_125_width(:quality => 75, :extension => "jpeg").should == "/S_125_WIDTH_extension_jpeg_q_75__path.jpeg"
86
+ end
87
+
88
+ it "preserves original extension if file has alpha channel" do
89
+ File.should_receive(:exist?).with("/S_125_WIDTH_extension_jpeg_q_75__path.jpeg").and_return(false)
90
+ File.should_receive(:exist?).with("//file.png").and_return(true)
91
+ subject.should_receive(:convert_command).with(/-quality 75/)
92
+ subject.should_receive(:has_alpha?).with("//file.png").and_return(true)
93
+ subject.s_125_width(:quality => 75, :extension => "jpeg").should == "/S_125_WIDTH_extension_jpeg_q_75__path.png"
94
+ end
95
+
96
+ end
97
+ end
98
+
99
+ end
@@ -0,0 +1,34 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+
4
+ class Hash
5
+ def symbolize_keys!
6
+ keys.each do |key|
7
+ self[(key.to_sym rescue key) || key] = delete(key)
8
+ end
9
+ self
10
+ end
11
+ end
12
+
13
+ class Paperclip
14
+ def self.options
15
+ {}
16
+ end
17
+ def self.log msg
18
+ end
19
+ class Attachment
20
+ def initialize
21
+ end
22
+ def path
23
+ "/path.png"
24
+ end
25
+ def url
26
+ "/url"
27
+ end
28
+ def original_filename
29
+ "/file.png"
30
+ end
31
+ end
32
+ end
33
+
34
+ require_relative '../lib/attachment_on_the_fly'
metadata CHANGED
@@ -1,39 +1,37 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: attachment_on_the_fly
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.1.2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
6
5
  platform: ruby
7
- authors:
6
+ authors:
8
7
  - Jeff Sutherland
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
-
13
- date: 2011-02-18 00:00:00 -07:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
11
+ date: 2013-12-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
17
14
  name: paperclip
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
20
- none: false
21
- requirements:
22
- - - ">="
23
- - !ruby/object:Gem::Version
24
- version: "0"
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
25
20
  type: :runtime
26
- version_requirements: *id001
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
27
  description: A Paperclip mix-in to allow auto-generation of resized images
28
28
  email: jefferey.sutherland@gmail.com
29
29
  executables: []
30
-
31
30
  extensions: []
32
-
33
- extra_rdoc_files:
31
+ extra_rdoc_files:
34
32
  - README
35
33
  - README.rdoc
36
- files:
34
+ files:
37
35
  - README
38
36
  - README.rdoc
39
37
  - Rakefile
@@ -41,33 +39,29 @@ files:
41
39
  - attachment_on_the_fly.gemspec
42
40
  - init.rb
43
41
  - lib/attachment_on_the_fly.rb
44
- has_rdoc: true
42
+ - spec/attachment_on_the_fly_spec.rb
43
+ - spec/spec_helper.rb
45
44
  homepage: http://github.com/drpentode/Attachment-on-the-Fly
46
45
  licenses: []
47
-
46
+ metadata: {}
48
47
  post_install_message:
49
48
  rdoc_options: []
50
-
51
- require_paths:
49
+ require_paths:
52
50
  - lib
53
- required_ruby_version: !ruby/object:Gem::Requirement
54
- none: false
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- version: "0"
59
- required_rubygems_version: !ruby/object:Gem::Requirement
60
- none: false
61
- requirements:
62
- - - ">="
63
- - !ruby/object:Gem::Version
64
- version: "0"
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
65
61
  requirements: []
66
-
67
62
  rubyforge_project:
68
- rubygems_version: 1.5.0
63
+ rubygems_version: 2.1.11
69
64
  signing_key:
70
- specification_version: 3
65
+ specification_version: 4
71
66
  summary: A Paperclip mix-in to allow auto-generation of resized images
72
67
  test_files: []
73
-