From: Lars Haugseth Date: 2009-02-11T07:58:55+09:00 Subject: Re: [QUIZ] Mathematical Image Generator (#191) This is my first quiz submission. Any comments appreciated. I opted for RMagick to generate the image from raw pixels. There might be faster options (GD?), but the time spent converting pixel values to an image and writing this to file is negligible compared to actually generating the pixels, especially when the functions get more complex. I found I could shave some time off the pixel generation by wrapping the whole iteration process inside a single eval instead of calling functions (or worse, doing an eval) for each iteration. $ cat gen_image.rb #!/usr/bin/env ruby require 'rubygems' require 'RMagick' class FunctionGenerator def initialize @functions = [] end def <<(function) @functions << function end def random_function_of_depth(depth) if depth == 0 ['x', 'y', '-x', '-y'][rand(4)] else function = @functions[rand(@functions.size)] function.gsub('expr') { random_function_of_depth(depth - 1) } end end end class ImageGenerator include Math # Functions for red, green and blue attr_accessor :red, :green, :blue # Generate image and store to file def generate_image(filename, width, height) @width = width @height = height generate_pixels store_image(filename) end private # Generate pixels of image def generate_pixels @pixels = "" eval <<"." 0.upto(@height - 1) do |y_pos| y = (y_pos.to_f / @height) 0.upto(@width - 1) do |x_pos| x = (x_pos.to_f / @width) @pixels << (127.99 + 127.99 * #{@red}).to_i.chr @pixels << (127.99 + 127.99 * #{@green}).to_i.chr @pixels << (127.99 + 127.99 * #{@blue}).to_i.chr end end . end # Store generated image to file def store_image(filename) image = Magick::Image.new(@width, @height) image.import_pixels(0, 0, @width, @height, 'RGB', @pixels) image.opacity = 0 image.write(filename) end end func_gen = FunctionGenerator.new func_gen << '(expr + expr) / 2' func_gen << '(expr) ** 3' func_gen << 'expr * expr' func_gen << 'sin(expr * PI)' func_gen << 'cos(expr * PI)' image_gen = ImageGenerator.new image_gen.red = func_gen.random_function_of_depth(4) image_gen.green = func_gen.random_function_of_depth(4) image_gen.blue = func_gen.random_function_of_depth(4) puts "r: #{image_gen.red}" puts "g: #{image_gen.green}" puts "b: #{image_gen.blue}" image_gen.generate_image('image.png', 800, 800) -- Lars Haugseth "If anyone disagrees with anything I say, I am quite prepared not only to retract it, but also to deny under oath that I ever said it." -Tom Lehrer