Module: ChunkyPNG::Canvas::Operations

Included in:
ChunkyPNG::Canvas
Defined in:
lib/chunky_png/canvas/operations.rb

Overview

The ChunkyPNG::Canvas::Operations module defines methods to perform operations on a ChunkyPNG::Canvas. The module is included into the Canvas class so all these methods are available on every canvas.

Note that some of these operations modify the canvas, while some operations return a new canvas and leave the original intact.

See Also:

Instance Method Summary collapse

Instance Method Details

#change_mask_color!(new_color) ⇒ Object

Changes the color of a mask image.

This method works on acanavs extracte out of another image using the #extract_mask method. It can then be applied on the extracted base image. See #change_theme_color! to perform these operations in one go.

Parameters:

  • new_color (Integer)

    The color to replace the original mask color with.

Raises:

  • (ChunkyPNG::ExpectationFailed)

    when this canvas is not a mask image, i.e. its palette has more than once color, disregarding transparency.

See Also:



152
153
154
155
156
# File 'lib/chunky_png/canvas/operations.rb', line 152

def change_mask_color!(new_color)
  raise ChunkyPNG::ExpectationFailed, "This is not a mask image!" if palette.opaque_palette.size != 1
  pixels.map! { |pixel| (new_color & 0xffffff00) | ChunkyPNG::Color.a(pixel) }
  self
end

#change_theme_color!(old_theme_color, new_theme_color, bg_color = ChunkyPNG::Color::WHITE, tolerance = 5) ⇒ ChunkyPNG::Canvas

Creates a new image, based on the current image but with a new theme color.

This method will replace one color in an image with another image. This is done by first extracting the pixels with a color close to the original theme color as a mask image, changing the color of this mask image and then apply it on the original image.

Mask extraction works best when the theme colored pixels are clearly distinguishable from a background color (preferably white). You can set a tolerance level to influence the extraction process.

Parameters:

  • old_theme_color (Integer)

    The original theme color in this image.

  • new_theme_color (Integer)

    The color to replace the old theme color with.

  • The (Integer)

    backrgound color opn which the theme colored pixels are placed.

  • tolerance (Integer) (defaults to: 5)

    The tolerance level to use when extracting the mask image. Five is the default; increase this if the masked image does not extract all the required pixels, decrease it if too many pixels get extracted.

Returns:

See Also:



98
99
100
101
102
# File 'lib/chunky_png/canvas/operations.rb', line 98

def change_theme_color!(old_theme_color, new_theme_color, bg_color = ChunkyPNG::Color::WHITE, tolerance = 5)
  base, mask = extract_mask(old_theme_color, bg_color, tolerance)
  mask.change_mask_color!(new_theme_color)
  self.replace(base.compose(mask))
end

#compose(other, offset_x = 0, offset_y = 0) ⇒ ChunkyPNG::Canvas

Composes another image onto this image using alpha blending.

If you simply want to replace pixels or when the other image does not have transparency, it is faster to use #replace.

Parameters:

  • other (ChunkyPNG::Canvas)

    The foreground canvas to compose on the current canvas, using alpha compositing.

  • offset_x (Integer) (defaults to: 0)

    The x-offset to apply the new forgeround on.

  • offset_y (Integer) (defaults to: 0)

    The y-offset to apply the new forgeround on.

Returns:

  • (ChunkyPNG::Canvas)

    Returns itself, but with the other canvas composed onto it.

Raises:

  • (ChunkyPNG::OutOfBounds)

    when the other canvas doesn’t fit on this one, given the offset and size of the other canavs.

See Also:



27
28
29
30
31
32
33
34
35
36
# File 'lib/chunky_png/canvas/operations.rb', line 27

def compose(other, offset_x = 0, offset_y = 0)
  check_size_constraints!(other, offset_x, offset_y)

  for y in 0...other.height do
    for x in 0...other.width do
      set_pixel(x + offset_x, y + offset_y, ChunkyPNG::Color.compose(other.get_pixel(x, y), get_pixel(x + offset_x, y + offset_y)))
    end
  end
  self
end

#crop(x, y, crop_width, crop_height) ⇒ ChunkyPNG::Canvas

Crops an image, given the coordinates and size of the image that needs to be cut out. This will leave the original image intact and return a new, cropped image with pixels copied from the original image.

Parameters:

  • x (Integer)

    The x-coordinate of the top left corner of the image to be cropped.

  • y (Integer)

    The y-coordinate of the top left corner of the image to be cropped.

  • crop_width (Integer)

    The width of the image to be cropped.

  • crop_height (Integer)

    The height of the image to be cropped.

Returns:

Raises:

  • (ChunkyPNG::OutOfBounds)

    when the crop dimensions plus the given coordinates are bigger then the original image.



67
68
69
70
71
72
73
74
75
76
77
# File 'lib/chunky_png/canvas/operations.rb', line 67

def crop(x, y, crop_width, crop_height)
  
  raise ChunkyPNG::OutOfBounds, "Image width is too small!" if crop_width + x > width
  raise ChunkyPNG::OutOfBounds, "Image width is too small!" if crop_height + y > height
  
  new_pixels = []
  for cy in 0...crop_height do
    new_pixels += pixels.slice((cy + y) * width + x, crop_width)
  end
  ChunkyPNG::Canvas.new(crop_width, crop_height, new_pixels)
end

#extract_mask(mask_color, bg_color = ChunkyPNG::Color::WHITE, tolerance = 5) ⇒ Array<ChunkyPNG::Canvas, ChunkyPNG::Canvas>

Creates a base image and a mask image from an original image that has a particular theme color. This can be used to easily change a theme color in an image.

It will extract all the pixels that look like the theme color (with a tolerance level) and put these in a mask image. All the other pixels will be stored in a base image. Both images will be of the exact same size as the original image. The original image will be left untouched.

The color of the mask image can be changed with #change_mask_color!. This new mask image can then be composed upon the base image to create an image with a new theme color. A call to #change_theme_color! will perform this in one go.

Parameters:

  • mask_color (Integer)

    The current theme color.

  • bg_color (Integer) (defaults to: ChunkyPNG::Color::WHITE)

    The background color on which the theme colored pxiels are applied.

  • tolerance (Integer) (defaults to: 5)

    The tolerance level to use when extracting the mask image. Five is the default; increase this if the masked image does not extract all the required pixels, decrease it if too many pixels get extracted.

Returns:

See Also:



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/chunky_png/canvas/operations.rb', line 124

def extract_mask(mask_color, bg_color = ChunkyPNG::Color::WHITE, tolerance = 5)
  base_pixels = []
  mask_pixels = []

  pixels.each do |pixel|
    if ChunkyPNG::Color.alpha_decomposable?(pixel, mask_color, bg_color, tolerance)
      mask_pixels << ChunkyPNG::Color.decompose_color(pixel, mask_color, bg_color, tolerance)
      base_pixels << bg_color
    else
      mask_pixels << (mask_color & 0xffffff00)
      base_pixels << pixel
    end
  end
  
  [ self.class.new(width, height, base_pixels), self.class.new(width, height, mask_pixels) ]
end

#flip_horizontallyChunkyPNG::Canvas

Flips the image horizontally.

This will flip the image on its horizontal axis, e.g. pixels on the top will now be pixels on the bottom. Chaining this method twice will return the original canvas. This method will leave the original object intact and return a new canvas.

Returns:



165
166
167
168
169
170
171
# File 'lib/chunky_png/canvas/operations.rb', line 165

def flip_horizontally
  self.class.new(width, height).tap do |flipped|
    for y in 0...height do
      flipped.replace_row!(height - (y + 1), row(y))
    end
  end
end

#flip_verticallyChunkyPNG::Canvas

Flips the image horizontally.

This will flip the image on its vertical axis, e.g. pixels on the left will now be pixels on the right. Chaining this method twice will return the original canvas. This method will leave the original object intact and return a new canvas.

Returns:



180
181
182
183
184
185
186
# File 'lib/chunky_png/canvas/operations.rb', line 180

def flip_vertically
  self.class.new(width, height).tap do |flipped|
    for x in 0...width do
      flipped.replace_column!(width - (x + 1), column(x))
    end
  end
end

#replace(other, offset_x = 0, offset_y = 0) ⇒ ChunkyPNG::Canvas

Replaces pixels on this image by pixels from another pixels, on a given offset.

This will completely replace the pixels of the background image. If you want to blend them with semi-transparent pixels from the foreground image, see #compose.

Returns:

  • (ChunkyPNG::Canvas)

    Returns itself, but with the other canvas composed onto it.

Raises:

  • (ChunkyPNG::OutOfBounds)

    when the other canvas doesn’t fit on this one, given the offset and size of the other canavs.

See Also:



47
48
49
50
51
52
53
54
# File 'lib/chunky_png/canvas/operations.rb', line 47

def replace(other, offset_x = 0, offset_y = 0)
  check_size_constraints!(other, offset_x, offset_y)

  for y in 0...other.height do
    pixels[(y + offset_y) * width + offset_x, other.width] = other.pixels[y * other.width, other.width]
  end
  self
end

#rotate_180ChunkyPNG::Canvas

Rotates the image 180 degrees. This method will leave the original object intact and return a new canvas.

Returns:



216
217
218
219
220
221
222
# File 'lib/chunky_png/canvas/operations.rb', line 216

def rotate_180
  self.class.new(width, height).tap do |flipped|
    for y in 0...height do
      flipped.replace_row!(height - (y + 1), row(y).reverse)
    end
  end
end

#rotate_leftChunkyPNG::Canvas

Rotates the image 90 degrees counter-clockwise. This method will leave the original object intact and return a new canvas.

Returns:



204
205
206
207
208
209
210
# File 'lib/chunky_png/canvas/operations.rb', line 204

def rotate_left
  self.class.new(height, width).tap do |rotated|
    for i in 0...width do
      rotated.replace_row!(width - (i + 1), column(i))
    end
  end
end

#rotate_rightChunkyPNG::Canvas

Rotates the image 90 degrees clockwise. This method will leave the original object intact and return a new canvas.

Returns:



192
193
194
195
196
197
198
# File 'lib/chunky_png/canvas/operations.rb', line 192

def rotate_right
  self.class.new(height, width).tap do |rotated|
    for i in 0...width do
      rotated.replace_row!(i, column(i).reverse)
    end
  end
end