| Module | ChunkyPNG::Canvas::Resampling |
| In: |
lib/chunky_png/canvas/resampling.rb
|
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
# File lib/chunky_png/canvas/resampling.rb, line 139
139: def resample_bilinear(new_width, new_height)
140: dup.resample_bilinear!(new_width, new_height)
141: 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, line 103
103: def resample_bilinear!(new_width, new_height)
104: index_x, interp_x = steps_residues(width, new_width)
105: index_y, interp_y = steps_residues(height, new_height)
106:
107: pixels = Array(size=new_width*new_height)
108: i = 0
109: for y in 1..new_height
110: # Clamp the indicies to the edges of the image
111: y1 = [index_y[y-1], 0].max
112: y2 = [index_y[y-1] + 1, height - 1].min
113: y_residue = interp_y[y-1]
114:
115: for x in 1..new_width
116: # Clamp the indicies to the edges of the image
117: x1 = [index_x[x-1], 0].max
118: x2 = [index_x[x-1] + 1, width - 1].min
119: x_residue = interp_x[x-1]
120:
121: pixel_11 = get_pixel(x1, y1)
122: pixel_21 = get_pixel(x2, y1)
123: pixel_12 = get_pixel(x1, y2)
124: pixel_22 = get_pixel(x2, y2)
125:
126: # Interpolate by Row
127: pixel_top = ChunkyPNG::Color.interpolate_quick(pixel_21, pixel_11, x_residue)
128: pixel_bot = ChunkyPNG::Color.interpolate_quick(pixel_22, pixel_12, x_residue)
129:
130: # Interpolate by Column
131:
132: pixels[i] = ChunkyPNG::Color.interpolate_quick(pixel_bot, pixel_top, y_residue)
133: i += 1
134: end
135: end
136: replace_canvas!(new_width.to_i, new_height.to_i, pixels)
137: end
# File lib/chunky_png/canvas/resampling.rb, line 95
95: def resample_nearest_neighbor(new_width, new_height)
96: dup.resample_nearest_neighbor!(new_width, new_height)
97: 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, line 78
78: def resample_nearest_neighbor!(new_width, new_height)
79: steps_x = steps(width, new_width)
80: steps_y = steps(height, new_height)
81:
82:
83: pixels = Array(size=new_width*new_height)
84: i = 0
85: for y in steps_y
86: for x in steps_x
87: pixels[i] = get_pixel(x, y)
88: i += 1
89: end
90: end
91:
92: replace_canvas!(new_width.to_i, new_height.to_i, pixels)
93: 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, line 24
24: def steps(width, new_width)
25: indicies, residues = steps_residues(width, new_width)
26:
27: for i in 1..new_width
28: indicies[i-1] = (indicies[i-1] + (residues[i-1] + 127)/255)
29: end
30: return indicies
31: 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, line 41
41: def steps_residues(width, new_width)
42: indicies = Array.new(size=new_width, obj=nil)
43: residues = Array.new(size=new_width, obj=nil)
44:
45: # This works by accumulating the fractional error and
46: # overflowing when necessary.
47:
48: # We use mixed number arithmetic with a denominator of
49: # 2 * new_width
50: base_step = width / new_width
51: err_step = (width % new_width) << 1
52: denominator = (new_width) << 1
53:
54: # Initial pixel
55: index = (width - new_width) / denominator
56: err = (width - new_width) % denominator
57:
58: for i in 1..new_width
59: indicies[i-1] = index
60: residues[i-1] = (255.0 * err.to_f / denominator.to_f).round
61:
62: index += base_step
63: err += err_step
64: if err >= denominator
65: index += 1
66: err -= denominator
67: end
68: end
69:
70: return indicies, residues
71: end