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
# 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
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
# 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
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
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
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