Pular para o conteúdo principal

Do Browser para Impressora - Considerações Finais

Problemas com XML-FO
Solução Flying Saucer


Apesar de ser apreciável a iniciativa da Apache com o XML-FO, o Apache FOP não está suficiente maduro para ser utilizado em qualquer
ocasião. Uma interessante alternativa é outro projeto que realiza uma transformação XSL mas diretamente para PDF. Esse é o projeto Flying
Saucer, que contém entre outras coisas suporte para CSS3. Para o meu problema, O Flying Saucer tem mostrado como a melhor solução em termos de precisão além de contar com qualidades como flexibilidade e eficiência.

Podemos verificar no projeto que ele faz uso do iText para gerar o arquivo PDF, mas tem a possibilidade de utilizar renderizadores para arquivos de saída diferentes.

Procedimento necessário

  1. Instalar o Flying Saucer e suas dependências no Classpath do seu projeto. No caso de um projeto WEB, adicionar as bibliotecas no
    diretório WEB-INF.
  2. Utilizar o JAPX (The Java API for XML Processing ) para converter um arquivo XML num documento DOM (org.w3c.dom.Document).
    DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    InputSource inputSource = new InputSource(new InputStreamReader(arrayInputStream, "ISO-8859-1"));
    builder.setEntityResolver(new CatalogResolver());
    Document doc = builder.parse(inputSource);
    
  3. Passar o documento para o Flying Saucer:
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ITextRenderer renderer = new ITextRenderer();
    renderer.setDocument(doc, rootPath);
    renderer.layout();
    renderer.createPDF(bos);
    
PROBLEMAS COM ANÁLISE SINTÁTICA
Solução XML Catalog

Cabe aqui uma observação sobre o uso do Docbuilder – o analisador sintático (parser) de XML da especificação JAPX. O comportamento padrão do DocumentBuilder é processar o arquivo de origem com base nos recursos descritos nele mesmo, incluindo seus descritores como o DTD ou
XSD. O problema que a declaração do tipo do documento (Document Type Declaration or Doctype) geralmente aponta para a URL do publicador. Por exemplo :

DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd
E especificações grandes como o Xhtml são particionados em vários fragmentos dtd que apontam para outros resultando numa míriade de documentos virtualmente remotos.

Para que o Docbuilder faça a análise sintática, é necessário que o processo tenha acesso a essas localizações. Num servidor de aplicação, acessos remotos poderiam ser impedido por questões de segurança. Nesse caso é preciso ter uma cópia de cada recurso localmente e utilizar um proxy que converta as localizações virtualmente remotas para os arquivos locais.

Na verdade, seria possível abrir arquivo por arquivo e procurar as referências remotas e trocá-las por referências locais, mas isso poderia dar um trabalho demasiado grande e sujeito a erros.

XML CatalogO propósito do XML Catalog da Apache Foundation (explicado em detalhes nesse artigo) é servir de proxy para o analisador sintático encontrar os recursos descritos nos documentos com localizações universais. A solução é bem simples. Uma objeto (Factory) cria o proxy com base num arquivo properties localizado no mesmo nível que o classloader. Isso é feito de forma transparente, ao instanciar um objeto da classe CatalogResolver.

A solução passo a passo seria a seguinte:

  1. Procure o projeto catalog da apache. Coloque o resolver.jar no seu classpath... (WEB-INF,etc)
  2. Baixe o sgml-lib da w3c. Adicione o contéudo do sgml-lib no diretório de códigos-fonte da sua aplicação.
  3. Adicione também o arquivo Catalog.properties.
    relative-catalogs=no
    catalogs=sgml-lib/xml.soc
    verbosity=0
    prefer=system
    allow-oasis-xml-catalog-pi=no
    static-catalog=yes
    
  4. E adiciona o suporte ao catálogo no Parser.
    builder.setEntityResolver(new CatalogResolver());
    
    
Problemas com Mime Type
Solução: Especificar o Mime Type


Ter um arquivo PDF em memória, não garante sua renderização correta no cliente. Essa questão é resolvida com atributos MIME. Aespecificação dos Servlet descreve como os tipos MIME podem ser especificados na interface de resposta (Response) do Servlet.

response.setContentType("application/pdf");
response.setHeader("Content-disposition", "attachment; filename=NotaFiscal.pdf");
response.setContentLength(bos.size());
OutputStream os = response.getOutputStream();
bos.writeTo(os);
os.flush();
os.close();
Problemas com o processo manual de imprissão
Solução: Incluir Javascript no PDF

Em casos extremos, fornecer um arquivo PDF para o usuário, com o Adobe Acrobat Reader instalado em sua máquina não é o suficiente paraque ele se sinta a vontade para imprimir o documento corretamente. Para evitar maiores transtornos com a parte de treinamente, é possível automatizar o processo de impressão.

Para isso, felizmente, o arquivo PDF permite a inclusão de scripts que, por sua vez, permitem a interação entre os recurso da máquinacliente e o documento a ser exibido/imprimido. É uma excelente oportunidade para demonstrar como a API do iText pode incluir Script em um PDF ao mesmo tempo que automatizo a ação de imprimir na máquina cliente. Para realizar tal tarefa é necessário duplicar o documento a ser imprimido.

PdfReader reader = new PdfReader(bytes);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
com.lowagie.text.Document document = new com.lowagie.text.Document(new Rectangle(585, 936), 0 ,0 ,0 ,0);
PdfWriter writer = PdfWriter.getInstance(document, bos);
document.open();
PdfContentByte cb = writer.getDirectContent();
document.newPage();
PdfImportedPage page = writer.getImportedPage(reader, 1);
cb.addTemplate(page, 0, 0);

Agora, basta incluir o fragmento Javascript via PDFWriter:

writer.addJavaScript("this.print({bUI: false,bSilent: false,bShrinkToFit: true});" + "\r\n"+ "this.closeDoc();");
document.close();
return bos;

Ufa! Isso é tudo.

Comentários

Postagens mais visitadas deste blog

Um texto pós-moderno - better man

Espere olhando para as horas... são 4 horas. Tem que parar. Nesse tom melancólico, começa a modesta música "better man", uma balada pop composta por Eddie Vedder ainda na adolescência. A música é a ilustração perfeita da ironia. O próprio título é irônico, uma vez que em momento algum na música aparece um better man. She lies and says she's in love with him, can't find a better man... Irônico, não!? Para começar, com a personagem central da história, a mulher que aguarda tarde da noite seu esposo... Ela chega a treinar com o espelho o fim do relacionamento. E o que faz? Diz a negação do que queria dizer. Vedder escreve músicas sobre sentimentos fortes. Sua relação com a mãe foi bastante complicada pelo o que descreve em suas canções. Na trilogia Mommy, Vedder descreve um homem perturbado com o relacionamento materno; a mãe mente para o filho sobre a identidade do pai, revela a verdade para o garoto na puberdade dizendo a ele como se parece com o verdadeiro pai e o

Pequeno manual do ócio em terras alemãs

  Pequeno manual do ócio em terras alemãs Como Lei alemã favorece aproveitadoras (e alguns aproveitadores que nunca tive o desprazer de conhecer)   Há algumas vias pelas quais pessoas de países em desenvolvimento migram para países como a Alemanha.   Por exemplo, é sabido que países desenvolvidos sofrem de escassez de mão-de-obra qualificada. Por esse motivo, países como a Alemanha dispõe vistos "especiais" para profissionais em demanda. Esse é o conceito do Blaukart (Blue Card) que na Alemanha se destina a profissionais salário anual seja superior a 55 mil euros ou 43 mil no caso de profissionais de áreas em alta demanda. Não há como recrutar essa mão-de-obra sem que a família desses profissionais também possa ser relocada. Então esses profissionais e seus familiares são relocados.   Além de se qualificar para essas vagas em demanda, ou ser parte direta da família qualificada, outra via possível para a imigração para o território alemão é através do matrimôni

O argumento anti-álcool

A lógica contra a produção do álcool é mais ou menos a seguinte: Os produtores capitalistas, produtores do combustível de humanos e máquinas irão preferir vender combustível mais caro para os mais ricos do que comida barata para os mais pobres. Máquinas e homens irão competir por combustível... Mas enquanto os ricos terão dinheiro para comprar comida e combustível o que sobrará aos pobres!? Vale lembrar que não importa se a produção é de cana ou de milho, a competição é pela terra e não pelo grão. Ainda, mesmo que o país agrícola taxe o produtor de combustível de maneira diferenciada ao produtor de comida, o governo teria maiores dificuldades em repartir o "bolo", haja vista que os governos que temos não são as instituições mais eficientes e, além do que, a comida estará mais cara. Ora, esquecem os "amigos" comunistas que a venda de biocombustível dará aos países agrícolas uma oportunidade ímpar de participar da economia mundial como protagonistas, e não meros fi