22 June 2009

Обрезаем фото в стиле «ВКонтакте»

Ruby on Rails
image
В этом HOWTO я раскажу вам как обрезать фотографию до нужного вам размера и залить её на сервер с помощью Ruby on Rails.

Итак, для наших целей наиболее подходят 2 плагина:
Prototype JavaScript Image Cropper UI
jQuery image crop plugin

Написаны они, как вы понимает на 2 разных библиотеках, и так как в моем проекте уже был установлен JRails и второй плагин мне показался более продвинутым, я остановил свой выбор на нем. Но суть примера от этого не меняется.

Я не буду тратить время на рассказ о том, как сделать Hello world на RoR, поэтому просто создадим модель и контроллер:
$ script/generate model upload description:string
$ script/generate paperclip upload photo
$ script/generate controller uploads
#models/upload.rb
 
class Upload < ActiveRecord::Base

  has_attached_file :photo,
                    :styles => {
                      :thumb => ["100x100", :jpg],
                      :pagesize => ["500x400", :jpg],
                    },
                    :default_style => :pagesize
end
Подключаем библиотеки:
# views/layouts/application.html.erb
 
<%= javascript_include_tag 'lib/jquery.min.js' %>
<%= javascript_include_tag 'cropper/jquery.jcrop.js' %>
И делаем представление «Edit»:
# view/uploads/edit.html.erb

<script type="text/javascript" language="JavaScript">
function showCoords( c ) {
  $( 'upload_x1' ).val(c.x);
  $( 'upload_y1' ).val(c.y);
  $( 'upload_width' ).val(c.w);
  $( 'upload_height' ).val(c.h);
}
$(function(){
	$('#jcrop_target').Jcrop({
		onChange: showCoords,
		onSelect: showCoords
	});
});
</script>
 
<h1>Editing upload</h1>
 
<% form_for(@upload) do |f| %>
  <%= f.error_messages %>
 
  <p>
    <%= f.label :description %><br />
    <%= f.text_field :description %>
  </p>
 
  <!-- CROP FORM -->
  <div id='jcrop_target'>
    <%= image_tag @upload.photo.url, :id => 'cropimage' %>
  </div>
 
  <div id='cropresults'>
    <%= f.label 'x1' %>
    <%= f.text_field 'x1', :size => 6 %>
    <br />
    <%= f.label 'y1' %>
    <%= f.text_field 'y1', :size => 6 %>
    <br />
    <%= f.label 'width' %>
    <%= f.text_field 'width', :size => 6 %>
    <br />
    <%= f.label 'height' %>
    <%= f.text_field 'height', :size => 6 %>
    <br />
  </div> <!-- cropresults -->
  <!-- END CROP FORM -->
 
  <p>
    <%= f.submit "Update" %>
  </p>
<% end %>
Почти все, добавляем событие update:
# controllers/uploads_controller.rb
 
def update
  @upload = Upload.find params[:id]
  if @upload.update_attributes params[:upload]
    flash[:notice] = 'Upload was successfully updated.'
    redirect_to @upload
  else
    render :action => "edit"
  end
end
И наконец вот она, основная магия:
# models/upload/upload.rb

require 'RMagick'
 
attr_accessor :x1, :y1, :width, :height

def update_attributes(att)
 
  scaled_img = Magick::ImageList.new(self.photo.path)
  orig_img = Magick::ImageList.new(self.photo.path(:original))
  scale = orig_img.columns.to_f / scaled_img.columns
 
  args = [ att[:x1], att[:y1], att[:width], att[:height] ]
  args = args.collect { |a| a.to_i * scale }
 
  orig_img.crop!(*args)
  orig_img.write(self.photo.path(:original))
 
  self.photo.reprocess!
  self.save
 
  super(att)
end
Здесь мы рассчитываем коэффициент масштабирования. Далее мы готовим четыре аргумента для RMagick crop функции, которая ожидает X1, Y2, ширину и высоту. Изображение изменяется и записывается заменив собой оригинал.

Все, всем спасибо за внимание. Здесь пример для prototype.
Tags:rubyrailscroppaperclipjqueryjavascriptrmagickimagemagickprototype
Hubs: Ruby on Rails
Comments 25
Ads