module ChunkyPNG::Canvas::Resampling

The ChunkyPNG::Canvas::Resampling module defines methods to perform image resampling to a {ChunkyPNG::Canvas}.

Currently, only the nearest neighbor algorithm is implemented. Bilinear and cubic algorithms may be added later on.

@see ChunkyPNG::Canvas

Public Instance Methods

resample(new_width, new_height)
Also aliased as: resize
resample_bilinear(new_width, new_height) click to toggle source
    # File lib/chunky_png/canvas/resampling.rb
132 def resample_bilinear(new_width, new_height)
133   dup.resample_bilinear!(new_width, new_height)
134 end
resample_bilinear!(new_width, new_height) click to toggle source

Resamples the canvas with bilinear interpolation. @param [Integer] new_width The width of the resampled canvas. @param [Integer] new_height The height of the resampled canvas. @return [ChunkyPNG::Canvas] A new canvas instance with the resampled pixels.

    # File lib/chunky_png/canvas/resampling.rb
 96 def resample_bilinear!(new_width, new_height)
 97   index_x, interp_x = steps_residues(width, new_width)
 98   index_y, interp_y = steps_residues(height, new_height)
 99 
100   pixels = Array.new(new_width * new_height)
101   i = 0
102   for y in 1..new_height
103     # Clamp the indicies to the edges of the image
104     y1 = [index_y[y - 1], 0].max
105     y2 = [index_y[y - 1] + 1, height - 1].min
106     y_residue = interp_y[y - 1]
107 
108     for x in 1..new_width
109       # Clamp the indicies to the edges of the image
110       x1 = [index_x[x - 1], 0].max
111       x2 = [index_x[x - 1] + 1, width - 1].min
112       x_residue = interp_x[x - 1]
113 
114       pixel_11 = get_pixel(x1, y1)
115       pixel_21 = get_pixel(x2, y1)
116       pixel_12 = get_pixel(x1, y2)
117       pixel_22 = get_pixel(x2, y2)
118 
119       # Interpolate by Row
120       pixel_top = ChunkyPNG::Color.interpolate_quick(pixel_21, pixel_11, x_residue)
121       pixel_bot = ChunkyPNG::Color.interpolate_quick(pixel_22, pixel_12, x_residue)
122 
123       # Interpolate by Column
124 
125       pixels[i] = ChunkyPNG::Color.interpolate_quick(pixel_bot, pixel_top, y_residue)
126       i += 1
127     end
128   end
129   replace_canvas!(new_width.to_i, new_height.to_i, pixels)
130 end
resample_nearest_neighbor(new_width, new_height) click to toggle source
   # File lib/chunky_png/canvas/resampling.rb
88 def resample_nearest_neighbor(new_width, new_height)
89   dup.resample_nearest_neighbor!(new_width, new_height)
90 end
Also aliased as: resample
resample_nearest_neighbor!(new_width, new_height) click to toggle source

Resamples the canvas using nearest neighbor interpolation. @param [Integer] new_width The width of the resampled canvas. @param [Integer] new_height The height of the resampled canvas. @return [ChunkyPNG::Canvas] A new canvas instance with the resampled pixels.

   # File lib/chunky_png/canvas/resampling.rb
72 def resample_nearest_neighbor!(new_width, new_height)
73   steps_x = steps(width, new_width)
74   steps_y = steps(height, new_height)
75 
76   pixels = Array.new(new_width * new_height)
77   i = 0
78   for y in steps_y
79     for x in steps_x
80       pixels[i] = get_pixel(x, y)
81       i += 1
82     end
83   end
84 
85   replace_canvas!(new_width.to_i, new_height.to_i, pixels)
86 end
resize(new_width, new_height)
Alias for: resample
steps(width, new_width) click to toggle source

Integer Interpolation between two values

Used for generating indicies for interpolation (eg, nearest neighbour).

@param [Integer] width The width of the source @param [Integer] new_width The width of the destination @return [Array<Integer>] An Array of Integer indicies

   # File lib/chunky_png/canvas/resampling.rb
19 def steps(width, new_width)
20   indicies, residues = steps_residues(width, new_width)
21 
22   for i in 1..new_width
23     indicies[i - 1] = (indicies[i - 1] + (residues[i - 1] + 127) / 255)
24   end
25   indicies
26 end
steps_residues(width, new_width) click to toggle source

Fractional Interpolation between two values

Used for generating values for interpolation (eg, bilinear). Produces both the indices and the interpolation factors (residues).

@param [Integer] width The width of the source @param [Integer] new_width The width of the destination @return [Array<Integer>, Array<Integer>] Two arrays of indicies and residues

   # File lib/chunky_png/canvas/resampling.rb
36 def steps_residues(width, new_width)
37   indicies = Array.new(new_width, nil)
38   residues = Array.new(new_width, nil)
39 
40   # This works by accumulating the fractional error and
41   # overflowing when necessary.
42 
43   # We use mixed number arithmetic with a denominator of
44   # 2 * new_width
45   base_step = width / new_width
46   err_step = (width % new_width) << 1
47   denominator = new_width << 1
48 
49   # Initial pixel
50   index = (width - new_width) / denominator
51   err = (width - new_width) % denominator
52 
53   for i in 1..new_width
54     indicies[i - 1] = index
55     residues[i - 1] = (255.0 * err.to_f / denominator.to_f).round
56 
57     index += base_step
58     err += err_step
59     if err >= denominator
60       index += 1
61       err -= denominator
62     end
63   end
64 
65   [indicies, residues]
66 end