Outputs two versions of the image: a simple pixelated version and a version inspired by Andy Warhol.
ruby derp.rb
input.png |
require 'chunky_png' | |
module ChunkyPNG | |
class PixelChunk | |
attr_reader :image, :left, :top, :right, :bottom | |
def initialize(image, left, top, right, bottom) | |
@image, @left, @top, @right, @bottom = image, left, top, right, bottom | |
end | |
def points | |
@points ||= [*left..right].product([*top..bottom]) | |
end | |
def pixels | |
points.map { |x, y| image[x, y] } | |
end | |
def average | |
pix = self.pixels | |
red = pix.map { |p| Color.r p }.inject(:+) / pix.size | |
green = pix.map { |p| Color.g p }.inject(:+) / pix.size | |
blue = pix.map { |p| Color.b p }.inject(:+) / pix.size | |
Color.rgb(red, green, blue) | |
end | |
def color=(color) | |
points.each do |x, y| | |
image[x, y] = color | |
end | |
end | |
def pixelize! | |
self.color = average | |
end | |
def quadrant(size) | |
xs = (0..image.width).step(image.width / size).each_cons(2).map { |a,b| a..b } | |
ys = (0..image.height).step(image.height / size).each_cons(2).map { |a,b| a..b } | |
[xs.index { |x| x.cover? right }, ys.index { |y| y.cover? bottom }] | |
end | |
end | |
class Image | |
def pixelize(size) | |
dup.pixelize!(size) | |
end | |
def pixelize!(size) | |
pixel_chunks(size).each(&:pixelize!) | |
self | |
end | |
def pixelize_with_warhol(size) | |
dup.pixelize_with_warhol!(size) | |
end | |
def pixelize_with_warhol!(size) | |
pixel_chunks(size).each_with_index do |chunk, index| | |
avg = chunk.average | |
red = Color.r(avg) | |
green = Color.g(avg) | |
blue = Color.b(avg) | |
it = 0.5 | |
case chunk.quadrant(3) | |
when [0,0], [1,1], [2,2] | |
green -= green * it | |
when [1,0], [2,1], [0,2] | |
blue -= blue * it | |
else | |
red -= red * it | |
end | |
chunk.color = Color.rgb(red.to_i, green.to_i, blue.to_i) | |
end | |
self | |
end | |
def pixel_chunks(size) | |
unless @pixel_chunks | |
xs = (0...width).step(size).to_a | |
ys = (0...height).step(size).to_a | |
@pixel_chunks = xs.product(ys).map { |x,y| PixelChunk.new(self, x, y, [x+size, width].min - 1, [y+size, height].min - 1) } | |
end | |
@pixel_chunks | |
end | |
end | |
end | |
image = ChunkyPNG::Image.from_file('input.png') | |
image.pixelize(10).save('output.png') | |
image.pixelize_with_warhol(10).save('warhol.png') | |
`open output.png` rescue nil | |
`open warhol.png` rescue nil |