HashCode

An organizer of symbols

Archive for the ‘RGhost’ Category

RGhost Barcode no Github

Monday, December 29th, 2008

Onde posso encontrar 32 tipos de código de barras, de graça? Tenho que gerar em PDF ou imagens?

A solução está aqui no GitHub RGhost Barcode

Poli-hashcode sempre uma solução para salvar sua vida. :)

RGhost no Github

Saturday, December 27th, 2008

Depois de muita enrolação, configuração e formatação acabo de colocar o RGhost no Github, vou manter o código lá e as gems continuarão no Ruby Forge pois no Github não está funcionando direito.

Criei umas 40 páginas de wiki(em inglês) e prometo(juro) que vou colocar mais exemplos.

Vou tentar migrar o RGhost Barcodes ainda este ano(eu acho).

Gostaria de agradecer a toda comunidade nacional e internacional que colaboram dando dicas e reportando bugs. Obrigado a vcs!

RGhost 0.8.6 amigo do Prawn e do Ruport

Thursday, November 6th, 2008

Já está disponível RGhost 0.8.6, compatível com Prawn e Ruport, isto é, agora você pode fazer seu benchmark sem precisar desinstalar o RGhost para usar o Prawn ou vise-versa.

A outra novidade é o ganho de 50 milissegundos pra cada template(EPS) renderizado, tal façanha pode não parecer muita coisa mas se seu documento tiver 100 páginas, são 5 segundos a menos(tempo de um gole de cerveja). Isso devido a criação de uma nova forma de vetorizar fontes em Postscript.

Divirtam-se e ganhem dinheiro!

RGhost 0.8.5 ênfase na criação de PDF em Ruby

Friday, September 12th, 2008

Acabei de atualizar o RGhost para a versão 0.8.5, adicionei novas features e correção de uns bugzinhos, abaixo as principais mudanças.

Mac OS e Linux plug and play

Detecta e configura o path do ghostscript automaticamente para MacOS e Linux, avisa quando não detectou o executável e avisa o cara, com abaixo

Ghostscript not found in your environment.
Install it and set the variable RGhost::Config::GS[:path] with the executable path.
Example: RGhost::Config::GS[:path]='/path/to/my/gs'      #unix-style
 RGhost::Config::GS[:path]="C:\\gs\\bin\\gswin32c.exe"  #windows-style

Para windows vou fazer depois mais pode configurar manualmente.

PDF Quality

Permite configurar a qualidade final do PDF que podem ser

  • :screen - Baixa resolução, alta compressão, similar a opção “Screen Optimized” Acrobat Distiller.
  • :ebook - Resolução mediana similar a opção “eBook” do Acrobat Distiller.
  • :printer - Similar a opção “Print Optimized” do Acrobat Distiller ótima resolução pra impressão.
  • :prepress - Qualidade para apresentação em tela cheia similar a “Prepress Optimized” do Acrobat Distiller.

Use o parâmetro :quality no método render

doc=RGhost::Document.new
doc... #algo aqui
doc.render :pdf, :quality => :ebook

PDF Document Info

Declara informações sobre o documento
Nas propriedades aparecerá

Usando o novo método Document#info

doc.info :Title => "My Report about XXX",
         :Author => "Company XXX",
         :Subject => "RGhost new version",
         :Creator => "We system",
         :Keywords => "foo bar bas to search enginers"

Fontes externas TTF ou Type1

Carregamento de fontes externas via método tag com a opção :from

doc.define_tags  do
  tag :one_font, :name => "HelveticaOblique", :size => 12
  tag :another, :name => "Monaco",  :size => 30 , :from => "/tmp/monaco.ttf"
end

PDF Security

Agora permite atribuir uma senha para usuários e para o dono do documento essa senha desabilita opções de abertura, impressão etc. O código fica da seguinte forma

doc.security do |sec|
  sec.owner_password ="testXXX"
  sec.user_password ="testYYY"
  sec.disable :print, :copy
end

Acima estou desabilitando a impressão e a cópia do conteúdo. Agora desabilitando tudo

doc.security do |sec|
  sec.owner_password ="test123"
  sec.user_password ="test567"
  sec.disable :all
end

Quando o documento for aberto uma senha será solicitada.

A senha com total privilégio e a do “owner” e limite total para “user”.

PDF Hyperlink(Text and Rectangle)

O campeão de pedidos o hyperlink. Criado com base na clase text_in e bem simples de usar

doc.text_link "Click here",:url => "http://mysite", :tag => :link, :color => :blue

Posicionamento absoluto

doc.text_link "Click here",:x=> 2, :y=> 4, :url => "http://mysite"

Exemplo de um link que checa informações online do PDF.


Ou defina um retângulo clicável

Com o simples código

doc.rectangle_link :url=> "http://www.hashcode.eti.br",
                   :width => 10, :height => 5,
                   :x  => 5,:y => 22,
                   :color => :blue

Grid::Rails dentro do Document

Crie suas grids usando um bloco dentro do documento, veja

doc.rails_grid :style => :border_lines, :width => 4 do |grid|
  grid.column :title,   :title => "Título",
  grid.column :name, :title => "Comentário", :format => lambda {|s| s.gsub(/^(.{20}).*$/,'\1...')}
  grid.column :created_on, :title => "Data",  :format => lambda {|s| s.strftime("%d %b")}
  grid.data Post.find(:all, :limit => 100)
end

Bugs

  • Correção do encoding do header da Grid::Rails e do callback grid.header.before_create.
  • Correção da métrica em 2 décimos entre Cm e Inch.
  • Correção do yield do Document não recebia instância atualizada, agora funfa.

Lembre-se

gem install rghost

Espero que gostem!

RGhost on Mac OSX

Monday, August 25th, 2008

Abaixo instruções de instalação do RGhost no MacOS

Requirimentos:
- Ruby
- RubyGems
- Xcode
- Mac Port

Primeiro instale o Ghostscript via macport

sudo port install ghostscript

Agora RGhost

sudo gem install rghost

Agora precisamos saber onde o executável do Ghostscript foi instalado para isso execute

hashcode:tmp shairon$ type gs
gs is /opt/local/bin/gs

Observe que na minha instalação o path ficou /opt/local/bin/gs.
Vamos configurar e testar em um arquivo .rb ou via IRB

require 'rubygems'
require 'rghost'

#use o path do seu gs aqui
RGhost::Config::GS[:path]="/opt/local/bin/gs"
RGhost::Config.is_ok?.render :pdf, :filename => "/tmp/is_ok.pdf"

Uma página será gerada como essa
You environment is done.

Em breve no manual em English.

RGhost 0.8 e RGhost Barcode publicado

Thursday, June 19th, 2008

Rubeiros,

Publiquei hoje um nova versão do RGhost http://rghost.rubyforge.org totalmente refatorada.
Bati forte em desempenho e na doçura da sintaxe, ficando mais fácil programar em Ruby e gerar códigos em Postscript.
Fiz um teste estuprador até 10K páginas com template e passou legal.

Abaixo algumas das mudanças.

  • Namespace RGhost adicionado e algumas nomes de classes/módulos mudaram.
  • Teste de ambiente e de fonts como RGhost::Config.is_ok?.render :pdf, :filename => “/tmp/test.pdf” e environment_fonts.
  • Retirado o suporte aos 4 códigos de barras GNU Barcode.
  • Criado o projeto rghost_barcode http://rghost-barcode.rubyforge.org que suporta 32 tipos de códigos de barras incluindo uns doidão.
  • Suporte a qualquer fonte TTF e Type 1.
  • Possibilita agora a cópia da API para a memória de impressoras de alto volume.
  • Tag scope para personalização de fontes.
  • Reformulação de vetores e adicionado: canto arredondados, polígono, etc.
  • Melhora do uso de templates registrando-os do dicionário interno da pilha PS.
  • As classes TextArea e Text foram reformuladas, suporte a alinhamento do texto, tags, e outros.
  • Virtual page.
  • Reestruturado o suporte ao ActiveRecord, agora podemos usar n Grid::Rails em um doc.
  • Alguns callbacks mudaram de posição como o before_page_create e o odd_pages.
  • Documentação em Inglês
  • o resto eu esqueci :)

Se alguém se interessar por traduzir o manual em português é só enviar um email para mim em pvt que eu mando o odt.

Agradeço a todos que reportaram bugs e me ajudaram a testar.

Desculpem a demora. Espero que gostem.

Distribuição com PL/Ruby e DbLink no Postgresql

Saturday, January 12th, 2008

Depois de uma escravização no fim do ano passado e no inicio deste, estou de volta para “espalhar a maldade”!

Vou falar sobre PL/Ruby ou melhor fazer funcionar.

PL/Ruby é uma linguagem procedural acoplada dentro do Postgresql. Entre as linguagem do Postgres é a mais flexível e fácil.
Demonstrarei inicialmente “o jeitão da coisa” e depois uma implementação distribuída.

Instalação
Instale o banco e o módulo plruby, se o postres já estiver instalado, instale apenas o módulo(claro!)

apt-get install postgresql-8.1 postgresql-8.1-plruby

Agora conecte via psql

psql template1

Criaremos um banco novo para todos os testes deste tutorial, o banco “ruby_test”, então vamos lá

template1=# create database ruby_test;

conecte no banco novo

template1=# \c ruby_test

Crie a função/linguagem via o script plruby.sql que faz parte do pacote postgresql-8.1-plruby, se a sua distro difere de ubuntu, verifique onde o arquivo plruby.sql está e invoque com \i semelhante ao exemplo abaixo.

ruby_test=# \i /usr/share/postgresql-8.1-plruby/plruby.sql

Jeitão
Para familiarizarmos um pouco vamos criar uma função que produz uma seqüencia de números separados por espaço.
Portanto a função abaixo cria um Range do primeiro argumento(args[0]) até o segundo argumento(args[1]), converte o range para Array e depois para String separando os elementos por espaço.

create or replace function string_array(int,int) returns text as $RUBY$


  (args[0]..args[1]).to_a.join " "

$RUBY$ language plruby;

Executando

ruby_test=# select string_array(10,20);

Produzindo

"10 11 12 13 14 15 16 17 18 19 20"

Agora uma função que procura um padrão dentro do um texto, se o padrão for encontrado, o mesmo ficará entre tags <b>.

create or replace function find(varchar,text) returns text as $RUBY$


  args[1].gsub(/(#{args[0]})/,'<b>\1</b>')

$RUBY$ language plruby;
ruby_test=# select find('[tT]he','The method PL#context and PL#context= give the possibility to store information between the call')

Produto

"<b>The</b> method PL#context and PL#context= give <b>the</b> possibility to store information between <b>the</b> call"

Até agora demonstramos duas funções, faz uma lógica e retorna apenas uma tupla.
Ficou bem elegante essa implementação do PL/Ruby para vários registros(setof) sendo que cada registro é um objeto lançado pelo operador yield do Ruby.
Uma função em PL/Ruby para resolver a função(x ao quadrado vezes a raíz de 2)

f(x) = x^2 * raiz(2)

sendo x inteiro variando de x1 a x2.

create or replace function fx(int,int) returns setof float as $RUBY$


  (args[0]..args[1]).each {|x|  yield x.to_i**2 * Math.sqrt(2) }

$RUBY$ language plruby;

Executando com * from pois estamos pegando vários registros

ruby_test=# select * from fx(1,10);

Resultando em

1.4142135623731
5.65685424949238
12.7279220613579
22.6274169979695
35.3553390593274
50.9116882454314
69.2964645562817
90.5096679918781
114.551298552221
141.42135623731

Manipulando dados
Vamos criar uma tabela denominada “users” para povoarmos de dados para os testes.

ruby_test=# CREATE TABLE users(
  id serial not null primary key,
  name varchar(255) not null ,
  login varchar(80),
  email varchar(80),
  password varchar(80)
) ;

Inserindo alguns registros

ruby_test=# insert into users(name,login,email,password) values ('Fulano de tal','fulano','fulano@server.com','fulanopwd');
ruby_test=# insert into users(name,login,email,password) values ('Maria da Silva','maria','maria.silva@server.com','mariapwd');
ruby_test=# insert into users(name,login,email,password) values ('Sem nome','semnome','semnome@server.com','semnomepwd');

Daqui a pouco faremos a distribuição dos dados via trigger para bancos remotos, portanto criaremos uma função para criação dos inserts.
A função make_insert faz engenharia reversa na ddl e nos dados utilizando o módulo PL disponível no plruby

CREATE OR REPLACE FUNCTION make_insert(users) RETURNS text AS $RUBY$

    row=args[0]
    tn=PL.args_type.to_s
    cn=row.keys.join(',')
    values= row.values.map{|m| (m)?"'#{m}'":'NULL' }.join(',')
    "INSERT INTO #{tn}(#{cn}) values (#{values})"

$RUBY$ language plruby;

Veja o exemplo da execução

ruby_test=# select make_insert(users) from users;

Resultado

INSERT INTO users(name,id,password,login,email) values ('Fulano de tal','1','fulanopwd','fulano','fulano@server.com')
INSERT INTO users(name,id,password,login,email) values ('Maria da Silva','2','mariapwd','maria','maria.silva@server.com')
INSERT INTO users(name,id,password,login,email) values ('Sem nome','3','semnomepwd','semnome','semnome@server.com')

Sem aquela concatenação demasiada do plpgsql usando pipes e aspas para todo lado. Ah! a função make_insert é genérica para qualquer tabela mas no argumento de criação a sua tabela. Tipo

CREATE OR REPLACE FUNCTION make_insert(sua_tabela) RETURNS text AS $RUBY$
...

Semelhante aos parâmentos tabela%rowtype do postgres.

Distribuindo os dados
Já vou dizendo logo, isso não é comparável ao Slony-I, isso é uma simples utilização do dblink do postgresql.
As funções de dblink ficam no pacote contrib do postgres, a instalação com apt-get

apt-get install postgresql-contrib-8.1

Crie as funções com \i onde o argumento é o arquivo dblink.sql

ruby_test=#  \i /usr/share/postgresql/8.1/contrib/dblink.sql

Lembrando a assinatura da função dblink_exec é

select dblink_exec("connection string","query")

Exemplo

select dblink_exec('hostaddr=127.0.0.1 dbname=mydb user=shairon password=senha','insert into...');

Partiremos da seguinte extrategia: criaremos uma tabela chamada nodes onde armazenaremos os dados dos bancos de dados, selecionaremos apenas os nodes ativos e enviaremos os registros para os mesmos através da trigger replica_plruby(T) no evento after insert na tabela users master(A).
Veja o diagrama abaixo.
replica_plruby.png

Então temos a tabela nodes.

create table nodes(id serial not null primary key, host varchar(80), username varchar(80), password varchar(80), active boolean )

Dados para teste

insert into nodes(host,dbname,username,password,active) values ('127.0.0.1','mydb1','foo','bar',true);
insert into nodes(host,dbname,username,password,active) values ('192.168.0.7','mydb2','foo','bar',true);
insert into nodes(host,dbname,username,password,active) values ('10.0.0.38','mydb3','foo','bar',true);

Criando a trigger replica_plruby, acompanhe pelos comentários

CREATE OR REPLACE FUNCTION replica_plruby() RETURNS trigger AS  $RUBY$

  #obtendo a quantidade de nós ativos
  count=PL::exec("select count(*) from nodes where active=true",1,"value").to_s.to_i
  if count > 0
     #obtendo os nós ativos
     PL::Plan.new("select * from nodes where active=true").each do |row|
       #montando a conexão
       #cada row é um hash  tipo {"dbname"=>"delme", "username"=>"shairon" ...}
       conn="hostaddr=#{row['host']} dbname=#{row['dbname']} user=#{row['username']} password=#{row['password']}"
       #Nome das culunas via metadata
       keys  = new.keys.join(",")
       #Os valores com tratamento de nulo
       values = new.values.map{|m| (m)?"''#{m}''":'NULL' }.join(',')
       #Query final
       query = "INSERT INTO #{tg['relname']}(#{keys}) values (#{values})"
       #Disparo
       PL.exec("select dblink_exec('#{conn}','#{query}')")
     end
  end
  new
$RUBY$ LANGUAGE plruby;

Pronto! Insira novos dados na tabela users para ver o resultado.

Referências
Nos arquivos de documentação dos pacotes

ruby1.8
postgresql-8.1
postgresql-8.1-plruby
postgresql-contrib-8.1

rghost - Plugin ou Gem?

Tuesday, July 10th, 2007

Você escolhe!!
rghost_plugin.png
Pra quem pediu, disponibilizei o rghost como plugin no repositório do rghost no RubyForge só descompactar no RAILS_ROOT/lib e reiniciar a aplicação.

Impressão direta via TCP/IP com RubyGhost

Tuesday, July 10th, 2007

Geralmente as impressoras de médio e grande porte disponibilizam uma porta TCP conhecida como ‘porta bruta’ de número 9100. Demonstrarei aqui uma forma de imprimir diretamente neste tipo de printer, para o nosso exemplo usaremos o driver postscript genérico da Adobe(PS-Adobe-3.0).
Models Contas e Clientes

class Contas < ActiveRecord::Base
  belongs_to :clientes
end
class Clientes < ActiveRecord::Base
  has_one :contas
end

Configurando as colunas

require 'rghost'
clientes=Clientes.find :all, :include => :contas, :limit => 10000

grid=DataGrid::RailsGrid.new :width => 4 , :align => :center
grid.col :codigo, :title => "Código do Cliente", :width => 5
grid.col :nome, :title => "Nome"
grid.col :created_on, :title => "Data de Cadastro ", :format => :eurodate
grid.col lambda { contas.login }, :title => "Login"
grid.data(clientes)

Criando o documento com dados do ActiveRecord

doc=Document.new :paper => :A4, :landscape => true, :duplex => true
doc.before_page_create do
  set Image.for("/tmp/fatura.eps")
end
doc.set grid
doc.done

Enviando o documento

printer = TCPSocket.open('192.168.1.70', 9100)
printer.write doc.render_stream(:ps)

Deve ter saído lá na impressora… :)

Para mais informações no RGhost - RubyForge . Documentação em português no RubyForge

Rghost v0.7 Encodings e proxy charset

Wednesday, June 13th, 2007

Com a versão 0.7 podemos agora usar diferentes codificação de fontes e conversão de charset de Ruby para Postscript.
Encodings disponíveis

  • AdobeExpert
  • AdobeLatinEncoding
  • Bengali
  • CodePage1250
  • CodePage1251
  • CodePage1252
  • CodePage1253
  • CodePage1254
  • CodePage1256
  • CodePage1257
  • CodePage1258
  • CodePage874
  • IsoLatin
  • MacCentralEuropean
  • MacCyrillice
  • MacGreek
  • MacHebrew
  • TeX-CorkEncoding
  • TeX-LGR-Greek
  • TeXMathExtensionEncoding
  • TeXMathItalicEncoding
  • TeXMathSymbolEncoding
  • TeX-T2AModified2Encoding
  • TeX-T2BAdobeEncoding
  • TeX-T2CAdobeEncoding
  • TeX-X2AdobeEncoding
  • TeX-XL2encoding
  • US-ASCII
  • UTF-8

Ideal para código fonte Ruby no mesmo formato dos dados do documento. Existem duas formas de setar o encoding da fonte:
Antes de usar o documento

RubyGhostConfig::GS[:font_encoding] = 'CodePage1252'

Na criação do documento

doc=Document.new :font_encoding => 'CodePage1252'

Agora quando o charset do código fonte está diferente dos dados é necessário a conversão dos formatos. Para este fim usamos um bloco retornando uma string antes da criação do documento.

Exemplo para código fonte no padrão UTF-8 com acentuação.

RubyGhostConfig::GS[:charset_convert]= lambda {|text| Iconv::iconv('latin1','utf8', text).to_s}

O gem e o manual da versão 0.7 disponível no RubyForge.