Problema com unicode em geração de PDF com VRaptor e Html2Pdf

Olá Pessoal, tem um conjunto de classes que está me quebrando um galho enorme na geração de documentos em PDF.
As classes são as seguintes:

// GERA O PDF


import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import org.w3c.dom.Document;
import org.w3c.tidy.Tidy;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.DocumentException;

public class Html2Pdf {
	
	private Html2Pdf() {} // NOT INSTANCE

	public static void convert(String input, OutputStream out) throws DocumentException{
        convert(new ByteArrayInputStream(input.getBytes()), out);
	}
	
	public static void convert(InputStream input, OutputStream out) throws DocumentException{
    	Tidy tidy = new Tidy();        	
    	Document doc = tidy.parseDOM(input, null);
    	ITextRenderer renderer = new ITextRenderer();
        renderer.setDocument(doc, null);
        renderer.layout();      
        renderer.createPDF(out);
	}	

}

// CONSTRÓI O PDF PARA GERACAO


package br.com.brabus.epico.component;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import br.com.brabus.epico.infra.EUtil;

/**
 * IMPRESSÃO EM PDF 
 * http://today.java.net/pub/a/today/2007/06/26/generating-pdfs-with-flying-saucer-and-itext.html -- API
 * http://www.guj.com.br/java/77682-converta-html-para-pdf-com-06-linhas-de-codigo/7 -- COMUNIDADE
 * http://itextpdf.com/book/examples.php -- ITEXT EXEMPLOS
 */
public class EPdf {

	private OutputStream pdfStream;

	private FileReader cssReader;
	
	private String cssConteudo, cabecalho;
	
	private Logger log;
	
	public EPdf() {
	
		this.cabecalho = "";
		
		this.cssConteudo = "";
		
		this.log = LoggerFactory.getLogger(EPdf.class);
		
	}
	
	private boolean setPdfStream(String pdf){
		
		try {
			
			this.pdfStream = new FileOutputStream(pdf);
			
			return true;
			
		} catch (FileNotFoundException e) {
			
			EUtil.exToMsg(e, "Problemas ao criar o arquivo pdf." + pdf + "\n\r" );
			
			e.printStackTrace();
			
			return false;
			
		}
		
	}
	
	private boolean setCssReader(String css){
		
		try {
			
			cssReader = new FileReader( new File(css) );
			
		} catch (FileNotFoundException e) {
			
			EUtil.exToMsg(e, "Problemas ao ler o arquivo css." + css + "\n\r" );
			
			e.printStackTrace();
			
			return false;
			
		}
		
		BufferedReader bufferedReader = new BufferedReader( cssReader );

		String linha = "";
		
		try {
			
			while ( ( linha = bufferedReader.readLine() ) != null) {
			               
				cssConteudo += linha;
				
			}
			
		} catch (IOException e) {
			
			EUtil.exToMsg(e, "Problemas ao ler o arquivo css."+css+"\n\r" );
			
			e.printStackTrace();
			
			return false;
			
		}
		
		cssConteudo = "<style type=\"text/css\">"+cssConteudo+"</style>";
		
		return true;
		
	}
	
	private boolean criar(String conteudo){

		if( cabecalho.equals("") ){
			
			this.log.error("Erro ao criar o PDF. O atributo cabecalho não foi preenchido");
			
			return false;
			
		}else if( pdfStream == null ){
			
			this.log.error("Erro ao criar o PDF. O atributo pdfStream não foi instanciado");
			
			return false;
			
		}else if( conteudo == null ){
			
			this.log.error("Erro ao criar o PDF. O parametro conteudo foi recebido em branco");
			
			return false;
			
		}
		
		try {
			
			log.info( cabecalho );
			
			Html2Pdf.convert( cabecalho + conteudo + "</html>", pdfStream );
			
			pdfStream.close();
		
			return true;
			
		} catch (Exception e) {
			
			EUtil.exToMsg(e, "Problemas ao criar o arquivo pdf "+"\n\r" );
			
			e.printStackTrace();
			
			return false;
			
		}
		
	}
	
	private void setCabecalho(String titulo){
		
		cabecalho = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+ // "ISO-8859-1", "UTF-8", "UTF-16", "cp1252"
			   "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd \">"+ 
			   "<html xmlns=\"http://www.w3.org/1999/xhtml\">"+
			   "<head><title>"+titulo+"</title>"+
			   this.cssConteudo+
			   "</head>" ;
		
	}
	
	/**
	 * Com css
	 * @param pdf
	 * @param titulo
	 * @param conteudo
	 * @param css
	 * @return
	 */
	public boolean criar(String pdf, String conteudo, String titulo, String css){

		this.setPdfStream(pdf);

		this.setCssReader(css);
		
		this.setCabecalho(titulo);
		
		return this.criar(conteudo);
		
	}
	
	/**
	 * Sem css
	 * @param pdf
	 * @param titulo
	 * @param conteudo
	 * @return
	 */
	public boolean criar(String pdf, String conteudo, String titulo){

		this.setPdfStream(pdf);

		this.setCabecalho(titulo);
		
		return this.criar(conteudo);
		
	}
	
	/**
	 * Sem css, sem titulo
	 * @param pdf
	 * @param titulo
	 * @param conteudo
	 * @return
	 */
	public boolean criar(String pdf, String conteudo){

		this.setPdfStream(pdf);

		return this.criar(conteudo);
		
	}
	
}

Nesta ultima deixei comentado alguns encodes usados no cabeçalho do pdf gerado.


cabecalho = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+ // "ISO-8859-1", "UTF-8", "UTF-16", "cp1252"

Método que dispara a solicitação de construgeração do pdf

	@Public @Post("/analise/candidato/pdf")
	public void pdf(){
		
		EPdf ePdf = new EPdf();
		
		String pdf = E.getInstace().getDirApp()+"images"+E.getInstace().getBarra()+E.getInstace().getBarra()+"relatorio-analise-candidato.pdf";
		
		String css = E.getInstace().getDirApp()+"css"+E.getInstace().getBarra()+E.getInstace().getBarra()+"relatorioAnaliseCandidato\\pdf.css";
			
		ePdf.criar(
					pdf, 
					
					request.getParameter("conteudo_pdf"), 
					
					"Análise do candidato", 
					
					css
				);
		
		result.redirectTo("/images/relatorio-analise-candidato.pdf");
			
	}

Em ambientes windows funciona qualquer encode, uma maravilha, mas em produção :: Linux centos não está funcionando.

Me ajudem por favor!!!

Abçs

Me ajuda ai galera, como posso fazer para mudar/setar o encode/unicode no Linux e gerar meu PDF sem problemas?
Valeu! Abçs

vc precisa verificar se todas as partes do sistema estão usando o mesmo encoding.

passe o encoding na geração do pdf, não só no cabeçalho.

Olá Lucas, mais uma vez muito obrigado pela ajuda.
As páginas de visualização do Sistema (views), inclusive do V|Raptor, são tratadas, quanto a normalização de encodes através da aplicação, na própria página, e estão funcionando bem, como abaixo:

<%@page pageEncoding="iso-8859-1" contentType="text/html; charset=iso-8859-1" %>
<fmt:setLocale value="pt_BR" scope="session"/>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

Preciso de uma solução, como apontou, de mudar o encode em tempo de execução.

Já converti de ISO-8859-1 PARA UTF-8 criando nova String mas no meu caso não funcionou porque uso acentos e cedilhas dentro do código, ou seja, no meu código “ç” é realmente “ç” e não “ç”.

Exemplo de uma linha de código:

<div style="font-size: 17px; margin-left: 120px; " align="left" > Usuário: </div>

Criei uma classe @test para converter:

public class ConvertEncodeTest {
	
	@Test
	public void test() {

		String texto = "Relação Percentual x Classificação";
		
		/*texto = convertEncode( texto, "ISO-8859-1" , "UTF-8" );
		
		System.out.println( texto );*/
		
		texto = convertEncode( texto, "ISO-8859-1", "UTF-8" );
		
		System.out.println( texto );
		
	}


	public String convertEncode( String conteudo, String atualEncode, String novoEncode ){
		
		try {
			
			byte[] array = conteudo.getBytes( atualEncode );
			
			return new String( array, novoEncode );
		
		} catch (Exception e) {

			e.printStackTrace();
			
			return "ERRO NA CODIFICAÇÃO";
		}
		
	}

	
}

O meu PDF, onde estou tendo problemas, pois pede por unicode (UTF-8), recebe uma string da página (jsp) e imprime/converte em PDF.
Só aí acontece o problema por que uso “ç” e não “ç”.

Gostaria de saber se tem algum componente em java que recebe-se a string em um encode, mesmo que com acentos “é” e converta em utf-8.
Em javascript encontrei vários exemplos do que preciso em java:

http://www.brabus.com.br/unicode/converter001.html

http://www.brabus.com.br/unicode/converter002.html

http://www.brabus.com.br/unicode/converter003.html

Será que tem algum componente assim disponível na comunidade, pesquisei pra caramba e não achei nada.
Abçs.

jurava que tinha respondido esse tópico antes…

enfim, não adianta só setar o cabeçalho da resposta como UTF-8, a resposta precisa ser gerada usando esse encoding também…

veja se vc não tem como passar o encoding em algum dos passos da geração do relatório.

droga, cache do browser…

vc está usando o parâmetro de encoding do vraptor?

Olá Lucas,

Não usei o encode do V|Raptor até aqui porque já tem uns 2 anos de aplicação e nunca precisei seta-lo.

Vi o link: http://vraptor.caelum.com.br/documentacao/configuracoes-avancadas-sobrescrevendo-as-convencoes-e-comportamento-do-vraptor

Mas não preciso disso porque todas as minhas .jsp’s são em ISO com acento do tipo “éíóú”, cedilhas e tudo mais, com se escrito no word.

Uso o ISO setado nas views, e de alguma forma, tratado pelo “@page pageEncoding” das páginas:

<%@page pageEncoding="iso-8859-1" contentType="text/html; charset=iso-8859-1" %>
<fmt:setLocale value="pt_BR" scope="session"/>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

Já apontei no cabecalho do PDF o encode como ISO e também não rolou.

Tentei a conversão como na classe (acima) ConvertEncodeTest e também não funciona.

Preciso de UTF-8 somente para tratar os PDFs entende, o resto está maravilha.

Abçs,

se o problema são os dados que vêem do formulário, vc precisa setar o parâmetro de encoding do vraptor, pra garantir que ele le o parametro do request num encoding determinado.

Ótimo Lucas, consigo fazer isto para uma única página/.jsp?

vc quer mudar o encoding dos parâmetros enviados pelo formulário pra uma página apenas?

repare que isso não tem a ver com o jsp, e sim com o formulário HTML…

imprima no servidor os dados que vieram do formulário e veja se eles estão saindo com o encoding certo…

se esses dados são gravados no banco antes serem mandados pro relatório, vc precisa configurar o parâmetro do encoding do vraptor.

Olá Lucas, fiz alguns testes e o servidor está lendo o conteúdo “éééááá” como decimal ou hexadecimal:

&#233;&#233;&#233;&#225;&#225;&#225; // = "éééááá"

ou

&#xE9;&#xE9;&#xE9;&#xE1;&#xE1;&#xE1; // = "éééááá"

Funcionam perfeitamente.

Acho que pra resolver de vez, preciso setar na minha classe de conversã de string pre impressao (em real time) o encode de um destes.

Sabe qual encode correspondem?

aqui está aparecendo corretamente esses assentos

Acho que o Guj está convertendo

Está em Decimal ou Hexa.

éééááá

ou

éééááá

Preciso da referencial no getBytes(’???’)

os dois estão iguais :wink:

éééááá

não sei dizer qual é o encoding… mas talvez tenha alguma lib java que faça isso… nada que o tio google não resolva :wink:

Rs, a app está convertendo.
Veja na imagem os caracteres que estão sendo bem interpretados:
http://www.brabus.com.br/unicode/unicode.jpg
Abçs

Beleza Lucas, valeu, assim que estiver ok, passo a resolução e fecho como resolvido o tópico.
Valeu!!!
Abçs

se ele está virando os html entities das letras acentuadas, é só parsear isso antes de passar pro pdf… algo como decodeXML

Olá Lucas, pessoal.

Como os PDF’s são gerados a partir de HTML’s, não dava pra converter tudo em HTML decimal (*: http://en.wikipedia.org/wiki/HTML_decimal_character_rendering).
Vez que convertendo toda a string para este formato tags com “</ body >” sairiam do contexto de interpretação, virando " & # 6 0 ; & # 4 7 ; & # 9 8 ; & # 1 1 1 ; & # 1 0 0 ;& # 6 2 ; "
Assim, o PDF imprimiria exatamente o html, ao invés de interpreta-lo.

Se fosse possível interpretar tudo, eu poderia usar a classe Spring já dentro do V|Raptor “HtmlUtils.htmlEscapeDecimal(string)” que funciona perfeitamente bem.
Passei a usa-la em contextos de envio de email neste servidor.

O problema dos PDF’s resolvi da seguinte forma:
Criei um script javascript para converter apenas caracteres desejáveis em html decimal.
E chamo ele antes de enviar os dados.


function toDecimal(string) {
	
	// LETRAS

	string = replaceAll(string, 'á', '& #225;');
	string = replaceAll(string, 'à', '& #224;');
	string = replaceAll(string, 'ã', '& #227;');
	string = replaceAll(string, 'ä', '& #228;');
	string = replaceAll(string, 'â', '& #236;');
	
	string = replaceAll(string, 'é', '& #233;');
	string = replaceAll(string, 'è', '& #232;');
	string = replaceAll(string, 'ë', '& #235;');
	string = replaceAll(string, 'ê', '& #234;');

	string = replaceAll(string, 'í', '& #237;');
	string = replaceAll(string, 'ì', '& #236;');
	string = replaceAll(string, 'ï', '& #239;');
	string = replaceAll(string, 'î', '& #238;');
	
	string = replaceAll(string, 'ó', '& #243;');
	string = replaceAll(string, 'ò', '& #242;');
	string = replaceAll(string, 'õ', '& #245;');
	string = replaceAll(string, 'ö', '& #246;');
	string = replaceAll(string, 'ô', '& #244;');
	
	string = replaceAll(string, 'ú', '& #250;');
	string = replaceAll(string, 'ù', '& #249;');
	string = replaceAll(string, 'ü', '& #252;');
	string = replaceAll(string, 'û', '& #251;');
	
	string = replaceAll(string, 'ç', '& #231;');

	string = replaceAll(string, 'Á', '& #193;');
	string = replaceAll(string, 'À', '& #192;');
	string = replaceAll(string, 'Ã', '& #195;');
	string = replaceAll(string, 'Ä', '& #196;');
	string = replaceAll(string, 'Â', ' & #194;');
	
	string = replaceAll(string, 'É', '& #201;');
	string = replaceAll(string, 'È', '& #200;');
	string = replaceAll(string, 'Ë', '& #203;');
	string = replaceAll(string, 'Ê', '& #202;');
	
	string = replaceAll(string, 'Í', '& #205;');
	string = replaceAll(string, 'Ì', '& #204;');
	string = replaceAll(string, 'Ï', '& #207;');
	string = replaceAll(string, 'Î', '& #206;');
	
	string = replaceAll(string, 'Ó', '& #211;');
	string = replaceAll(string, 'Ò', '& #210;');
	string = replaceAll(string, 'Õ', '& #213;');
	string = replaceAll(string, 'Ö', '& #214;');
	string = replaceAll(string, 'Ô', '& #212;');
	
	string = replaceAll(string, 'Ú', '& #218;');
	string = replaceAll(string, 'Ù', '& #217;');
	string = replaceAll(string, 'Ü', '& #220;');
	string = replaceAll(string, 'Û', '& #219;');

	string = replaceAll(string, 'Ç', '& #199;');
	
	// SINAIS 
	
	// string = replaceAll(string, '!', '& #33;');
	// string = replaceAll(string, '"', '& #34;');
	// string = replaceAll(string, '\'', '& #92;');
	// string = replaceAll(string, '#', '& #35;');
	string = replaceAll(string, '$', '& #36;');
	string = replaceAll(string, '%', '& #37;');
	string = replaceAll(string, '¨', '& #168;');
	// string = replaceAll(string, '*', '& #42;');
	// string = replaceAll(string, '(', '& #40;');
	// string = replaceAll(string, ')', '& #41;');
	// string = replaceAll(string, '-', '& #45;');
	// string = replaceAll(string, '_', '& #95;');
	// string = replaceAll(string, '+', '& #43;');
	// string = replaceAll(string, '=', '& #61;');
	// string = replaceAll(string, '.', '& #46;');
	// string = replaceAll(string, '|', '& #124;');
	// string = replaceAll(string, ',', '& #44;');
	string = replaceAll(string, 'ª', '& #170;');
	string = replaceAll(string, 'º', '& #186;');
	string = replaceAll(string, '§', '& #167;');
	string = replaceAll(string, '¢', '& #162;');
	string = replaceAll(string, '¬', '& #172;');
	
	return string;
	
}

function replaceAll(string, token, newtoken) {
	
	while (string.indexOf(token) != -1) {
		
 		string = string.replace(token, newtoken);
 		
	}
	
	return string;
	
}

function removerHtmlInvalido( strMultiLineText, replaceWith ){

	return strMultiLineText.replace(new RegExp( "\\n", "g" ),replaceWith).replace(new RegExp( "\\t", "g" ),replaceWith).replace("<tbody>",replaceWith).replace("</tbody>",replaceWith).replace("<a","<span").replace("</a","</span");

}


function removerHtmlInvalidoToDecimal( strMultiLineText, replaceWith ){

	var string = removerHtmlInvalido( strMultiLineText, replaceWith );
	
	return toDecimal( string );

}

Para os pdf’s uso o metodo ‘removerHtmlInvalidoToDecimal’.
Obrigado pela ajuda.
Abçs,

JSign