Seam PDF - Marca dágua (watermark)

Gente,

alguém tem algum exemplo ou apostila que indique como disponibilizar uma marca dágua (imagem de fundo esmaecida) em um arquivo PDF gerado com as tags do seam/pdf ?

Agradeço antecipadamente qualquer ajuda.

Cara é o seguinte, na própria descrição do SEAM fala que o recurso de geração de PDF é limitado. Mas isso seria uma resposta bem escrota para sua pergunta… então vamos lá pois não vi nada aqui nem em lugar nenhum que possa lhe ajudar.

Pada adicionar um comportamento novo a um objeto temos o recurso de herança, aqui não vai ser diferente, iremos herdar o componente UIDocument e fazer um overhide de um método criando um ponto de extensão.

Primeiro devemos criar a classe UIDocumentoWatermark


package br.com.tiagoaramos.view.ui;

import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.faces.context.FacesContext;

import org.jboss.seam.pdf.ui.UIDocument;

import com.lowagie.text.BadElementException;
import com.lowagie.text.Image;
import com.lowagie.text.pdf.PdfWriter;

public class UIDocumentWatermark extends UIDocument {

	// COMPONENTE TYPE MAPEADO
	public static final String COMPONENT_TYPE = "br.com.tiagoaramos.view.ui.UIDocumentWatermark";
	   
	// Parametro que tera a path para imagem
	Object watermark;
	
	// Atributo interno com a imagem
	Image image;
	
	// Faces context para conseguirmos fazer o valueBinding do parametro watermark
	FacesContext context;
	
	/* 
	 * @Override no metodo para neste ponto para pegarmos o faces context para uso futuro 
	 */
	@Override
	public void createITextObject(FacesContext context) {
		super.createITextObject(context);
		this.context = context;
	}


	/* 
	 * O segredo é aqui, na hora que o componete Seam vai processar os cabeçalhos do componente
	 * adicionamos um PdfPageEventHelper, um recurso que é chamado a cada página gerada e permite
	 * interferências durante a construção do documento
	 */
	@Override
	protected void processHeaders() {
		super.processHeaders();
		PdfWriter writer = (PdfWriter) getWriter();
		try {
			
			writer.setPageEvent(new PdfPageEventHelperWatermark(getImage()));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * @param watermark the watermark to set
	 */
	public void setWatermark(String watermark) {
		this.watermark = watermark;
	}

	/**
	 * 
	 * Neste método privado, transformamos o atributos String em watermark que vem em imagem, este código
	 * foi copiado do componente UIImage da geração de PDF do seam, é o mesmo funcionamento.
	 * 	 * 
	 * @return the image
	 * @throws Exception 
	 */
	private Image getImage() throws Exception {
		if(image == null){
			// Pega o value binding
			watermark = valueBinding(context, "watermark", watermark);
	
	        // cria uma seamImage
	        org.jboss.seam.ui.graphicImage.Image seamImage = new org.jboss.seam.ui.graphicImage.Image();
	        
	        // Se foi passado um valuehandle de um beam como parametro aqui ja vai vir BufferedImage
	        if (watermark instanceof BufferedImage) {
	            seamImage.setBufferedImage((BufferedImage) watermark);
	        } else {
	        	// Caso contrario passa para o Seam transformar
	            seamImage.setInput(watermark);
	        }
	        
	        // Pega o array de bytes da imagem
	        byte[] data = seamImage.getImage();
	        
	        // transforma em imagem mesmo para servir de water mark
	        image = Image.getInstance(data);
		}
		return image;
	}

	
}

Feito a classe criamos agora o PdfPageEventHelper


package br.com.tiagoaramos.view.ui;

import java.awt.Color;

import com.lowagie.text.Document;
import com.lowagie.text.ExceptionConverter;
import com.lowagie.text.Image;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfGState;
import com.lowagie.text.pdf.PdfPageEventHelper;
import com.lowagie.text.pdf.PdfWriter;

public class PdfPageEventHelperWatermark extends PdfPageEventHelper {

	// Estado de impressão do PDF com opacidade baixa para a marca d'agua
	private PdfGState gstate;
	
	// A imagem que será colocada como marca d'agua
	private Image watermark;

	
	// No construtor criamos o gstate e guardamos a marca
	public PdfPageEventHelperWatermark(Image watermark) {
		super();
		gstate = new PdfGState();
        gstate.setFillOpacity(0.3f);
        gstate.setStrokeOpacity(0.3f);
        this.watermark = watermark;
	}
	
	
	// A cada fim de página alteramos para o gstate correto e adicionamos a imagem
	@Override
	public void onEndPage(PdfWriter writer, Document document) {
		PdfContentByte cb = writer.getDirectContent();
        cb.saveState();
        cb.setGState(gstate);
        try {
        	// Paramestro importantes aqui
            cb.addImage(watermark,  // a imagem
            			watermark.getWidth(),  // largura
            			0, 
            			0, 
            			watermark.getHeight(), // altura 
            			0, // eixo x
            			0 // exio y
            );
        }
        catch(Exception e) {
            throw new ExceptionConverter(e);
        }
        // volta para o state antigo para as coisas não ficarem transparente
        cb.restoreState();
	}
	
}

depois disso devemos mapear o novo componente, crie um arquivo pdf.taglib.xml dentro de uma pasta META-INF na raiz dos códigos fontes do seu projeto, se for maven, criar dentro de resources.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
                                "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
	<namespace>http://br.com.tiagoaramos.componentes</namespace>
	<tag>
		<tag-name>documentWatermark</tag-name>
		<component>
			<component-type>br.com.tiagoaramos.view.ui.UIDocumentWatermark</component-type>
		</component>
	</tag>

</facelet-taglib>

Com isso você já mapeia a classe como componente, agora é só trocar a tag p:document do Seam pela sua:

<!DOCTYPE composition 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"
	xmlns:s="http://jboss.com/products/seam/taglib"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:p="http://jboss.com/products/seam/pdf"
	xmlns:tc="http://br.com.tiagoaramos.componentes">


<tc:documentWatermark watermark="/images/logo/brasao_print.jpg" >
	<p:html>
	<table border="1">
		<ui:repeat var="usuario" value="#{relatorioMB.listaDeObjeto}">
		<tr>
		<td><h:outputText value="#{usuario.emailUsuario}" /></td>
		</tr>
		</ui:repeat>
	</table>
	</p:html>
</fnde:documentWatermark>

</html>

Acredito que pela data de sua postagem você já tenha mudado para jaspper ou dado uma solução alternativa para isto, mas como procurei algo pronto e não vi nada, tive que fazer, ai deixo aqui para quem precisar no futuro. :lol:

abraços

Cara,

antes de mais nada, MUITO, MAS MUITO, OBRIGADO MESMO pela tua ajuda !!! Admito, com pesar, que eu já havia desistido.

Acho que agora so me falta um detalhe de nada pra que a coisa funcione. Olha só:

Meu codigo na pagina está assim:


&lt;html 
xmlns="http://www.w3.org/1999/xhtml"  
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"            
xmlns:p="http://jboss.com/products/seam/pdf"
xmlns:tc="http://br.com.utilitarios.componentes"&gt;  

	&lt;tc:documentWatermark watermark="/img/LogoFundo.png" &gt;
		
		&lt;p:html&gt;  
		    &lt;table border="1"&gt;  
		        &lt;tr&gt;  
			        &lt;td&gt;&lt;h:outputText value="TESTE DO GIOVANNI" /&gt;&lt;/td&gt;  
		        &lt;/tr&gt;  
		    &lt;/table&gt;  
	    &lt;/p:html&gt;  

	&lt;/tc:documentWatermark&gt;    
    
&lt;/html&gt;

Ao renderizar a pagina, estou recebendo a seguinte mensagem de erro:

Joguei o xml de configuracao pra dentro da pasta WEB-INF do projeto. Acho que está correto, porque quando, no eclipse, digito TC: e dou um CTRL+espaco, a ajuda de contexto me oferece o componente documentWatermark.

Onde posso estar errando ?

Atenciosamente,

O xml deve ficar em uma pasta META-INF no mesmo nivel do primeiro pacote, ou seja,

src/
|__br
|…|__com
|…|__utilitarios
|META-INF
…|
pdf.taglib.xml

O erro que ta dando é que o componente p:html não esta considerando o seu componente como um seam document, porém você herdou dele, so ta faltando mesmo o mapeamento do componente no xml eu acho.

Valew, cara…

Vou testar na segunda feira.

Funcionando, tua cervejada da semana que vem vai ser por minha conta.

Obrigado

Pessoal, eu estou tentando fazer a mesma coisa, só que agora em 2015 rs e o seam ainda não dá suporte pra marca d’água, estou tendo o seguinte erro:

javax.faces.FacesException: Expression Error: Named Object: br.com.luiz.util.UIDocumentWatermark not found.

Vocês podem me ajudar?

Bom dia pessoal, o erro acima foi corrigido, caso alguém tenha o mesmo problema, a solução é adicionar as tags abaixo no arquivo faces-config.xml.

br.com.luiz.util.UIDocumentWatermark br.com.luiz.util.UIDocumentWatermark