papercrop 0.2.0 → 0.3.0

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
+ Zjk4MGM0YzdiN2Q3NjNjNGEwN2UzMmI3OGExOWU3YzA5NjNlYzcyYQ==
5
+ data.tar.gz: !binary |-
6
+ OTU0MDE4ODM4YmNkNjQ5MTIxMDFiOWJhOGZjMzM0MzE3ZTBmNmUwZQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YjRjOTM4MDZkYThjZTNlZGUwMTJmMzQxYjFlMGYxNzdjYzg2MGY3YTEzMDY1
10
+ OGI5MTY0NTI0ZDA5NzEzMTZlNTdhYWUzMjU3MDE1YmE2YzVjNDYxZjViZTJi
11
+ ODZmNTY2MWY1OTcwYTBmM2FhOTc0NDA3ZjJlYmU4YzAxN2UzNzA=
12
+ data.tar.gz: !binary |-
13
+ M2YzNmQ1NjUwMjEyMDY2MTIxMWIyYjQ0Yzk3NGM4ZTg2NmNkNjM4Mjk5ODkz
14
+ ZjM3NGQ4ZTAzMWU2MjFkZGE5ZGQ4OTBlMTg4MGJiMmFjYjJhZGY1NWE4NWQ3
15
+ MDNhNDEzZmQ1YmU3YTRhNDgwYmFmMzc2NzE1NmMzMmMyYzYwYmY=
@@ -0,0 +1,10 @@
1
+
2
+ appraise "rails_3_2" do
3
+ gem "rails", "3.2.13"
4
+ gem "paperclip", "3.4.0"
5
+ end
6
+
7
+ appraise "rails_4" do
8
+ gem "rails", "4.0.2"
9
+ gem "paperclip", "4.1.0"
10
+ end
data/README.md CHANGED
@@ -50,13 +50,37 @@ Regardless of the width, the preview box and the cropping area will have the asp
50
50
 
51
51
  If you're rendering it on ajax ensure to call init_papercrop() in js after loading the crop form to make things work properly.
52
52
 
53
+ ### Advanced features
54
+
55
+ **Unlock aspect ratio**
56
+
57
+ You can unlock the aspect ratio if you pass false as argument. NOTE: *preview will be disabled*
58
+
59
+ crop_attached_file :snapshot, :aspect => false
60
+
61
+ Regardless the model, you can always redefine/unlock aspect from the helper if you need to.
62
+
63
+ f.cropbox :snapshot, :width => 500, :aspect => 4..3
64
+
65
+ **Chaining processors**
66
+
67
+ Maybe you want to chain some custom processors to do amazing effects like crop+rotate images. Papercrop will add its processor in last place unless you declare it in the attachment definition
68
+
69
+ has_attached_file :landscape, :styles => {:big => '2000x1500'},
70
+ :processors => [:papercrop, :rotator]
71
+
53
72
  ### Running the Tests
54
73
 
55
- We are using a dummy application to handle some of our test cases. You can find this in the `/test_app` directory and should be able to run this as a regular Rails 4 app _(using the `rails s` command)_ if you're interested in taking a look. You may need to create the mock database for the `test_app` before your tests will start to pass. This means you need to run `rake db:create db:migrate db:test:prepare` from within the `test_app` directory.
74
+ We are using dummy applications to handle some of our test cases with different Gemfiles using [Appraisal](https://github.com/thoughtbot/appraisal). You can find them in the `/test_apps` directory and should be able to run them as a regular Rails app _(using the `rails s` command)_ if you're interested in taking a look. You may need to create mock databases for the `test_apps` before your tests will start to pass. This means you need to run the classics `rake db:create db:migrate db:test:prepare` through appraisal from the root directory.
75
+
76
+ appraisal rails_3_2 rake db:create db:migrate
77
+ appraisal rails_4 rake db:create db:migrate
78
+
79
+ Append RAILS_ENV=test to both commands to prepare each database for testing
56
80
 
57
81
  In order to fully test our gem, we needed to use [Selenium](http://docs.seleniumhq.org/download/). Getting this setup is beyond the scope of this Readme.
58
82
 
59
- Once you have everything setup, you should be able `bundle exec rake` from the root directory have everything run. If you've installed Selenium properly, you should see an automated instance of your browser _(eg. Firefox)_ pop up and run through some of the integration tests.
83
+ Once you have everything setup, you should be able `appraisal rake` from the root directory have everything run. If you've installed Selenium properly, you should see an automated instance of your browser _(eg. Firefox)_ pop up and run through some of the integration tests.
60
84
 
61
85
  That's all!
62
86
 
@@ -9,10 +9,14 @@
9
9
  var aspect = $("input#" + attachment + "_aspect").val();
10
10
  var width = $(this).width();
11
11
 
12
+ if (aspect === 'false') {
13
+ aspect = false
14
+ }
15
+
12
16
  update_crop = function(coords) {
13
17
  var preview_width, rx, ry;
14
18
 
15
- if (preview) {
19
+ if (preview && aspect) {
16
20
  preview_width = $("#" + attachment + "_crop_preview_wrapper").width();
17
21
 
18
22
  rx = preview_width / coords.w;
@@ -36,7 +40,7 @@
36
40
  onChange : update_crop,
37
41
  onSelect : update_crop,
38
42
  setSelect : [0, 0, 250, 250],
39
- aspectRatio : aspect,
43
+ aspectRatio : aspect === false ? undefined : aspect,
40
44
  boxWidth : $("input[id$='_" + attachment + "_box_w']").val()
41
45
  }, function() {
42
46
  jcrop_api = this;
@@ -0,0 +1,33 @@
1
+ require "paperclip"
2
+
3
+ module Paperclip
4
+ class Papercrop < Thumbnail
5
+
6
+ def transformation_command
7
+ if crop_command
8
+ crop_command + super.join(' ').sub(/ -crop \S+/, '').split(' ')
9
+ else
10
+ super
11
+ end
12
+ end
13
+
14
+
15
+ def crop_command
16
+ target = @attachment.instance
17
+
18
+ if target.cropping?(@attachment.name)
19
+ begin
20
+ w = Integer(target.send :"#{@attachment.name}_crop_w")
21
+ h = Integer(target.send :"#{@attachment.name}_crop_h")
22
+ x = Integer(target.send :"#{@attachment.name}_crop_x")
23
+ y = Integer(target.send :"#{@attachment.name}_crop_y")
24
+ ["-crop", "#{w}x#{h}+#{x}+#{y}"]
25
+ rescue Exception => e
26
+ ::Papercrop.log("[papercrop] #{@attachment.name} crop w/h/x/y were non-integer. Error: #{e.to_s}")
27
+ return
28
+ end
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -2,4 +2,5 @@ require 'papercrop/engine'
2
2
  require 'papercrop/reg_exp'
3
3
  require 'papercrop/model_extension'
4
4
  require 'papercrop/helpers'
5
- require 'paperclip_processors/cropper'
5
+ require 'papercrop/logger'
6
+ require 'paperclip_processors/papercrop'
@@ -1,10 +1,10 @@
1
1
  module Papercrop
2
2
  module Helpers
3
-
3
+
4
4
  # Form helper to render the cropping preview box of an attachment.
5
- # Box width can be handled by setting the :width option.
5
+ # Box width can be handled by setting the :width option.
6
6
  # Width is 100 by default. Height is calculated by the aspect ratio.
7
- #
7
+ #
8
8
  # crop_preview :avatar
9
9
  # crop_preview :avatar, :width => 150
10
10
  #
@@ -13,7 +13,7 @@ module Papercrop
13
13
  def crop_preview(attachment, opts = {})
14
14
  attachment = attachment.to_sym
15
15
  width = opts[:width] || 100
16
- height = (width / self.object.send(:"#{attachment}_aspect")).round
16
+ height = (width / self.object.send(:"#{attachment}_aspect")).round
17
17
 
18
18
  if self.object.send(attachment).class == Paperclip::Attachment
19
19
  wrapper_options = {
@@ -34,20 +34,26 @@ module Papercrop
34
34
  #
35
35
  # cropbox :avatar, :width => 650
36
36
  #
37
+ # You can override the aspect ratio used by Jcrop, and even unlock it by setting :aspect to a new value or false
38
+ #
39
+ # cropbox :avatar, :width => 650, :aspect => false
40
+ #
37
41
  # @param attachment [Symbol] attachment name
38
42
  # @param opts [Hash]
39
43
  def cropbox(attachment, opts = {})
40
44
  attachment = attachment.to_sym
41
- original_width = self.object.image_geometry(attachment, :original).width
42
- original_height = self.object.image_geometry(attachment, :original).height
43
- box_width = opts[:width] || original_width
45
+ original_width = self.object.image_geometry(attachment, :original).width.to_i
46
+ original_height = self.object.image_geometry(attachment, :original).height.to_i
47
+ box_width = opts.fetch :width, original_width
48
+ aspect = opts.fetch :aspect, self.object.send(:"#{attachment}_aspect")
44
49
 
45
50
  if self.object.send(attachment).class == Paperclip::Attachment
46
51
  box = self.hidden_field(:"#{attachment}_original_w", :value => original_width)
47
52
  box << self.hidden_field(:"#{attachment}_original_h", :value => original_height)
48
53
  box << self.hidden_field(:"#{attachment}_box_w", :value => box_width)
49
-
50
- for attribute in [:crop_x, :crop_y, :crop_w, :crop_h, :aspect] do
54
+ box << self.hidden_field(:"#{attachment}_aspect", :value => aspect, :id => "#{attachment}_aspect")
55
+
56
+ for attribute in [:crop_x, :crop_y, :crop_w, :crop_h] do
51
57
  box << self.hidden_field(:"#{attachment}_#{attribute}", :id => "#{attachment}_#{attribute}")
52
58
  end
53
59
 
@@ -64,4 +70,4 @@ if defined? ActionView::Helpers::FormBuilder
64
70
  ActionView::Helpers::FormBuilder.class_eval do
65
71
  include Papercrop::Helpers
66
72
  end
67
- end
73
+ end
@@ -0,0 +1,7 @@
1
+ module Papercrop
2
+
3
+ # Paperclip log wrapper
4
+ def self.log(text)
5
+ Paperclip.log(text)
6
+ end
7
+ end
@@ -7,42 +7,63 @@ module Papercrop
7
7
  #
8
8
  # crop_attached_file :avatar
9
9
  #
10
- # You can also define an aspect ratio for the crop and preview box through opts[:aspect]
10
+ # You can also define an initial aspect ratio for the crop and preview box through opts[:aspect]
11
11
  #
12
12
  # crop_attached_file :avatar, :aspect => "4:3"
13
+ #
14
+ # Or unlock it
15
+ #
16
+ # crop_attached_file :avatar, :aspect => false
13
17
  #
14
18
  # @param attachment_name [Symbol] Name of the desired attachment to crop
15
19
  # @param opts [Hash]
20
+ # @option opts [Range, String, FlaseClass] :aspect
16
21
  def crop_attached_file(attachment_name, opts = {})
22
+ opts = opts.dup
23
+
17
24
  [:crop_x, :crop_y, :crop_w, :crop_h, :original_w, :original_h, :box_w, :aspect, :cropped_geometries].each do |a|
18
25
  attr_accessor :"#{attachment_name}_#{a}"
19
26
  end
20
27
 
21
- if opts[:aspect].kind_of?(String) && opts[:aspect] =~ Papercrop::RegExp::ASPECT
22
- opts[:aspect] = Range.new *opts[:aspect].split(':').map(&:to_i)
23
- end
24
-
25
- unless opts[:aspect].kind_of?(Range)
26
- opts[:aspect] = 1..1
27
- end
28
+ aspect = normalize_aspect opts[:aspect]
28
29
 
29
30
  send :define_method, :"#{attachment_name}_aspect" do
30
- opts[:aspect].first.to_f / opts[:aspect].last.to_f
31
+ aspect.first.to_f / aspect.last.to_f if aspect
31
32
  end
32
33
 
33
34
  if respond_to? :attachment_definitions
34
- # for Paperclip <= 3.4
35
+ # for Paperclip <= 3.4
35
36
  definitions = attachment_definitions
36
37
  else
37
38
  # for Paperclip >= 3.5
38
39
  definitions = Paperclip::Tasks::Attachments.instance.definitions_for(self)
39
40
  end
40
41
 
41
- definitions[attachment_name][:processors] ||= []
42
- definitions[attachment_name][:processors] << :cropper
42
+ processors = definitions[attachment_name][:processors] ||= []
43
+ unless processors.include? :papercrop
44
+ processors << :papercrop
45
+ end
43
46
 
44
47
  after_update :"reprocess_to_crop_#{attachment_name}_attachment"
45
48
  end
49
+
50
+
51
+ # Returns a valid and normalized value for aspect ratio
52
+ # It will return 1.. if aspect is nil or a invalid string
53
+ # @param aspect [Range, String, FalseClass]
54
+ #
55
+ # @return [Range]
56
+ def normalize_aspect(aspect)
57
+ if aspect.kind_of?(String) && aspect =~ Papercrop::RegExp::ASPECT
58
+ Range.new *aspect.split(':').map(&:to_i)
59
+ elsif aspect.kind_of?(Range)
60
+ return aspect.first.to_i..aspect.last.to_i
61
+ elsif aspect == false
62
+ return aspect
63
+ else
64
+ 1..1
65
+ end
66
+ end
46
67
  end
47
68
 
48
69
 
@@ -50,7 +71,7 @@ module Papercrop
50
71
 
51
72
  # Asks if the attachment received a crop process
52
73
  # @param attachment_name [Symbol]
53
- #
74
+ #
54
75
  # @return [Boolean]
55
76
  def cropping?(attachment_name)
56
77
  !self.send(:"#{attachment_name}_crop_x").blank? &&
@@ -66,9 +87,12 @@ module Papercrop
66
87
  # @param style = :original [Symbol] attachment style
67
88
  # @return [Paperclip::Geometry]
68
89
  def image_geometry(attachment_name, style = :original)
69
- @geometry ||= {}
70
- path = (self.send(attachment_name).options[:storage] == :s3) ? self.send(attachment_name).url(style) : self.send(attachment_name).path(style)
71
- @geometry[style] ||= Paperclip::Geometry.from_file(path)
90
+ @geometry ||= {}
91
+ @geometry[attachment_name] ||= {}
92
+
93
+ path = (self.send(attachment_name).options[:storage] == :filesystem) ? self.send(attachment_name).path(style) : self.send(attachment_name).url(style)
94
+
95
+ @geometry[attachment_name][style] ||= Paperclip::Geometry.from_file(path)
72
96
  end
73
97
 
74
98
 
@@ -121,7 +145,7 @@ end
121
145
 
122
146
 
123
147
  # Mongoid support
124
- if defined? Mongoid::Document
148
+ if defined? Mongoid::Document
125
149
  Mongoid::Document::ClassMethods.module_eval do
126
150
  include Papercrop::ModelExtension::ClassMethods
127
151
  end
Binary file
@@ -4,7 +4,7 @@ describe "Form Helpers" do
4
4
 
5
5
  before do
6
6
  @landscape = Landscape.new(:name => "Mountains")
7
- @landscape.picture = open("test_app/test/fixtures/matterhorn.jpg")
7
+ @landscape.picture = open(mountains_img_path)
8
8
  @landscape.save
9
9
 
10
10
  @box = nil
@@ -17,10 +17,10 @@ describe "Form Helpers" do
17
17
  end
18
18
  @box = HTML::Document.new(@box)
19
19
 
20
- assert_select @box.root, 'input#landscape_picture_original_w', :value => "1024.0"
21
- assert_select @box.root, 'input#landscape_picture_original_h', :value => "768.0"
22
- assert_select @box.root, 'input#landscape_picture_box_w', :value => "1024.0"
23
- assert_select @box.root, 'input#picture_aspect', :value => @landscape.picture_aspect.to_s
20
+ assert_select @box.root, 'input#landscape_picture_original_w[value="1024"]'
21
+ assert_select @box.root, 'input#landscape_picture_original_h[value="768"]'
22
+ assert_select @box.root, 'input#landscape_picture_box_w[value="1024"]'
23
+ assert_select @box.root, "input#picture_aspect[value=\"#{@landscape.picture_aspect.to_s}\"]"
24
24
  assert_select @box.root, 'input#picture_crop_x'
25
25
  assert_select @box.root, 'input#picture_crop_y'
26
26
  assert_select @box.root, 'input#picture_crop_w'
@@ -38,7 +38,17 @@ describe "Form Helpers" do
38
38
  end
39
39
  @box = HTML::Document.new(@box)
40
40
 
41
- assert_select @box.root, 'input#landscape_picture_box_w', :value => "400"
41
+ assert_select @box.root, 'input#landscape_picture_box_w[value="400"]'
42
+ end
43
+
44
+
45
+ it "builds the crop box with unlocked aspect flag" do
46
+ form_for @landscape do |f|
47
+ @box = f.cropbox(:picture, :width => 400, :aspect => false)
48
+ end
49
+ @box = HTML::Document.new(@box)
50
+
51
+ assert_select @box.root, 'input#picture_aspect[value="false"]'
42
52
  end
43
53
 
44
54
 
@@ -48,8 +58,8 @@ describe "Form Helpers" do
48
58
  end
49
59
  @box = HTML::Document.new(@box)
50
60
 
51
- assert_select @box.root, 'div#picture_crop_preview_wrapper', :style => "width:100px; height:75px; overflow:hidden" do
52
- assert_select 'img#picture_crop_preview', :src => @landscape.picture.path(:original)
61
+ assert_select @box.root, 'div#picture_crop_preview_wrapper[style="width:100px; height:75px; overflow:hidden"]' do
62
+ assert_select "img#picture_crop_preview[src=\"#{@landscape.picture.url(:original)}\"]"
53
63
  end
54
64
  end
55
65
 
@@ -60,6 +70,6 @@ describe "Form Helpers" do
60
70
  end
61
71
  @box = HTML::Document.new(@box)
62
72
 
63
- assert_select @box.root, 'div#picture_crop_preview_wrapper', :style => "width:40px; height:30px; overflow:hidden"
73
+ assert_select @box.root, 'div#picture_crop_preview_wrapper[style="width:40px; height:30px; overflow:hidden"]'
64
74
  end
65
- end
75
+ end
@@ -8,7 +8,7 @@ describe "Image crop with JS", :js => true do
8
8
  click_link "New Landscape"
9
9
 
10
10
  fill_in "Name", :with => "Mountains"
11
- find("#landscape_picture").native.send_keys(File.expand_path("../../../test_app/test/fixtures/matterhorn.jpg", __FILE__))
11
+ find("#landscape_picture").native.send_keys(File.expand_path("../../../#{mountains_img_path}", __FILE__))
12
12
  click_button "Create Landscape"
13
13
 
14
14
  sleep 2
@@ -19,7 +19,7 @@ describe "Image crop with JS", :js => true do
19
19
  click_button "Crop image"
20
20
 
21
21
  sleep 1
22
- compare_images(CROPPED_IMG_PATH, Landscape.last.picture.path(:medium)).round(2).should eq(0.0)
22
+ compare_images(expected_mountains_img_path, Landscape.last.picture.path(:medium)).round(2).should eq(0.0)
23
23
  end
24
24
 
25
25
 
@@ -29,7 +29,7 @@ describe "Image crop with JS", :js => true do
29
29
  click_link "New Landscape"
30
30
 
31
31
  fill_in "Name", :with => "Mountains"
32
- find("#landscape_picture").native.send_keys(File.expand_path("../../../test_app/test/fixtures/matterhorn.jpg", __FILE__))
32
+ find("#landscape_picture").native.send_keys(File.expand_path(File.expand_path("../../../#{mountains_img_path}", __FILE__), __FILE__))
33
33
  click_button "Create Landscape"
34
34
 
35
35
  click_button "Crop image"
@@ -45,6 +45,6 @@ describe "Image crop with JS", :js => true do
45
45
  click_button "Crop image"
46
46
 
47
47
  sleep 1
48
- compare_images(CROPPED_IMG_PATH, Landscape.last.picture.path(:medium)).round(2).should eq(0.0)
48
+ compare_images(expected_mountains_img_path, Landscape.last.picture.path(:medium)).round(2).should eq(0.0)
49
49
  end
50
50
  end
@@ -8,7 +8,7 @@ describe "Image crop" do
8
8
  click_link "New Landscape"
9
9
 
10
10
  fill_in "Name", :with => "Mountains"
11
- attach_file "Picture", "test_app/test/fixtures/matterhorn.jpg"
11
+ attach_file "Picture", mountains_img_path
12
12
  click_button "Create Landscape"
13
13
 
14
14
  page.should have_css("#picture_crop_preview_wrapper")
@@ -17,18 +17,18 @@ describe "Image crop" do
17
17
 
18
18
  page.should have_css("#landscape_picture_original_w")
19
19
 
20
- find("#landscape_picture_original_w").value.should eq("1024.0")
21
- find("#landscape_picture_original_h").value.should eq("768.0")
20
+ find("#landscape_picture_original_w").value.should eq("1024")
21
+ find("#landscape_picture_original_h").value.should eq("768")
22
22
  find("#landscape_picture_box_w").value.should eq("600")
23
23
  find("#picture_aspect").value.should eq((4.0 / 3.0).to_s)
24
24
 
25
- find("#picture_crop_x").set "300.0"
26
- find("#picture_crop_y").set "200.0"
25
+ find("#picture_crop_x").set "300"
26
+ find("#picture_crop_y").set "200"
27
27
  find("#picture_crop_w").set "400"
28
28
  find("#picture_crop_h").set "300"
29
29
 
30
30
  click_button "Crop image"
31
31
 
32
- compare_images(CROPPED_IMG_PATH, Landscape.last.picture.path(:medium)).round(2).should eq(0.0)
32
+ compare_images(expected_mountains_img_path, Landscape.last.picture.path(:medium)).round(2).should eq(0.0)
33
33
  end
34
34
  end
@@ -4,14 +4,19 @@ describe "Model Extension" do
4
4
 
5
5
  before do
6
6
  @landscape = Landscape.new(:name => "Mountains")
7
- @landscape.picture = open("test_app/test/fixtures/matterhorn.jpg")
7
+ @landscape.picture = open(mountains_img_path)
8
8
  @landscape.save
9
+
10
+ @user = User.new(:name => "Bert", :email => "bert@sesame.street")
11
+ @user.avatar = open(bert_img_path)
12
+ @user.signature = open(mountains_img_path)
13
+ @user.save
9
14
  end
10
15
 
11
16
 
12
17
  it "clears the crop attributes" do
13
- @landscape.picture_crop_x = 0.0
14
- @landscape.picture_crop_y = 0.0
18
+ @landscape.picture_crop_x = 0
19
+ @landscape.picture_crop_y = 0
15
20
  @landscape.picture_crop_w = 400
16
21
  @landscape.picture_crop_h = 300
17
22
  @landscape.reset_crop_attributes_of(:picture)
@@ -24,13 +29,13 @@ describe "Model Extension" do
24
29
 
25
30
 
26
31
  it "crops images" do
27
- @landscape.picture_crop_x = 300.0
28
- @landscape.picture_crop_y = 200.0
32
+ @landscape.picture_crop_x = 300
33
+ @landscape.picture_crop_y = 200
29
34
  @landscape.picture_crop_w = 400
30
35
  @landscape.picture_crop_h = 300
31
36
  @landscape.save
32
37
  # Rounding to account for different versions of imagemagick
33
- compare_images(CROPPED_IMG_PATH, @landscape.picture.path(:medium)).round(2).should eq(0.0)
38
+ compare_images(expected_mountains_img_path, @landscape.picture.path(:medium)).round(2).should eq(0.0)
34
39
  end
35
40
 
36
41
 
@@ -51,25 +56,73 @@ describe "Model Extension" do
51
56
 
52
57
  it "knows when to crop" do
53
58
  @landscape.cropping?(:picture).should be(false)
54
- @landscape.picture_crop_x = 0.0
55
- @landscape.picture_crop_y = 0.0
59
+ @landscape.picture_crop_x = 0
60
+ @landscape.picture_crop_y = 0
56
61
  @landscape.picture_crop_w = 400
57
62
  @landscape.picture_crop_h = 300
58
63
  @landscape.cropping?(:picture).should be(true)
59
64
  end
60
65
 
61
66
 
67
+ it "normalizes aspect ratio" do
68
+ Landscape.normalize_aspect(4..3).should eq(4..3)
69
+ Landscape.normalize_aspect("4:3").should eq(4..3)
70
+ Landscape.normalize_aspect("4".."3").should eq(4..3)
71
+ Landscape.normalize_aspect(4.0..3.0).should eq(4..3)
72
+ Landscape.normalize_aspect(false).should eq(false)
73
+ Landscape.normalize_aspect(nil).should eq(1..1)
74
+ Landscape.normalize_aspect(true).should eq(1..1)
75
+ Landscape.normalize_aspect("foo").should eq(1..1)
76
+ end
77
+
78
+
62
79
  it "registers the post processor" do
63
- definitions = Paperclip::AttachmentRegistry.definitions_for(Landscape)
64
- definitions[:picture][:processors].should eq([:cropper])
80
+ definitions = retrieve_attachment_definitions_for(Landscape)
81
+
82
+ definitions[:picture][:processors].should eq([:papercrop])
83
+ end
84
+
85
+
86
+ it "does not register the processor if it's already there" do
87
+ Landscape.has_attached_file :processed, :styles => {:medium => "200x200#"}, :processors => [:papercrop, :rotator]
88
+ Landscape.crop_attached_file :processed
89
+
90
+ definitions = retrieve_attachment_definitions_for(Landscape)
91
+
92
+ definitions[:processed][:processors].should eq([:papercrop, :rotator])
93
+
94
+ Landscape._update_callbacks.delete_if {|e| e.instance_values['filter'] == :reprocess_to_crop_processed_attachment }
65
95
  end
66
96
 
67
97
 
68
98
  it "returns image properties" do
69
99
  @landscape.picture_aspect.should eq(4.0 / 3.0)
70
100
 
71
- @landscape.image_geometry(:picture).width.should eq(1024.0)
72
- @landscape.image_geometry(:picture).height.should eq(768.0)
101
+ @landscape.image_geometry(:picture).width.should eq(1024)
102
+ @landscape.image_geometry(:picture).height.should eq(768)
103
+ end
104
+
105
+
106
+ it "returns image geometry for two attachments" do
107
+ @user.image_geometry(:avatar).width.should eq(900)
108
+ @user.image_geometry(:avatar).height.should eq(900)
109
+ @user.image_geometry(:avatar, :medium).width.should eq(200)
110
+ @user.image_geometry(:avatar, :medium).height.should eq(200)
111
+ @user.image_geometry(:signature).width.should eq(1024)
112
+ @user.image_geometry(:signature).height.should eq(768)
113
+ @user.image_geometry(:signature, :medium).width.should eq(496)
114
+ @user.image_geometry(:signature, :medium).height.should eq(279)
115
+ end
116
+
117
+
118
+ it "sanitizes processor" do
119
+ Papercrop.expects(:log).with('[papercrop] picture crop w/h/x/y were non-integer. Error: invalid value for Integer(): "evil code"').twice
120
+
121
+ @landscape.picture_crop_x = "evil code"
122
+ @landscape.picture_crop_y = 200
123
+ @landscape.picture_crop_w = 400
124
+ @landscape.picture_crop_h = 300
125
+ @landscape.save
73
126
  end
74
127
 
75
128
 
@@ -80,4 +133,13 @@ describe "Model Extension" do
80
133
 
81
134
  @landscape.image_geometry(:picture)
82
135
  end
136
+
137
+
138
+ it "returns url for fog storage" do
139
+ @landscape.picture.expects(:url).returns("http://some-aws-s3-fog-storage-url").once
140
+ @landscape.picture.expects(:options).returns(:storage => :fog).once
141
+ Paperclip::Geometry.expects(:from_file).with("http://some-aws-s3-fog-storage-url").once
142
+
143
+ @landscape.image_geometry(:picture)
144
+ end
83
145
  end
@@ -1,6 +1,8 @@
1
1
  # This file is copied to spec/ when you run 'rails generate rspec:install'
2
2
  ENV["RAILS_ENV"] = 'test'
3
- require File.expand_path("../../test_app/config/environment", __FILE__)
3
+ ENV["TEST_APP"] ||= 'rails_4'
4
+
5
+ require File.expand_path("../../test_apps/#{ENV["TEST_APP"]}/config/environment", __FILE__)
4
6
  require 'rspec/rails'
5
7
  require 'rspec/autorun'
6
8
  require 'database_cleaner'
@@ -9,9 +11,6 @@ require 'database_cleaner'
9
11
  # in spec/support/ and its subdirectories.
10
12
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
13
 
12
- # Previously cropped image. Used for comparing test cropped images with RMagick
13
- CROPPED_IMG_PATH = "test_app/test/fixtures/test_img.jpg"
14
-
15
14
  RSpec.configure do |config|
16
15
  # ## Mock Framework
17
16
  #
@@ -5,4 +5,28 @@ def compare_images(test_image_path, cropped_image_path)
5
5
  target_img = Magick::Image::read(cropped_image_path).first
6
6
 
7
7
  test_img.compare_channel(target_img, Magick::MeanAbsoluteErrorMetric).second
8
+ end
9
+
10
+
11
+ def retrieve_attachment_definitions_for(model_class)
12
+ if model_class.respond_to?(:attachment_definitions)
13
+ model_class.attachment_definitions
14
+ else
15
+ Paperclip::AttachmentRegistry.definitions_for(model_class)
16
+ end
17
+ end
18
+
19
+
20
+ def mountains_img_path
21
+ "spec/fixtures/mountains.jpg"
22
+ end
23
+
24
+
25
+ def expected_mountains_img_path
26
+ "spec/fixtures/mountains_expected_result.jpg"
27
+ end
28
+
29
+
30
+ def bert_img_path
31
+ "spec/fixtures/bert.jpg"
8
32
  end
File without changes
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: papercrop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
5
- prerelease:
4
+ version: 0.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ruben Santamaria
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-02-28 00:00:00.000000000 Z
11
+ date: 2015-09-23 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rails
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ! '>='
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ! '>='
28
25
  - !ruby/object:Gem::Version
@@ -30,7 +27,6 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: jquery-rails
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ! '>='
36
32
  - !ruby/object:Gem::Version
@@ -38,7 +34,6 @@ dependencies:
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ! '>='
44
39
  - !ruby/object:Gem::Version
@@ -46,7 +41,6 @@ dependencies:
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: paperclip
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ! '>='
52
46
  - !ruby/object:Gem::Version
@@ -54,7 +48,6 @@ dependencies:
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ! '>='
60
53
  - !ruby/object:Gem::Version
@@ -62,7 +55,6 @@ dependencies:
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: rspec-rails
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - ~>
68
60
  - !ruby/object:Gem::Version
@@ -70,7 +62,6 @@ dependencies:
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - ~>
76
67
  - !ruby/object:Gem::Version
@@ -78,7 +69,6 @@ dependencies:
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: capybara
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
73
  - - ! '>='
84
74
  - !ruby/object:Gem::Version
@@ -86,7 +76,6 @@ dependencies:
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
80
  - - ! '>='
92
81
  - !ruby/object:Gem::Version
@@ -94,7 +83,6 @@ dependencies:
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: mocha
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
87
  - - ! '>='
100
88
  - !ruby/object:Gem::Version
@@ -102,7 +90,6 @@ dependencies:
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
94
  - - ! '>='
108
95
  - !ruby/object:Gem::Version
@@ -110,7 +97,6 @@ dependencies:
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: rmagick
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
101
  - - ! '>='
116
102
  - !ruby/object:Gem::Version
@@ -118,7 +104,6 @@ dependencies:
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
108
  - - ! '>='
124
109
  - !ruby/object:Gem::Version
@@ -126,7 +111,6 @@ dependencies:
126
111
  - !ruby/object:Gem::Dependency
127
112
  name: sass
128
113
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
114
  requirements:
131
115
  - - ! '>='
132
116
  - !ruby/object:Gem::Version
@@ -134,7 +118,6 @@ dependencies:
134
118
  type: :development
135
119
  prerelease: false
136
120
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
121
  requirements:
139
122
  - - ! '>='
140
123
  - !ruby/object:Gem::Version
@@ -142,7 +125,6 @@ dependencies:
142
125
  - !ruby/object:Gem::Dependency
143
126
  name: sqlite3
144
127
  requirement: !ruby/object:Gem::Requirement
145
- none: false
146
128
  requirements:
147
129
  - - ! '>='
148
130
  - !ruby/object:Gem::Version
@@ -150,7 +132,6 @@ dependencies:
150
132
  type: :development
151
133
  prerelease: false
152
134
  version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
135
  requirements:
155
136
  - - ! '>='
156
137
  - !ruby/object:Gem::Version
@@ -158,7 +139,6 @@ dependencies:
158
139
  - !ruby/object:Gem::Dependency
159
140
  name: database_cleaner
160
141
  requirement: !ruby/object:Gem::Requirement
161
- none: false
162
142
  requirements:
163
143
  - - ! '>='
164
144
  - !ruby/object:Gem::Version
@@ -166,7 +146,6 @@ dependencies:
166
146
  type: :development
167
147
  prerelease: false
168
148
  version_requirements: !ruby/object:Gem::Requirement
169
- none: false
170
149
  requirements:
171
150
  - - ! '>='
172
151
  - !ruby/object:Gem::Version
@@ -174,7 +153,6 @@ dependencies:
174
153
  - !ruby/object:Gem::Dependency
175
154
  name: selenium-webdriver
176
155
  requirement: !ruby/object:Gem::Requirement
177
- none: false
178
156
  requirements:
179
157
  - - ! '>='
180
158
  - !ruby/object:Gem::Version
@@ -182,7 +160,20 @@ dependencies:
182
160
  type: :development
183
161
  prerelease: false
184
162
  version_requirements: !ruby/object:Gem::Requirement
185
- none: false
163
+ requirements:
164
+ - - ! '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: appraisal
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
186
177
  requirements:
187
178
  - - ! '>='
188
179
  - !ruby/object:Gem::Version
@@ -193,21 +184,26 @@ executables: []
193
184
  extensions: []
194
185
  extra_rdoc_files: []
195
186
  files:
196
- - lib/assets/images/Jcrop.gif
197
- - lib/assets/javascripts/jquery.jcrop.js
198
187
  - lib/assets/javascripts/papercrop.js
199
- - lib/assets/stylesheets/jquery.jcrop.css
200
- - lib/paperclip_processors/cropper.rb
188
+ - lib/paperclip_processors/papercrop.rb
201
189
  - lib/papercrop/engine.rb
202
190
  - lib/papercrop/helpers.rb
191
+ - lib/papercrop/logger.rb
203
192
  - lib/papercrop/model_extension.rb
204
193
  - lib/papercrop/reg_exp.rb
205
194
  - lib/papercrop.rb
206
- - vendor/jcrop-v0.9.10/css/Jcrop.gif
207
- - vendor/jcrop-v0.9.10/css/jquery.Jcrop.css
208
- - vendor/jcrop-v0.9.10/js/jquery.Jcrop.js
209
- - vendor/jcrop-v0.9.10/MIT-LICENSE.txt
195
+ - vendor/assets/images/Jcrop.gif
196
+ - vendor/assets/javascripts/jquery.jcrop.js
197
+ - vendor/assets/stylesheets/jquery.jcrop.css
198
+ - vendor/src.jcrop-v0.9.10/css/Jcrop.gif
199
+ - vendor/src.jcrop-v0.9.10/css/jquery.Jcrop.css
200
+ - vendor/src.jcrop-v0.9.10/js/jquery.Jcrop.js
201
+ - vendor/src.jcrop-v0.9.10/MIT-LICENSE.txt
210
202
  - README.md
203
+ - Appraisals
204
+ - spec/fixtures/bert.jpg
205
+ - spec/fixtures/mountains.jpg
206
+ - spec/fixtures/mountains_expected_result.jpg
211
207
  - spec/helpers/form_helpers_spec.rb
212
208
  - spec/integration/papercrop_js_spec.rb
213
209
  - spec/integration/papercrop_spec.rb
@@ -218,35 +214,31 @@ files:
218
214
  homepage: https://github.com/rsantamaria/papercrop
219
215
  licenses:
220
216
  - MIT
217
+ metadata: {}
221
218
  post_install_message:
222
219
  rdoc_options: []
223
220
  require_paths:
224
221
  - lib
225
222
  required_ruby_version: !ruby/object:Gem::Requirement
226
- none: false
227
223
  requirements:
228
224
  - - ! '>='
229
225
  - !ruby/object:Gem::Version
230
226
  version: '0'
231
- segments:
232
- - 0
233
- hash: 3120983817575737500
234
227
  required_rubygems_version: !ruby/object:Gem::Requirement
235
- none: false
236
228
  requirements:
237
229
  - - ! '>='
238
230
  - !ruby/object:Gem::Version
239
231
  version: '0'
240
- segments:
241
- - 0
242
- hash: 3120983817575737500
243
232
  requirements: []
244
233
  rubyforge_project:
245
- rubygems_version: 1.8.25
234
+ rubygems_version: 2.1.0
246
235
  signing_key:
247
- specification_version: 3
236
+ specification_version: 4
248
237
  summary: Paperclip extension for cropping images
249
238
  test_files:
239
+ - spec/fixtures/bert.jpg
240
+ - spec/fixtures/mountains.jpg
241
+ - spec/fixtures/mountains_expected_result.jpg
250
242
  - spec/helpers/form_helpers_spec.rb
251
243
  - spec/integration/papercrop_js_spec.rb
252
244
  - spec/integration/papercrop_spec.rb
@@ -1,28 +0,0 @@
1
- require "paperclip"
2
-
3
- module Paperclip
4
- class Cropper < Thumbnail
5
-
6
- def transformation_command
7
- if crop_command
8
- crop_command + super.join(' ').sub(/ -crop \S+/, '').split(' ')
9
- else
10
- super
11
- end
12
- end
13
-
14
-
15
- def crop_command
16
- target = @attachment.instance
17
-
18
- if target.cropping?(@attachment.name)
19
- w = target.send :"#{@attachment.name}_crop_w"
20
- h = target.send :"#{@attachment.name}_crop_h"
21
- x = target.send :"#{@attachment.name}_crop_x"
22
- y = target.send :"#{@attachment.name}_crop_y"
23
- ["-crop", "#{w}x#{h}+#{x}+#{y}"]
24
- end
25
- end
26
-
27
- end
28
- end