paper_cropper 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 765ec5c7bbb8a9db019e7c04a976c98a61d0b5ce
4
+ data.tar.gz: db472297bc0ae0fe57f463d113141514198fefaa
5
+ SHA512:
6
+ metadata.gz: 8005e706ae466fb0029f9c34aee3fe5929fbee660b7bd9486347267c1ad657a84717e3204fc2caf83338f709a57b2784659a3acdab82f9938f516a61ebe7f68e
7
+ data.tar.gz: 81906bd23691a56d4617c5ebe2981efc16b9995c37315eca45adae02ced0d7a3137e8bea97dc2e0f03b669e789da56db4df93c5fcf6e62aabffa9d7a2eaebdb0
data/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # PaperCropper gem
2
+
3
+ PaperCropper gem is a gem for cropping images using [cropper js](https://github.com/fengyuanchen/cropperjs) and [Paperclip](https://github.com/thoughtbot/paperclip)
4
+
5
+ All examples are based on a `cover` attachment
6
+
7
+ ## migrations
8
+
9
+ ```ruby
10
+ create_table :gallery_albums do |t|
11
+ t.attachment :cover # paperclip required
12
+ t.crop_attachment :cover # add extra columns for crop
13
+ end
14
+ ```
15
+
16
+ ## model
17
+
18
+ ```ruby
19
+ # aspect 1:1
20
+ crop_attached_file :cover
21
+
22
+ # aspect 16:4
23
+ crop_attached_file :cover, aspect: '16:4'
24
+
25
+ # free (without aspect restriction)
26
+ crop_attached_file :cover, aspect: false
27
+ ```
28
+
29
+ ## controler
30
+ Take care of permitted params. Add the following fields to ```permitted``` strong attributes:
31
+
32
+ ```ruby
33
+ :cover_crop_x, :cover_crop_y, :cover_crop_width, :cover_crop_height
34
+ ```
35
+
36
+ ## javascripts
37
+
38
+ ~~~
39
+ //= require cropper
40
+ //= require paper_cropper
41
+
42
+ // Crop
43
+ $('.crop-image-container').each(function(){
44
+ papercropper = new PaperCropper(this, {})
45
+ });
46
+ ~~~
47
+
48
+ ## scss
49
+
50
+ ~~~
51
+ @import "cropper";
52
+ @import "paper_cropper";
53
+ ~~~
54
+
55
+ The paper_cropper is not required, is only for a small changes. The only thing required from 'paper_cropper' is this rule:
56
+
57
+ ~~~
58
+ /* Limit image width to avoid overflow the container */
59
+ .crop-image-container img.crop-image {
60
+ max-width: 100%; /* This rule is very important, please do not ignore this! */
61
+ }
62
+ ~~~
63
+
64
+ ---------------------------------------------
65
+
66
+ ## helpers
67
+
68
+ helper, with twitter bootstrap classes, custom formatted, and other things
69
+
70
+ ~~~
71
+ <%= form_for ..... %>
72
+ <%= f.tws_cropper_box :cover %>
73
+ <% end %>
74
+ ~~~
75
+
76
+ **custom (without helper)**
77
+
78
+ if you do not want to use helper, you can do what you want, for example you could make the file selector ".crop-image-file-input" below the picture "crop-image-wrapper"
79
+
80
+ the most important thing is to keep the "crop-image ..." classes and "crop-image-container" and "crop-image-wrapper" containers
81
+
82
+ for example:
83
+
84
+ ~~~
85
+ <!-- [required] Main container (you need to supply this in JS constructor) -->
86
+ <div class="crop-image-container">
87
+ <!-- [required] Hidden input for save the crop values -->
88
+ <input class="crop-image-value-x" type="hidden" name="cover_crop_x" value="">
89
+ <input class="crop-image-value-y" type="hidden" name="cover_crop_y" value="">
90
+ <input class="crop-image-value-width" type="hidden" name="cover_crop_width" value="">
91
+ <input class="crop-image-value-height" type="hidden" name="cover_crop_height" value="">
92
+
93
+ <!-- [required] Wrap the image or canvas element with a block element (container) -->
94
+ <div class="crop-image-wrapper">
95
+ <!-- [required] Image to crop -->
96
+ <img class="crop-image" src="">
97
+ </div>
98
+
99
+ <!-- [required] File input for change the image -->
100
+ <input class="crop-image-file-input" type="file">
101
+
102
+ <!-- [optional] Buttons -->
103
+ <button class="crop-image-btn-zoom-in" type="button">Zoom in</button>
104
+ <button class="crop-image-btn-zoom-out" type="button">Zoom out</button>
105
+ <button class="crop-image-btn-move-left" type="button">Move left</button>
106
+ <button class="crop-image-btn-move-right" type="button">Move right</button>
107
+ <button class="crop-image-btn-move-up" type="button">Move up</button>
108
+ <button class="crop-image-btn-move-down" type="button">Move down</button>
109
+ </div>
110
+ ~~~
111
+
112
+ # License
113
+
114
+ PaperCropper is Copyright © 2016 CodiTramuntana SL. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
115
+
116
+ # About CodiTramuntana
117
+
118
+ ![coditramuntana](http://www.coditramuntana.com/assets/ic_logo_medium.png)
119
+
120
+ PaperCropper is maintained by [CodiTramuntana](http://www.coditramuntana.com).
121
+ PaperCropper is the mix of [cropper js](https://github.com/fengyuanchen/cropperjs) and
122
+ [Paperclip](https://github.com/thoughtbot/paperclip) and some glue code to make things
123
+ easier.
124
+
125
+ The names and logos for CodiTramuntana are trademarks of CodiTramuntana SL.
126
+
127
+ We love open source software!
@@ -0,0 +1,149 @@
1
+ /**
2
+ * PaperCropper
3
+ *
4
+ * @param container
5
+ * Main container of objects
6
+ * @param options
7
+ * Extra options
8
+ *
9
+ * Example, important all classes used for crop starts with "crop-image*"
10
+ * The buttons, classes 'crop-image-btn-*' are optional
11
+ *
12
+ <!-- Main container (you need to supply this in constructor) -->
13
+ <div class="crop-image-container">
14
+ <!-- Hidden input for save the crop values -->
15
+ <input class="crop-image-value-x" type="hidden" name="cover_crop_x" value="">
16
+ <input class="crop-image-value-y" type="hidden" name="cover_crop_y" value="">
17
+ <input class="crop-image-value-width" type="hidden" name="cover_crop_width" value="">
18
+ <input class="crop-image-value-height" type="hidden" name="cover_crop_height" value="">
19
+
20
+ <!-- File input for change the image -->
21
+ <input class="crop-image-file-input" type="file">
22
+
23
+ <hr>
24
+
25
+ <!-- Wrap the image or canvas element with a block element (container) -->
26
+ <div class="crop-image-wrapper">
27
+ <img class="crop-image" src="">
28
+ </div>
29
+
30
+ <hr>
31
+
32
+ <button class="crop-image-btn-zoom-in" type="button">Zoom in</button>
33
+ <button class="crop-image-btn-zoom-out" type="button">Zoom out</button>
34
+ <button class="crop-image-btn-move-left" type="button">Move left</button>
35
+ <button class="crop-image-btn-move-right" type="button">Move right</button>
36
+ <button class="crop-image-btn-move-up" type="button">Move up</button>
37
+ <button class="crop-image-btn-move-down" type="button">Move down</button>
38
+ </div>
39
+
40
+ */
41
+ function PaperCropper(container, opt) {
42
+ var that = this;
43
+ this.container = $(container);
44
+ this.image = $(container).find('.crop-image');
45
+ this.inputX = $(container).find('.crop-image-value-x');
46
+ this.inputY = $(container).find('.crop-image-value-y');
47
+ this.inputWidth = $(container).find('.crop-image-value-width');
48
+ this.inputHeight = $(container).find('.crop-image-value-height');
49
+
50
+ var aspect = $(container).attr('data-crop-image-range');
51
+ if( isNaN(aspect) ) {
52
+ this.aspect = null;
53
+ } else {
54
+ this.aspect = parseFloat(aspect);
55
+ }
56
+
57
+ this.init();
58
+ }
59
+
60
+ /** Check if browswer support it */
61
+ PaperCropper.isSupported = function() {
62
+ return (typeof FileReader !== "undefined");
63
+ }
64
+
65
+ /** Initializes all */
66
+ PaperCropper.prototype.init = function() {
67
+ var fileInput = this.container.find('input.crop-image-file-input');
68
+ var that = this;
69
+
70
+ // file input change
71
+ fileInput.change(function(event){
72
+ that.fileInputChange(event);
73
+ });
74
+
75
+ // cropper
76
+ this.cropper = new Cropper(this.image[0], {
77
+ aspectRatio: this.aspect,
78
+ crop: function(event){
79
+ that.cropperCrop(event);
80
+ },
81
+ built: function() {
82
+ console.log('cropper build')
83
+ that.cropperBuild();
84
+ }
85
+ });
86
+
87
+
88
+ // buttons
89
+ this.container.find('.crop-image-btn-zoom-in').click(function(){
90
+ that.cropper.zoom(0.1);
91
+ });
92
+ this.container.find('.crop-image-btn-zoom-out').click(function(){
93
+ that.cropper.zoom(-0.1);
94
+ });
95
+ this.container.find('.crop-image-btn-move-left').click(function(){
96
+ that.cropper.move(-10,0);
97
+ });
98
+ this.container.find('.crop-image-btn-move-right').click(function(){
99
+ that.cropper.move(10,0);
100
+ });
101
+ this.container.find('.crop-image-btn-move-up').click(function(){
102
+ that.cropper.move(0,-10);
103
+ });
104
+ this.container.find('.crop-image-btn-move-down').click(function(){
105
+ that.cropper.move(0,10);
106
+ });
107
+ }
108
+
109
+ /** Callback method used when cropper are full loaded */
110
+ PaperCropper.prototype.cropperBuild = function() {
111
+ // set initial values
112
+ this.setCropperData(this.inputX.val(), this.inputY.val(), this.inputWidth.val(), this.inputHeight.val());
113
+ }
114
+
115
+ /** Callback method used when the user changes the crop */
116
+ PaperCropper.prototype.cropperCrop = function (event) {
117
+ console.log('crop:',event.detail)
118
+ console.log('crop crop data:',this.cropper.getData())
119
+ this.inputX.val(parseInt(event.detail.x));
120
+ this.inputY.val(parseInt(event.detail.y));
121
+ this.inputWidth.val(parseInt(event.detail.width));
122
+ this.inputHeight.val(parseInt(event.detail.height));
123
+ }
124
+
125
+ /** Callback method used when the user changes the file */
126
+ PaperCropper.prototype.fileInputChange = function (event) {
127
+ var input = event.target;
128
+ var that = this;
129
+ if (input.files && input.files[0]) {
130
+ var reader = new FileReader();
131
+ reader.onload = function (e) {
132
+ that.cropper.replace(e.target.result);
133
+ }
134
+ reader.readAsDataURL(input.files[0]);
135
+ }
136
+ }
137
+
138
+ /** Set the cropper data */
139
+ PaperCropper.prototype.setCropperData = function (x, y, width, height) {
140
+ this.cropper.setData({
141
+ 'x': parseInt(x),
142
+ 'y': parseInt(y),
143
+ 'width': parseInt(width),
144
+ 'height': parseInt(height),
145
+ 'rotate': 0,
146
+ 'scaleX': 1,
147
+ 'scaleY': 1,
148
+ });
149
+ }
@@ -0,0 +1,7 @@
1
+ /* Limit image width to avoid overflow the container */
2
+ .crop-image-container img.crop-image {
3
+ max-width: 100%; /* This rule is very important, please do not ignore this! */
4
+ }
5
+ .crop-image-container div.crop-image-wrapper {
6
+ max-height: 300px;
7
+ }
@@ -0,0 +1,4 @@
1
+ module PaperCropper
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,66 @@
1
+ module PaperCropper
2
+ module FormHelpers
3
+
4
+ # Create a new cropper box with all buttons and classe. This will be use the
5
+ # twitter bootstrap classes
6
+ # @param attachment_name [Symbol] Name of the attachment to crop
7
+ def tws_cropper_box attachment_name
8
+ obj = self.object
9
+ form_helper = self
10
+ aspect_ratio = obj.send "#{attachment_name}_aspect"
11
+
12
+ out = "<div class='crop-image-container' data-crop-image-range='#{aspect_ratio}'>"
13
+
14
+ out << form_helper.hidden_field(:"#{attachment_name}_crop_x", class: 'crop-image-value-x')
15
+ out << form_helper.hidden_field(:"#{attachment_name}_crop_y", class: 'crop-image-value-y')
16
+ out << form_helper.hidden_field(:"#{attachment_name}_crop_width", class: 'crop-image-value-width')
17
+ out << form_helper.hidden_field(:"#{attachment_name}_crop_height", class: 'crop-image-value-height')
18
+
19
+ out << form_helper.file_field(attachment_name, class: 'crop-image-file-input', label_col: "col-sm-3", control_col: "col-sm-9")
20
+
21
+ out << '<hr>'
22
+
23
+ image_src = obj.send("#{attachment_name}?") ? obj.send(attachment_name).url : ''
24
+ out << '<div class="crop-image-wrapper">'
25
+ out << "<img class='crop-image' class='crop-image' src='#{image_src}'>"
26
+ out << '</div>'
27
+
28
+ out << '<hr>'
29
+
30
+ out << '<div class="btn-group pull-left" role="group">'
31
+ out << "<button type='button' class='crop-image-btn-zoom-in btn btn-default'>&#43;</button>"
32
+ out << "<button type='button' class='crop-image-btn-zoom-out btn btn-default'>&#45;</button>"
33
+ out << '</div>'
34
+
35
+ out << '<div class="btn-group pull-right" role="group">'
36
+ out << "<button type='button' class='crop-image-btn-move-left btn btn-default'>left</button>"
37
+ out << "<button type='button' class='crop-image-btn-move-right btn btn-default'>right</button>"
38
+ out << "<button type='button' class='crop-image-btn-move-up btn btn-default'>up</button>"
39
+ out << "<button type='button' class='crop-image-btn-move-down btn btn-default'>down</button>"
40
+ out << '</div>'
41
+
42
+ out << '</div>'
43
+
44
+ out.html_safe
45
+ end
46
+
47
+ end
48
+ end
49
+
50
+
51
+ # ActionView::Helpers::FormBuilder support
52
+ # #########################################################################
53
+ if defined? ActionView::Helpers::FormBuilder
54
+ ActionView::Helpers::FormBuilder.class_eval do
55
+ include PaperCropper::FormHelpers
56
+ end
57
+ end
58
+
59
+
60
+ # BootstrapForm::FormBuilder support
61
+ # #########################################################################
62
+ # if defined? BootstrapForm::FormBuilder
63
+ # BootstrapForm::FormBuilder.class_eval do
64
+ # include PaperCropper::FormHelpers
65
+ # end
66
+ # end
@@ -0,0 +1,6 @@
1
+ module PaperCropper
2
+ # Paperclip log wrapper
3
+ def self.log(text)
4
+ Paperclip.log(text)
5
+ end
6
+ end
@@ -0,0 +1,129 @@
1
+ module PaperCropper
2
+ module ModelExtension
3
+ # Class methods
4
+ # #########################################################################
5
+ # Initializes attachment cropping in your model
6
+ #
7
+ # crop_attached_file :avatar
8
+ #
9
+ # You can also define an initial aspect ratio for the crop and preview box through opts[:aspect]
10
+ #
11
+ # crop_attached_file :avatar, :aspect => "4:3"
12
+ #
13
+ # Or unlock it
14
+ #
15
+ # crop_attached_file :avatar, :aspect => false
16
+ #
17
+ # @param attachment_name [Symbol] Name of the desired attachment to crop
18
+ # @param opts [Hash]
19
+ # @option opts [Range, String, FalseClass] :aspect
20
+ module ClassMethods
21
+ def crop_attached_file(attachment_name, opts = {})
22
+ opts = opts.dup
23
+
24
+ include PaperCropper::ModelExtension::InstanceMethods
25
+
26
+ aspect = normalize_aspect opts[:aspect]
27
+ send :define_method, :"#{attachment_name}_aspect" do
28
+ aspect.first.to_f / aspect.last.to_f if aspect
29
+ end
30
+
31
+ if respond_to? :attachment_definitions
32
+ # for Paperclip <= 3.4
33
+ definitions = attachment_definitions
34
+ else
35
+ # for Paperclip >= 3.5
36
+ definitions = Paperclip::Tasks::Attachments.instance.definitions_for(self)
37
+ end
38
+ processors = definitions[attachment_name][:processors] ||= []
39
+ unless processors.include? :paper_cropper
40
+ processors << :paper_cropper
41
+ end
42
+
43
+ after_save :"reprocess_to_crop_#{attachment_name}_attachment"
44
+ after_update {
45
+ if send(:attachment_changed?, attachment_name)
46
+ self.update_column(:"#{attachment_name}_updated_at", Time.now)
47
+ end
48
+ }
49
+ end
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 =~ PaperCropper::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
67
+ end
68
+
69
+ # Instance methods
70
+ # #########################################################################
71
+ module InstanceMethods
72
+ # Asks if the attachment received a crop process
73
+ # @param attachment_name [Symbol]
74
+ #
75
+ # @return [Boolean]
76
+ def cropping?(attachment_name)
77
+ !self.send(:"#{attachment_name}_crop_x").blank? &&
78
+ !self.send(:"#{attachment_name}_crop_y").blank? &&
79
+ !self.send(:"#{attachment_name}_crop_width").blank? &&
80
+ !self.send(:"#{attachment_name}_crop_height").blank?
81
+ end
82
+
83
+ def attachment_changed?(attachment_name)
84
+ ["#{attachment_name}_name", "#{attachment_name}_content_type",
85
+ "#{attachment_name}_file_size", "#{attachment_name}_updated_at",
86
+ "#{attachment_name}_crop_x", "#{attachment_name}_crop_y",
87
+ "#{attachment_name}_crop_width",
88
+ "#{attachment_name}_crop_height"
89
+ ].any? { |attr|
90
+ method= "#{attr}_changed?".to_sym
91
+ if respond_to?(method)
92
+ self.send(method)
93
+ end
94
+ }
95
+ end
96
+
97
+ # Uses method missing to responding the model callback for reprocess the image
98
+ def method_missing(method, *args)
99
+ if method.to_s =~ PaperCropper::RegExp::CALLBACK
100
+ reprocess_cropped_attachment(
101
+ method.to_s.scan(PaperCropper::RegExp::CALLBACK).flatten.first.to_sym
102
+ )
103
+ else
104
+ super
105
+ end
106
+ end
107
+
108
+ private
109
+ # Saves the attachment if the crop attributes are present
110
+ # @param attachment_name [Symbol]
111
+ def reprocess_cropped_attachment(attachment_name)
112
+ if cropping?(attachment_name)
113
+ attachment_instance = send(attachment_name)
114
+ attachment_instance.assign(attachment_instance)
115
+ attachment_instance.save
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+
123
+ # ActiveRercord support
124
+ # #########################################################################
125
+ if defined? ActiveRecord::Base
126
+ ActiveRecord::Base.class_eval do
127
+ extend PaperCropper::ModelExtension::ClassMethods
128
+ end
129
+ end
@@ -0,0 +1,6 @@
1
+ module PaperCropper
2
+ module RegExp
3
+ ASPECT = /^([1-9]{1}\d*):([1-9]{1}\d*)$/
4
+ CALLBACK = /reprocess_to_crop_(\S{1,})_attachment/
5
+ end
6
+ end
@@ -0,0 +1,76 @@
1
+ # Custom migration data type
2
+ # Based on papercli schema.rb from: https://github.com/thoughtbot/paperclip => /lib/paperclip/schema.rb
3
+ module PaperCropper
4
+ module Schema
5
+ COLUMNS = {
6
+ crop_x: :integer,
7
+ crop_y: :integer,
8
+ crop_width: :integer,
9
+ crop_height: :integer
10
+ }
11
+
12
+ #
13
+ # #########################################################################
14
+ module Statements
15
+ def add_crop_attachment(table_name, *attachment_names)
16
+ raise ArgumentError, "Please specify attachment name in your add_attachment call in your migration." if attachment_names.empty?
17
+
18
+ options = attachment_names.extract_options!
19
+
20
+ attachment_names.each do |attachment_name|
21
+ COLUMNS.each_pair do |column_name, column_type|
22
+ column_options = options.merge(options[column_name.to_sym] || {})
23
+ add_column(table_name, "#{attachment_name}_#{column_name}", column_type, column_options)
24
+ end
25
+ end
26
+ end
27
+
28
+ def remove_crop_attachment(table_name, *attachment_names)
29
+ raise ArgumentError, "Please specify attachment name in your remove_attachment call in your migration." if attachment_names.empty?
30
+
31
+ attachment_names.each do |attachment_name|
32
+ COLUMNS.keys.each do |column_name|
33
+ remove_column(table_name, "#{attachment_name}_#{column_name}")
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ #
40
+ # #########################################################################
41
+ module TableDefinition
42
+ def crop_attachment(*attachment_names)
43
+ options = attachment_names.extract_options!
44
+ attachment_names.each do |attachment_name|
45
+ COLUMNS.each_pair do |column_name, column_type|
46
+ column_options = options.merge(options[column_name.to_sym] || {})
47
+ column("#{attachment_name}_#{column_name}", column_type, column_options)
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ #
54
+ # #########################################################################
55
+ module CommandRecorder
56
+ def add_attachment(*args)
57
+ record(:add_attachment, args)
58
+ end
59
+
60
+ private
61
+
62
+ def invert_add_attachment(args)
63
+ [:remove_attachment, args]
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+
70
+
71
+ # ActiveRecord support
72
+ # #########################################################################
73
+ ActiveRecord::ConnectionAdapters::Table.send :include, PaperCropper::Schema::TableDefinition
74
+ ActiveRecord::ConnectionAdapters::TableDefinition.send :include, PaperCropper::Schema::TableDefinition
75
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.send :include, PaperCropper::Schema::Statements
76
+ ActiveRecord::Migration::CommandRecorder.send :include, PaperCropper::Schema::CommandRecorder
@@ -0,0 +1,12 @@
1
+ module PaperCropper
2
+ # Changelog based on Semantic Versioning: http://semver.org
3
+ # REMEMBER: Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.
4
+
5
+ # 0.0.2 PATCH
6
+ #- Added ActiveRecord extensions to force attachment updated_at field to be setted
7
+ # on every attachment change.
8
+
9
+ unless defined?(PaperCropper::VERSION)
10
+ VERSION = "0.0.2".freeze
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ require 'paper_cropper/engine'
2
+ require 'paper_cropper/schema'
3
+ require 'paper_cropper/reg_exp'
4
+ require 'paper_cropper/model_extension'
5
+ require 'paper_cropper/helpers'
6
+ require 'paper_cropper/logger'
7
+ require 'paperclip_processors/paper_cropper'
@@ -0,0 +1,31 @@
1
+ require "paperclip"
2
+
3
+ module Paperclip
4
+ class PaperCropper < Thumbnail
5
+ def transformation_command
6
+ if crop_command
7
+ crop_command + super.join(' ').sub(/ -crop \S+/, '').split(' ')
8
+ else
9
+ super
10
+ end
11
+ end
12
+
13
+ def crop_command
14
+ target = @attachment.instance
15
+
16
+ if target.cropping?(@attachment.name)
17
+ begin
18
+ x = Integer(target.send :"#{@attachment.name}_crop_x")
19
+ y = Integer(target.send :"#{@attachment.name}_crop_y")
20
+ w = Integer(target.send :"#{@attachment.name}_crop_width")
21
+ h = Integer(target.send :"#{@attachment.name}_crop_height")
22
+ ["-crop", "#{w}x#{h}+#{x}+#{y}"]
23
+ rescue Exception => e
24
+ ::PaperCropper.log("[paper_cropper] #{@attachment.name} crop w/h/x/y were non-integer. Error: #{e.to_s}")
25
+ return
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ end
Binary file