Permalink
Browse files

getting there

  • Loading branch information...
1 parent 0a4679b commit e3329e550c609fac62db3aaffdeb9be073e2c2df @will-r will-r committed Apr 13, 2012
Showing with 182 additions and 113 deletions.
  1. +0 −107 app/models/upload.rb
  2. +25 −6 lib/cropper/attachment.rb
  3. +123 −0 lib/cropper/upload.rb
  4. +34 −0 lib/cropper/uploads_controller.rb
View
@@ -1,107 +0,0 @@
-# Uploads are created by users in the course of adding a picture record.
-# The upload is a raw form that is presented in the edting interface to let the user chosoe
-# the scale and crop: those decisions are applied when the upload's file is assigned as the
-# user's image.
-
-class Upload < ActiveRecord::Base
- belongs_to :person
-
- # So here we create relatively few styles. There is an `:icon` in case we ever want to display an
- # upload chooser, and there is a large `:precrop` style for presentation in the scaling-and-cropping
- # interface, where it will be dragged and resized until the page looks right and the image is saved.
- #
- has_attached_file :file,
- :path => ":rails_root/public/system/:class/:attachment/:id/:style/:filename",
- :url => "/system/:class/:attachment/:id/:style/:filename",
- :styles => { :thumb => "100x100#", :precrop => "1200x1600>" }
-
- ## Image dimensions
- #
- # We need to know dimensions of the precrop image in order to set up the cropping interface, so we
- # examine the uploaded file before it is flushed.
- #
- after_post_process :read_dimensions
-
- # *original_geometry* returns the discovered dimensions of the uploaded file as a paperclip geometry object.
- #
- def original_geometry
- @original_geometry ||= Paperclip::Geometry.new(original_width, original_height)
- end
-
- # *geometry*, given a style name, returns the dimensions of the file if that style were applied. For
- # speed we calculate this rather than reading the file, which might be in S3 or some other distant place.
- #
- # The logic is in [lib/paperclip/geometry_tranformation.rb](/lib/paperclip/geometry_tranformation.html),
- # which is a ruby library that mimics the action of imagemagick's convert command.
- #
- def geometry(style_name='original')
- # These calculations are all memoised.
- @geometry ||= {}
- begin
- @geometry[style_name] ||= if style_name.to_s == 'original'
- # If no style name is given, or it is 'original', we return the original discovered dimensions.
- original_geometry
- else
- # Otherwise, we apply a mock transformation to see what dimensions would result.
- style = self.file.styles[style_name.to_sym]
- original_geometry.transformed_by(style.geometry)
- end
- rescue Paperclip::TransformationError => e
- # In case of explosion, we always return the original dimensions so that action can continue.
- original_geometry
- end
- end
-
- # *width* returns the width of this image in a given style.
- #
- def width(style_name='original')
- geometry(style_name).width.to_i
- end
-
- # *height* returns the height of this image in a given style.
- #
- def height(style_name='original')
- geometry(style_name).height.to_i
- end
-
- # *square?* returns true if width and height are the same.
- #
- def square?(style_name='original')
- geometry(style_name).square?
- end
-
- # *vertical?* returns true if the image, in the given style, is taller than it is wide.
- #
- def vertical?(style_name='original')
- geometry(style_name).vertical?
- end
-
- # *horizontal?* returns true if the image, in the given style, is wider than it is tall.
- #
- def horizontal?(style_name='original')
- geometry(style_name).horizontal?
- end
-
- # *dimensions_known?* returns true we have managed to discover the dimensions of the original file.
- #
- def dimensions_known?
- original_width? && original_height?
- end
-
-private
-
- # *read_dimensions* is called after post processing to record in the database the original width, height
- # and extension of the uploaded file. At this point the file queue will not have been flushed but the upload
- # should be in place. We grab dimensions from the temp file and calculate thumbnail dimensions later, on demand.
- #
- def read_dimensions
- if file = self.file.queued_for_write[:original]
- geometry = Paperclip::Geometry.from_file(file)
- self.original_width = geometry.width
- self.original_height = geometry.height
- self.original_extension = File.extname(file.path)
- end
- true
- end
-
-end
View
@@ -32,7 +32,9 @@ def has_upload(attachment_name=:image, options={})
end
options.reverse_merge!(:geometry => "640x960#", :cropped => true)
- options[:geometry].sub!(/\D*$/, '#') if options[:cropped]
+ options[:geometry].sub!(/\D*$/, '') if options[:cropped]
+ # raise here if geometry is not useable
+
class_variable_set(:"@@#{attachment_name}_cropped", options[:cropped])
# The essential step is present in this style definition. It specifies the OffsetThumbnail processor,
@@ -46,15 +48,17 @@ def has_upload(attachment_name=:image, options={})
# The processor will first scale the image to the width that is specified by the scale_width property of the instance
:scale => lambda { |att|
- width = send :"#{attachment_name}_scale_width"
+ STDERR.puts "scale #{att.inspect}"
+ width = att.instance.send :"#{attachment_name}_scale_width"
"#{width}x"
},
# ...then perform the crop described by the width, height, offset_top and offset_left properties of the instance.
:crop_and_offset => lambda { |att|
- width, height = size.split('x')
- left = send :"#{attachment_name}_offset_left"
- top = send :"#{attachment_name}_offset_top"
+ STDERR.puts "crop_and_offset #{att.inspect}"
+ width, height = options[:geometry].split('x')
+ left = att.instance.send :"#{attachment_name}_offset_left"
+ top = att.instance.send :"#{attachment_name}_offset_top"
"%dx%d%+d%+d" % [width, height, -left, -top]
}
}
@@ -64,7 +68,7 @@ def has_upload(attachment_name=:image, options={})
# [uploads](/app/models/upload.html) are the raw image files uploaded by this person.
# They are held separately as the basis for repeatable (and shareable) image assignment.
#
- belongs_to :"#{attachment_name}_upload"
+ belongs_to :"#{attachment_name}_upload", :class_name => "Upload"
before_save :"read_#{attachment_name}_upload"
### Attachment
@@ -93,6 +97,7 @@ def has_upload(attachment_name=:image, options={})
# and apply the current crop and scale values.
#
define_method :"read_#{attachment_name}_upload" do
+ STDERR.puts ">> read_#{attachment_name}_upload"
if self.send(:"reprocess_#{attachment_name}?") && upload = self.send(:"#{attachment_name}_upload")
self.send :"#{attachment_name}=", upload.file
end
@@ -103,14 +108,28 @@ def has_upload(attachment_name=:image, options={})
cols = [:upload_id]
cols += [:upload_id, :scale_width, :offset_top, :offset_left] if options[:cropped]
define_method :"reprocess_#{attachment_name}?" do
+ STDERR.puts ">> reprocess_#{attachment_name}?"
cols.any? {|col| send(:"#{attachment_name}_#{col}_changed?") }
end
# * [name]_cropped? returns true if the named attachment is cropped on assignment. It can be useful in a form partial.
#
define_method :"#{attachment_name}_cropped?" do
+ STDERR.puts ">> #{attachment_name}_cropped?"
!!class_variable_get(:"@@#{attachment_name}_cropped")
end
+
+
+
+
+
+ define_method :"#{attachment_name}_for_cropping" do
+ if upload = send(:"#{attachment_name}_upload")
+ # here we introduce a convention that might not stand up
+ STDERR.puts ">> #{attachment_name}_for_cropping"
+ upload.url(:"#{attachment_name}")
+ end
+ end
end
end
View
@@ -0,0 +1,123 @@
+# This is a base class for your uploads. It defines all the essential methods and offers some hooks that
+# you can override to set local style definitions. All you need is something like this:
+#
+# class Upload << Cropper::Upload
+# def thumbnail_styles
+# {:precrop => "500x500>"}
+# end
+#
+# If you have models with very different image-crop outcomes you may want to define a different precrop
+# style for each one.
+#
+module Cropper
+ class Upload < ActiveRecord::Base
+ belongs_to :person
+
+ has_attached_file :file,
+ :path => ":rails_root/public/system/:class/:attachment/:id/:style/:filename",
+ :url => "/system/:class/:attachment/:id/:style/:filename",
+ :processors => lambda { |att| att.instance.precrop_processors },
+ :styles => lambda { |att| att.instance.precrop_styles }
+
+ def precrop_styles
+ {
+ :icon => { :geometry => "40x40#" },
+ :precrop => { :geometry => "1600x1600>" },
+ }
+ end
+
+ def precrop_processors
+ [:thumbnail]
+ end
+
+ ## Image dimensions
+ #
+ # We need to know dimensions of the precrop image in order to set up the cropping interface, so we
+ # examine the uploaded file before it is flushed.
+ #
+ after_post_process :read_dimensions
+
+ # *original_geometry* returns the discovered dimensions of the uploaded file as a paperclip geometry object.
+ #
+ def original_geometry
+ @original_geometry ||= Paperclip::Geometry.new(original_width, original_height)
+ end
+
+ # *geometry*, given a style name, returns the dimensions of the file if that style were applied. For
+ # speed we calculate this rather than reading the file, which might be in S3 or some other distant place.
+ #
+ # The logic is in [lib/paperclip/geometry_tranformation.rb](/lib/paperclip/geometry_tranformation.html),
+ # which is a ruby library that mimics the action of imagemagick's convert command.
+ #
+ def geometry(style_name='original')
+ # These calculations are all memoised.
+ @geometry ||= {}
+ begin
+ @geometry[style_name] ||= if style_name.to_s == 'original'
+ # If no style name is given, or it is 'original', we return the original discovered dimensions.
+ original_geometry
+ else
+ # Otherwise, we apply a mock transformation to see what dimensions would result.
+ style = self.file.styles[style_name.to_sym]
+ original_geometry.transformed_by(style.geometry)
+ end
+ rescue Paperclip::TransformationError => e
+ # In case of explosion, we always return the original dimensions so that action can continue.
+ original_geometry
+ end
+ end
+
+ # *width* returns the width of this image in a given style.
+ #
+ def width(style_name='original')
+ geometry(style_name).width.to_i
+ end
+
+ # *height* returns the height of this image in a given style.
+ #
+ def height(style_name='original')
+ geometry(style_name).height.to_i
+ end
+
+ # *square?* returns true if width and height are the same.
+ #
+ def square?(style_name='original')
+ geometry(style_name).square?
+ end
+
+ # *vertical?* returns true if the image, in the given style, is taller than it is wide.
+ #
+ def vertical?(style_name='original')
+ geometry(style_name).vertical?
+ end
+
+ # *horizontal?* returns true if the image, in the given style, is wider than it is tall.
+ #
+ def horizontal?(style_name='original')
+ geometry(style_name).horizontal?
+ end
+
+ # *dimensions_known?* returns true we have managed to discover the dimensions of the original file.
+ #
+ def dimensions_known?
+ original_width? && original_height?
+ end
+
+ private
+
+ # *read_dimensions* is called after post processing to record in the database the original width, height
+ # and extension of the uploaded file. At this point the file queue will not have been flushed but the upload
+ # should be in place. We grab dimensions from the temp file and calculate thumbnail dimensions later, on demand.
+ #
+ def read_dimensions
+ if file = self.file.queued_for_write[:original]
+ geometry = Paperclip::Geometry.from_file(file)
+ self.original_width = geometry.width
+ self.original_height = geometry.height
+ self.original_extension = File.extname(file.path)
+ end
+ true
+ end
+
+ end
+end
@@ -0,0 +1,34 @@
+class UploadsController < ApplicationController
+ respond_to :js
+
+ def show
+ @upload = params[:id] == 'latest' || params[:id].blank? ? current_user.last_upload : Upload.find(params[:id])
+ respond_with(@upload)
+ end
+
+ def create
+ @upload = Upload.create(params[:upload])
+ render :partial => 'crop'
+ end
+
+ def edit
+ @upload = Upload.find(params[:id])
+ if @person && @upload = @person.upload
+ render :partial => 'crop', :locals => {
+ :scale_w => @person.image_scale_width,
+ :scale_h => @person.image_scale_height,
+ :scale_t => @person.image_offset_top,
+ :scale_l => @person.image_offset_left
+ }
+ else
+ render :partial => 'crop'
+ end
+ end
+
+ def destroy
+ @upload = Upload.find(params[:id])
+ @upload.destroy
+ respond_with(@upload)
+ end
+
+end

0 comments on commit e3329e5

Please sign in to comment.