Rasem

rasem is a pure ruby gem that allows you to describe your SVG images in ruby code.

Why Rasem

Rasem allows you to generate SVG images that can be easily exported to other formats and embed in an HTML 5 page.

Features

Coming features:

Rasem is still in alpha release. Please report your bugs so that we can work on it. You are welcome to contribute to the project by adding more features and fixing bugs. The end goal of the project is to fully support SVG standard and make it easy to use.

Installation

gem install rasem

Usage

There are two main methods to generate images with Rasem.

Command line

Create a file with extension .rasem. Here is a sample file test.rasem

self.width = 100
self.height = 100
circle 20, 20, 5
circle 50, 50, 5
line 20, 20, 50, 50

Save this file and execute the command

rasem test.rasem

A file test.svg will be generated.

Ruby code

You can generate the image from your ruby code. This has several uses such as sending the image on the fly from a Rails application.

Here is a simple example

require 'rasem'
img = Rasem::SVGImage.new(:width=>100, :height=>100) do
  circle 20, 20, 5
  circle 50, 50, 5
  line 20, 20, 50, 50
end

puts img.output

img.output is the SVG code generated for this images.

More Examples

The following examples are for .rasem files. These are actually ruby scripts that are executed to generate the image. So, you can write arbitrary ruby code in .rasem files as you will see.

simple_graph.rasem

nodes = [[10,10], [20,20], [10,20]]
radius = 3
with_style :fill=>"white", :stroke=>"black" do
  for node in nodes
    circle node.first, node.last, radius
  end
end

line nodes[0].first, nodes[0].last, nodes[1].first, nodes[1].last,
  :stroke=>"blue"

Here is a more sophisticated example.

tictactoe.rasem

self.width = 150
self.height = 150
board = [['x', 'o', 'x'],
         ['o', '-', 'o'],
         ['x', 'o', 'x']]
def draw_x(x,y)
  group :stroke=>"red" do
    line x-20, y-20, x+20, y+20
    line x-20, y+20, x+20, y-20
  end
end

def draw_o(x,y)
  circle x, y, 20, :stroke=>"blue", :fill=>"white"
end

group :stroke=>"black" do  
  rectangle 0, 0, 150, 150, :stroke_width=>2, :fill=>"white"
  line 50, 0, 50, 150
  line 100, 0, 100, 150
  line 0, 50, 150, 50
  line 0, 100, 150, 100
end

board.each_with_index do |row, row_index|
  row.each_with_index do |cell, column_index|
    if cell == "x"
      draw_x row_index * 50 + 25, column_index * 50 + 25
    elsif cell == "o"
      draw_o row_index * 50 + 25, column_index * 50 + 25
    end
  end
end

Here are some examples that show how you can generate images from your ruby code.

You can generate SVG and store it to file

img = Rasem::SVGImage.new(:width => 100, :height => 100)
img.line(0, 0, 100, 100)

File.open("test.svg", w") do |f|
  img.write(f)
end

You can use pass a block to SVGImage.new to make things more compact

img = Rasem::SVGImage.new(100, 100) do
  line(0, 0, 100, 100)
end
# Image is closed automatically
# Write to file

You can make your code even more compact by passing the file as a last argument to SVGImage.new

File.open("test.svg", "w") do |f|
  Rasem::SVGImage.new({:width => 100, :height => 100}, f) do
    line(0, 0, 100, 100)
  end
end

You can use transformations on created objects (translate, scale, rotate, skew, matrix)

img = Rasem::SVGImage.new(:width => 100, :height => 100) do
  circle(0, 0, 10).translate(50, 50).scale(2, 1.5)
end

Here is an example showing how to generate a path using ruby code.

require 'rasem'

width = 100
height = 200

img = Rasem::SVGImage.new(:width => width, :height => height) do
  path("stroke" => "black") do
    moveToA(0, height / 2.0)
    vlineTo(height / 2.0 - 50)
    curveTo(50, 40, 0, 0, 50, 0)
    curveTo(-30, -50, 0, 0, 10, -30)
    vlineTo(-(height / 2.0 - 60))
  end
end

File.open("path.svg", "w") do |f|
  img.write(f)
end

Using definitions and reuse them later

img = Rasem::SVGImage.new(:width => 100, :height => 100) do
  defs do
    group(:id => "group1") do
      circle(0, 0, 20)
      text(0, 5, :fill => "red") { raw "hi!" }
    end
  end

  use("group1", :x => 50, :y => 25)
  use("group1", :x => 50, :y => 75, :fill => "blue")
end

Ruby method def_group to use definitions. It create a group inside 'defs' with the given id and populate it using the block. The second optional argument controls the behaviour if the id is already in use, you can :fail, :update the existing element (and return the new one), or :skip the new one (effectively skipping the block, and returning the existing element).

img = Rasem::SVGImage.new(:width => 100, :height => 100) do

  g = def_group("group1") do
    circle(0, 0, 20)
  end

  g = def_group("group1", :update) do
    circle(0, 0, 20)
    text(0, 5, :fill => "red") { raw "hi!" }
  end

  use(g, :x => 50, :y => 25)
  use(g, :x => 50, :y => 75, :fill => "blue")
end

An example of gradients usage

img = Rasem::SVGImage.new(:width => 100, :height => 100) do

  r1 = radialGradient("rgrad1") do
    stop("0%", "green", 1)
    stop("100%", "blue", 1)
  end

  r2 = radialGradient("rgrad2") do
    stop("0%", "yellow", 1)
    stop("100%", "red", 1)
  end

  r2 = radialGradient("rgrad2", {}, :skip) do
    stop("0%", "blue", 1)
    stop("100%", "red", 1)
  end

  circle(50, 25, 20, :fill => r1.fill)
  circle(50, 75, 20, :fill => r2.fill)
end

Contributing to rasem

Copyright © 2011 Ahmed Eldawy. See LICENSE.txt for further details.