Skip to content

Instantly share code, notes, and snippets.

@tony-brewerio
Created July 3, 2011 06:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tony-brewerio/1062015 to your computer and use it in GitHub Desktop.
Save tony-brewerio/1062015 to your computer and use it in GitHub Desktop.
ChunkyImagePixelizer

ChunkyImagePixelizer

A very blunt attempt - slice the image in blocks, determine normalized color as a mean of all pixels colors ( pixels that are closer to the block center have more "weight" in result ), then paint entire rectangle with new color. Supports arbitrary shape of blocks.

ChunkyImagePixelizer.pixelize_image("input.png", "output.png", :width => 10, :height => 10)
require "chunky_png"
module ChunkyImagePixelizer
class PixelsBlock
def initialize(image, left, top, right, bottom)
@image = image
@left, @top, @right, @bottom = left, top, right, bottom
end
def normalized_color
center_x = (@left + @right) / 2.0
center_y = (@top + @bottom) / 2.0
colors = (@left..@right).collect do |x|
(@top..@bottom).collect do |y|
{
:color => @image[x,y],
:distance => (1 + Math.hypot((x - center_x).abs, (y - center_y).abs)) ** 2
}
end
end.flatten
max_distance = colors.collect{|c| c[:distance]}.max * 1.1
new_color = [0, 0, 0, 0]
new_color_count = colors.inject(0.0) do |i, c|
weight = max_distance - c[:distance]
ChunkyPNG::Color.to_truecolor_alpha_bytes(c[:color]).each_with_index do |c, i|
new_color[i] += weight * c
end
i + weight
end
ChunkyPNG::Color.rgba(*new_color.map{|c| (c / new_color_count).round})
end
def normalize_color!
color = normalized_color
@image.rect(@left, @top, @right, @bottom, color, color)
end
end
class Slicer
include Enumerable
def initialize(image, shape)
@image = image
@width, @height, @shape = image.width, image.height, shape
@left = @width % shape[:width] / -2
@top = @height % shape[:height] / -2
@right = @width - @left
@bottom = @height - @top
end
def each
(@left..@right).step(@shape[:width]) do |x|
(@top..@bottom).step(@shape[:height]) do |y|
if x < @width and y < @height
yield PixelsBlock.new(
@image,
[x, 0].max, [y, 0].max,
[x + @shape[:width], @width].min - 1,
[y + @shape[:height], @height].min - 1
)
end
end
end
end
end
def self.pixelize!(image, options = {})
options = {:width => 10, :height => 10}.merge(options)
Slicer.new(image, options).each(&:normalize_color!)
image
end
def self.pixelize_image(input_filename, output_filename, options = {})
pixelize!(ChunkyPNG::Image.from_file(input_filename), options).save(output_filename)
end
end
ChunkyImagePixelizer.pixelize_image("input.png", "output_10.png")
ChunkyImagePixelizer.pixelize_image("input.png", "output_8.png", :width => 8, :height => 8)
ChunkyImagePixelizer.pixelize_image("input.png", "output_6.png", :width => 6, :height => 6)
ChunkyImagePixelizer.pixelize_image("input.png", "output_4x8.png", :width => 4, :height => 8)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment