Class: Turing::Image

Inherits:
Object
  • Object
show all
Defined in:
lib/turing/image.rb

Overview

Simple obfuscated image generator with plugin design

Generates obfuscated image containing given word by using one of its registered plugins.

For it’s operation it requires gd2 gem, available from gd2.rubyforge.org/.

Example of use:

gem 'turing'
require 'turing'
ti = Turing::Image.new(:width => 280, :height => 115)
ti.generate(File.join(Dir.getwd, 'a.jpg'), "randomword")

In this case we generate image using random plugin containing word “randomword”. It is saved as `pwd`/a.jpg.

Example Rails controller (action):

# Could be placed in config/environment.rb
gem 'turing'
require 'turing'

# Could be part of app/controllers/site_controller.rb
class SiteController < ApplicationController
    def image
        ti = ::Turing::Image.new(:width => 280, :height => 115)
        fn = get_tmpname
        ti.generate(fn, rand(1e8).to_s)
        send_file fn, :type => "image/jpeg", :disposition => "inline"
    end 

    def get_tmpname
        pat = "tmpf-%s-%s-%s"
        fn = pat % [Process::pid, Time.now.to_f.to_s.tr(".",""), rand(1e8)]
        File.join(Dir::tmpdir, fn)
    end 
    private :get_tmpname
end

A word about plugins

All plugins are “registered” by subclassing Turing::Image (which is implemented using self.inherited). It makes sense to subclass Turing::Image because that way you’ll also get goodies like #write_string.

Plugins are auto-loaded by require from lib/turing/image_plugins after Turing::Image is created but you’re free to manually load any plugin you like.

For inspiration on how to write new plugin visit any of the existing plugins in image_plugins dir, minimal template would be:

class MyCoolPlugin < Turing::Image
    def initialize(opts = {})
        super(opts)
    end

    def generate(img, word)
        write_string(img, 'cour.ttf', GD2::Color[0, 0, 0], word, 48)
    end
end

Direct Known Subclasses

BlackSquaring, Blending, RandomNoise, Spiral, WhiteSquaring

Defined Under Namespace

Modules: SquaringHelper Classes: BlackSquaring, Blending, RandomNoise, Spiral, WhiteSquaring

Constant Summary collapse

@@plugins =

All content generating plugins

[]

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Image

Configure instance using options hash.

Warning: Keys of this hash must be symbols.

Accepted options:

  • fontdir: Directory containing .ttf fonts required by plugins. Default: gem’s shared/fonts directory.

  • bgdir: Directory containing .jpeg files used as background by plugins. Default: gem’s shared/bgs directory.

  • outdir: Output directory where to put image in case absolute path wasn’t specified.

  • width: Width of the image.

  • height: Height of the image.

  • method: Use specified plugin instead of randomly selected. You must give class that implements generate instance method. Default: nil.

Raises:

  • (ArgumentError)


89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/turing/image.rb', line 89

def initialize(opts = {}) # {{{
	raise ArgumentError, "Opts must be hash!" unless opts.kind_of? Hash
	
	base = File.join(File.dirname(__FILE__), '..', '..', 'shared')
	@options = {
		:fontdir => File.join(base, 'fonts'),
		:bgdir => File.join(base, 'bgs'),
		:outdir => ENV["TMPDIR"] || '/tmp',
		:width => 280,
		:height => 115,
	}

	@options.merge!(opts)
end

Instance Method Details

#generate(outname, word, method = nil) ⇒ Object

Generate image into outname containing word (using method).

Warning: If you pass absolute filename as outname, outdir will have no effect.

Warning: There’s no way to reset method to random if it was specified upon instance creation.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/turing/image.rb', line 109

def generate(outname, word, method = nil) # {{{
	# select appropriate output plugin # {{{
	m = method || @options[:method]
	if m.nil?
		if @@plugins.empty?
			raise RuntimeError, "no generators plugins available!"
		end
		m = @@plugins[rand(@@plugins.size)]
	end
	unless m.instance_methods.include?("generate")
		raise ArgumentError, "plugin #{m} doesn't have generate method"
	end
	# }}}

	# prepend outname with outdir, if no absolute path given
	unless Pathname.new(outname).absolute?
		outname = File.join(@options[:outdir], outname)
	end
	
	img = GD2::Image.new(@options[:width], @options[:height])

	img.draw do |canvas|
		canvas.color = GD2::Color[255, 255, 255]
		canvas.rectangle(0, 0, img.width - 1, img.height - 1, true)
	end

	m.new(@options).generate(img, word)
	
	img.draw do |canvas|
		canvas.color = GD2::Color[0, 0, 0]
		canvas.rectangle(0, 0, img.width - 1, img.height - 1)
	end

	begin
		File.open(outname, 'w') { |f| f.write(img.jpeg(90)) }
	rescue
		raise "Unable to write challenge: #{$!}"
	end

	true
end