attachment_on_the_fly 0.1.2 → 0.1.3

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.
@@ -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
-