class Pxlsrt::Seed

Plant seeds, have them spiral out and sort.

Public Class Methods

seed(input, o = {}) click to toggle source

The main attraction of the Seed class. Returns a ChunkyPNG::Image that is sorted according to the options provided. Will raise any error that occurs.

# File lib/pxlsrt/seed.rb, line 17
def self.seed(input, o = {})
        startTime = Time.now
        defOptions = {
                :reverse => false,
                :smooth => false,
                :method => "sum-rgb",
                :verbose => false,
                :trusted => false,
                :middle => false,
                :random => false,
                :distance => 100,
                :threshold => 0.1
        }
        defRules = {
                :reverse => :anything,
                :smooth => [false, true],
                :method => Pxlsrt::Colors::METHODS,
                :verbose => [false, true],
                :trusted => [false, true],
                :middle => :anything,
                :random => [false, {:class => [Fixnum]}],
                :distance => [false, {:class => [Fixnum]}],
                :threshold => [{:class => [Float, Fixnum]}]
        }
        options = defOptions.merge(o)
        if o.length == 0 or options[:trusted] == true or (options[:trusted] == false and o.length != 0 and Pxlsrt::Helpers.checkOptions(options, defRules) != false)
                if input.class == String
                        Pxlsrt::Helpers.verbose("Getting image from file...") if options[:verbose]
                        if File.file?(input)
                                if Pxlsrt::Colors.isPNG?(input)
                                        input = ChunkyPNG::Image.from_file(input)
                                else
                                        Pxlsrt::Helpers.error("File #{input} is not a valid PNG.") if options[:verbose]
                                        raise "Invalid PNG"
                                end
                        else
                                Pxlsrt::Helpers.error("File #{input} doesn't exist!") if options[:verbose]
                                raise "File doesn't exit"
                        end
                elsif input.class != String and input.class != ChunkyPNG::Image
                        Pxlsrt::Helpers.error("Input is not a filename or ChunkyPNG::Image") if options[:verbose]
                        raise "Invalid input (must be filename or ChunkyPNG::Image)"
                end
                Pxlsrt::Helpers.verbose("Seed mode.") if options[:verbose]
                Pxlsrt::Helpers.verbose("Creating Pxlsrt::Image object") if options[:verbose]
                png = Pxlsrt::Image.new(input)
                traversed = [false] * (png.getWidth * png.getHeight)
                count = 0
                seeds = []
                if options[:random] != false
                        Pxlsrt::Helpers.progress("Planting seeds", 0, options[:random]) if options[:verbose]
                        for s in (0...options[:random])
                                x = (0...png.getWidth).to_a.sample
                                y = (0...png.getHeight).to_a.sample
                                seeds.push({
                                        :spiral => Pxlsrt::Spiral.new(x, y),
                                        :pixels => [png[x, y]],
                                        :xy => [{:x => x, :y=>y}],
                                        :placed => true,
                                        :retired => false,
                                        :anchor => {
                                                :x => x,
                                                :y => y
                                        }
                                })
                                Pxlsrt::Helpers.progress("Planting seeds", s + 1, options[:random]) if options[:verbose]
                        end
                else
                        Pxlsrt::Helpers.progress("Planting seeds", 0, png.getWidth * png.getHeight) if options[:verbose]
                        kernel = [[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]]
                        i = (png.getWidth + png.getHeight - 2) * 2
                        for y in (1...(png.getHeight - 1))
                                for x in (1...(png.getWidth - 1))
                                        sum = 0
                                        for ky in ((-1)..1)
                                                for kx in ((-1)..1)
                                                        sum += kernel[ky + 1][kx + 1] * (ChunkyPNG::Color.r(png[x + kx, y + ky]))
                                                end
                                        end
                                        if sum < options[:threshold]
                                                seeds.push({
                                                        :spiral => Pxlsrt::Spiral.new(x, y),
                                                        :pixels => [png[x, y]],
                                                        :xy => [{:x => x, :y=>y}],
                                                        :placed => true,
                                                        :retired => false,
                                                        :anchor => {
                                                                :x => x,
                                                                :y => y
                                                        }
                                                })
                                        end
                                        i += 1
                                        Pxlsrt::Helpers.progress("Planting seeds", i, png.getWidth * png.getHeight) if options[:verbose]
                                end
                        end
                        if options[:distance] != false
                                Pxlsrt::Helpers.progress("Removing seed clusters", 0, seeds.length) if options[:verbose]
                                results = []
                                i = 0
                                for current in seeds
                                        add = true
                                          for other in results
                                          d = Math.sqrt((current[:anchor][:x] - other[:anchor][:x]) ** 2 + (current[:anchor][:y] - other[:anchor][:y]) ** 2)
                                          add = false if d > 0 and d < options[:distance]
                                          end
                                          if add
                                                 results.push(current)
                                        end
                                        i += 1
                                        Pxlsrt::Helpers.progress("Removing seed clusters", i, seeds.length) if options[:verbose]
                                end
                                seeds = results
                        end
                end
                for r in (0...seeds.length)
                        traversed[seeds[r][:anchor][:x] + seeds[r][:anchor][:y] * png.getWidth] = r
                        count += 1
                end
                Pxlsrt::Helpers.verbose("Planted #{seeds.length} seeds") if options[:verbose]
                step = 0
                Pxlsrt::Helpers.progress("Watch them grow!", count, traversed.length) if options[:verbose]
                while count < traversed.length and seeds.length != 0
                        r = 0
                        retired = []
                        for seed in seeds
                                if !seed[:retired]
                                        n = seed[:spiral].next
                                        if n[:x] >= 0 and n[:y] >= 0 and n[:x] < png.getWidth and n[:y] < png.getHeight and !traversed[n[:x] + n[:y] * png.getWidth]
                                                seed[:pixels].push(png[n[:x], n[:y]])
                                                traversed[n[:x] + n[:y] * png.getWidth] = r
                                                seed[:xy].push(n)
                                                seed[:placed] = true
                                                count += 1
                                        else
                                                if seed[:placed] == true
                                                        seed[:placed] = {
                                                                :count => 1,
                                                                :direction => seed[:spiral].direction,
                                                                :cycle => seed[:spiral].cycles
                                                        }
                                                        case seed[:placed][:direction]
                                                        when "up", "down"
                                                                seed[:placed][:value] = seed[:spiral].pos[:y]
                                                                seed[:placed][:valueS] = :y
                                                        when "left", "right"
                                                                seed[:placed][:value] = seed[:spiral].pos[:x]
                                                                seed[:placed][:valueS] = :x
                                                        end
                                                else
                                                        seed[:placed][:count] += 1
                                                        if seed[:spiral].cycles != seed[:placed][:cycle] and seed[:placed][:direction] == seed[:spiral].direction and seed[:placed][:value] == seed[:spiral].pos[seed[:placed][:valueS]]
                                                                seed[:retired] = true
                                                        end
                                                end
                                        end
                                end
                                r += 1
                        end
                        step += 1
                        Pxlsrt::Helpers.progress("Watch them grow!", count, traversed.length) if options[:verbose]
                end
                Pxlsrt::Helpers.progress("Sort seeds and place pixels", 0, seeds.length) if options[:verbose]
                r = 0
                for seed in seeds
                        spiral = Pxlsrt::Spiral.new(seed[:anchor][:x], seed[:anchor][:y])
                        band = Pxlsrt::Helpers.handlePixelSort(seed[:pixels], options)
                        i = 0
                        for k in seed[:xy]
                                png[k[:x], k[:y]] = band[i]
                                i += 1
                        end
                        r += 1
                        Pxlsrt::Helpers.progress("Sort seeds and place pixels", r, seeds.length) if options[:verbose]
                end
                endTime=Time.now
                timeElapsed=endTime-startTime
                if timeElapsed < 60
                        Pxlsrt::Helpers.verbose("Took #{timeElapsed.round(4)} second#{ timeElapsed!=1.0 ? "s" : "" }.") if options[:verbose]
                else
                        minutes=(timeElapsed/60).floor
                        seconds=(timeElapsed % 60).round(4)
                        Pxlsrt::Helpers.verbose("Took #{minutes} minute#{ minutes!=1 ? "s" : "" } and #{seconds} second#{ seconds!=1.0 ? "s" : "" }.") if options[:verbose]
                end
                Pxlsrt::Helpers.verbose("Returning ChunkyPNG::Image...") if options[:verbose]
                return png.returnModified
        else
                Pxlsrt::Helpers.error("Options specified do not follow the correct format.") if options[:verbose]
                raise "Bad options"
        end
end
suite(inputFileName, outputFileName, o={}) click to toggle source

Uses Pxlsrt::Seed.seed to input and output from one method.

# File lib/pxlsrt/seed.rb, line 9
def self.suite(inputFileName, outputFileName, o={})
        kml = Pxlsrt::Seed.seed(inputFileName, o)
        if Pxlsrt::Helpers.contented(kml)
                kml.save(outputFileName)
        end
end