4

I have used resize_to_fill down to a [1,1] size thus reducing the image to a single pixel containing what is basically the average color of the entire image (provided the image does not have a huge disparity between height and width, of course). Now I'm attempting to retrieve the color of this single pixel in hex format.

From the terminal window I am able to run the convert command like this:

convert image.png txt:
# ImageMagick pixel enumeration: 1,1,255,rgb
0,0: (154,135,116) #9A8774 rgb(154,135,116)

I am however uncertain of how I could run this command from inside the application during the before_save section of the model that the image belongs to. The image is uploaded and attached using carrierwave

So far I have retrieved the image:

image = MiniMagick::Image.read(File.open(self.image.path))

But I'm not quite certain how to procede from here.

ken-guru
  • 43
  • 4

3 Answers3

7

You could add a pixel_at method like this:

module MiniMagick
  class Image
    def pixel_at(x, y)
      case run_command("convert", "#{escaped_path}[1x1+#{x}+#{y}]", "-depth 8", "txt:").split("\n")[1]
      when /^0,0:.*(#[\da-fA-F]{6}).*$/ then $1
      else nil
      end
    end
  end
end

And then use it like this:

i = MiniMagick::Image.open("/path/to/image.png")
puts i.pixel_at(100, 100)

Outputs:

#34555B
Mattias Wadman
  • 11,172
  • 2
  • 42
  • 57
  • Cool. Im now sure how it will have if you poke outside the image or if there is a alpha channel. So be aware of that :) – Mattias Wadman Jan 17 '12 at 13:28
  • I think that having scaled down the image to a 1px by 1px size first should eliminate that issue, but definitely worth keeping in mind for another implementation. – ken-guru Jan 17 '12 at 14:01
  • 2
    What is escaped_path? ~ I am actually trying this and getting ```undefined method `escaped_path' for # (NoMethodError)``` – Nobita Nov 13 '13 at 23:14
  • It's a instance method in `MiniMagick::Image` returning the shell escaped path for the image, see https://github.com/probablycorey/mini_magick/blob/master/lib/mini_magick.rb#L187 But by your error message it looks like some code is calling `escaped_path` on a or inside a `MiniMagick::CommandBuilder` instance. – Mattias Wadman Nov 13 '13 at 23:41
  • But I assume that your code was also using Minimagick, and therefore Mogrify. Interesting, I fail to see how to use escaped_path in order to use the path of the image and not having it to pass it to your method (which btw is being really useful :P) – Nobita Nov 14 '13 at 00:00
  • Yes my code snippet extends the `MiniMagick::Image` class with a new method. How do you add my code, the whole thing or just added `pixel_at` somewhere? could you give some example of how you open or create an image and then try to call `pixel_at`? – Mattias Wadman Nov 14 '13 at 00:20
  • 1
    `Rails 3.2.x` implementation of this answer and solution to `MiniMagick::CommandBuilder` error: https://gist.github.com/awesome/9964231#file-minimagick-pixel-at-get-hex-color-rb – SoAwesomeMan Apr 03 '14 at 22:36
  • What was the problem? feel free to update my answer to add note about the fix for 3.2.x. – Mattias Wadman Apr 03 '14 at 23:14
4

For recent versions of MiniMagick change escaped_path to path like this:

module MiniMagick
  class Image
    def pixel_at x, y
      run_command("convert", "#{path}[1x1+#{x.to_i}+#{y.to_i}]", 'txt:').split("\n").each do |line|
        return $1 if /^0,0:.*(#[0-9a-fA-F]+)/.match(line)
      end
      nil
    end
  end
end
Peter
  • 545
  • 5
  • 14
1

To use with Rails 4 the code needs to be slightly different:

# config/application.rb

module AwesomeAppName
  class Application < Rails::Application
    config.after_initialize do
      require Rails.root.join('lib', 'gem_ext.rb')
    end
  end
end

# lib/gem_ext.rb
require "gem_ext/mini_magick"

# lib/gem_ext/mini_magick.rb
require "gem_ext/mini_magick/image"

# lib/gem_ext/mini_magick/image.rb
module MiniMagick
  class Image
    def pixel_at(x, y)
      case run_command("convert", "#{path}[1x1+#{x}+#{y}]", "-depth", '8', "txt:").split("\n")[1]
      when /^0,0:.*(#[\da-fA-F]{6}).*$/ then $1
      else nil
      end
    end
  end
end

# example
#$ rails console
image = MiniMagick::Image.open(File.expand_path('~/Desktop/truck.png'))
#=> #<MiniMagick::Image:0x007f9bb8cc3638 @path="/var/folders/1q/fn23z3f11xd7glq3_17vhmt00000gp/T/mini_magick20140403-1936-phy9c9.png", @tempfile=#<File:/var/folders/1q/fn23z3f11xd7glq3_17vhmt00000gp/T/mini_magick20140403-1936-phy9c9.png (closed)>>
image.pixel_at(1,1)
#=> "#01A30D"
The Whiz of Oz
  • 6,763
  • 9
  • 48
  • 85