require 'rubygems' require 'gbarcode' require 'dl' require 'rbconfig' module GBC VERSION = '1.0'.freeze class Printer def self.cairo_library_name case Config::CONFIG['arch'] when /darwin/ 'libcairo.2.dylib' when /mswin32/, /cygwin/ 'cairo.dll' else 'libcairo.so.2' end end def self.name_for_symbol(symbol, signature) case Config::CONFIG['arch'] when /mswin32/, /cygwin/ sum = -4 signature.each_byte do |char| sum += case char when ?D: 8 else 4 end end "#{symbol}@#{sum}" else symbol.to_s end end private_class_method :cairo_library_name, :name_for_symbol LIB = DL.dlopen(cairo_library_name) SYM = {:cairo_image_surface_create => 'PIII', :cairo_create => 'PP', :cairo_get_target => 'PP', :cairo_destroy => '0P', :cairo_surface_destroy => '0P', :cairo_surface_write_to_png => '0PS', :cairo_set_source_rgb => '0PDDD', :cairo_move_to => '0PDD', :cairo_line_to => '0PDD', :cairo_set_line_width => '0PD', :cairo_stroke => '0P', :cairo_select_font_face => '0PSII', :cairo_set_font_size => '0PD', :cairo_show_text => '0PS'}.inject({}) { |x, (k, v)| x[k] = LIB[name_for_symbol(k, v), v]; x } def self.surface w,h r, rs = SYM[:cairo_image_surface_create].call(0,w,h) # puts "R#{r} #{r.class}:: RS #{rs} #{rs.class}" return r end def self.context(s) r,rs = SYM[:cairo_create].call(s) # puts "S [#{s} => #{s.class}] :: R[#{r} => #{r.class}] :: RS[#{rs} => #{rs.class}]" SYM[:cairo_set_source_rgb].call(r,0.0,0.0,0.0) # puts "S [#{s} => #{s.class}] :: R[#{r} => #{r.class}] :: RS[#{rs} => #{rs.class}]" return r end def self.ctx w,h context(surface(w,h)) end def self.ctx_destroy(c) r,rs = SYM[:cairo_destroy].call(c) end def self.add_bar(c,x,y,w,h) # cairo_move_to(cr,11.0,20.5); # cairo_line_to(cr,11.0,70.5); # cairo_set_line_width(cr,1.85); # cairo_stroke(cr); SYM[:cairo_move_to].call(c,x,y) SYM[:cairo_line_to].call(c,x,h) SYM[:cairo_set_line_width].call(c,w) SYM[:cairo_stroke].call(c) end def self.add_text(c,txt,x,y) # cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL = 0, CAIRO_FONT_WEIGHT_BOLD = 1); # cairo_set_font_size (cr, 12.0); # cairo_move_to (cr, 21.0, 90.0); # cairo_show_text (cr, "TEST1234"); SYM[:cairo_select_font_face].call(c,"serif",0,1) SYM[:cairo_set_font_size].call(c,12.0) SYM[:cairo_move_to].call(c,x,y) SYM[:cairo_show_text].call(c,txt) end def self.draw(c,fname) # surface = cairo_get_target(cr) # cairo_destroy(cr); # cairo_surface_write_to_png (surface, "hello.png"); # cairo_surface_destroy (surface); r,rs = SYM[:cairo_get_target].call(c) SYM[:cairo_destroy].call(c); SYM[:cairo_surface_write_to_png].call(r,fname) SYM[:cairo_surface_destroy].call(r); end def self.bc2png(bc,fname) partial = bc.partial.split(//).map {|e| e.to_i } len = 0 partial.map {|e| len += e } # if no height given, use default h= 150 # width = length * 2 pixels + margins (30 px) w = len * 2 + 30 ct = self.ctx(w,h) # divide up the width into chunks to use for bars bw = (w - 30).to_f / len.to_f # start the box encoding x = margin = 15.0 y = 20.0 bh = (h - y - (margin * 2) ) # puts w,h,len,bw,bh partial.each_index do |idx| #draw a bar if index is even if (idx % 2 != 0) self.add_bar(ct,x,y,(bw * partial[idx]), bh) end x += bw * partial[idx] end # add the text self.add_text(ct,bc.ascii, (margin + 10).to_f, (h - margin).to_f ) # draw png & destroy ctx self.draw(ct,fname) fname end end class Barcode include Gbarcode def initialize(text,enc = nil) @ascii = text enc = enc ? enc : BARCODE_ANY @bc = barcode_create(text) r = barcode_encode(@bc,enc) if r != 0 raise Exception.new("INVALID ENCODING #{enc.class} FOR TEXT #{text}") end @encoding = @bc.encoding @partial = @bc.partial() end attr_accessor :ascii, :encoding, :partial def to_png(fname) return Printer.bc2png(self,fname) end end end