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

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 ...

Expressões, preconceito e racismo

Expressões preconceituosas e racistas Antes de alguma outra frase, primeiro peço licença para falar de mais um assunto do qual não domino. Falo por acreditar que um leigo presta serviço maior ao debater assunto com base em fontes (ainda que seja uma Wikipedia) e no pensamento lógico do que simplesmente se manter mudo a questões do cotidiano. Em voga agora está em falar quais são ou eram as expressões preconceituosas e racistas que até a pouco eram toleradas em muitos meios. Como é covarde dizer que em boca fechada não entra racismo. O racismo não é perpetrado apenas por quem profere mas por quem se cala à agressão perpetrada a outrem. Mas veremos que a questão é muito mais complexa que os cães raivosos do politicamente correto querem dizer. Tomo aqui a palavra racista, como sendo algo usado para impor a dominação de uma “raça” sobre outra. Portanto, a acusação de racismo vai muito além da mera acusação de preconceito. Não tenho o menor apreso por vitimismo barato, onde expressões q...

The escape of blue eyed vampires (answer)

The island of blue eyed vampires (answer) An initial idea Each one needs to figure out if him/herself is blue eyed. They assume having blue eyes and see how the others react. A technical details There are some variations to formalize this problem using different type of logic: modal logic, temporal logic, Public Announcement Logic and so on. I believe that those kind of prove are tedious to write and read. For now, I will write a sketch to a prove but I belive the best way to prove is using an algorimthm what basically, it would be an adaptation of DPLL algorithm (Davis–Putnam–Logemann–Loveland) that uses dedutive reasoning and prove by contraction. Legend \[\begin{matrix} BlueEyed(X) :X \text{ is blue eyed.} \\ Leave(X) :X \text{ leaves.} \\ O(y) :y \text{ holds at the next (temporal) state.} \end{matrix}\] In this temporal simplified logic, we have a set of state that holds the in- formation of days, \(W = \{d_0, d_1, d_2, d3 \ldots , d_n\}\) and transition \(S : W \rightarrow ...