require 'barby/outputter'
module Barby
#Renders the barcode to a simple SVG image using pure ruby
#
#Registers the to_svg, bars_to_path, and bars_to_rects method
#
#Bars can be rendered as a stroked path or as filled rectangles. Path
#generally yields smaller files, but this doesn't render cleanly in Firefox
#3 for odd xdims. My guess is that the renderer tries to put half a pixel
#on one side of the path and half on the other, leading to fuzzy dithering
#instead of sharp, clean b&w.
#
#Therefore, default behavior is to use a path for even xdims, and
#rectangles for odd. This can be overridden by calling with explicit
#:use => 'rects' or :use => 'path' options.
class SvgOutputter < Outputter
register :to_svg, :bars_to_rects, :bars_to_path
attr_writer :title, :xdim, :ydim, :height, :rmargin, :lmargin, :tmargin, :bmargin, :xmargin, :ymargin, :margin
def initialize(*)
super
@title, @xdim, @ydim, @height, @rmargin, @lmargin, @tmargin, @bmargin, @xmargin, @ymargin, @margin = nil
end
def to_svg(opts={})
with_options opts do
case opts[:use]
when 'rects' then bars = bars_to_rects
when 'path' then bars = bars_to_path
else
xdim_odd = (xdim % 2 == 1)
bars = xdim_odd ? bars_to_rects : bars_to_path
end
<<-"EOT"
EOT
end
end
def bars_to_rects(opts={})
rects = ''
with_options opts do
x, y = lmargin, tmargin
if barcode.two_dimensional?
boolean_groups.each do |line|
line.each do |bar, amount|
bar_width = xdim * amount
if bar
rects << %Q|\n|
end
x += bar_width
end
y += ydim
x = lmargin
end
else
boolean_groups.each do |bar, amount|
bar_width = xdim * amount
if bar
rects << %Q|\n|
end
x += bar_width
end
end
end # with_options
rects
end
def bars_to_path(opts={})
with_options opts do
%Q||
end
end
def bars_to_path_data(opts={})
path_data = ''
with_options opts do
x, y = lmargin+(xdim/2), tmargin
if barcode.two_dimensional?
booleans.each do |line|
line.each do |bar|
if bar
path_data << "M#{x} #{y}V #{y+ydim}"
end
x += xdim
end
y += ydim
x = lmargin+(xdim/2)
end
else
booleans.each do |bar|
if bar
path_data << "M#{x} #{y}V#{y+height}"
end
x += xdim
end
end
end # with_options
path_data
end
def title
@title || barcode.to_s
end
def width
length * xdim
end
def height
barcode.two_dimensional? ? (ydim * encoding.length) : (@height || 100)
end
def full_width
width + lmargin + rmargin
end
def full_height
height + tmargin + bmargin
end
def xdim
@xdim || 1
end
def ydim
@ydim || xdim
end
def lmargin
@lmargin || _xmargin
end
def rmargin
@rmargin || _xmargin
end
def tmargin
@tmargin || _ymargin
end
def bmargin
@bmargin || _ymargin
end
def xmargin
return nil if @lmargin || @rmargin
_margin
end
def ymargin
return nil if @tmargin || @bmargin
_margin
end
def margin
return nil if @ymargin || @xmargin || @tmargin || @bmargin || @lmargin || @rmargin
_margin
end
def length
barcode.two_dimensional? ? encoding.first.length : encoding.length
end
def svg_width(opts={})
opts[:rot] ? full_height : full_width
end
def svg_height(opts={})
opts[:rot] ? full_width : full_height
end
def transform(opts={})
opts[:rot] ? %Q|transform="rotate(-90) translate(-#{full_width}, 0)"| : nil
end
private
def _xmargin
@xmargin || _margin
end
def _ymargin
@ymargin || _margin
end
def _margin
@margin || 10
end
#Escape XML special characters <, & and >
def escape(str)
str.gsub('&', '&').gsub('<', '<').gsub('>', '>')
end
end
end