Average Color of a Picture With Rails

Yesterday I worked to find a way to display a picture nicely and I was really impressed by the way to display the pictures in Pinterest. All the pictures before they are loaded in the page have already the right size and even a background color related to the picture and this is really nice.

So my plan was to do almost the same using carrierwave gem to upload a picture and on each pictures save the main color and the size of it.

For that there is one tool really impressive… ImageMagick. This tool can transform any kind of picture, change the size, the color, apply mask… and of course you can use it easily with carrierwave.

picture_uploader.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class PictureUploader < CarrierWave::Uploader::Base
  include CarrierWave::RMagick

  process :get_color

  def get_color
    manipulate! do |source|
      avgColor = source.scale(1, 1).pixel_color(0, 0)
      c = avgColor.to_color Magick::AllCompliance, false, Magick::QuantumDepth, true
      model.color = "##{c[1..2]}#{c[5..6]}#{c[9..10]}"
      source
    end
  end
end

We have to define a new process to manipulate the picture. In this manipulation you can put your tricky stuff.

To have the “average” of a color in a picture you can just scale it to 1x1 px source.scale(1, 1) then get the color on the first (and only) pixel pixel_color(0, 0). This will return a color from Magick and we just have to convert it in hexadecimal like #123456. For now I didn’t find any function to have this directly so I have to get the color in string and force to write it in hex to_color Magick::AllCompliance, false, Magick::QuantumDepth, true # true for hexadecimal format. So now we have a color with hexadecimal format but the format cannot be read in your css #123412341234… This is because Magick return more informations about the color but not needed for web so let’s just parse it with "##{c[1..2]}#{c[5..6]}#{c[9..10]}" (ok this is a bit dirty…).

Now everytime you will upload a picture your model will have the main color saved and you can so display as background color or box-shadow or whatever.

Bonus, if you want to have the size of the picture you can also with source.columns for the width and source.rows for the height.

1
2
3
4
5
6
<img src="<%= my_obj.picture %>"
     style="
       background-color: <%= my_obj.color %>; 
       width: <%= my_obj.width %>px; 
       height: <%= my_obj.height %>px;
       box-shadow: 0 0 10px 4px <%= my_obj.color %>">

Done, you have the same display as Pinterest for your pictures ;)

Comments

Copyright © 2014 - Anthony Estebe -