Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Solution for codebrawl PNG pixelation challenge

View input.png
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
require 'rubygems'
require 'chunky_png'
 
# Pixelator will pixelate your pngs
# defaults to a 10 pixel block, but will gladly accept
# larger or smaller blocks
# also includes a pointelize method which does color averaged dots
# instead of blocks
class Pixelator
 
include ChunkyPNG::Color
 
def initialize(image_path)
@image = ChunkyPNG::Image.from_file(image_path)
end
 
# anytime we set the block size the number of block rows
# and block columns needs to be updated as well
def set_block_size(blck_size)
@block_size = blck_size
@col_blocks = (@image.width.to_f / @block_size.to_f)
@row_blocks = (@image.height.to_f / @block_size.to_f)
end
 
def pixelate(blck_size=10)
 
set_block_size(blck_size)
 
# iterate through each "block" as defined by the block size
each_block do |x, y|
 
# setting current block size handles partial blocks at the ends of rows, columns, or both
@curr_x_block_size = x + 1 > @col_blocks ? @image.width - (@col_blocks.to_i * @block_size) : @block_size
@curr_y_block_size = y + 1 > @row_blocks ? @image.height - (@row_blocks.to_i * @block_size) : @block_size
 
# gets an array containing the averages for each color channel
averages = average_color_for_block(x, y, @curr_x_block_size, @curr_y_block_size)
 
# set every pixel from the current block to the averaged color value
each_pixel_from_block(@curr_x_block_size, @curr_y_block_size) do |xp, yp|
@image[(x * @block_size) + xp, (y * @block_size) + yp] = rgba(averages[0], averages[1], averages[2], averages[3])
end
end
 
@image
end
 
def pointelize(blck_size=10, padding=2)
set_block_size(blck_size)
 
each_block do |x, y|
# setting current block size handles partial blocks at the ends of rows, columns, or both
@curr_x_block_size = x + 1 > @col_blocks ? @image.width - (@col_blocks.to_i * @block_size) : @block_size
@curr_y_block_size = y + 1 > @row_blocks ? @image.height - (@row_blocks.to_i * @block_size) : @block_size
 
averages = average_color_for_block(x, y, @curr_x_block_size, @curr_y_block_size)
 
averaged_color = rgba(averages[0], averages[1], averages[2], averages[3])
 
# paint the block all white
each_pixel_from_block(@curr_x_block_size, @curr_y_block_size) do |xp, yp|
@image[(x * @block_size) + xp, (y * @block_size) + yp] = rgba(0, 0, 0, averages[3])
end
 
# draw the circle
@image.circle(
x * @block_size + (@block_size / 2),
y * @block_size + (@block_size / 2),
(@block_size - padding) / 2,
averaged_color,
averaged_color
)
end
 
@image
end
 
private
 
def average_color_for_block(x, y, x_block_size, y_block_size)
red = []
green = []
blue = []
alpha = []
 
# iterate through the pixels in the current block and pull out all the color info
each_pixel_from_block(x_block_size, y_block_size) do |xp, yp|
pixel = @image[(x * @block_size) + xp, (y * @block_size) + yp]
 
red << r(pixel)
green << g(pixel)
blue << b(pixel)
alpha << a(pixel)
end
 
averages = []
 
# average each color channel
[red, green, blue, alpha].each do |color|
averages << color.inject{ |sum,i| sum + i } / color.size
end
 
averages
end
 
def each_block
@row_blocks.ceil.times do |y|
@col_blocks.ceil.times do |x|
yield(x,y)
end
end
end
 
def each_pixel_from_block(x_block_size, y_block_size)
(0..x_block_size - 1).each do |xp|
(0..y_block_size - 1).each do |yp|
yield(xp, yp)
end
end
end
 
end
 
# demo usage of each method
 
p = Pixelator.new('input.png')
 
i = p.pointelize(20, 5)
i.save("pointelized.png")
 
p = Pixelator.new('input.png')
 
i = p.pixelate
i.save("pixelated.png")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.