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 matrimôni

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

Answering: top reasons I hate living in Brazil

Yes, some guys shared a teasing topic about “Top reasons why I hate living in Brazil”: http://www.gringoes.com/forum/forum_posts.asp?TID=17615&PN=1&title=top-reasons-i-hate-living-in-brazil What is the point here? The whole text is loaded of cliclés, people that you will hardly find, etc most of time just pissing people off.   I don’t think Brazil is the best country in the world. Also, I don’t think Brazilians don’t make mistakes. Actually we do all the time but most of us really care about our mistakes specially those were pointed out. Some feel like an expatriate, alien in own country. Others reflect about how we could improve. Others  simply don’t accept teases from John Does. So, I’m actually truly bothered with people believing in a bunch of false statements (specially Brazilians) or supporting some cynical arguments disguised “sincere” criticisms . Yes, I make mistakes all the time, and as most of Brazilians, I don’t speak English. However, I will