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