Class: ImageVise::EllipseStencil

Inherits:
Object
  • Object
show all
Defined in:
lib/image_vise/operators/ellipse_stencil.rb

Overview

Applies an elliptic stencil around the entire image. The stencil will fit inside the image boundaries, with about 1 pixel cushion on each side to provide smooth anti-aliased edges. If the input image to be provessed is square, the ellipse will turn into a neat circle.

This adds an alpha channel to the image being processed (and premultiplies the RGB channels by it). This will force the RenderEngine to return the processed image as a PNG in all cases, instead of keeping it in the original format.

The corresponding Pipeline method is ‘ellipse_stencil`.

Instance Method Summary collapse

Instance Method Details

#apply!(magick_image) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/image_vise/operators/ellipse_stencil.rb', line 15

def apply!(magick_image)
  width, height = magick_image.columns, magick_image.rows
  
  # This is a bit involved. We need to do a manual composite. Here is what it entails.
  #
  # Given a premultiplied RGB image B, and a grayscale mask A, we need to do the following
  # operation:
  #
  #    BrBgBb / Ba * (Ba * A)
  #
  # Since ImageMagick works with unpremultiplied alphas, it is doable - but special care
  # must be taken not to overmult or overdivide.
  #
  # To begin,generate a black and white image for the stencil
  mask = Magick::Image.new(width, height)
  draw_circle(mask, width, height)
  
  # At this stage the mask contains a B/W image of the circle, black outside, white inside.
  # Retain the alpha of the original in a separate image
  only_alpha = magick_image.copy
  only_alpha.alpha(Magick::ExtractAlphaChannel)
  mask.composite!(only_alpha, Magick::CenterGravity, Magick::MultiplyCompositeOp)
  
  # With this composite op, enabling alpha on the destination image is
  # not required - it will be enabled automatically.
  # The CopyOpacityCompositeOp implies that we copy the grayscale version
  # of the RGB channels as the alpha channel, so for some weird reason we need
  # to disable the alpha on our mask image
  mask.alpha(Magick::DeactivateAlphaChannel)
  # And perform the operation (set gray(RGB) of mask as the A of magick_image)
  magick_image.composite!(mask, Magick::CenterGravity, Magick::CopyOpacityCompositeOp)
ensure
  [mask, only_alpha].each do |maybe_image|
    ImageVise.destroy(maybe_image)
  end
end

#draw_circle(into_image, width, height) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/image_vise/operators/ellipse_stencil.rb', line 52

def draw_circle(into_image, width, height)
  center_x = (width / 2.0)
  center_y = (height / 2.0)
  # Make sure all the edges are anti-aliased
  radius_width = center_x - 1.5
  radius_height = center_y - 1.5

  gc = Magick::Draw.new
  gc.fill C_black
  gc.rectangle(0, 0, width, height)
  gc.fill C_white
  gc.ellipse(center_x, center_y, radius_width, radius_height, deg_start=0, deg_end=360)
  gc.draw(into_image)
ensure
  ImageVise.destroy(gc)
end