2011-07-07 10 views
6

Jestem (luźno) podążam za RailsCasts tutorial #182, która używa Paperclip, ImageMagick i Jcrop, aby umożliwić niestandardowe przycinanie przesłanych obrazów.Przycinanie przy użyciu spinacza spinacza, ImageMagick, Jcrop i S3: Dlaczego nie "image.reprocess!" powtórzyć?

Ponieważ używam Amazon S3 do przechowywania plików, musiałem ponownie dopasować części samouczka, aby pasowały. Wydaje się, że wszystko działa doskonale z wyjątkiem, ponieważ przycięta wersja mojego obrazu nie jest ponownie przetwarzana (lub wynik tego procesu nie jest ponownie przesyłany do S3) - więc po procesie kadrowania jestem pozostawione z tym samym obrazem, który pierwotnie przesłałem (dotyczy to wszystkich rozmiarów obrazów, które przechowuję dla każdego obrazu).

Oto moja funkcja (jak w Feature Image) Model:

class Feature < ActiveRecord::Base 
    require "#{Rails.root}/lib/paperclip_processors/cropper.rb" 

    attr_accessible :image_file_name, :image 
    attr_accessor  :crop_x, :crop_y, :crop_w, :crop_h 
    after_update  :reprocess_image, :if => :cropping? 

    if Rails.env == "production" 
    S3_CREDENTIALS = { :access_key_id  => '<REDACTED>', 
        :secret_access_key => '<REDACTED>', 
        :bucket   => "<REDACTED>"} 
    else 
    S3_CREDENTIALS = { :access_key_id  => '<REDACTED>', 
        :secret_access_key => '<REDACTED>', 
        :bucket   => "<REDACTED>"} 
    end 

    has_attached_file :image, 
        :styles   => { :small => "240x135>", :croppable => "960x960>", :display => "960x540>" }, 
        :processors  => [:cropper], 
        :storage   => :s3, 
        :s3_credentials => S3_CREDENTIALS, 
        :path   => "features/:id/:style.:extension" 

    validates_attachment_content_type :image, :content_type => ['image/jpeg', 'image/gif', 'image/png', 
                   'image/pjpeg', 'image/x-png'], 
              :message => 'must be a JPEG, GIF or PNG image' 

    def cropping? 
    !crop_x.blank? && !crop_y.blank? && !crop_w.blank? && !crop_h.blank? 
    end 

    def image_geometry(style = :original) 
    @geometry ||= {} 
    path = (image.options[:storage]==:s3) ? image.url(style) : image.path(style) 
    @geometry[style] ||= Paperclip::Geometry.from_file(path) 
    end 

    private 

    def reprocess_image 
    image.reprocess! 
    end 
end 

Oto mój 'cropper.rb' (procesor Spinacz):

module Paperclip 
    class Cropper < Thumbnail 
    def transformation_command 
     if crop_command 
     crop_command + super.sub(/ -crop \S+/, '') 
     else 
     super 
     end 
    end 

    def crop_command 
     target = @attachment.instance 
     if target.cropping? 
     " -crop '#{target.crop_w}x#{target.crop_h}+#{target.crop_x}+#{target.crop_y}'" 
     end 
    end 
    end 
end 

Odpowiednie działania mojego FeaturesController:

class FeaturesController < ApplicationController 

    def new 
    @feature = Feature.new 
    end 

    def create 
    @feature = Feature.new(params[:feature]) 
    if @feature.save 
     if params[:feature][:image].blank? 
     flash[:notice] = "New feature added!" 
     redirect_to @feature 
     else 
     render :crop 
     end 
    else 
     @title = "Add a New Feature" 
     render :new 
    end 
    end 

    def edit 
    @feature = Feature.find(params[:id]) 
    @title = "Edit #{@feature.headline}" 
    end 

    def update 
    @feature = Feature.find(params[:id]) 
    if @feature.update_attributes(params[:feature]) 
     if params[:feature][:image].blank? 
     flash[:notice] = "Feature updated!" 
     redirect_to @feature 
     else 
     render :crop 
     end 
    else 
     @title = "Edit Feature" 
     render :edit 
    end 
    end 
end 

a stosowne linie mojego 'crop.html.erb' widok:

<% content_for :javascript_includes do %> 
    <%= javascript_include_tag 'jquery.Jcrop.min' %> 
    <script type="text/javascript" charset="utf-8"> 
    $(function() { 
     $('#cropbox').Jcrop({ 
      onChange: update_crop, 
      onSelect: update_crop, 
      setSelect: [0, 0, 960, 540], 
      aspectRatio: 960/540 
     }); 
    }); 

    function update_crop(coords) { 
     var ratio = <%= @feature.image_geometry(:original).width %>/<%= @feature.image_geometry(:croppable).width %>; 
     $("#crop_x").val(Math.round(coords.x * ratio)); 
     $("#crop_y").val(Math.round(coords.y * ratio)); 
     $("#crop_w").val(Math.round(coords.w * ratio)); 
     $("#crop_h").val(Math.round(coords.h * ratio)); 
    }; 
    </script> 
<% end %> 
<% content_for :style_includes do %> 
    <%= stylesheet_link_tag 'jquery.Jcrop', :media => 'screen' %> 
<% end %> 

<%= image_tag @feature.image.url(:croppable), :id => "cropbox" %> 

<% form_for @feature do |f| %> 
    <% for attribute in [:crop_x, :crop_y, :crop_w, :crop_h] %> 
     <%= f.hidden_field attribute, :id => attribute %> 
    <% end %> 
    <p><%= f.submit "Crop" %></p> 
<% end %> 

Problemem nie że wystąpi błąd z niestandardowych uprawy (offset, powierzchni zasiewów, etc.), jest to, że nie ma żadnych upraw dzieje gdy klikam „crop” - jestem po prostu zostawiłem zdjęcia, które dostałem z oryginalnego uploadu/procesu. Nie wydaje się, że "image.reprocess!" w ogóle się dzieje (lub wyniki ponownego przetworzenia nie są zapisywane w S3).

Dlaczego to możliwe i co mogę z tym zrobić?

Odpowiedz

2

Ok, niech starają się pomóc :)

Po pierwsze, można nie obejmować procesor spinacza w modelu, niech Spinacz poradzić.

Po drugie, usuń :after_update i wymień na :before_update, który powinien ustawić twój image.options[ :crop ] dla procesora. W procesora, spróbuj tego:

def initialize file, options = {}, attachment = nil 
    super 
    #...... 

    @crop = options[ :crop ] 

    #...... 

Po trzecie, modyfikować swój transformation_command w procesorze:

def transformation_command 
    if @crop 
     trans = " -quality 75" 
     trans << " -crop \"#{<YOUR_CODE>}\" +repage" if @crop 
     trans 
    end 
end 

A potem pisać swoje spostrzeżenia :)

+0

Tak! Miałem ten sam problem co oryginalny pytający, a twoja sugestia zmiany after_update na before_update naprawiła to dla mnie. Dzięki wielkie! –

0

ja również tego samego RailsCast wideo, aby pomóc mnie przycinam do pracy. Wystąpił podobny problem z błędem NOSUCHKEY, który udało mi się prześledzić do ponownego przetworzenia! połączenie, które było wywoływane after_update. Udało mi się naprawić problem, używając odpowiedzi Visha i modyfikując go. Moje rozwiązanie może nie być dokładnie tym, czego potrzebujesz, ponieważ przycinam za każdym razem.

Po prostu usunąłem wywołanie after_update w celu ponownego przetworzenia! i zostawił wszystko na swoim miejscu. To spowodowało, że przekazany procesor (narzędzie do przycinania w twoim przypadku) został użyty zamiast domyślnego i występuje przed przesłaniem obrazu do S3. Ponieważ przycinasz plik przed przesłaniem go po raz pierwszy wszystko działa!

Jeśli chcesz mieć przycinanie warunkowe, powinieneś zrobić to, co zaproponował Vish, czyli ustawić zmienną lub przekazać opcję z obiektem obrazu w before_update. Musi być dostępny w niestandardowym procesorze, aby można było wprowadzić warunkową logikę uprawy w oparciu o jego wartość.