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

    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.

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 25

      0
      Хороший пример, в закладки :)
        0
        Cогласен, плюс и закладка :)
          +6
          Где рабочий пример?
            +4
            Популярность Ruby среди домохозяек и блондинок резко повыситься!
            Не хватает только кода для автоматического добавления на фотографии всякой блестящей и розовой фигни, надписей ГЛАМУР и ЛЬВИЦА :) Думаю надо дополнить статью;)
              0
              разве хабр для домохозяек и блондинок? или вам надо пример на php?
                +1
                меня смутило наверно слово ВКонтакте! Видимо у контакта есть какой то свой особенный стиль в обрезке фотографий;)
              • UFO just landed and posted this here
                +1
                у меня где-то был рабочий код на prototype+php
                  +6
                  в стиле «ВКонтакте» — У Контакта есть стиль? Ну серьёзно )))
                    +1
                    «в стиле ВКонтакте» это как?
                      –1
                      Я дерусь в стиле «вконтакте»: знаю 1 прием, но зато какой — «скопипастить верстку с фейсбука».

                      По ссылкам сходите и поймете — имелось ввиду джаваскрипт кропанье. Тем не менее, я бы не стал это называть «стиль вконтакте».
                        +3
                        видимо, чтобы общая масса населения поняла, где можно посмотреть рабочий пример, хотя, я сомневаюсь, что людям, которые живут в «вконтаке», будет полезная эта статья :)
                      +1
                      Кстати, у кого-нибудь были проблемы с производительностью Rmagick… при генерации простейшей капчи из-за Rmagick сервер жутко тормозил, в версии RoR 1.6? Rmagick вообще выдерживает большие нагрузки?

                      А за статью автору спасибо.
                        +1
                        я отказался от использования Rmagick из-за утечек памяти, проще напрямую обращаться к ImageMagick
                        +1
                        Сражаюсь с похожей проблемой и очень расстраивает, что она очень проста, но пока не решаема этим простым способом с помощью jQuery UI из-за бага.

                        Простая реализация выделения части изображения прекрасно реализована на photosight.ru, где поверх нормального изображения добавляется полупрозрачная маска и блок с нормальным изображением с навешенным на него resizable и draggable, но там используется Prototype. Вот еще хороший и простой пример решения задачи другой библиотекой: interface.eyecon.ro/demos/resize.html

                        В jQuery UI же как-то плохо реагирует event на resize сверху и слева, судя по всему передает неправильные координаты из-за чего реализация такой проблемы на нем становится дерганой и с рандомными отступами области кропа. Создал баг, надеюсь пофиксят: dev.jqueryui.com/ticket/4554
                          0
                          Кстати, раз заговорили уже о jQuery. Может подскажете где взять подобный скрипт в инете?
                            0
                            Какой подобный? В аттаче тикета бага есть мой пример схожего решения, там все просто.
                          –2
                          Признаться ржал над «в стиле ВКонтакте».
                          Дааа, вконтакте был первым и самым известным, кто использовал эту технику.
                          Маразм.
                            +1
                            Тут имелось в виду не то, кто был первым, а то, на каком из популярных сайтов это сейчас применяется (цитата от КО). Я, например, вообще не знаю ни одного сайта, где это применяется, и в контакте не зарегистрирован.
                              0
                              Мне очень жаль за кругозор людей, которые знают только вконтакте…
                            0
                            а йа йай, ну не надо таких вещей делать с помощью rmagick. посмотрите на paperclip, там внутри есть удобные обертки для работы с imagemagick напрямую.
                              0
                              может вы поделитесь примером какие ключи использовать для этого? я с удовольствием добавлю в статью
                            • UFO just landed and posted this here
                                0
                                Хорошая статья с плохим названием. «Кроп в браузере» или что-то в этом духе было бы намного понятней ИМХО.
                                  +2
                                  Ваше название ничем не лучше… :)

                                Only users with full accounts can post comments. Log in, please.