simple_crop 0.1.1

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,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
@@ -0,0 +1,9 @@
1
+ == 0.1.1
2
+
3
+ * Force processing if no style defined
4
+
5
+ == 0.1.0
6
+
7
+ * Create basic logic
8
+ * Create generator
9
+ * simple_crop:install
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ gem "rails", ">= 3.0.0"
5
+ gem "paperclip", ">= 2.3.7"
6
+
7
+ # Add dependencies to develop your gem here.
8
+ # Include everything needed to run rake, tests, features, etc.
9
+ group :development do
10
+ gem "shoulda", ">= 0"
11
+ gem "bundler", "~> 1.0.0"
12
+ gem "jeweler", "~> 1.5.1"
13
+ gem "rcov", ">= 0"
14
+ end
@@ -0,0 +1,86 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionmailer (3.0.3)
6
+ actionpack (= 3.0.3)
7
+ mail (~> 2.2.9)
8
+ actionpack (3.0.3)
9
+ activemodel (= 3.0.3)
10
+ activesupport (= 3.0.3)
11
+ builder (~> 2.1.2)
12
+ erubis (~> 2.6.6)
13
+ i18n (~> 0.4)
14
+ rack (~> 1.2.1)
15
+ rack-mount (~> 0.6.13)
16
+ rack-test (~> 0.5.6)
17
+ tzinfo (~> 0.3.23)
18
+ activemodel (3.0.3)
19
+ activesupport (= 3.0.3)
20
+ builder (~> 2.1.2)
21
+ i18n (~> 0.4)
22
+ activerecord (3.0.3)
23
+ activemodel (= 3.0.3)
24
+ activesupport (= 3.0.3)
25
+ arel (~> 2.0.2)
26
+ tzinfo (~> 0.3.23)
27
+ activeresource (3.0.3)
28
+ activemodel (= 3.0.3)
29
+ activesupport (= 3.0.3)
30
+ activesupport (3.0.3)
31
+ arel (2.0.6)
32
+ builder (2.1.2)
33
+ erubis (2.6.6)
34
+ abstract (>= 1.0.0)
35
+ git (1.2.5)
36
+ i18n (0.5.0)
37
+ jeweler (1.5.1)
38
+ bundler (~> 1.0.0)
39
+ git (>= 1.2.5)
40
+ rake
41
+ mail (2.2.12)
42
+ activesupport (>= 2.3.6)
43
+ i18n (>= 0.4.0)
44
+ mime-types (~> 1.16)
45
+ treetop (~> 1.4.8)
46
+ mime-types (1.16)
47
+ paperclip (2.3.8)
48
+ activerecord
49
+ activesupport
50
+ polyglot (0.3.1)
51
+ rack (1.2.1)
52
+ rack-mount (0.6.13)
53
+ rack (>= 1.0.0)
54
+ rack-test (0.5.6)
55
+ rack (>= 1.0)
56
+ rails (3.0.3)
57
+ actionmailer (= 3.0.3)
58
+ actionpack (= 3.0.3)
59
+ activerecord (= 3.0.3)
60
+ activeresource (= 3.0.3)
61
+ activesupport (= 3.0.3)
62
+ bundler (~> 1.0)
63
+ railties (= 3.0.3)
64
+ railties (3.0.3)
65
+ actionpack (= 3.0.3)
66
+ activesupport (= 3.0.3)
67
+ rake (>= 0.8.7)
68
+ thor (~> 0.14.4)
69
+ rake (0.8.7)
70
+ rcov (0.9.9)
71
+ shoulda (2.11.3)
72
+ thor (0.14.6)
73
+ treetop (1.4.9)
74
+ polyglot (>= 0.3.1)
75
+ tzinfo (0.3.23)
76
+
77
+ PLATFORMS
78
+ ruby
79
+
80
+ DEPENDENCIES
81
+ bundler (~> 1.0.0)
82
+ jeweler (~> 1.5.1)
83
+ paperclip (>= 2.3.7)
84
+ rails (>= 3.0.0)
85
+ rcov
86
+ shoulda
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Marian André Plösch
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,81 @@
1
+ = SimpleCrop
2
+
3
+ Easy rails implementation for Jcrop that lets you arbitrarily crop paperclip images.
4
+
5
+ This gem is very young and under development, so take a look at the source code before usage.
6
+
7
+ There are other implementations of Jcrop for rails, which served as a source of inspiration to this gem.
8
+ Take a look at:
9
+ * http://github.com/syfo/jcropper
10
+ * http://github.com/jschwindt/rjcrop
11
+
12
+ == Installation
13
+
14
+ Install the gem:
15
+
16
+ gem install simple_crop
17
+
18
+ Add it to your Gemfile and run the generator:
19
+
20
+ rails generate simple_crop:install
21
+
22
+ == Basic Usage
23
+
24
+ Now create a model with a paperclip attachment defined, simple_crop defined as processor and call the simple_crop method.
25
+
26
+ class Image < ActiveRecord::Base
27
+ has_attached_file :image, :processors => "simple_crop"
28
+ simple_crop
29
+ end
30
+
31
+ Ensure you load these javascripts in your view.
32
+
33
+ <%= javascript_include_tag 'jquery.Jcrop.min.js' %>
34
+ <%= javascript_include_tag 'simple_crop.js' %>
35
+ <%= stylesheet_link_tag 'jquery.Jcrop.css' %>
36
+
37
+ Call simple_crop on a paperclip attachment in your **edit** action's view (won't work on a new object, as no image is there to crop yet).
38
+ For example:
39
+
40
+ <%= form_for @image do |f| %>
41
+ <%= f.simple_crop :image %>
42
+ <%= f.submit :submit %>
43
+ <% end %>
44
+
45
+ == Advanced Usage
46
+
47
+ Let's assume your model setup is like this:
48
+
49
+ class Image < ActiveRecord::Base
50
+ has_attached_file :image,
51
+ :styles => {
52
+ :small => "170x100#",
53
+ :medium => "600x500>",
54
+ :original => "950x800>" },
55
+ :processors => "simple_crop"
56
+ simple_crop
57
+ end
58
+
59
+ The default crop occurs on the original style of your image.
60
+ If you want to let users select on a certain style and crop another style, just do:
61
+
62
+ <%= f.simple_crop :image, {:crop => :small, :select => :medium} %>
63
+
64
+ If the :crop and :select parameters aren't the same, it will add a preview panel next to your crop image.
65
+
66
+ The simple crop form helper also outputs some javascript for initialization.
67
+ If you want to manually fire it instead, use this:
68
+
69
+ <%= f.simple_crop :image, {:script => false} %>
70
+
71
+ You can make the helper output the jQuery plugin initialization to any yield section in your layouts too:
72
+
73
+ <%= f.simple_crop :image, {:script => :js_bottom} %>
74
+
75
+ == TODO
76
+
77
+ See TODO document.
78
+
79
+ == Copyright
80
+
81
+ Copyright (c) 2010 Marian André. Bitflut Media.
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "simple_crop"
16
+ gem.homepage = "http://github.com/bitflut/simple_crop"
17
+ gem.license = "MIT"
18
+ gem.summary = "Makes cropping images easy"
19
+ gem.description = "Arbitrarily crop different styles of your paperclip images"
20
+ gem.email = "marian@bitflut.com"
21
+ gem.authors = ["Marian"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ gem.add_runtime_dependency 'paperclip', '>= 2.3.7'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/test_*.rb'
40
+ test.verbose = true
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "simple_crop #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/TODO ADDED
@@ -0,0 +1,13 @@
1
+ * Only use simple crop processor when necessary
2
+ * Remove necessity of defining simple_crop as paperclip processor and dynamically add it on request
3
+
4
+ * Turn aspect-ratio on and off
5
+ * Default use of aspect-ratio on styles that will crop
6
+ * Suggest no use of aspect-ratio for styles that only resize
7
+ * Add aspect-ratio == (true || false) to options
8
+
9
+ * Refactor attr_accessors of simple_crop models to arrays with naming conventions for possible crops on multiple styles on one request
10
+
11
+ * Error handling when form input is used on a new object
12
+
13
+ * Write tests! :)
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'simple_crop'
@@ -0,0 +1,3 @@
1
+ To copy all necessary files type this:
2
+
3
+ rails generate simple_crop:install
@@ -0,0 +1,22 @@
1
+ module SimpleCrop
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ desc "Copy SimpleCrop default files"
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+ def copy_simple_crop_file
8
+ copy_file 'jquery.simple-crop.js', 'public/javascripts/jquery.simple-crop.js'
9
+ end
10
+
11
+ def copy_jcrop_files
12
+ copy_file 'jquery.Jcrop.min.js', 'public/javascripts/jquery.Jcrop.min.js'
13
+ copy_file 'jquery.Jcrop.css', 'public/stylesheets/jquery.Jcrop.css'
14
+ copy_file 'Jcrop.gif', 'public/images/Jcrop.gif'
15
+ end
16
+
17
+ def show_readme
18
+ readme "README" if behavior == :invoke
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+
2
+ ===============================================================================
3
+
4
+ We got this far, there's not much left to do:
5
+
6
+ 1. Now create a model with a paperclip attachment defined, simple_crop
7
+ defined as processor and call the simple_crop method:
8
+
9
+ has_attached_file :image,
10
+ :styles => {
11
+ :small => "170x100#",
12
+ :medium => "600x500>",
13
+ :original => "950x800>" },
14
+ :processors => "simple_crop"
15
+ simple_crop
16
+
17
+ 2. Ensure you load these javascripts in your view.
18
+
19
+ <%= javascript_include_tag 'jquery.Jcrop.min.js' %>
20
+ <%= javascript_include_tag 'jquery.simple-crop.js' %>
21
+ <%= stylesheet_link_tag 'jquery.Jcrop.css' %>
22
+
23
+ 3. Call simple_crop on a paperclip attachment in your form.
24
+ For example:
25
+
26
+ <%= f.simple_crop :image %>
27
+
28
+ 4. See README for options like defining the selection style and crop style.
29
+
30
+ http://github.com/bitflut/simple_crop
31
+
32
+ ===============================================================================
@@ -0,0 +1,35 @@
1
+ /* Fixes issue here http://code.google.com/p/jcrop/issues/detail?id=1 */
2
+ .jcrop-holder { text-align: left; }
3
+
4
+ .jcrop-vline, .jcrop-hline
5
+ {
6
+ font-size: 0;
7
+ position: absolute;
8
+ background: white url('/images/Jcrop.gif') top left repeat;
9
+ }
10
+ .jcrop-vline { height: 100%; width: 1px !important; }
11
+ .jcrop-hline { width: 100%; height: 1px !important; }
12
+ .jcrop-handle {
13
+ font-size: 1px;
14
+ width: 7px !important;
15
+ height: 7px !important;
16
+ border: 1px #eee solid;
17
+ background-color: #333;
18
+ *width: 9px;
19
+ *height: 9px;
20
+ }
21
+
22
+ .jcrop-tracker { width: 100%; height: 100%; }
23
+
24
+ .custom .jcrop-vline,
25
+ .custom .jcrop-hline
26
+ {
27
+ background: yellow;
28
+ }
29
+ .custom .jcrop-handle
30
+ {
31
+ border-color: black;
32
+ background-color: #C7BB00;
33
+ -moz-border-radius: 3px;
34
+ -webkit-border-radius: 3px;
35
+ }
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Jcrop v.0.9.8 (minimized)
3
+ * (c) 2008 Kelly Hallman and DeepLiquid.com
4
+ * More information: http://deepliquid.com/content/Jcrop.html
5
+ * Released under MIT License - this header must remain with code
6
+ */
7
+
8
+
9
+ (function($){$.Jcrop=function(obj,opt)
10
+ {var obj=obj,opt=opt;if(typeof(obj)!=='object')obj=$(obj)[0];if(typeof(opt)!=='object')opt={};if(!('trackDocument'in opt))
11
+ {opt.trackDocument=$.browser.msie?false:true;if($.browser.msie&&$.browser.version.split('.')[0]=='8')
12
+ opt.trackDocument=true;}
13
+ if(!('keySupport'in opt))
14
+ opt.keySupport=$.browser.msie?false:true;var defaults={trackDocument:false,baseClass:'jcrop',addClass:null,bgColor:'black',bgOpacity:.6,borderOpacity:.4,handleOpacity:.5,handlePad:5,handleSize:9,handleOffset:5,edgeMargin:14,aspectRatio:0,keySupport:true,cornerHandles:true,sideHandles:true,drawBorders:true,dragEdges:true,boxWidth:0,boxHeight:0,boundary:8,animationDelay:20,swingSpeed:3,allowSelect:true,allowMove:true,allowResize:true,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){}};var options=defaults;setOptions(opt);var $origimg=$(obj);var $img=$origimg.clone().removeAttr('id').css({position:'absolute'});$img.width($origimg.width());$img.height($origimg.height());$origimg.after($img).hide();presize($img,options.boxWidth,options.boxHeight);var boundx=$img.width(),boundy=$img.height(),$div=$('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({position:'relative',backgroundColor:options.bgColor}).insertAfter($origimg).append($img);;if(options.addClass)$div.addClass(options.addClass);var $img2=$('<img />').attr('src',$img.attr('src')).css('position','absolute').width(boundx).height(boundy);var $img_holder=$('<div />').width(pct(100)).height(pct(100)).css({zIndex:310,position:'absolute',overflow:'hidden'}).append($img2);var $hdl_holder=$('<div />').width(pct(100)).height(pct(100)).css('zIndex',320);var $sel=$('<div />').css({position:'absolute',zIndex:300}).insertBefore($img).append($img_holder,$hdl_holder);var bound=options.boundary;var $trk=newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)).css({position:'absolute',top:px(-bound),left:px(-bound),zIndex:290}).mousedown(newSelection);var xlimit,ylimit,xmin,ymin;var xscale,yscale,enabled=true;var docOffset=getPos($img),btndown,lastcurs,dimmed,animating,shift_down;var Coords=function()
15
+ {var x1=0,y1=0,x2=0,y2=0,ox,oy;function setPressed(pos)
16
+ {var pos=rebound(pos);x2=x1=pos[0];y2=y1=pos[1];};function setCurrent(pos)
17
+ {var pos=rebound(pos);ox=pos[0]-x2;oy=pos[1]-y2;x2=pos[0];y2=pos[1];};function getOffset()
18
+ {return[ox,oy];};function moveOffset(offset)
19
+ {var ox=offset[0],oy=offset[1];if(0>x1+ox)ox-=ox+x1;if(0>y1+oy)oy-=oy+y1;if(boundy<y2+oy)oy+=boundy-(y2+oy);if(boundx<x2+ox)ox+=boundx-(x2+ox);x1+=ox;x2+=ox;y1+=oy;y2+=oy;};function getCorner(ord)
20
+ {var c=getFixed();switch(ord)
21
+ {case'ne':return[c.x2,c.y];case'nw':return[c.x,c.y];case'se':return[c.x2,c.y2];case'sw':return[c.x,c.y2];}};function getFixed()
22
+ {if(!options.aspectRatio)return getRect();var aspect=options.aspectRatio,min_x=options.minSize[0]/xscale,min_y=options.minSize[1]/yscale,max_x=options.maxSize[0]/xscale,max_y=options.maxSize[1]/yscale,rw=x2-x1,rh=y2-y1,rwa=Math.abs(rw),rha=Math.abs(rh),real_ratio=rwa/rha,xx,yy;if(max_x==0){max_x=boundx*10}
23
+ if(max_y==0){max_y=boundy*10}
24
+ if(real_ratio<aspect)
25
+ {yy=y2;w=rha*aspect;xx=rw<0?x1-w:w+x1;if(xx<0)
26
+ {xx=0;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}
27
+ else if(xx>boundx)
28
+ {xx=boundx;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}}
29
+ else
30
+ {xx=x2;h=rwa/aspect;yy=rh<0?y1-h:y1+h;if(yy<0)
31
+ {yy=0;w=Math.abs((yy-y1)*aspect);xx=rw<0?x1-w:w+x1;}
32
+ else if(yy>boundy)
33
+ {yy=boundy;w=Math.abs(yy-y1)*aspect;xx=rw<0?x1-w:w+x1;}}
34
+ if(xx>x1){if(xx-x1<min_x){xx=x1+min_x;}else if(xx-x1>max_x){xx=x1+max_x;}
35
+ if(yy>y1){yy=y1+(xx-x1)/aspect;}else{yy=y1-(xx-x1)/aspect;}}else if(xx<x1){if(x1-xx<min_x){xx=x1-min_x}else if(x1-xx>max_x){xx=x1-max_x;}
36
+ if(yy>y1){yy=y1+(x1-xx)/aspect;}else{yy=y1-(x1-xx)/aspect;}}
37
+ if(xx<0){x1-=xx;xx=0;}else if(xx>boundx){x1-=xx-boundx;xx=boundx;}
38
+ if(yy<0){y1-=yy;yy=0;}else if(yy>boundy){y1-=yy-boundy;yy=boundy;}
39
+ return last=makeObj(flipCoords(x1,y1,xx,yy));};function rebound(p)
40
+ {if(p[0]<0)p[0]=0;if(p[1]<0)p[1]=0;if(p[0]>boundx)p[0]=boundx;if(p[1]>boundy)p[1]=boundy;return[p[0],p[1]];};function flipCoords(x1,y1,x2,y2)
41
+ {var xa=x1,xb=x2,ya=y1,yb=y2;if(x2<x1)
42
+ {xa=x2;xb=x1;}
43
+ if(y2<y1)
44
+ {ya=y2;yb=y1;}
45
+ return[Math.round(xa),Math.round(ya),Math.round(xb),Math.round(yb)];};function getRect()
46
+ {var xsize=x2-x1;var ysize=y2-y1;if(xlimit&&(Math.abs(xsize)>xlimit))
47
+ x2=(xsize>0)?(x1+xlimit):(x1-xlimit);if(ylimit&&(Math.abs(ysize)>ylimit))
48
+ y2=(ysize>0)?(y1+ylimit):(y1-ylimit);if(ymin&&(Math.abs(ysize)<ymin))
49
+ y2=(ysize>0)?(y1+ymin):(y1-ymin);if(xmin&&(Math.abs(xsize)<xmin))
50
+ x2=(xsize>0)?(x1+xmin):(x1-xmin);if(x1<0){x2-=x1;x1-=x1;}
51
+ if(y1<0){y2-=y1;y1-=y1;}
52
+ if(x2<0){x1-=x2;x2-=x2;}
53
+ if(y2<0){y1-=y2;y2-=y2;}
54
+ if(x2>boundx){var delta=x2-boundx;x1-=delta;x2-=delta;}
55
+ if(y2>boundy){var delta=y2-boundy;y1-=delta;y2-=delta;}
56
+ if(x1>boundx){var delta=x1-boundy;y2-=delta;y1-=delta;}
57
+ if(y1>boundy){var delta=y1-boundy;y2-=delta;y1-=delta;}
58
+ return makeObj(flipCoords(x1,y1,x2,y2));};function makeObj(a)
59
+ {return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]};};return{flipCoords:flipCoords,setPressed:setPressed,setCurrent:setCurrent,getOffset:getOffset,moveOffset:moveOffset,getCorner:getCorner,getFixed:getFixed};}();var Selection=function()
60
+ {var start,end,dragmode,awake,hdep=370;var borders={};var handle={};var seehandles=false;var hhs=options.handleOffset;if(options.drawBorders){borders={top:insertBorder('hline').css('top',$.browser.msie?px(-1):px(0)),bottom:insertBorder('hline'),left:insertBorder('vline'),right:insertBorder('vline')};}
61
+ if(options.dragEdges){handle.t=insertDragbar('n');handle.b=insertDragbar('s');handle.r=insertDragbar('e');handle.l=insertDragbar('w');}
62
+ options.sideHandles&&createHandles(['n','s','e','w']);options.cornerHandles&&createHandles(['sw','nw','ne','se']);function insertBorder(type)
63
+ {var jq=$('<div />').css({position:'absolute',opacity:options.borderOpacity}).addClass(cssClass(type));$img_holder.append(jq);return jq;};function dragDiv(ord,zi)
64
+ {var jq=$('<div />').mousedown(createDragger(ord)).css({cursor:ord+'-resize',position:'absolute',zIndex:zi});$hdl_holder.append(jq);return jq;};function insertHandle(ord)
65
+ {return dragDiv(ord,hdep++).css({top:px(-hhs+1),left:px(-hhs+1),opacity:options.handleOpacity}).addClass(cssClass('handle'));};function insertDragbar(ord)
66
+ {var s=options.handleSize,o=hhs,h=s,w=s,t=o,l=o;switch(ord)
67
+ {case'n':case's':w=pct(100);break;case'e':case'w':h=pct(100);break;}
68
+ return dragDiv(ord,hdep++).width(w).height(h).css({top:px(-t+1),left:px(-l+1)});};function createHandles(li)
69
+ {for(i in li)handle[li[i]]=insertHandle(li[i]);};function moveHandles(c)
70
+ {var midvert=Math.round((c.h/2)-hhs),midhoriz=Math.round((c.w/2)-hhs),north=west=-hhs+1,east=c.w-hhs,south=c.h-hhs,x,y;'e'in handle&&handle.e.css({top:px(midvert),left:px(east)})&&handle.w.css({top:px(midvert)})&&handle.s.css({top:px(south),left:px(midhoriz)})&&handle.n.css({left:px(midhoriz)});'ne'in handle&&handle.ne.css({left:px(east)})&&handle.se.css({top:px(south),left:px(east)})&&handle.sw.css({top:px(south)});'b'in handle&&handle.b.css({top:px(south)})&&handle.r.css({left:px(east)});};function moveto(x,y)
71
+ {$img2.css({top:px(-y),left:px(-x)});$sel.css({top:px(y),left:px(x)});};function resize(w,h)
72
+ {$sel.width(w).height(h);};function refresh()
73
+ {var c=Coords.getFixed();Coords.setPressed([c.x,c.y]);Coords.setCurrent([c.x2,c.y2]);updateVisible();};function updateVisible()
74
+ {if(awake)return update();};function update()
75
+ {var c=Coords.getFixed();resize(c.w,c.h);moveto(c.x,c.y);options.drawBorders&&borders['right'].css({left:px(c.w-1)})&&borders['bottom'].css({top:px(c.h-1)});seehandles&&moveHandles(c);awake||show();options.onChange(unscale(c));};function show()
76
+ {$sel.show();$img.css('opacity',options.bgOpacity);awake=true;};function release()
77
+ {disableHandles();$sel.hide();$img.css('opacity',1);awake=false;};function showHandles()
78
+ {if(seehandles)
79
+ {moveHandles(Coords.getFixed());$hdl_holder.show();}};function enableHandles()
80
+ {seehandles=true;if(options.allowResize)
81
+ {moveHandles(Coords.getFixed());$hdl_holder.show();return true;}};function disableHandles()
82
+ {seehandles=false;$hdl_holder.hide();};function animMode(v)
83
+ {(animating=v)?disableHandles():enableHandles();};function done()
84
+ {animMode(false);refresh();};var $track=newTracker().mousedown(createDragger('move')).css({cursor:'move',position:'absolute',zIndex:360})
85
+ $img_holder.append($track);disableHandles();return{updateVisible:updateVisible,update:update,release:release,refresh:refresh,setCursor:function(cursor){$track.css('cursor',cursor);},enableHandles:enableHandles,enableOnly:function(){seehandles=true;},showHandles:showHandles,disableHandles:disableHandles,animMode:animMode,done:done};}();var Tracker=function()
86
+ {var onMove=function(){},onDone=function(){},trackDoc=options.trackDocument;if(!trackDoc)
87
+ {$trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);}
88
+ function toFront()
89
+ {$trk.css({zIndex:450});if(trackDoc)
90
+ {$(document).mousemove(trackMove).mouseup(trackUp);}}
91
+ function toBack()
92
+ {$trk.css({zIndex:290});if(trackDoc)
93
+ {$(document).unbind('mousemove',trackMove).unbind('mouseup',trackUp);}}
94
+ function trackMove(e)
95
+ {onMove(mouseAbs(e));};function trackUp(e)
96
+ {e.preventDefault();e.stopPropagation();if(btndown)
97
+ {btndown=false;onDone(mouseAbs(e));options.onSelect(unscale(Coords.getFixed()));toBack();onMove=function(){};onDone=function(){};}
98
+ return false;};function activateHandlers(move,done)
99
+ {btndown=true;onMove=move;onDone=done;toFront();return false;};function setCursor(t){$trk.css('cursor',t);};$img.before($trk);return{activateHandlers:activateHandlers,setCursor:setCursor};}();var KeyManager=function()
100
+ {var $keymgr=$('<input type="radio" />').css({position:'absolute',left:'-30px'}).keypress(parseKey).blur(onBlur),$keywrap=$('<div />').css({position:'absolute',overflow:'hidden'}).append($keymgr);function watchKeys()
101
+ {if(options.keySupport)
102
+ {$keymgr.show();$keymgr.focus();}};function onBlur(e)
103
+ {$keymgr.hide();};function doNudge(e,x,y)
104
+ {if(options.allowMove){Coords.moveOffset([x,y]);Selection.updateVisible();};e.preventDefault();e.stopPropagation();};function parseKey(e)
105
+ {if(e.ctrlKey)return true;shift_down=e.shiftKey?true:false;var nudge=shift_down?10:1;switch(e.keyCode)
106
+ {case 37:doNudge(e,-nudge,0);break;case 39:doNudge(e,nudge,0);break;case 38:doNudge(e,0,-nudge);break;case 40:doNudge(e,0,nudge);break;case 27:Selection.release();break;case 9:return true;}
107
+ return nothing(e);};if(options.keySupport)$keywrap.insertBefore($img);return{watchKeys:watchKeys};}();function px(n){return''+parseInt(n)+'px';};function pct(n){return''+parseInt(n)+'%';};function cssClass(cl){return options.baseClass+'-'+cl;};function getPos(obj)
108
+ {var pos=$(obj).offset();return[pos.left,pos.top];};function mouseAbs(e)
109
+ {return[(e.pageX-docOffset[0]),(e.pageY-docOffset[1])];};function myCursor(type)
110
+ {if(type!=lastcurs)
111
+ {Tracker.setCursor(type);lastcurs=type;}};function startDragMode(mode,pos)
112
+ {docOffset=getPos($img);Tracker.setCursor(mode=='move'?mode:mode+'-resize');if(mode=='move')
113
+ return Tracker.activateHandlers(createMover(pos),doneSelect);var fc=Coords.getFixed();var opp=oppLockCorner(mode);var opc=Coords.getCorner(oppLockCorner(opp));Coords.setPressed(Coords.getCorner(opp));Coords.setCurrent(opc);Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);};function dragmodeHandler(mode,f)
114
+ {return function(pos){if(!options.aspectRatio)switch(mode)
115
+ {case'e':pos[1]=f.y2;break;case'w':pos[1]=f.y2;break;case'n':pos[0]=f.x2;break;case's':pos[0]=f.x2;break;}
116
+ else switch(mode)
117
+ {case'e':pos[1]=f.y+1;break;case'w':pos[1]=f.y+1;break;case'n':pos[0]=f.x+1;break;case's':pos[0]=f.x+1;break;}
118
+ Coords.setCurrent(pos);Selection.update();};};function createMover(pos)
119
+ {var lloc=pos;KeyManager.watchKeys();return function(pos)
120
+ {Coords.moveOffset([pos[0]-lloc[0],pos[1]-lloc[1]]);lloc=pos;Selection.update();};};function oppLockCorner(ord)
121
+ {switch(ord)
122
+ {case'n':return'sw';case's':return'nw';case'e':return'nw';case'w':return'ne';case'ne':return'sw';case'nw':return'se';case'se':return'nw';case'sw':return'ne';};};function createDragger(ord)
123
+ {return function(e){if(options.disabled)return false;if((ord=='move')&&!options.allowMove)return false;btndown=true;startDragMode(ord,mouseAbs(e));e.stopPropagation();e.preventDefault();return false;};};function presize($obj,w,h)
124
+ {var nw=$obj.width(),nh=$obj.height();if((nw>w)&&w>0)
125
+ {nw=w;nh=(w/$obj.width())*$obj.height();}
126
+ if((nh>h)&&h>0)
127
+ {nh=h;nw=(h/$obj.height())*$obj.width();}
128
+ xscale=$obj.width()/nw;yscale=$obj.height()/nh;$obj.width(nw).height(nh);};function unscale(c)
129
+ {return{x:parseInt(c.x*xscale),y:parseInt(c.y*yscale),x2:parseInt(c.x2*xscale),y2:parseInt(c.y2*yscale),w:parseInt(c.w*xscale),h:parseInt(c.h*yscale)};};function doneSelect(pos)
130
+ {var c=Coords.getFixed();if(c.w>options.minSelect[0]&&c.h>options.minSelect[1])
131
+ {Selection.enableHandles();Selection.done();}
132
+ else
133
+ {Selection.release();}
134
+ Tracker.setCursor(options.allowSelect?'crosshair':'default');};function newSelection(e)
135
+ {if(options.disabled)return false;if(!options.allowSelect)return false;btndown=true;docOffset=getPos($img);Selection.disableHandles();myCursor('crosshair');var pos=mouseAbs(e);Coords.setPressed(pos);Tracker.activateHandlers(selectDrag,doneSelect);KeyManager.watchKeys();Selection.update();e.stopPropagation();e.preventDefault();return false;};function selectDrag(pos)
136
+ {Coords.setCurrent(pos);Selection.update();};function newTracker()
137
+ {var trk=$('<div></div>').addClass(cssClass('tracker'));$.browser.msie&&trk.css({opacity:0,backgroundColor:'white'});return trk;};function animateTo(a)
138
+ {var x1=a[0]/xscale,y1=a[1]/yscale,x2=a[2]/xscale,y2=a[3]/yscale;if(animating)return;var animto=Coords.flipCoords(x1,y1,x2,y2);var c=Coords.getFixed();var animat=initcr=[c.x,c.y,c.x2,c.y2];var interv=options.animationDelay;var x=animat[0];var y=animat[1];var x2=animat[2];var y2=animat[3];var ix1=animto[0]-initcr[0];var iy1=animto[1]-initcr[1];var ix2=animto[2]-initcr[2];var iy2=animto[3]-initcr[3];var pcent=0;var velocity=options.swingSpeed;Selection.animMode(true);var animator=function()
139
+ {return function()
140
+ {pcent+=(100-pcent)/velocity;animat[0]=x+((pcent/100)*ix1);animat[1]=y+((pcent/100)*iy1);animat[2]=x2+((pcent/100)*ix2);animat[3]=y2+((pcent/100)*iy2);if(pcent<100)animateStart();else Selection.done();if(pcent>=99.8)pcent=100;setSelectRaw(animat);};}();function animateStart()
141
+ {window.setTimeout(animator,interv);};animateStart();};function setSelect(rect)
142
+ {setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);};function setSelectRaw(l)
143
+ {Coords.setPressed([l[0],l[1]]);Coords.setCurrent([l[2],l[3]]);Selection.update();};function setOptions(opt)
144
+ {if(typeof(opt)!='object')opt={};options=$.extend(options,opt);if(typeof(options.onChange)!=='function')
145
+ options.onChange=function(){};if(typeof(options.onSelect)!=='function')
146
+ options.onSelect=function(){};};function tellSelect()
147
+ {return unscale(Coords.getFixed());};function tellScaled()
148
+ {return Coords.getFixed();};function setOptionsNew(opt)
149
+ {setOptions(opt);interfaceUpdate();};function disableCrop()
150
+ {options.disabled=true;Selection.disableHandles();Selection.setCursor('default');Tracker.setCursor('default');};function enableCrop()
151
+ {options.disabled=false;interfaceUpdate();};function cancelCrop()
152
+ {Selection.done();Tracker.activateHandlers(null,null);};function destroy()
153
+ {$div.remove();$origimg.show();};function interfaceUpdate(alt)
154
+ {options.allowResize?alt?Selection.enableOnly():Selection.enableHandles():Selection.disableHandles();Tracker.setCursor(options.allowSelect?'crosshair':'default');Selection.setCursor(options.allowMove?'move':'default');$div.css('backgroundColor',options.bgColor);if('setSelect'in options){setSelect(opt.setSelect);Selection.done();delete(options.setSelect);}
155
+ if('trueSize'in options){xscale=options.trueSize[0]/boundx;yscale=options.trueSize[1]/boundy;}
156
+ xlimit=options.maxSize[0]||0;ylimit=options.maxSize[1]||0;xmin=options.minSize[0]||0;ymin=options.minSize[1]||0;if('outerImage'in options)
157
+ {$img.attr('src',options.outerImage);delete(options.outerImage);}
158
+ Selection.refresh();};$hdl_holder.hide();interfaceUpdate(true);var api={animateTo:animateTo,setSelect:setSelect,setOptions:setOptionsNew,tellSelect:tellSelect,tellScaled:tellScaled,disable:disableCrop,enable:enableCrop,cancel:cancelCrop,focus:KeyManager.watchKeys,getBounds:function(){return[boundx*xscale,boundy*yscale];},getWidgetSize:function(){return[boundx,boundy];},release:Selection.release,destroy:destroy};$origimg.data('Jcrop',api);return api;};$.fn.Jcrop=function(options)
159
+ {function attachWhenDone(from)
160
+ {var loadsrc=options.useImg||from.src;var img=new Image();img.onload=function(){$.Jcrop(from,options);};img.src=loadsrc;};if(typeof(options)!=='object')options={};this.each(function()
161
+ {if($(this).data('Jcrop'))
162
+ {if(options=='api')return $(this).data('Jcrop');else $(this).data('Jcrop').setOptions(options);}
163
+ else attachWhenDone(this);});return this;};})(jQuery);
@@ -0,0 +1,54 @@
1
+ (function($){
2
+ var methods = {
3
+
4
+ onChange : function(coords) {
5
+ methods.updateCoords(coords);
6
+
7
+ var rx = 170 / coords.w;
8
+ var ry = 100 / coords.h;
9
+
10
+ if (methods.hasPreviewMask())
11
+ {
12
+ methods.previewMask().css({
13
+ width: Math.round(rx * width * ratio) + 'px',
14
+ height: Math.round(ry * height * ratio) + 'px',
15
+ marginLeft: '-' + Math.round(rx * coords.x) + 'px',
16
+ marginTop: '-' + Math.round(ry * coords.y) + 'px'
17
+ });
18
+ }
19
+ },
20
+
21
+ updateCoords : function(coords) {
22
+ ["x", "y", "h", "w"].forEach( function(obj) {
23
+ $('#'+croppable_name+'_simple_crop_'+obj).val(coords[obj]);
24
+ });
25
+ },
26
+
27
+ hasPreviewMask : function() {
28
+ return methods.previewMask().length > 0;
29
+ },
30
+
31
+ previewMask : function() {
32
+ return $('#'+croppable_name+'_simple_crop_preview img');
33
+ }
34
+ };
35
+
36
+ var width;
37
+ var height;
38
+ var ratio;
39
+ var croppable_name;
40
+
41
+ $.fn.SimpleCrop = function() {
42
+ width = $(this[0]).width();
43
+ height = $(this[0]).height();
44
+ croppable_name = $(this[0]).attr('data-crop-for');
45
+ ratio = $(this[0]).attr('data-crop-ratio').split('/');
46
+ ratio = ratio[0] / ratio[1];
47
+
48
+ return $(this).Jcrop({
49
+ onChange: methods.onChange,
50
+ aspectRatio: 170/100,
51
+ trueSize: [width*ratio, height*ratio]
52
+ });
53
+ };
54
+ })(jQuery);
@@ -0,0 +1,14 @@
1
+ require 'action_view'
2
+ require 'active_record'
3
+ require 'paperclip'
4
+
5
+ require 'simple_crop/action_view_extensions/form_helper'
6
+ require 'simple_crop/action_view_extensions/builder'
7
+ require 'simple_crop/action_view_extensions/instance_tag'
8
+
9
+ require 'simple_crop/active_record/simple_crop'
10
+
11
+ require 'simple_crop/paperclip_patches/attachment'
12
+ require 'simple_crop/paperclip_patches/style'
13
+
14
+ require 'simple_crop/paperclip_processors/processor'
@@ -0,0 +1,13 @@
1
+ module SimpleCrop
2
+ module ActionViewExtensions
3
+
4
+ module FormBuilder
5
+ def simple_crop(method, options = {})
6
+ @template.send("simple_crop", @object_name, method, objectify_options(options))
7
+ end
8
+ end
9
+
10
+ end
11
+ end
12
+
13
+ ActionView::Helpers::FormBuilder.send :include, SimpleCrop::ActionViewExtensions::FormBuilder
@@ -0,0 +1,39 @@
1
+ module ActionView
2
+ module Helpers
3
+ module FormHelper
4
+ def simple_crop(object_name, method, options = {})
5
+ default_options = {"select" => :original, "crop" => :original, "script" => true}
6
+ options = options.stringify_keys!
7
+ options = default_options.merge(options)
8
+ script = options["script"]
9
+
10
+ # Build image and preview
11
+ output = InstanceTag.new(object_name, method, self, options).to_simple_crop_tag(options)
12
+ output << InstanceTag.new(object_name, method, self, options).to_simple_crop_preview_tag(options) unless (options["select"] == options["crop"])
13
+
14
+ # Build hidden fields for accessors on model used by simple_crop
15
+ output << InstanceTag.new(object_name, :simple_crop_x, self).to_input_field_tag("hidden")
16
+ output << InstanceTag.new(object_name, :simple_crop_y, self).to_input_field_tag("hidden")
17
+ output << InstanceTag.new(object_name, :simple_crop_w, self).to_input_field_tag("hidden")
18
+ output << InstanceTag.new(object_name, :simple_crop_h, self).to_input_field_tag("hidden")
19
+ output << InstanceTag.new(object_name, :simple_crop_style, self).to_input_field_tag("hidden", {:value => options["crop"]})
20
+
21
+ # Initialize jQuery plugin
22
+ # Either output inline or yield to provided template
23
+ if script === true
24
+ output << %Q(<script type="text/javascript" charset="utf-8">$(window).load(function() {$('img[data-crop-for="#{sanitized_object_name(object_name)}"]').SimpleCrop();});</script>).html_safe
25
+ elsif not script === false
26
+ content_for script do
27
+ %Q($('img[data-crop-for="#{sanitized_object_name(object_name)}"]').SimpleCrop();).html_safe
28
+ end
29
+ end
30
+
31
+ output
32
+ end
33
+
34
+ def sanitized_object_name(object_name)
35
+ object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ module ActionView
2
+ module Helpers
3
+ module InstanceTagMethods
4
+ def to_simple_crop_preview_tag(options)
5
+ paperclip = options["object"].send(@method_name)
6
+ target_crop_geometry = paperclip_geometry(paperclip, options["crop"])
7
+ div_style = "padding:0;overflow:hidden;width:#{target_crop_geometry.width.to_i.to_s}px;height:#{target_crop_geometry.height.to_i.to_s}px;"
8
+ content_tag("div", tag("img",{:src => paperclip.url(options["select"])}), {:class => "simple-crop-preview", :id => "#{sanitized_object_name}_simple_crop_preview", :style => div_style})
9
+ end
10
+
11
+ def to_simple_crop_tag(options)
12
+ paperclip = options["object"].send(@method_name)
13
+ tag("img",{:src => paperclip.url(options["select"]), :"data-crop-ratio" => crop_ratio(paperclip, options["select"]), :"data-crop-for" => sanitized_object_name})
14
+ end
15
+
16
+ def crop_ratio paperclip, select_style
17
+ original_geometry = paperclip_geometry(paperclip, :original)
18
+ select_geometry = paperclip_geometry(paperclip, select_style)
19
+ "#{original_geometry.width.to_i.to_s}/#{select_geometry.width.to_i.to_s}"
20
+ end
21
+
22
+ def paperclip_geometry(paperclip, style)
23
+ Paperclip::Geometry.from_file paperclip.to_file(style)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ module SimpleCrop
2
+ module ActiveRecord
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def simple_crop
9
+ class_eval <<-EOV
10
+ include SimpleCrop::ActiveRecord::InstanceMethods
11
+ before_save :simple_crop_reprocess
12
+ attr_accessor :simple_crop_x, :simple_crop_y, :simple_crop_h, :simple_crop_w, :simple_crop_style
13
+ EOV
14
+ end
15
+ end
16
+
17
+ module InstanceMethods
18
+ def wants_simple_crop?
19
+ eval (%w(x y w h).collect {|v| "!simple_crop_#{v}.blank?"}.join(" and ")+" and !simple_crop_style.blank?")
20
+ end
21
+
22
+ def simple_crop_string
23
+ "#{simple_crop_w}x#{simple_crop_h}+#{simple_crop_x}+#{simple_crop_y}"
24
+ end
25
+
26
+ private
27
+
28
+ def simple_crop_reprocess
29
+ if wants_simple_crop?
30
+ self.image.reprocess!(self.simple_crop_style.to_sym)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ ActiveRecord::Base.class_eval { include SimpleCrop::ActiveRecord }
@@ -0,0 +1,63 @@
1
+ module Paperclip
2
+ class Attachment
3
+ def reprocess!(*style_args)
4
+ new_original = Tempfile.new("paperclip-reprocess")
5
+ new_original.binmode
6
+ if old_original = to_file(:original)
7
+ new_original.write( old_original.respond_to?(:get) ? old_original.get : old_original.read )
8
+ new_original.rewind
9
+
10
+ @queued_for_write = { :original => new_original }
11
+ post_process(*style_args)
12
+
13
+ old_original.close if old_original.respond_to?(:close)
14
+
15
+ save
16
+ else
17
+ true
18
+ end
19
+ end
20
+
21
+ def post_process(*style_args) #:nodoc:
22
+ return if @queued_for_write[:original].nil?
23
+ instance.run_paperclip_callbacks(:post_process) do
24
+ instance.run_paperclip_callbacks(:"#{name}_post_process") do
25
+ post_process_styles(*style_args)
26
+ end
27
+ end
28
+ end
29
+
30
+ def post_process_styles(*style_args) #:nodoc:
31
+ styles.each do |name, style|
32
+ begin
33
+ if style_args.empty? || style_args.include?(name)
34
+ raise RuntimeError.new("Style #{name} has no processors defined.") if style.processors.blank?
35
+ @queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor|
36
+ Paperclip.processor(processor).make(file, style.processor_options, self)
37
+ end
38
+ end
39
+ rescue PaperclipError => e
40
+ log("An error was received while processing: #{e.inspect}")
41
+ (@errors[:processing] ||= []) << e.message if @whiny
42
+ end
43
+ end
44
+ end
45
+
46
+ def styles
47
+ unless @normalized_styles
48
+ @normalized_styles = {}
49
+ (@styles.respond_to?(:call) ? @styles.call(self) : @styles).each do |name, args|
50
+ @normalized_styles[name] = Paperclip::Style.new(name, args.dup, self)
51
+ end
52
+ end
53
+
54
+ if @normalized_styles.blank? and instance.wants_simple_crop?
55
+ temporary_simple_crop_style = {}
56
+ temporary_simple_crop_style[:original] = Paperclip::Style.new(:original, "100000x100000>", self)
57
+ return temporary_simple_crop_style
58
+ end
59
+
60
+ @normalized_styles
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,14 @@
1
+ module Paperclip
2
+ class Style
3
+ def processor_options
4
+ args = {}
5
+ @other_args.each do |k,v|
6
+ args[k] = v.respond_to?(:call) ? v.call(attachment) : v
7
+ end
8
+ [:processors, :geometry, :format, :whiny, :convert_options, :name].each do |k|
9
+ (arg = send(k)) && args[k] = arg
10
+ end
11
+ args
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ module Paperclip
2
+ class SimpleCrop < Thumbnail
3
+ alias :normal_transformation_command :transformation_command
4
+ def transformation_command
5
+ if wants_simpe_crop?
6
+ scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
7
+ trans = []
8
+ trans << "-crop" << %["#{simple_crop_string}"]
9
+ trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
10
+ trans
11
+ else
12
+ normal_transformation_command
13
+ end
14
+ end
15
+
16
+ def wants_simpe_crop?
17
+ eval (%w(x y w h).collect {|v| "!@attachment.instance.simple_crop_#{v}.blank?"}.join(" and ")+" and !@attachment.instance.simple_crop_style.blank? and @attachment.instance.simple_crop_style.to_sym == options[:name]")
18
+ end
19
+
20
+ def simple_crop_string
21
+ @attachment.instance.simple_crop_string
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,91 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{simple_crop}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Marian"]
12
+ s.date = %q{2010-12-17}
13
+ s.description = %q{Arbitrarily crop different styles of your paperclip images}
14
+ s.email = %q{marian@bitflut.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc",
18
+ "TODO"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ "CHANGELOG.rdoc",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "TODO",
29
+ "VERSION",
30
+ "init.rb",
31
+ "lib/generators/simple_crop/USAGE",
32
+ "lib/generators/simple_crop/install_generator.rb",
33
+ "lib/generators/simple_crop/templates/Jcrop.gif",
34
+ "lib/generators/simple_crop/templates/README",
35
+ "lib/generators/simple_crop/templates/jquery.Jcrop.css",
36
+ "lib/generators/simple_crop/templates/jquery.Jcrop.min.js",
37
+ "lib/generators/simple_crop/templates/jquery.simple-crop.js",
38
+ "lib/simple_crop.rb",
39
+ "lib/simple_crop/action_view_extensions/builder.rb",
40
+ "lib/simple_crop/action_view_extensions/form_helper.rb",
41
+ "lib/simple_crop/action_view_extensions/instance_tag.rb",
42
+ "lib/simple_crop/active_record/simple_crop.rb",
43
+ "lib/simple_crop/paperclip_patches/attachment.rb",
44
+ "lib/simple_crop/paperclip_patches/style.rb",
45
+ "lib/simple_crop/paperclip_processors/processor.rb",
46
+ "simple_crop.gemspec",
47
+ "test/helper.rb",
48
+ "test/test_simple_crop.rb"
49
+ ]
50
+ s.homepage = %q{http://github.com/bitflut/simple_crop}
51
+ s.licenses = ["MIT"]
52
+ s.require_paths = ["lib"]
53
+ s.rubygems_version = %q{1.3.7}
54
+ s.summary = %q{Makes cropping images easy}
55
+ s.test_files = [
56
+ "test/helper.rb",
57
+ "test/test_simple_crop.rb"
58
+ ]
59
+
60
+ if s.respond_to? :specification_version then
61
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
62
+ s.specification_version = 3
63
+
64
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
65
+ s.add_runtime_dependency(%q<rails>, [">= 3.0.0"])
66
+ s.add_runtime_dependency(%q<paperclip>, [">= 2.3.7"])
67
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
68
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
70
+ s.add_development_dependency(%q<rcov>, [">= 0"])
71
+ s.add_runtime_dependency(%q<paperclip>, [">= 2.3.7"])
72
+ else
73
+ s.add_dependency(%q<rails>, [">= 3.0.0"])
74
+ s.add_dependency(%q<paperclip>, [">= 2.3.7"])
75
+ s.add_dependency(%q<shoulda>, [">= 0"])
76
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
77
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
78
+ s.add_dependency(%q<rcov>, [">= 0"])
79
+ s.add_dependency(%q<paperclip>, [">= 2.3.7"])
80
+ end
81
+ else
82
+ s.add_dependency(%q<rails>, [">= 3.0.0"])
83
+ s.add_dependency(%q<paperclip>, [">= 2.3.7"])
84
+ s.add_dependency(%q<shoulda>, [">= 0"])
85
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
86
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
87
+ s.add_dependency(%q<rcov>, [">= 0"])
88
+ s.add_dependency(%q<paperclip>, [">= 2.3.7"])
89
+ end
90
+ end
91
+
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'simple_crop'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestSimpleCrop < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,204 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_crop
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Marian
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-17 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ type: :runtime
23
+ prerelease: false
24
+ name: rails
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 7
31
+ segments:
32
+ - 3
33
+ - 0
34
+ - 0
35
+ version: 3.0.0
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ type: :runtime
39
+ prerelease: false
40
+ name: paperclip
41
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 13
47
+ segments:
48
+ - 2
49
+ - 3
50
+ - 7
51
+ version: 2.3.7
52
+ requirement: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ type: :development
55
+ prerelease: false
56
+ name: shoulda
57
+ version_requirements: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirement: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ type: :development
69
+ prerelease: false
70
+ name: bundler
71
+ version_requirements: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ hash: 23
77
+ segments:
78
+ - 1
79
+ - 0
80
+ - 0
81
+ version: 1.0.0
82
+ requirement: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ type: :development
85
+ prerelease: false
86
+ name: jeweler
87
+ version_requirements: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ~>
91
+ - !ruby/object:Gem::Version
92
+ hash: 1
93
+ segments:
94
+ - 1
95
+ - 5
96
+ - 1
97
+ version: 1.5.1
98
+ requirement: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ type: :development
101
+ prerelease: false
102
+ name: rcov
103
+ version_requirements: &id006 !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ hash: 3
109
+ segments:
110
+ - 0
111
+ version: "0"
112
+ requirement: *id006
113
+ - !ruby/object:Gem::Dependency
114
+ type: :runtime
115
+ prerelease: false
116
+ name: paperclip
117
+ version_requirements: &id007 !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 13
123
+ segments:
124
+ - 2
125
+ - 3
126
+ - 7
127
+ version: 2.3.7
128
+ requirement: *id007
129
+ description: Arbitrarily crop different styles of your paperclip images
130
+ email: marian@bitflut.com
131
+ executables: []
132
+
133
+ extensions: []
134
+
135
+ extra_rdoc_files:
136
+ - LICENSE.txt
137
+ - README.rdoc
138
+ - TODO
139
+ files:
140
+ - .document
141
+ - CHANGELOG.rdoc
142
+ - Gemfile
143
+ - Gemfile.lock
144
+ - LICENSE.txt
145
+ - README.rdoc
146
+ - Rakefile
147
+ - TODO
148
+ - VERSION
149
+ - init.rb
150
+ - lib/generators/simple_crop/USAGE
151
+ - lib/generators/simple_crop/install_generator.rb
152
+ - lib/generators/simple_crop/templates/Jcrop.gif
153
+ - lib/generators/simple_crop/templates/README
154
+ - lib/generators/simple_crop/templates/jquery.Jcrop.css
155
+ - lib/generators/simple_crop/templates/jquery.Jcrop.min.js
156
+ - lib/generators/simple_crop/templates/jquery.simple-crop.js
157
+ - lib/simple_crop.rb
158
+ - lib/simple_crop/action_view_extensions/builder.rb
159
+ - lib/simple_crop/action_view_extensions/form_helper.rb
160
+ - lib/simple_crop/action_view_extensions/instance_tag.rb
161
+ - lib/simple_crop/active_record/simple_crop.rb
162
+ - lib/simple_crop/paperclip_patches/attachment.rb
163
+ - lib/simple_crop/paperclip_patches/style.rb
164
+ - lib/simple_crop/paperclip_processors/processor.rb
165
+ - simple_crop.gemspec
166
+ - test/helper.rb
167
+ - test/test_simple_crop.rb
168
+ has_rdoc: true
169
+ homepage: http://github.com/bitflut/simple_crop
170
+ licenses:
171
+ - MIT
172
+ post_install_message:
173
+ rdoc_options: []
174
+
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ hash: 3
183
+ segments:
184
+ - 0
185
+ version: "0"
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ none: false
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ hash: 3
192
+ segments:
193
+ - 0
194
+ version: "0"
195
+ requirements: []
196
+
197
+ rubyforge_project:
198
+ rubygems_version: 1.3.7
199
+ signing_key:
200
+ specification_version: 3
201
+ summary: Makes cropping images easy
202
+ test_files:
203
+ - test/helper.rb
204
+ - test/test_simple_crop.rb