Romain Tribes
Romain Tribes

Reputation: 1818

Port ImageMagick commands to RMagick

I'm doing image processing with ImageMagick commands and I would like to port them to RMagick. The goal of this task is to take a picture and to pixelate given areas (one or more) for privacy purpose.

Here is my bash script (script.sh), which works very well using the convert command:

convert invoice.png -scale 10% -scale 1000% pixelated.png
convert invoice.png -gamma 0 -fill white -draw "rectangle 35, 110, 215, 250" mask.png
convert invoice.png pixelated.png mask.png -composite result.png

Now I want to create the Ruby version of this script using ImageMagick. Here is what I have now:

require 'rmagick'

# pixelate_areas('invoice.png', [ [ x1, y1, width, height ] ])
def pixelate_areas(image_path, areas)
  image     = Magick::Image::read(image_path).first
  pixelated = image.scale(0.1).scale(10)
  mask      = Magick::Image.new(image.columns, image.rows) { self.background_color = '#000' }

  areas.each do |coordinates|
    area = Magick::Image.new(coordinates[2], coordinates[3]) { self.background_color = '#fff' }
    mask.composite!(area, coordinates[0], coordinates[1], Magick::OverCompositeOp)
  end

  # Now, how can I merge my 3 images?
  # I need to extract the part of pixelated that overlap with the white part of the mask (everything else must be transparent).
  # Then I have to superpose the resulting image to the original (it's the easy part).
end

As you can see, I'm stuck at the last step. What operation do I need to do with my original picture, my pixelated picture and my mask in order to have this result?

How can I build an image with just the overlapping of the white part of the mask and the pixelated picture. Just like this one but with transparency instead of black?

Upvotes: 2

Views: 829

Answers (1)

Darshan Rivka Whittle
Darshan Rivka Whittle

Reputation: 34031

First, why are you porting commands to RMagick when you've got something that already works? The bash version is short and comprehensible. If this is just part of a larger script that you're porting, don't be afraid of system().

That said, here's a different tack that I believe accomplishes what you're trying to do in a more straightforward manner.

require 'RMagick'

def pixelate_area(image_path, x1, y1, x2, y2)
  image          = Magick::Image::read(image_path).first
  sensitive_area = image.crop(x1, y1, x2 - x1, y2 - y1).scale(0.1).scale(10)

  image.composite!(sensitive_area, x1, y1, Magick::AtopCompositeOp)
  image.write('result.png') { self.depth = image.depth }
end

This then seems to do the same as your original bash commands:

pixelate_area('invoice.png', 35, 110, 215, 250)

Since it looks like you want to handle multiple areas to blur out, here's a version that takes an array of areas (each as [x1, y1, x2, y2]):

def pixelate_areas(image_path, areas)
  image = Magick::Image::read(image_path).first

  areas.each do |area|
    x1, y1, x2, y2 = area

    sensitive_area = image.crop(x1, y1, x2 - x1, y2 - y1).scale(0.1).scale(10)
    image.composite!(sensitive_area, x1, y1, Magick::AtopCompositeOp)
  end

  image.write('result.png') { self.depth = image.depth }
end

Upvotes: 2

Related Questions