attachment_fu Thumbnail Size

As I mentioned earlier, when working with attachment_fu and image science the width and height of thumbnails were not being set correctly. So here is a method that I use to make sure that the data is set.



def set_image_dimensions
  if @image.width.blank? || @image.height.blank?
    ImageScience.with_image("#{RAILS_ROOT}/public/" << @image.public_filename) do |img|
      @image.height = img.height
      @image.width = img.width
    end
    @image.update_attribute('height',@image.height)
    @image.update_attribute('width',@image.width)
  end
end

Is anyone doing it differently ? Has this been addressed ?

Comments welcome.

Hamza

Fun with attachment_fu

As I mentioned in my previous post I am going to outline my experiences with attachment_fu. I will try to extend the brilliant tutorial that first introduced me to attachment_fu and to ImageScience.

The problem

The simple problem I had was that I wanted to be able to associate a image (and thumbnails) to a article. Although this sounds easy, I had some trouble along the way (hence the post).

Write the Migration models



class CreateImages < ActiveRecord::Migration

  def self.up
    create_table :images do |t|
      t.column :parent_id,  :integer
      t.column :content_type, :string
      t.column :filename, :string    
      t.column :thumbnail, :string 
      t.column :size, :integer
      t.column :width, :integer
      t.column :height, :integer
      t.column :content_id, :integer
    end
  end

  def self.down
    drop_table :images
  end
end

class CreateContents < ActiveRecord::Migration

  def self.up
    create_table :contents do |t|
      t.column :title , :string
      t.column :summary, :text
      t.column :body, :text
      t.column :status, :string
    end
  end

  def self.down
    drop_table :contents
  end
end

The only thing to note here is that I have placed a content_id foreign key into the image table, to allow them to be linked.

Write the models

The models are going to have two different associations, both of type has_one. The first association has an extra condition that allows it to only return the parent image, the second association returns the parent image and all its associated thumbnails.


class Content < ActiveRecord::Base
  has_one :image, :conditions => 'parent_id is null'
  has_one :all_images, :class_name => 'Image' # all photos + thumbnails
end

The Image model has the standard attachment_fu declaration along side the thumbnail declarations.


class Image < ActiveRecord::Base
  has_attachment :content_type => :image, 
                   :storage => :file_system,
                   :thumbnails => { :thumb => '107x76>'}    
end

Write the form view


<% form_for(:content, :url => { :action=>'create'}, 
                      :html => { :multipart => true }) do |f| -%>

<p>
  <label for="title">Title</label><br/>
  <%= f.text_field :title %>
</p>

<p>
  <label for="summary">Summary</label><br/>
  <%= f.text_area :summary %>
</p>

<p>
  <label for="title">Body</label><br/>
  <%= f.text_area :body %>
</p>

 <p>
    <label for="image">Associate Image:</label><br/>
    <%= file_field 'image','uploaded_data' %>
  </p>
  <p>
    <%= submit_tag 'Create' %>
  </p>
<% end -%>

As you can see I have placed the image in a different hash, as you can’t associate the file directly to the model. All of the other fields are pretty standard. To test out the update method you just need to change the URL to point to the update method and pass it the content id. I will leave it out here for simplicity.

Write the controller

This is where I was having most trouble. No matter what I did, it just did not save the dam thing. So here is my create and update actions in my contents controller


def create
    #Create the content
    @content = Content.new(params[:content])
    respond_to do |format|
      if @content.save
        #Here comes the important bit!
        if !params[:image][:uploaded_data].blank?
          @content.image = Image.create(params[:image])       
        end
        flash[:notice] = 'Content was successfully created.'
        format.html { redirect_to :action=>'show', :id=>@content }
      else
        format.html { render :action => "new" }
      end
    end
  end  

OK that was not that hard :). But I was having problems on the update action. The create action seemed to be working fine. Here is the update action.


  def update
      @content = Content.find(params[:id])
      respond_to do |format|
        if @content.update_attributes(params[:content])
          # Heres the important bit!
          if !params[:image][:uploaded_data].blank?
            #find current image
            @image = @content.image ||= Image.new
            @image = @content.image.build(params[:image])
            @image.save       
          end
          format.html { redirect_to :action=>'show', :id=>@content }
        else
          format.html { render :action => "edit" }
        end
      end
    end
 

As you can see I am using the build method to create the image. I am not sure why, but If I put the build method into the create method it just fails. Oh yeah and in a real application I would group the image methods into their own respective functions.

The content view

So for all the code we have written we can now show the images that are associated with a specific article.


  <h2><%=@content.title%> </h2>
  <p><%=@content.summary%></p>

<%if !@content.image.blank?%> 
  <p>
    Original Image : <%=image_tag @content.image.public_filename %>
  </p>
  <p>
    Thumbnail : <%=image_tag @content.image.public_filename(:thumb) %>
  </p>
  <p>
    <%=@content.body%>
  </p>
<%end%>

Outstanding issues

There a few bugs in attachment_fu that I came across, they are :

  • The width and the height are not being set for thumbnails when I use ImageScience and attachment_fu.
  • The size (in the database field) of the thumbnails are not correct. They just display the original file’s image size.

I will blog again regarding these issues in the near future.

Code

In writing this post, I made a test rails app so I could make sure that the code I have above is correct and compiles without any errors. If anyone wants this I can put a link to it here, just leave a comment.

As usual all comments welcome.

Hamza

Compiling FreeImage on OS X (Power PC)

I was very excited when I read this excellent blog post by Mike Clark, detailing how to use attachment_fu. Even more interesting was that I did not have to use RMagick anymore. I could not quite get it working correctly for me, not to mention the reported memory leaks and CPU cycles it takes up.

Instead I could use ImageScience which is a small Inline Ruby library that re-sizes images. However for me to install ImageScience I had to install FreeImage on my mac.

Whatever I did I could not get it installed on my power pc mac laptop. I tried the instructions given, but nothing worked. I then noticed that there was a problem with the current release for macs and was advised to use the subversion repository. I tried to do this, but whenever I tried to run make, it just kept on complaining that it can’t find the libs that were related to the Intel 386 platform. So the make file was not correctly working for the power pc architecture.

I posted to the forums, and luckily Josh emailed me with a makefile that stripped out all of the 386 calls (i tried this myself but did not get very far). The new make file did the trick. Thanks Josh :)

So if anyone else is having the same problem here is the make file

In my next post I will be talking about my adventures with attachment_fu and extending the tutorial laid out in Mike Clark’s blog post.

Hamza