Pixelizing images with ChunkyPNG

Ever heard of ChunkyPNG? It’s an amazing PNG manipulation library that is easy and fun to use. This week’s challenge is to pixelize the image below, so your resulting image is built up from blocks of 10 by 10 pixels. Remember: you can’t change the size of the image.

The contest's input image. It has a tapir.

If you’ve never used ChunkyPNG before, check out the wiki, you can find some great examples in there.

Again, put your solution in a Gist, together with your resulting image, like this example (please don’t include the input image and don’t fork the example gist). You can’t add images using Gist’s web interface, so you’ll have to clone your Gist and add it using git.

Like last week, you have a week to get your entry in, so I’m sure you have enough time to write a great implementation. Good luck!

This contest is finished

Congratulations to this week's winners! The entries and the contestant names are shown below.

  • output.png
    solution.rb
    require 'chunky_png'
    
    module ChunkyPNG
      class Image
        def pixelize!(size=10)
          [[:row, height], [:column, width]].each do |orientation, length|
            for i in 0...length
              pixelated = []; send(orientation, i).each_slice(size) do |slice|
                pixelated += [Color.rgba(*[:r,:g,:b,:a].map{|chan| 
                  (slice.map{|c| Color.send(chan, c)}.inject(0.0){|sum, v| sum += v} / slice.length).round
                })] * slice.length
              end
              send("replace_#{orientation}!", i, pixelated)
            end
          end
        end
      end
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    image.pixelize!
    image.save('output.png')
    
    View full entry
    Finished in 1st place with a final score of 3.6/5. (View the Gist)
  • output.png
    pixelize.rb
    require 'chunky_png'
    
    module ChunkyPNG::Color
      def self.average(pixels)
        new_r = pixels.map{|p| r(p)}.inject(&:+) / pixels.size
        new_g = pixels.map{|p| g(p)}.inject(&:+) / pixels.size
        new_b = pixels.map{|p| b(p)}.inject(&:+) / pixels.size
        rgb(new_r,new_g,new_b)
      end
    end
    
    class BlockyImage < ChunkyPNG::Image
    
      def block(x,y,n)
        positions = block_positions(x,y,n)
        positions.map{|x,y| get_pixel(x,y)}
      end
    
      def set_block(x,y,n,color)
        positions = block_positions(x,y,n)
        positions.map{|x,y| set_pixel(x,y,color)}
      end
    
      def pixelize(n)
        xtimes = (width / n.to_f).ceil
        ytimes = (height / n.to_f).ceil
        
        positions = (0...xtimes).map{|x| x * n}.product((0...ytimes).map{|y| y * n})
    
        positions.each do |x,y| 
          color = ChunkyPNG::Color.average(block(x, y, n))
          set_block(x, y, n, color)     
        end
      end
    
      private
      
      def block_positions(x,y,n)
        nx = [width, x + n].min
        ny = [height, y + n].min
        (x...nx).to_a.product((y...ny).to_a)  
      end
    end
    
    image = BlockyImage.from_file('input.png')
    image.pixelize(10)
    image.save('output.png')
    
    View full entry
    Finished in 2nd place with a final score of 3.4/5. (View the Gist)
  • .gitignore
    input.png
    README.md

    Doing the damn thing

    Outputs two versions of the image: a simple pixelated version and a version inspired by Andy Warhol.

    Run it

    ruby derp.rb
    
    output.png
    warhol.png
    derp.rb
    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
    
    View full entry
    Finished in 3rd place with a final score of 3.3/5. (View the Gist)
  • rbg.png
    brg.png
    gbr.png
    lightest.png
    first.png
    darkest.png
    random-component.png
    grb.png
    average.png
    random-pixel.png
    bgr.png
    lightest.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        reds = []
        greens = []
        blues = []
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              reds << ChunkyPNG::Color.r(image[i*pixel_size+k,j*pixel_size+l])
              greens << ChunkyPNG::Color.g(image[i*pixel_size+k,j*pixel_size+l])
              blues << ChunkyPNG::Color.b(image[i*pixel_size+k,j*pixel_size+l])
            rescue
            end
          end
        end
        color = ChunkyPNG::Color.rgba(reds.max,greens.max,blues.max,255)
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = color
            rescue
            end
          end
        end
      end
    end
    
    image.save('lightest.png')
    
    random-pixel.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        color = image[[(i*pixel_size+rand(pixel_size)),image.width-1].min,[(j*pixel_size+rand(pixel_size)),image.height-1].min]
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = color
            rescue
            end
          end
        end
      end
    end
    
    image.save('random-pixel.png')
    
    grb.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    def average(array)
      array.inject(0) { |sum, el| sum + el } / array.size
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        reds = []
        greens = []
        blues = []
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              reds << ChunkyPNG::Color.r(image[i*pixel_size+k,j*pixel_size+l])
              greens << ChunkyPNG::Color.g(image[i*pixel_size+k,j*pixel_size+l])
              blues << ChunkyPNG::Color.b(image[i*pixel_size+k,j*pixel_size+l])
            rescue
            end
          end
        end
        color = ChunkyPNG::Color.rgba(average(greens),average(reds),average(blues),255)
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = color
            rescue
            end
          end
        end
      end
    end
    
    image.save('grb.png')
    
    darkest.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        reds = []
        greens = []
        blues = []
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              reds << ChunkyPNG::Color.r(image[i*pixel_size+k,j*pixel_size+l])
              greens << ChunkyPNG::Color.g(image[i*pixel_size+k,j*pixel_size+l])
              blues << ChunkyPNG::Color.b(image[i*pixel_size+k,j*pixel_size+l])
            rescue
            end
          end
        end
        color = ChunkyPNG::Color.rgba(reds.min,greens.min,blues.min,255)
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = color
            rescue
            end
          end
        end
      end
    end
    
    image.save('darkest.png')
    
    bgr.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    def average(array)
      array.inject(0) { |sum, el| sum + el } / array.size
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        reds = []
        greens = []
        blues = []
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              reds << ChunkyPNG::Color.r(image[i*pixel_size+k,j*pixel_size+l])
              greens << ChunkyPNG::Color.g(image[i*pixel_size+k,j*pixel_size+l])
              blues << ChunkyPNG::Color.b(image[i*pixel_size+k,j*pixel_size+l])
            rescue
            end
          end
        end
        color = ChunkyPNG::Color.rgba(average(blues),average(greens),average(reds),255)
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = color
            rescue
            end
          end
        end
      end
    end
    
    image.save('bgr.png')
    
    rbg.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    def average(array)
      array.inject(0) { |sum, el| sum + el } / array.size
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        reds = []
        greens = []
        blues = []
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              reds << ChunkyPNG::Color.r(image[i*pixel_size+k,j*pixel_size+l])
              greens << ChunkyPNG::Color.g(image[i*pixel_size+k,j*pixel_size+l])
              blues << ChunkyPNG::Color.b(image[i*pixel_size+k,j*pixel_size+l])
            rescue
            end
          end
        end
        color = ChunkyPNG::Color.rgba(average(reds),average(blues),average(greens),255)
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = color
            rescue
            end
          end
        end
      end
    end
    
    image.save('rbg.png')
    
    average.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    def average(array)
      array.inject(0) { |sum, el| sum + el } / array.size
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        reds = []
        greens = []
        blues = []
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              reds << ChunkyPNG::Color.r(image[i*pixel_size+k,j*pixel_size+l])
              greens << ChunkyPNG::Color.g(image[i*pixel_size+k,j*pixel_size+l])
              blues << ChunkyPNG::Color.b(image[i*pixel_size+k,j*pixel_size+l])
            rescue
            end
          end
        end
        color = ChunkyPNG::Color.rgba(average(reds),average(greens),average(blues),255)
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = color
            rescue
            end
          end
        end
      end
    end
    
    image.save('average.png')
    
    gbr.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    def average(array)
      array.inject(0) { |sum, el| sum + el } / array.size
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        reds = []
        greens = []
        blues = []
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              reds << ChunkyPNG::Color.r(image[i*pixel_size+k,j*pixel_size+l])
              greens << ChunkyPNG::Color.g(image[i*pixel_size+k,j*pixel_size+l])
              blues << ChunkyPNG::Color.b(image[i*pixel_size+k,j*pixel_size+l])
            rescue
            end
          end
        end
        color = ChunkyPNG::Color.rgba(average(greens),average(blues),average(reds),255)
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = color
            rescue
            end
          end
        end
      end
    end
    
    image.save('gbr.png')
    
    random-component.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    def random(array)
      array[rand(array.size)]
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        reds = []
        greens = []
        blues = []
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              reds << ChunkyPNG::Color.r(image[i*pixel_size+k,j*pixel_size+l])
              greens << ChunkyPNG::Color.g(image[i*pixel_size+k,j*pixel_size+l])
              blues << ChunkyPNG::Color.b(image[i*pixel_size+k,j*pixel_size+l])
            rescue
            end
          end
        end
        color = ChunkyPNG::Color.rgba(random(reds),random(greens),random(blues),255)
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = color
            rescue
            end
          end
        end
      end
    end
    
    image.save('random-component.png')
    
    brg.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    def average(array)
      array.inject(0) { |sum, el| sum + el } / array.size
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        reds = []
        greens = []
        blues = []
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              reds << ChunkyPNG::Color.r(image[i*pixel_size+k,j*pixel_size+l])
              greens << ChunkyPNG::Color.g(image[i*pixel_size+k,j*pixel_size+l])
              blues << ChunkyPNG::Color.b(image[i*pixel_size+k,j*pixel_size+l])
            rescue
            end
          end
        end
        color = ChunkyPNG::Color.rgba(average(blues),average(reds),average(greens),255)
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = color
            rescue
            end
          end
        end
      end
    end
    
    image.save('brg.png')
    
    first.rb
    require 'chunky_png'
    
    pixel_size = 10
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (image.width.to_f/pixel_size).round.times do |i|
      (image.height.to_f/pixel_size).round.times do |j|
        pixel_size.times do |k|
          pixel_size.times do |l|
            begin
              image[i*pixel_size+k,j*pixel_size+l] = image[i*pixel_size,j*pixel_size]
            rescue
            end
          end
        end
      end
    end
    
    image.save('first.png')
    
    View full entry
    Finished in 4th place with a final score of 3.3/5. (View the Gist)
  • 4bit_r.png
    4bit_b.png
    4bit_g.png
    8bit.png
    brawl2.rb
    require 'chunky_png'
    include ChunkyPNG
    
    #   ten by ten pixles?
    # might as well go 8 bit
    #   while we are at it
    
    def reduce_depth(color, bits)
      Color.rgb(*Color.to_truecolor_bytes(color).
        map{ |c| c.to_f/256 }.each_with_index.map { |c,i|
          (256.0 * (c*bits[i]).round / bits[i]).to_i
        })
    end
    
    def reduce_image(output, bits)
      image = Image.from_file('input.png')
      (0..image.width-1).step(10).each do |x|
        (0..image.height-1).step(10).each do |y|
          color = reduce_depth image[x,y], bits
          10.times {|i| 10.times {|j|
            image.set_pixel_if_within_bounds x+i, y+j, color
          }}
        end
      end
      image.save("#{output}.png")
    end
    
    reduce_image "8bit",   [8,8,4]
    reduce_image "4bit_r", [4,2,2]
    reduce_image "4bit_g", [2,4,2]
    reduce_image "4bit_b", [2,2,4]
    
    View full entry
    Finished in 5th place with a final score of 3.3/5. (View the Gist)
  • output.png
    solution.rb
    require 'chunky_png'
    
    class Pixelizer
      attr_reader :image, :block_width, :block_height
      
      def initialize(image, block_width, block_height)
        @image = image
        @block_width = block_width
        @block_height = block_height
      end
      
      def pixelize!
        each_block do |canvas, x, y|
          color = average_color canvas
          image.rect x, y, x + canvas.width, y + canvas.height, color, color
        end
      end
      
      private
      
      def average_color(canvas)
        sum_r, sum_g, sum_b = 0, 0, 0
        canvas.pixels.each do |pixel|
          sum_r += ChunkyPNG::Color.r pixel
          sum_g += ChunkyPNG::Color.g pixel
          sum_b += ChunkyPNG::Color.b pixel
        end
        area = canvas.area
        ChunkyPNG::Color.rgb(sum_r / area, sum_g / area, sum_b / area)
      end
    
      def each_block
        rows = (image.height.to_f / block_height).ceil
        cols = (image.width.to_f / block_width).ceil
    
        rows.times do |row|
          cols.times do |col|
            x, y = col * block_width, row * block_height
            width = [block_width, image.width - x].min
            height = [block_height, image.height - y].min
            yield image.crop(x, y, width, height), x, y
          end
        end
      end
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    Pixelizer.new(image, 10, 10).pixelize!
    image.save('output.png')
    
    View full entry
    Finished in 6th place with a final score of 3.2/5. (View the Gist)
  • simple_output.png
    output.png
    simple_solution.rb
    require 'chunky_png'
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    width, height = image.width, image.height
    image.resample_nearest_neighbor!(width/10, height/10)
    image.resample_nearest_neighbor!(width, height)
    
    image.save('output.png')
    
    solution.rb
    require 'chunky_png'
    
    module ChunkyPNG
      class Canvas
        module BilinearResampling
          def resample_bilinear!(new_width, new_height)
            width_ratio  = width.to_f / new_width.to_f
            height_ratio = height.to_f / new_height.to_f
    
            pixels = []
            1.upto(new_height) do |y|
              1.upto(new_width) do |x|
                pixels << get_bilinear_pixel((x-0.5)*width_ratio, (y-0.5)*height_ratio, width_ratio, height_ratio)
              end
            end
            replace_canvas!(new_width, new_height, pixels)
          end
    
        private
          def get_bilinear_pixel(x, y, sample_width, sample_height)
            x = x - sample_width/2
            y = y - sample_height/2
            pixel_weights = []
            (y.floor..[(y+sample_height).ceil, height-1].min).each do |image_y|
              weight_y = 1
              offset = y - image_y
              weight_y = offset if offset > 0
              offset = image_y - (y + sample_height)
              weight_y = offset if offset > 0
              (x.floor..[(x+sample_width).ceil, width-1].min).each do |image_x|
                weight = weight_y
                offset = x - image_x
                weight = (weight_y ** 2 + offset ** 2) ** 0.5 if offset > 0
                offset = image_x - (x + sample_width)
                weight = (weight_y ** 2 + offset ** 2) ** 0.5 if offset > 0
                pixel_weights << [get_pixel(image_x, image_y), weight]
              end
            end
            total_weight = pixel_weights.inject(0){|acc,(_,w)| acc+w }
            ChunkyPNG::Color.rgba(
              (pixel_weights.inject(0){|acc,(p,w)| acc+ChunkyPNG::Color.r(p)*w }/total_weight).round,
              (pixel_weights.inject(0){|acc,(p,w)| acc+ChunkyPNG::Color.g(p)*w }/total_weight).round,
              (pixel_weights.inject(0){|acc,(p,w)| acc+ChunkyPNG::Color.b(p)*w }/total_weight).round,
              (pixel_weights.inject(0){|acc,(p,w)| acc+ChunkyPNG::Color.a(p)*w }/total_weight).round
            )
          end
        end
    
        include BilinearResampling
      end
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    width, height = image.width, image.height
    image.resample_bilinear!(width/10, height/10)
    image.resample_nearest_neighbor!(width, height)
    image.save('output.png')
    
    View full entry
    Finished in 7th place with a final score of 3.2/5. (View the Gist)
  • output.png
    pixelizer.rb
    #!/usr/bin/env ruby
    begin
      require 'chunky_png'
    rescue LoadError
      require 'rubygems'
      require 'chunky_png'
    end
    
    class Pixelizer
      def initialize(source, chunkSize = 10)
        @source = ChunkyPNG::Image.from_file(source)
        @output = ChunkyPNG::Image.new(@source.width, @source.height)
        @size = chunkSize
      end
    
      def pixelize
        (0...@source.width).step(@size) do |x|
          (0...@source.height).step(@size) do |y|
            color = average_of_area(x, y)
            @output.rect(x, y, x + @size, y + @size, color, color)
          end
        end
      end
    
      def in_bounds?(x,y)
        x.between?(0, @source.width) && y.between?(0, @source.height)
      end
    
      def save(file)
        @output.save(file)
      end
    
      private
      def average_of_area(x, y)
        colors = {:r => [], :g => [], :b => []}
    
        x.upto(x + @size) do |_x|
          y.upto(y + @size) do |_y|
            next unless in_bounds?(_x, _y)
            pixel = @source.get_pixel(_x, _y)
            colors.each_key { |c| colors[c] << ChunkyPNG::Color.send(c, pixel) }
          end
        end
    
        color = ChunkyPNG::Color.rgb(
          average_of_color(colors[:r]),
          average_of_color(colors[:g]),
          average_of_color(colors[:b])
        )
      end
    
      def average_of_color(values)
        return 0 unless values.size > 0
        values.inject { |s,e| s + e } / values.size
      end
    end
    
    p = Pixelizer.new('input.png')
    p.pixelize
    p.save('output.png')
    
    View full entry
    Finished in 8th place with a final score of 3.2/5. (View the Gist)
  • output_cheat.png
    output_average.png
    output_nearest.png
    chunkypixel_average.rb
    #! usr/bin/env ruby
    require 'chunky_png'
    
    class ChunkyPNG::Image
      # s: Integer (pixel size)
      def pixelize s = 10
        temp = Array.new((height*1.0/s).ceil) {Array.new((width*1.0/s).ceil) {Array.new(3) {0}}}
        height.times {|j| width.times {|i| ChunkyPNG::Color.to_truecolor_bytes(get_pixel(i,j)).each.with_index {|e,k| temp[j/s][i/s][k] += e}}}
        png = ChunkyPNG::Image.new width, height
        sq = s**2
        height.times {|j| width.times {|i| png.set_pixel(i,j, ChunkyPNG::Color.parse(ChunkyPNG::Color.rgb(*temp[j/s][i/s].map {|e| e/sq})))}}
        png
      end
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    image.pixelize.save('output_average.png')
    
    chunkypixel_cheat.rb
    #! usr/bin/env ruby
    require 'chunky_png'
    
    # ChunkyPNG::Image#resize is already implemented
    image = ChunkyPNG::Image.from_file('input.png')
    w, h = image.width, image.height
    image.resize(w/10, h/10).resize(w, h).save('output_cheat.png')
    
    chunkypixel_nearest.rb
    #! usr/bin/env ruby
    require 'chunky_png'
    
    class ChunkyPNG::Image
      # s: Integer (pixel size)
      def pixelize s = 10
        png = ChunkyPNG::Image.new width, height
        height.times {|j| width.times {|i| png.set_pixel(i,j, get_pixel(i/s*s, j/s*s))}}
        png
      end
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    image.pixelize.save('output_nearest.png')
    
    View full entry
    Finished in 9th place with a final score of 3.2/5. (View the Gist)
  • output.png
    solution.rb
    require 'chunky_png'
    
    image = ChunkyPNG::Image.from_file('input.png')
    pixel_size = 10
    
    (0...image.width).group_by { |n| n / pixel_size }.values.each do |xs|
      (0...image.height).group_by { |n| n / pixel_size }.values.each do |ys|
        area = xs.length * ys.length
    
        avg_color = ChunkyPNG::Color.rgb(*( 
          xs.inject([0,0,0]) { |sum, x|
            ys.inject(sum) { |subsum, y|
              %w(r g b).zip(subsum).map { |channel, n|
                n  + ChunkyPNG::Color.send(channel, image[x,y])
              }
            }
          }.map { |n| n / area } 
        ))
    
        image.rect(xs.first, ys.first, xs.last, ys.last, avg_color, avg_color)
      end
    end
    
    image.save('output.png')
    
    View full entry
    Finished in 10th place with a final score of 3.2/5. (View the Gist)
  • chunky3.png
    pixelize.rb
    require 'chunky_png'
    
    module Pixelize
    
      # Replace chunks of an image with a single color.
      #
      # @param size Number of pixels to consolidate
      #
      def pixelize!(size)
        # Step over each chunk horizontally and vertically, being careful
        # not to exceed the boundaries (hence subtracting one).
        0.step(self.width-1, size) do |x1|
          x2 = x1+size-1
          0.step(self.height-1, size) do |y1|
            y2 = y1+size-1
            rect(x1, y1, x2, y2, ChunkyPNG::Color::TRANSPARENT, self[x1,y1])
          end
        end
      end
    
    end
    
    
    class ChunkyPNG::Image
      include Pixelize  
    end
    
    
    img = ChunkyPNG::Image.from_file('output.png')
    img.pixelize!(10)
    img.save('chunky3.png')
    
    View full entry
    Finished in 11th place with a final score of 3.1/5. (View the Gist)
  • output.png
    solution.rb
    require 'chunky_png'
    
    module ChunkyPNG::Color
      def self.interpolate(*colors)
        r, g, b = 0, 0, 0
        colors.each do |c|
          r += r(c)
          g += g(c)
          b += b(c)
        end
        r, g, b = [r, g, b].map {|v| v / colors.length }
    
        rgb(r, g, b)
      end
    end
    
    class ChunkyPNG::Image
      def pixelate!(block_size = 10)
        (0..width - 1).step(block_size) do |x0|
          (0..height - 1).step(block_size) do |y0|
            x1 = x0 + block_size - 1
            y1 = y0 + block_size - 1
    
            int_color = interpolate_rect(x0, y0, x1, y1)
            rect(x0, y0, x1, y1, ChunkyPNG::Color::TRANSPARENT, int_color)
          end
        end
    
        self
      end
    
      private
    
      def interpolate_rect(x0, y0, x1, y1)
        colors = []
        (x0..x1).each do |x|
          (y0..y1).each do |y|
            colors << self[x, y] if include_xy?(x, y)
          end
        end
    
        ChunkyPNG::Color.interpolate(*colors)
      end
    end
    
    ChunkyPNG::Image.from_file('input.png').pixelate!.save('output.png')
    
    View full entry
    Finished in 12th place with a final score of 3.1/5. (View the Gist)
  • README
    Pixelise!
    =========
    
    This has two pixelising function, a straight average of the colour channels in a given block, or a weighted mean based
    upon a two dimensional normal distribution.
    
    The code uses the weighted version, but the other is kept on for display purposes.
    
    Name your image "input.png" and run the program.
    
    output.png
    pixelise.rb
    require 'chunky_png'
    
    # 2d gaussian
    #
    # @params  x    x coord
    # @params  y    y coord
    # @params  w    width of sample
    # @params  h    height of sample
    def twodguass(x,y,w,h)
    
      #distro constants
      big_a = 1
      a = 0.5
      b = 0
      c = 0.5
    
      x_0 = w/2
      y_0 = h/2
    
      p1 = a*((x-x_0)**2)
      p2 = 2*b*((x-x_0)*(y-y_0))
      p3 = c*((y-y_0)**2)
    
      p = (p1+p2+p3)*-1
      return big_a*(Math.exp(p))
    end
    
    # Pixelise functions
    
    # Return the average colour of a given area
    #
    # @params  image  image to manipulate
    # @params  x      x coord
    # @params  y      y coord 
    # @params  w      width of area
    # @params  h      height of area
    def av_area(image, x, y, w, h)
    
        # image meta for error checking
        i_w = image.width
        i_h = image.height
        
        # Total area
        tot = w*h
    
        # average bins
        av_r = 0
        av_g = 0
        av_b = 0
    
        # fill bins
        (0...w).each do |i|
          (0...h).each do |j|
            if(x+i >= i_w || y+j >= i_h)
              tot -=1
            else
              raw = image[x+i,y+j]
              av_r += ChunkyPNG::Color.r(raw)
              av_g += ChunkyPNG::Color.g(raw)
              av_b += ChunkyPNG::Color.b(raw)
            end
          end
        end
    
        # divide bins
        av_r /= tot
        av_g /= tot
        av_b /= tot
    
        return ChunkyPNG::Color.rgb(av_r, av_g, av_b)
    end
    
    # Return the weighted average colour of a given area
    #
    # @params  image  image to manipulate
    # @params  x      x coord
    # @params  y      y coord 
    # @params  w      width of area
    # @params  h      height of area
    def w_av_area(image, x, y, w, h)
    
        # image meta for error checking
        i_w = image.width
        i_h = image.height
        
        # Total weight 
        tot = 0
    
        # average bins
        av_r = 0
        av_g = 0
        av_b = 0
    
        # fill bins
        (0...w).each do |i|
          (0...h).each do |j|
            if(x+i >= i_w || y+j >= i_h)
            else
              weight = twodguass(i,j,w,h)
              tot += weight
              raw = image[x+i,y+j]
              av_r += ChunkyPNG::Color.r(raw) * weight
              av_g += ChunkyPNG::Color.g(raw) * weight
              av_b += ChunkyPNG::Color.b(raw) * weight
            end
          end
        end
    
        # divide bins
        av_r /= tot
        av_g /= tot
        av_b /= tot
    
    
        return ChunkyPNG::Color.rgb(av_r.to_i, av_g.to_i, av_b.to_i)
    end
    
    # Pixelise function
    #
    # @params  image		image to pixelise
    # @params  b_w      block width
    # @params  b_h      block height
    #
    # @return						pixelised image
    def pixelise(image, b_w, b_h)
    
      # Get image size
      w = image.width
      h = image.height
    
      # Number of blocks
      nbx = (w/b_w.to_f).ceil
      nby = (h/b_h.to_f).ceil
    
      # Go through each "block" in the image
      (0...nbx).each do |p_x|
        (0...nby).each do |p_y|
    
          # Top left coord
          x = p_x * b_w
          y = p_y * b_h
    
          # Get the average colour of the block
          p_colour = w_av_area(image, x, y, b_w, b_h);
    
          # Fill in block
          (0...b_w).each do |x1|
            (0...b_h).each do |y1|
              # Fill in up to edges
              image[x+x1,y+y1] = p_colour if !(x+x1 >= w || y+y1 >= h) 
            end
          end
        end
      end
      return image
    end
    
    ### Script
    
    # Grab image
    image = ChunkyPNG::Image.from_file('input.png')
    
    # Size of pixeled area
    b_w = 10
    b_h = 10
    
    
    # Run the pixelisation
    image = pixelise(image, b_w, b_h)
    
    # save
    image.save('output.png')
    
    View full entry
    Finished in 13th place with a final score of 3.1/5. (View the Gist)
  • output.png
    pixelize.rb
    require 'chunky_png'
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    image.height.times do |y|
      image.width.times do |x|
        # As we iterate over each pixel, copy only the color of the pixel
        # from the top left corner of this pixels 10x10 region
        #  e.g. the pixel at [69,17] will get set to the color from [60,10]
        image[x, y] = image[x / 10 * 10, y / 10 * 10]
      end
    end
    
    image.save('output.png')
    
    View full entry
    Finished in 14th place with a final score of 3.0/5. (View the Gist)
  • output.png
    pixelize.rb
    require 'chunky_png'
    
    module ChunkyPNG::Color
      def self.average(pixels)
        pixel_rgbs = pixels.map{|p| to_truecolor_bytes(p)}
        averaged_rgb = [0,0,0].zip(*pixel_rgbs).map{|colors| colors.inject(&:+) / pixels.size}
        rgb(*averaged_rgb)
      end
    end
    
    module Pixelizeable
      def pixilize!(pixel_width, pixel_height = pixel_width)
        collect_block!(pixel_height, pixel_width) do |block|
          new_color = ChunkyPNG::Color.average(block.pixels)
          new_pixels = (0...(block.width * block.height)).collect{new_color}
          ChunkyPNG::Canvas.new(block.width, block.height, new_pixels)
        end
      end
      
      def collect_block!(pixel_width, pixel_height)
        image_block_width = (width.to_f / pixel_width.to_f).ceil
        image_block_height = (height.to_f / pixel_height.to_f).ceil
        x_offsets = (0...image_block_width).map{|x| x * pixel_width}
        y_offsets = (0...image_block_height).map{|x| x * pixel_height}
        xy_offsets = x_offsets.product(y_offsets)
        
        xy_offsets.each do |x_offset, y_offset|
          block_width = [pixel_width, width - x_offset].min
          block_height = [pixel_height, height - y_offset].min
          new_block = yield crop(x_offset, y_offset, block_width, block_height)
          replace!(new_block, x_offset, y_offset)
        end
      end
    end
    ChunkyPNG::Image.send :include, Pixelizeable
    
    image = ChunkyPNG::Image.from_file('input.png')
    image.pixilize!(10)
    image.save('output.png')
    
    View full entry
    Finished in 15th place with a final score of 3.0/5. (View the Gist)
  • output.png
    pixelize.rb
    require 'rubygems'
    require 'chunky_png'
    include ChunkyPNG
    
    class Pixelizer
      attr_reader :canvas
      
      def initialize(canvas, size=10)
        @canvas = canvas
        @size = size.to_i
        @rows = (@canvas.height.to_f / @size).ceil
        @columns = (@canvas.width.to_f / @size).ceil
      end
      
      # Fills each block with the average color of its pixels
      def pixelize
        blocks.each do |block|
          block.fill(block.average_color)
        end
        self
      end
      
      # An array of the blocks composing the canvas
      def blocks
        @blocks ||= [].tap do |blocks|
          @rows.times do |row|
            @columns.times do |column|
              blocks << Block.new(@canvas, @size * column, @size * row, @size, @size)
            end
          end
        end
      end
      
      class Block
        def initialize(canvas, x, y, width, height)
          @canvas = canvas
          @x0, @y0, @x1, @y1 = x, y, x + width, y + height
        end
        
        def average_color
          colors = []
          for x in @x0...@x1
            for y in @y0...@y1
              colors << Color.to_truecolor_bytes(@canvas[x, y]) if @canvas.include_xy?(x, y)
            end
          end
          Color.rgb *colors.transpose.map { |c| c.inject(:+) / c.size }
        end
        
        def fill(color)
          @canvas.rect(@x0, @y0, @x1, @y1, Color::TRANSPARENT, color)
        end
      end
    end
    
    input = Image.from_file('input.png')
    output = Pixelizer.new(input).pixelize.canvas
    output.save('output.png')
    
    View full entry
    Finished in 16th place with a final score of 3.0/5. (View the Gist)
  • output.png
    pixelate.rb
    require 'rubygems'
    require 'chunky_png'
    
    include ChunkyPNG
    
    BLOCK_SIZE = 10
    
    def main in_file = 'input.png', out_file = 'output.png'
      image = Image.from_file in_file
      
      0.step(image.width, BLOCK_SIZE) do |x|
        0.step(image.height, BLOCK_SIZE) do |y|
    
          section = image.safe_crop x, y, BLOCK_SIZE, BLOCK_SIZE
    
          unless section.pixels.length <= 0
            section.fill Color.rgb_average(*section.pixels)
            image.replace! section, x, y
          end
    
        end
      end
      
      image.save out_file
    end
    
    class Canvas
      def safe_crop x, y, crop_width, crop_height
        crop_width = [crop_width, self.width - x].min
        crop_height = [crop_height, self.height - y].min
        
        self.crop x, y, crop_width, crop_height
      end
    
      def fill color
        self.rect 0, 0, self.width-1, self.height-1, ChunkyPNG::Color::TRANSPARENT, color
      end
    end
    
    module Color
      def rgb_average *args
        r, g, b = [args.map{|c| r(c)}, args.map{|c| g(c)}, args.map{|c| b(c)}].map &:average
        rgb(r, g, b)
      end
    end
    
    class Array
      def average
        return self.inject(:+) / self.length
      end
    end
    
    main
    
    View full entry
    Finished in 17th place with a final score of 3.0/5. (View the Gist)
  • README.md

    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)
    
    output_10.png
    output_4x8.png
    output_6.png
    output_8.png
    solution.rb
    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] += times * 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)
    
    View full entry
    Finished in 18th place with a final score of 2.9/5. (View the Gist)
  • output.png
    mosaic.rb
    require 'chunky_png'
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    (0...image.width).each do |x|
      (0...image.height).each do |y|
        image[x, y] = image[x/10*10, y/10*10]
      end
    end
    
    image.save('output.png')
    
    View full entry
    Finished in 19th place with a final score of 2.9/5. (View the Gist)
  • output.png
    pixelate.rb
    # Code for http://codebrawl.com/contests/pixelizing-images-with-chunkypng - @jamesu
    require 'rubygems'
    require 'open-uri'
    require 'chunky_png'
    
    open("https://gist.github.com/raw/5dace61b37de19a56637/032f70a3023e37a7dc1fe4a619cd8c4f970d1677/output.png") do |f|
      p=ChunkyPNG;image=p::Image.from_blob(f.read);col=p::Color
      
      (0...(image.width)).each_slice(10) {|x|
        (0...(image.height)).each_slice(10) {|y|
          sum = [0,0,0]
          x.each{|xp| y.each{|yp|
            p = image.get_pixel(xp,yp)
            sum[0]+=col.r(p); sum[1]+=col.g(p); sum[2]+=col.b(p)
          }}
          sum.map!{|c| c /= x.length*y.length}
          sum_color = ChunkyPNG::Color.rgb(sum[0],sum[1],sum[2])
          image.rect(x[0],y[0],x[0]+9,y[0]+9,sum_color,sum_color)
      }}
      
      image.save('output.png')
    end
    
    View full entry
    Finished in 20th place with a final score of 2.9/5. (View the Gist)
  • output.png
    pixelize.rb
    require 'chunky_png'
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    
    BLOCK_SIZE = 10
    (0...image.height).each_slice(BLOCK_SIZE) do |y_range|
      (0...image.width).each_slice(BLOCK_SIZE) do |x_range|
        block = x_range.map { |x| y_range.map { |y| [x, y] } }.flatten(1)
        r, g, b, a, size = 0, 0, 0, 0, block.size
        block.each do |x, y|
          m, n, o, p = ChunkyPNG::Color.to_truecolor_alpha_bytes(image[x, y])
          r, g, b, a = r + m, g + n, b + o, a + p
        end
        avg = ChunkyPNG::Color.rgba(r / size, g / size, b / size, a / size)
        block.each { |x, y| image[x, y] = avg }
      end
    end
    
    image.save('output.png')
    
    View full entry
    Finished in 21st place with a final score of 2.9/5. (View the Gist)
  • README.md

    Pixelizer entry for Codebrawl

    This example needs Ruby 1.9.

    Two ways to run this:

    $ ./pixelizer.rb infile.png > outfile.png
    $ ./pixelizer.rb - > outfile.png < infile.png
    
    output.png
    pixelizer.rb
    #!/usr/bin/env ruby
    
    require 'chunky_png'
    
    class Pixelizer
      include ChunkyPNG
    
      # The ChunkyPNG::Image instance.
      attr_reader :png
    
      # The pixelizer accepts an IO object, like a file handle or $stdin.
      def initialize(io)
        @png = Image.from_io io
      end
    
      # Pixelizes using a very simple algorithm. Every block of 10x10 pixels
      # is evaluated, and replaced by one single color closest to the set of
      # colors within that block. You can overwrite the 10x10 pixels by setting
      # the first argument.
      def pixelize!(block_size = 10)
        dimension = @png.dimension
        @block_point = Point.new 0, 0
    
        while @block_point.within_bounds? dimension
          y_delta = dimension.height - @block_point.y
          @block_height = y_delta < block_size ? y_delta : block_size
    
          while @block_point.within_bounds? dimension
            x_delta = dimension.width - @block_point.x
            @block_width = x_delta < block_size ? x_delta : block_size
    
            pixelize_block!
    
            @block_point.x += block_size
          end
    
          @block_point.x = 0
          @block_point.y += block_size
        end
      end
    
      protected
    
      # Replaces the block with a single color.
      def pixelize_block!
        new_color = blur_color
    
        for block_y in 0...@block_height
          for block_x in 0...@block_width
            @png[@block_point.x + block_x, @block_point.y + block_y] = new_color
          end
        end
      end
    
      # Calculates the new color for a block based on surrounding colors.
      # Completely transparent pixels don't count of course.
      def blur_color
        colors = {r: [], g: [], b: [], a: []}
    
        for block_y in  0...@block_height
          for block_x in 0...@block_width
            color = @png[@block_point.x + block_x, @block_point.y + block_y]
            unless Color.fully_transparent? color
              colors.keys.each do |channel|
                colors[channel] << Color.send(channel, color)
              end
            end
          end
        end
    
        return Color::TRANSPARENT if colors[:r].empty?
    
        Color.rgba *(colors.map do |chan, set|
                       set.inject(:+) / set.length
                     end)
      end
    end
    
    unless ARGV[0]
      $stderr.puts "Usage: #{$0} [input.png | -] > output.png"
      exit 1
    end
    
    begin
      io = ARGV[0] == '-' ? $stdin : File.open(ARGV[0], 'rb')
      pix = Pixelizer.new io
      pix.pixelize!
      pix.png.write $stdout
    rescue
      $stderr.puts "Sorry, something went wrong.\n#{$!}"
      exit 1
    end
    
    View full entry
    Finished in 22nd place with a final score of 2.9/5. (View the Gist)
  • output.png
    solution.rb
    # Solution for Codebrawl #2
    # Author: Sam Pohlenz
    
    require 'chunky_png'
    
    class Pixelator
      attr_reader :resolution
      
      def initialize(resolution=10)
        @resolution = resolution
      end
      
      # Pixelates a ChunkyPNG Image (in place) according to the current resolution
      def pixelate(image)
        columns = (image.width / resolution.to_f).ceil
        rows = (image.height / resolution.to_f).ceil
    
        rows.times do |row|
          columns.times do |column|
            color = sample(image, column, row)
            paint(image, column, row, color)
          end
        end
      end
      
      # Finds the average color within a block determined by the current resolution
      def sample(image, column, row)
        pixels = 0
        r = g = b = 0
    
        each_pixel_in(image, column, row) do |x, y|
          color = image[x, y]
    
          r += ChunkyPNG::Color.r(color)
          g += ChunkyPNG::Color.g(color)
          b += ChunkyPNG::Color.b(color)
          pixels += 1
        end
        
        raise ChunkyPNG::OutOfBounds, "Block #{column}, #{row} out of bounds" if pixels.zero?
        ChunkyPNG::Color.rgb(r / pixels, g / pixels, b / pixels)
      end
    
      # Fills a block with a given color
      def paint(image, column, row, color)
        each_pixel_in(image, column, row) do |x, y|
          image[x, y] = color
        end
      end
    
    private
      def each_pixel_in(image, column, row)
        resolution.times do |x|
          resolution.times do |y|
            image_x, image_y = column*resolution + x, row*resolution + y
            next unless image.include_xy?(image_x, image_y)
            yield image_x, image_y
          end
        end
      end
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    Pixelator.new(10).pixelate(image)
    image.save('output.png')
    
    View full entry
    Finished in 23rd place with a final score of 2.8/5. (View the Gist)
  • output.png
    solution.rb
    require 'chunky_png'
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    chunks = [] #the tuples we're going to operate on [start-x, start-y, delta-x, delta-y]
    
    chunk_size = 10 #how many square pixels per normal sized chunk
    
    #dimensions
    w = image.dimension.width
    h = image.dimension.height
    
    #remainders
    wr = w % chunk_size
    hr = h % chunk_size
    
    #limits
    hl = h - hr
    wl = w - wr
    
    #grab each square chunk
    (0..(w-wr-chunk_size)).step(chunk_size).each do |x|
    	(0..(h-hr-chunk_size)).step(chunk_size).each do |y|
    		chunks << [x, y, chunk_size, chunk_size] 
    	end
    	
    	#if there's a remainder on the Y axis, add that
    	if hr > 0
    		chunks << [x, hl, chunk_size, hr] #odd height chunk
    	end
    end
    
    #if there's a remainder on the X axis
    if wr > 0
    	(0..(h-hr-chunk_size)).step(chunk_size).each do |y|
    		chunks << [wl, y, wr, chunk_size] #odd width chunk
    	end
    	if hr > 0 #remainder on both X and Y
    		chunks << [wl, hl, wr, hr] #bottom right corner chunk, odd width and height
    	end
    end
    
    chunks.each do |chunk|
    	c_r = c_g = c_b = 0
    	x,y,dx,dy = chunk
    	pixels = dx*dy
    	#sum the indvidual color values for all pixels in the chunk
    	(x..(x + dx - 1)).each do |a|
    		(y..(y + dy - 1)).each do |b|
    			c_r += ChunkyPNG::Color.r(image[a,b])
    			c_g += ChunkyPNG::Color.g(image[a,b])
    			c_b += ChunkyPNG::Color.b(image[a,b])
    		end
    	end
    	#divide by total number of pixels
    	c_r /= pixels
    	c_g /= pixels
    	c_b /= pixels
    	color = ChunkyPNG::Color.rgb(c_r,c_g,c_b) #color to set the chunk to
    	(x..(x + dx - 1)).each do |a|
    		(y..(y + dy - 1)).each do |b|
    			image[a,b] = color
    		end
    	end
    end
    
    image.save('output.png')
    
    View full entry
    Finished in 24th place with a final score of 2.8/5. (View the Gist)
  • Gemfile
    source :rubygems
    
    gem "chunky_png", :git => "git://github.com/mariusgrigoriu/chunky_png.git"
    
    out.png
    operations.rb
          # Pixelizes the canvas
          #
          # This method will modify the canvas. To obtain a new canvas and leave the
          # current instance intact use {#pixelize} instead.
          #
          # @param [Integer] size_x The width of the block used to pixelize the image
          # @param [Integer] size_y The height of the block used to pixelize the image
          # @return [ChunkyPNG::Canvas] Returns itself, pixelized.
          # @see {#pixelize!}
          def pixelize!(size_x, size_y)
            Struct.new("RGBA", :r, :g, :b, :a, :count)
            bins = Array.new((height/size_y.to_f).ceil) do
              Array.new((width/size_x.to_f).ceil) { Struct::RGBA.new(0,0,0,0,0)}
            end
    
            for y in 0...height do
              for x in 0...width do
                bin = bins[y/size_y][x/size_x]
                bin.r += ChunkyPNG::Color.r(get_pixel(x,y))
                bin.g += ChunkyPNG::Color.g(get_pixel(x,y))
                bin.b += ChunkyPNG::Color.b(get_pixel(x,y))
                bin.a += ChunkyPNG::Color.a(get_pixel(x,y))
                bin.count += 1
              end
            end
    
            for y in 0...height do
              for x in 0...width do
                bin = bins[y/size_y][x/size_x]
                divisor = bin.count.to_f
                set_pixel(x,y, ChunkyPNG::Color(
                  (bin.r/divisor).round,
                  (bin.g/divisor).round,
                  (bin.b/divisor).round,
                  (bin.a/divisor).round)
                )
              end
            end
            
            return self
          end
    
    pixelize-chunky_fork.rb
    require 'chunky_png'
    
    ChunkyPNG::Image.from_file('in.png').pixelize!(10, 10).save('out.png')
    
    View full entry
    Finished in 25th place with a final score of 2.8/5. (View the Gist)
  • output.png
    pixelize.rb
    require 'chunky_png'
    
    image = ChunkyPNG::Image.from_file('input.png')
    original = image.dup
    
    block_size = 10
    
    xs = 0.upto((image.width - 1) / block_size).to_a.map { |x| x * block_size }
    ys = 0.upto((image.height - 1) / block_size).to_a.map { |y| y * block_size }
    
    xs.each do |x|
      ys.each do |y|
        color = original[x, y]
        image.rect x, y, x + block_size, y + block_size, color, color
      end
    end
    
    image.save('output.png')
    
    View full entry
    Finished in 26th place with a final score of 2.8/5. (View the Gist)
  • output.png
    pixelator.rb
    require 'rubygems'
    require 'chunky_png'
    
    # Pixelator will pixelify your pngs 
    # defaults to a 10 pixel block, but will gladly accept
    # larger or smaller 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|
          red = []
          green = []
          blue = []
          alpha = []
    
          # 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
    
          # iterate through the pixels in the current block and pull out all the color info
          each_pixel_from_block(curr_x_block_size, curr_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
    
          # 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] = ChunkyPNG::Color.rgba(averages[0], averages[1], averages[2], averages[3])
          end
        end
    
        @image
      end
    
      private
    
      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
    
    Pixelator.new('input.png').pixelate(10).save("output.png")
    
    View full entry
    Finished in 27th place with a final score of 2.7/5. (View the Gist)
  • output.png
    Pixelize.rb
    require 'chunky_png'
    include ChunkyPNG::Color
    include ChunkyPNG::Canvas::Drawing
    
    input = ChunkyPNG::Image.from_file('input.png')
    # Put your logic to averageize `image` here.
    
    BLOCK_SIZE = 10
    
    height = input.height
    width = input.width
    
    heightIterations = height / BLOCK_SIZE
    widthIterations  = width / BLOCK_SIZE
    
    canvas = ChunkyPNG::Canvas.new(width, height, WHITE)
    
    def averageArray(array)
      return (array.inject { |sum, el| sum + el }.to_f / array.size).to_i
    end
    
    heightIterations.times do |y|
      widthIterations.times do |x|
    
        reds, greens, blues = [], [], []
    
        BLOCK_SIZE.times do |cy|
          BLOCK_SIZE.times do |cx|
            pixel = input[x * BLOCK_SIZE + cx, y * BLOCK_SIZE + cy]
            index = cy * BLOCK_SIZE + cx
            reds[index], greens[index], blues [index] = r(pixel), g(pixel), b(pixel)
          end
        end
    
        average = rgb(averageArray(reds), averageArray(greens), averageArray(blues))
    
        canvas.rect(x * BLOCK_SIZE, y * BLOCK_SIZE, (x+1) * BLOCK_SIZE, (y+1) * BLOCK_SIZE, average, average)
      end
    end
    
    # Save image
    canvas.save('output.png')
    
    View full entry
    Finished in 28th place with a final score of 2.7/5. (View the Gist)
  • README.md

    CodeBrawl #2: Pixelizing images with ChunkyPNG

    Requirements

    • ruby 1.9.x
    • chunky_png gem

    Usage

    ruby pixelize.rb

    output.png
    pixelize.rb
    require 'chunky_png'
    
    class Pixelizer
      
      include ChunkyPNG
    
      def initialize(input, output, blk_size)
        @input_filename = input
        @output_filename = output
        @block_size = blk_size
      end
      
      # run it
      def run
        @input = Image.from_file(@input_filename)
        @input_h = @input.height
        @input_w = @input.width
    
        @output = Image.new(@input_w, @input_h)
        (0...@input_w).step(@block_size) do |x|
          (0...@input_h).step(@block_size) do |y|
            get_block(x,y) { |blk| get_pixels(blk) { |pixels| pixelize(pixels) { |color| write_block(x, y, color) } } }
          end
        end
        @output.save(@output_filename)
      end
      
      private
      
      # grab a block of the image starting at start_x, start_y with dimensions of @block_size
      def get_block(start_x, start_y)
        raise OutOfBounds if !@input.dimension.include?([start_x, start_y])  
        stop_x = @input.include_x?(start_x+@block_size-1) ? start_x+@block_size-1 : @input.width-1
        stop_y = @input.include_y?(start_y+@block_size-1) ? start_y+@block_size-1 : @input.height-1
      
        blk = []
        (start_y..stop_y).each do |y|
          row = []
          (start_x..stop_x).each do |x|
            row << @input[x,y]
          end
          blk << row
        end
        yield blk if block_given?
        blk
      end
    
      # grab the pixel values from the block, separating into rgba values
      def get_pixels(blk)
        pixels = blk.flatten.collect do |p|
          pix = p.to_s(16).rjust(8, "0")
          { :red => pix[0,2].hex, :green => pix[2,2].hex, :blue => pix[4,2].hex, :alpha => pix[6,2].hex }
        end
        yield pixels if block_given?
        pixels
      end
    
      # just avg the colors of the block
      def colorize(pixels, color)
        pixels.collect { |p| p[color] }.inject(0) { |sum, p| sum + p }/pixels.size
      end
    
      # determine the color of the block
      def pixelize(pixels)
        color = [:red, :green, :blue, :alpha].collect { |color| colorize(pixels, color) }
        yield color if block_given?
        color
      end
    
      # write the new pixelized block
      def write_block(x, y, color)
        (x...x+@block_size).each do |a|
          (y...y+@block_size).each do |b|
            @output.set_pixel_if_within_bounds(a, b, Color.rgba(color[0], color[1], color[2], color[3]))
          end
        end
      end
    end
    
    pix = Pixelizer.new('input.png', 'output.png', 10)
    pix.run
    
    View full entry
    Finished in 29th place with a final score of 2.6/5. (View the Gist)
  • output_1309375058.png
    pngbrawl.rb
    #! /usr/bin/env ruby
    
    require 'rubygems'
    require 'chunky_png'
    
    image = ChunkyPNG::Image.from_file('input.png')
    h = image.dimension.height
    print "height #{h} \n"
    w = image.dimension.width
    print "width #{w} \n"
    
    
    def pixel_bomb(x, y, image)
      currentGreen = ChunkyPNG::Color.g(image[x,y])
    
      color = ChunkyPNG::Color(image[x,y])
      sz = case currentGreen
           when 0..63
           rand(2)
           when 63..127
           1
           when 127..191
           2
           when 191..255
           4
           end
    
      (-sz..sz).to_a.each do |xn|
        (-sz..sz).to_a.each do |yn|
          p = x + xn
          q = y + yn
          image.set_pixel_if_within_bounds(p,q, color)
        end
      end
    end
    
    def back_to_xy(int, width, height)
      x = int % width
      y = (int / width)
      [x, y]
    end
    
    hash = Hash.new{|h, k| h[k] = []}
    
    (0..h-1).each do |y|
      (0..w-1).each do |x|
        this_one = (y * w) + x
        currentGreen = ChunkyPNG::Color.g(image[x,y])
        hash[currentGreen] << this_one
      end
    end
    
    shash = hash.sort
    
    shash.each do |k, v|
      v.each do |pixel|
        x, y = back_to_xy(pixel, w, h)
        pixel_bomb(x, y, image)
      end
    end
    
    image.save('output_' + Time.now.to_i.to_s + '.png')
    
    View full entry
    Finished in 30th place with a final score of 2.6/5. (View the Gist)
  • output.png
    chunky_pixels.rb
    require 'rubygems'
    require 'chunky_png'
    
    orig = ChunkyPNG::Image.from_file('input.png')
    rows = (orig.width / 10.0).ceil
    cols = (orig.height / 10.0).ceil
    canvas = ChunkyPNG::Canvas.new(rows * 10, cols * 10).replace(orig)
    
    (0...rows).each do |row|
      x = row * 10
      (0...cols).each do |col|
        y = col * 10
        chunk = canvas.crop(x, y, 10, 10).resample(100, 100).crop(45, 45, 10, 10)
        canvas.replace!(chunk, x, y)
      end
    end
    
    canvas.crop(0, 0, orig.width, orig.height).save('output.png')
    
    View full entry
    Finished in 31st place with a final score of 2.6/5. (View the Gist)
  • output.png
    pixelator.rb
    require 'chunky_png'
    
    class Pixelator  
      def self.pixelate source_path, output_path, pixel_size = 10
        source = ChunkyPNG::Image.from_file( source_path )
        output = ChunkyPNG::Image.new( source.width, source.height, ChunkyPNG::Color::TRANSPARENT )
        
        # output cols & rows
        cols = (source.height.to_f / pixel_size).ceil
        rows = (source.width.to_f / pixel_size).ceil
        
        cols.times do |y|      
          rows.times do |x|
            # check for out of bounds pixel
            x_min = x * pixel_size
            y_min = y * pixel_size
            x_max = [x_min + pixel_size, source.width].min
            y_max = [y_min + pixel_size, source.height].min
            
            # get color
            color = source.get_pixel( x_min, y_min )
            
            # draw
            output.rect( x_min, y_min, x_max, y_max, ChunkyPNG::Color::TRANSPARENT, color )
          end
        end
    
        output.save( output_path )
      end
    end
    
    Pixelator.pixelate( 'input.png', 'output.png' )
    
    View full entry
    Finished in 32nd place with a final score of 2.6/5. (View the Gist)
  • output.png
    solution.rb
    require 'rubygems'
    require 'chunky_png'
    
    PIXEL_SIZE = 10
    
    input = ChunkyPNG::Image.from_file('input.png')
    
    PIXELATED_width = (input.width.to_f/PIXEL_SIZE).ceil.to_i * PIXEL_SIZE
    PIXELATED_height = (input.height.to_f/PIXEL_SIZE).ceil.to_i * PIXEL_SIZE
    output = ChunkyPNG::Image.new(PIXELATED_width, PIXELATED_height, ChunkyPNG::Color::TRANSPARENT)
    
    # divide into pixel grid
    # deals with the remainder (i.e. output.width%PIXEL_SIZE) by cropping image afterwards
    (PIXELATED_width/PIXEL_SIZE).times do |x|
      (PIXELATED_height/PIXEL_SIZE).times do |y|
        w = x*PIXEL_SIZE
        h = y*PIXEL_SIZE
        # get square of pixels
        begin
          pxl_space = input.crop(w,h,PIXEL_SIZE,PIXEL_SIZE)
        rescue ChunkyPNG::OutOfBounds
          pxl_space = input.crop(w,h,input.width-w,input.height-h)
        end
        # determine output pixel colour
        pxl_r = pxl_space.pixels.inject(0) { |s,v| s+=ChunkyPNG::Color.r(v) }/pxl_space.pixels.count
        pxl_g = pxl_space.pixels.inject(0) { |s,v| s+=ChunkyPNG::Color.g(v) }/pxl_space.pixels.count
        pxl_b = pxl_space.pixels.inject(0) { |s,v| s+=ChunkyPNG::Color.b(v) }/pxl_space.pixels.count
        # paint pixel
        output.rect(w, h, w+PIXEL_SIZE, h+PIXEL_SIZE, ChunkyPNG::Color::TRANSPARENT, ChunkyPNG::Color.rgb(pxl_r,pxl_g,pxl_b))
      end
    end
    
    
    # crop
    output.crop!(0,0, input.width, input.height)
    output.save('output.png')
    
    View full entry
    Finished in 33rd place with a final score of 2.6/5. (View the Gist)
  • output.png
    pixelit.rb
    require 'rubygems'
    require 'chunky_png'
    
    module Pixelization
    
      def pixelizing_replace!(size)
        # This method uses the (0,0) color value for the (size,size) grid
        # as the value throughout the pixelization
    
        (0..self.height-1).step(size) do |h|
    
          row = self.row(h)
          indices = (0..width-size).step(size).to_a
    
          indices.each do |i|
            row[i,size] = size.times.map { row[i] }
          end
    
          size.times do |h_delta|
            if (h + h_delta) < self.height
              self.replace_row!(h + h_delta, row)
            end
          end
    
        end
      end
    
    end
    
    
    image = ChunkyPNG::Image.from_file('input.png')
    image.extend Pixelization
    image.pixelizing_replace!(10)
    image.save("output.png")
    
    View full entry
    Finished in 34th place with a final score of 2.6/5. (View the Gist)
  • output.png
    solution.rb
    #!/usr/bin/env ruby
    
    require 'chunky_png'
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    # Size of the blocks in pixels by pixels
    blockSize = 10
    
    # Process block by block
    w = 0
    while w < image.width do
      h = 0
      while h < image.height do
        sum = [0, 0, 0] # Sum of all the rgb values of the pixels in the block
        pixels = 0 # Number of pixels in the block (blocks at the right/bottom may be incomplete)
        avg = [0, 0, 0] # Average color for that block
    
        # Process all pixels in that block (blockSize x blockSize)
        0.upto(blockSize) do |x|
          next if (w + x) >= image.width # Check bounds!
          0.upto(blockSize) do |y|
            next if (h + y) >= image.height # Check bounds!
            # Get the RGB representation for that pixel
            color = ChunkyPNG::Color.to_truecolor_bytes(image[w + x, h + y])
            # Aggregate pixel value to the accumulative array
            sum[0] += color[0]
            sum[1] += color[1]
            sum[2] += color[2]
            # Another pixel processed for this block
            pixels += 1
          end
        end
    
        # Just calculate the average of the three components
        avg[0] = sum[0] / pixels
        avg[1] = sum[1] / pixels
        avg[2] = sum[2] / pixels
    
        # Update every pixel in the block with the same average color
        0.upto(blockSize) do |x|
          next if (w + x) >= image.width
          0.upto(blockSize) do |y|
            next if (h + y) >= image.height
            image[w + x, h + y] = ChunkyPNG::Color(avg[0], avg[1], avg[2])
          end
        end
    
        # Next row
        h += blockSize
      end
      # Next column
      w += blockSize
    end
    
    image.save('output.png')
    
    View full entry
    Finished in 35th place with a final score of 2.6/5. (View the Gist)
  • output.png
    solution.rb
    require 'chunky_png'
    
    image = ChunkyPNG::Image.from_file('input.png')
    
    # Not exactly elegant, but it gets the job done
    
    sample_y = 0
    
    while sample_y < image.height do
      sample_x = 0
      while sample_x < image.width do
        sample_color = image.get_pixel(sample_x + 4, sample_y + 4)
    
        (sample_x).upto(sample_x + 9) do |x|
          (sample_y).upto(sample_y + 9) do |y|
            image.set_pixel_if_within_bounds(x, y, sample_color)
          end
        end
        sample_x += 10
      end
      sample_y += 10
    end
    
    image.save('output.png')
    
    View full entry
    Finished in 36th place with a final score of 2.5/5. (View the Gist)
  • output.png
    pixelize.rb
    #!/usr/bin/env ruby
    require 'chunky_png'
    
    # A chunky monkey patch... am I going to get sued by Ben and Jerry?
    class ChunkyPNG::Image < ChunkyPNG::Canvas
      def pixelize_area!(vector)
        red_vals = []
        green_vals = []
        blue_vals = []
        vector.each do |pixel|
          red_vals << ChunkyPNG::Color.r(self[pixel.x, pixel.y])
          green_vals << ChunkyPNG::Color.g(self[pixel.x, pixel.y])
          blue_vals << ChunkyPNG::Color.b(self[pixel.x, pixel.y])
        end
        pixel_color = ChunkyPNG::Color.rgb(avg(red_vals),avg(green_vals),avg(blue_vals))
        self.rect(vector.min.x, vector.min.y, vector.max.x, vector.max.y, pixel_color, pixel_color)
        return self
      end
      
      def pixelize!(blocksize)
        grid_x = (0..self.dimension.width).reject{|x| x%blocksize != 0}
        grid_y = (0..self.dimension.height).reject{|y| y%blocksize != 0}
        grid_x.each_with_index do |x,i|
          grid_y.each_with_index do |y,j|
            next_x = [grid_x[i+1], self.dimension.width-1].reject{|i| i == nil}.min
            next_y = [grid_y[j+1], self.dimension.height-1].reject{|i| i == nil}.min
            width = next_x - x
            height = next_y - y
            unless width <= 0 || height <= 0
              va = []
              (x..next_x).each do |vx|
                (y..next_y).each do |vy|
                  va << [vx, vy]
                end
              end
              vector = ChunkyPNG::Vector(*va)
              self.pixelize_area!(vector)
            end
          end
        end
        return self
      end
      
      private
      
        def avg(array)
          ((array.reduce{|sum,n| sum+n})/(array.size)).to_i
        end
    end
    
    image = ChunkyPNG::Image.from_file(ARGV[0])
    image.pixelize!(ARGV[2] ? ARGV[2].to_i : 10)
    image.save(ARGV[1])
    puts "done"
    
    View full entry
    Finished in 37th place with a final score of 2.5/5. (View the Gist)
  • output.png
    pixelate.rb
    require 'chunky_png'
    
    module ChunkyPNG
      class Canvas
        module Pixelate
          # Pixelate image or part of the image
          # @param [Integer] block size for pixalating
          # @param [Integer] start x-coordinate for pixelating
          # @param [Integer] start y-coordinate for pixelating
          # @param [Integer] end x-coordinate for pixelating
          # @param [Integer] end y-coordinate for pixelating
          # @return [ChunkyPNG::Canvas] Itself, with pixelated applied
          def pixelate(block_size, x0 = 0, y0 = 0, x1 = self.width - 1, y1 = self.height - 1)
            half_block = block_size / 2
    
            x = x0
            y = y0
    
            while y <= y1
              while x <= x1
                x_color_point = min(x + half_block, width - 1)
                y_color_point = min(y + half_block, height - 1)
    
                x_end = min(x + block_size - 1, x1)
                y_end = min(y + block_size - 1, y1)
    
                color = self.get_pixel(x_color_point, y_color_point)
                self.rect(x, y, x_end, y_end, ChunkyPNG::Color::TRANSPARENT, color)
                x += block_size
              end
    
              x = x0
              y += block_size
            end
    
            self
          end
    
          private
    
          # internal simple function to calculate minimum of two values
          def min(a, b)
            return a if a < b
            return b
          end
        end
    
        # include module on Canvas
        include Pixelate
      end
    end
    
    image = ChunkyPNG::Image.from_file('input.png')
    image.pixelate(10)
    image.save('output.png')
    
    View full entry
    Finished in 38th place with a final score of 2.4/5. (View the Gist)
  • output.png
    gistfile1.rb
    require 'chunky_png'
    
    @image = ChunkyPNG::Image.from_file('input.png')
    
    def pixelate(a, b)
    	if a+10 > @image.dimension.width
    		w = @image.dimension.width - a
    	else
    		w = 10
    	end
    	
    	if b+10 > @image.dimension.height
    		h = @image.dimension.height - b
    	else
    		h = 10
    	end
    	
    	color1 = @image[a, b]
    	
    	w.times do |i|
    		h.times do |j|
    			color2 = @image[i+a, j+b]
    			c1_r = ChunkyPNG::Color.r(color1)
    			c2_r = ChunkyPNG::Color.r(color2)
    			c1_g = ChunkyPNG::Color.g(color1)
    			c2_g = ChunkyPNG::Color.g(color2)
    			c1_b = ChunkyPNG::Color.b(color1)
    			c2_b = ChunkyPNG::Color.b(color2)
    			color1 = ChunkyPNG::Color.rgb(((c1_r + c2_r)/2), ((c1_g + c2_g)/2), ((c1_b + c2_b)/2))
    		end
    	end
    
    	w.times do |i|
    		h.times do |j|
    			@image[i+a, j+b] = color1
    		end
    	end
    end
    
    w = dim.width
    h =	dim.height
    		
    i = 0
    while (i < w)
    	j = 0
    	while (j < h)
    		pixelate(i, j)
    		j = j + 10
    	end
    	i = i + 10
    end
    
    @image.save('output.png')
    
    View full entry
    Finished in 39th place with a final score of 2.4/5. (View the Gist)
  • output.png
    pixellate.rb
    require 'chunky_png'
    
    def pixellate(tile_size = 10)
      tile_length = ((tile_size * tile_size) - 1)
    
      image = ChunkyPNG::Image.from_file('input.png')
    
      rework = image.resample_nearest_neighbor(image.width / tile_size, image.height / tile_size)
    
      rework.height.times do |y|
        rework.width.times do |x|
          flat_pixel = rework[x, y]
          (0..tile_length).each do |off|
            image[(x * tile_size) + (off / tile_size), (y * tile_size) + (off % tile_size)] = flat_pixel
          end
        end
      end
    
      image.save('output.png')
    end
    
    View full entry
    Finished in 40th place with a final score of 2.3/5. (View the Gist)
  • output.png
    solution.rb
    # Basic requirements for pixelator
    require 'chunky_png'
    include ChunkyPNG::Color
    
    # Pixelator - a quick script to pixelate PNGs.
    #
    # @author Timmy Christensen
    class Pixelator 
    
      # Initialize attributes
      attr_accessor :file_name, :pixel_size
     
      ####################################################################
      # Initialize
      ####################################################################
    
      # Create a new instance of Pixelator.
      #
      # @param [String] file_name The name of the image file in the current directory.
      # @param [Integer] pixel_size The square dimensions of the pixelation.
      def initialize(file_name, pixel_size)
        @file_name = file_name
        @pixel_size = pixel_size
      end
    
      ####################################################################
      # Pixelate
      ####################################################################
    
      # Create a pixelated copy of the image file.
      #
      # The pixelated image is saved as `output.png` in the current directory.
      def pixelate
        image = ChunkyPNG::Image.from_file(@file_name)
        hex = from_hex('#ffffffff')
    
        x = 0
        y = 0
    
        while y < image.height
          while x < image.row(y).length
    
            hex = to_hex image[x,y]
    
            0.upto(@pixel_size - 1) { |i|      
              0.upto(@pixel_size - 1) { |j|
                if (x+i < image.width && y+j < image.height)
                  image[x+i,y+j] = from_hex(hex) 
                end
              }
            }
    
            x += @pixel_size
          end
          x = 0
          y += @pixel_size
        end
    
        image.save('output.png') # Overwrites the file.
      end
    
    end
    
    ####################################################################
    # Usage
    ####################################################################
    
    # Call the script from the command using `ruby pixelator.rb <filename> <pixelsize>`
    p = Pixelator.new(ARGV[0] || 'input.png', ARGV[1].to_i < 2 ? 10 : ARGV[1].to_i)
    p.pixelate
    
    View full entry
    Finished in 41st place with a final score of 2.3/5. (View the Gist)
  • output.png
    pixelizer.rb
    #!/usr/bin/env ruby
    
    require 'chunky_png'
    
    @image = ChunkyPNG::Image.from_file('input.png')
    
    @pxSize = 10
    
    def rectLoop(i, j)
    	(0..@pxSize-1).each do |x| (0..@pxSize-1).each do |y| yield(i*@pxSize+x, j*@pxSize+y) end end
    end
    
    def savePixel(x, y)
    	return unless @image.include_xy?(x, y)
    	c = ChunkyPNG::Color.to_truecolor_alpha_bytes(@image[x,y])
    	(0..3).each do |i| @colorT[i] += c[i] end
    	@countPixels += 1
    end
    
    (0..(@image.width-1)/@pxSize).each do |i|
    	(0..(@image.height-1)/@pxSize).each do |j|
    		@colorT = [0,0,0,0]
    		@countPixels = 0
    		rectLoop(i,j) do |x,y| savePixel(x, y) end
    		@colorT.map! do |p| p/@countPixels end
    		color = ChunkyPNG::Color.rgba(@colorT[0],@colorT[1],@colorT[2],@colorT[3],)
    		rectLoop(i,j) do |x,y| @image[x,y] = color if @image.include_xy?(x, y) end
    	end
    end
    
    @image.save('output.png')
    
    View full entry
    Finished in 42nd place with a final score of 2.2/5. (View the Gist)
  • README
    ____ ____ _  _ ____ __   ____ ___  ____ 
    | . \|___\|\/_\| __\| |  |___\| _\ | __\
    | __/| /  _><__|  ]_| |__| /  [__ \|  ]_
    |/   |/   |/\_/|___/|___/|/   |___/|___/
    ----------------------------------------
    Down and dirty solution to the Code Brawl 2 Problem.
    
    Execution:
    ruby pixelise.rb
    
    Input file should be named input.png
    output.png
    pixelate.rb
    require 'chunky_png'
    
    inputImage = ChunkyPNG::Image.from_file('input.png')
    newImage = ChunkyPNG::Image.new(inputImage.width, inputImage.height, ChunkyPNG::Color::TRANSPARENT)
    
    # Allocate starting anchor points
    pos_x = (inputImage.width - 1) 
    pos_x_anchor = (inputImage.width - 1)
    pos_y_anchor = (inputImage.height - 1)
    
    while (!(pos_y_anchor < 0))
      if (pos_x > 0)
        # Find the color at the anchor point
        pixel = inputImage[pos_x_anchor, pos_y_anchor]
    
        # Colour section
        while (pos_x > (pos_x_anchor - 10)) 
          pos_y = pos_y_anchor
          while (pos_y > (pos_y_anchor - 10) )
            newImage.set_pixel(pos_x, pos_y, pixel)
            pos_y -= 1
          end
          pos_x -= 1
        end
        
        # Move down the position of the image
        pos_x_anchor -= 10
        pos_x = pos_x_anchor
       else
        # Reinitialise the anchor points and move to the next position
        pos_x = (inputImage.width - 1)
        pos_x_anchor = (inputImage.width - 1)
        pos_y_anchor -= 10
      end
    end 
    
    newImage.save('output.png', :interlace => true)
    
    View full entry
    Finished in 43rd place with a final score of 2.2/5. (View the Gist)
  • pixelator.rb
    require 'chunky_png'
    
    module Pixelator
      extend self
    
      # Go go go!
      def pixelize!(image)
        for_each_block_of image do |x, y|
          color = average_of all_colors_from block: [x, y], of: image
          fill block: [x, y], with: color, of: image
        end
    
        image
      end
    
      # Iterates through each block of an image
      def for_each_block_of(image, &blk)
        (0..image.width/ten).each do |x|
          (0..image.height/ten).each { |y| yield x, y }
        end
      end
    
      # Fill a block with a color
      def fill(options)
        x, y  = options[:block]
        color = options[:with]
        image = options[:of]
    
        image.rect x*ten, y*ten, x*ten+ten, y*ten+ten, color, color  if color
      end
    
      # Returns all colors in a given block range
      def all_colors_from(options)
        x, y  = options[:block]
        image = options[:of]
    
        (0...ten * ten).map do |i|
          _x, _y = (x * ten + i/ten), (y * ten + i%ten)
          image[_x, _y]  if image.include_xy?(_x, _y)
        end.compact
      end
    
      # Adds a color to a hash-color
      def add_color(hash, color)
        channels.each { |chan|
          hash[chan] ||= 0
          hash[chan] += ChunkyPNG::Color.send(chan, color)
        }
        hash
      end
    
      # Divides a hash-color by a divisor
      def divide_color(hash, divisor)
        channels.each { |chan| hash[chan] /= divisor }
        hash
      end
    
      # Averages a list of colors
      def average_of(array)
        if array.length > 0
          h = array.inject({}) { |h, color| add_color(h, color) }
          h = divide_color(h, array.length)
          ChunkyPNG::Color.rgba(h[:r], h[:g], h[:b], h[:a])
        end
      end
    
      # Color channels
      def channels() [:r, :g, :b, :a]; end
    
      # Block size
      def ten() 10; end
    end
    
    image = Pixelator.pixelize! ChunkyPNG::Image.from_file('input.png')
    image.save('output.png')
    
    View full entry
    Finished in 44th place with a final score of 2.0/5. (View the Gist)
  • mw_chunky_pixelizer.rb
    require 'chunky_png'
    require 'backports' unless RUBY_VERSION >= "1.8.7"
    include ChunkyPNG
    
    image = Image.from_file('input.png')
    
    xslices = (0...image.width).each_slice(10).to_a
    yslices = (0...image.height).each_slice(10).to_a
    xslices.product(yslices) do |xslice, yslice|
      tots = [0, 0, 0, 0]
      xslice.product(yslice).each do |x, y|
        rgba = Color.to_truecolor_alpha_bytes(image[x,y])
        tots.map! { |t| t + rgba.shift }
      end
      weight = xslice.size * yslice.size
      pixelzd_color = Color.rgba(*tots.map { |t| (t.to_f / weight).round })
      image.rect(xslice.first, yslice.first, xslice.last, yslice.last, Color::TRANSPARENT, pixelzd_color)
    end
    
    image.save('output.png')
    
    View full entry
    Finished in 45th place with a final score of 1.9/5. (View the Gist)