Inicial > JSF > JSF 2 – PRIMEFACES – PHOTOCAM COM IMAGECROPPER

JSF 2 – PRIMEFACES – PHOTOCAM COM IMAGECROPPER


O desenvolvimento de novas versões do Primefaces, como seu próprio líder fala, está em chamas. Na última semana timemos a conclusão e lançamento da versão 3 e no mesmo dia o lançamento de novos componentes da versão 3.1.

Neste POST irei demonstrar como utilizar o componente PHOTOCAM para capturar uma imagem da sua webcam e como recortar esta imagem em seguida utilizando o IMAGECROPPER.

No nosso exemplo utilizamos:

  • Mojarra 2.1.3
  • Primefaces 3.1 SNAPSHOT
  • GlassFish 3.1.1

Let’s Rock!

Crie um novo projeto no Netbeans e dentro da pasta source crie um pacote para o managed bean, dentro da pasta web crie uma pasta para as imagens e nela uma outra pasta tmp. Veja a imagem abaixo com a estrutura básica do projeto:

Imagem 1 – Novo Projeto Netbeans

Adicione o jar do primerfaces na versão indicada acima. Na pasta web crie o arquivo index.xhtml e insira nele o código abaixo:

Codificação 1

<!--?xml version='1.0' encoding='UTF-8' ?-->



        Exemplo PhotoCam + ImageCropper











            

                Aguarde...



No arquivo index.xhtml temos o componete imagecropper definido a seguir:

Codificação 2


No atributo value definimos um objeto do tipo org.primefaces.model.CroppedImage que receberá a imagem recortada com o componente, em initialCoords definimos onde o retângulo marcador do recorte deve aparecer quando a imagem for renderizada. Além disso, temos um id para o componete, a definição se ele está ou não renderizado na view e um  outro atributo que merece um pouco mais de destaque.

No atributo image devemos especificar o caminho para a imagem capturada pela webcam, é salientar que neste atributo devemos colocar o caminho absoluto da imagem como por exemplo:

Para conseguir este caminho com precisão, coloque da forma como esta na codificação 2, pegando o caminho do contexto.

No componente photocam devemos definir um widgetVar para ser usado para chamar uma função javascript capture(), em update colocamos os ids do que deve ser atualizado ao capturar a imagem e em listenner o método a ser executado quando a captura for finalizada.

Codificação 3





Abaixo veremos a codificação do PhotoCamController:

Codificação 4

    private CroppedImage imagemRecortada;
    private String foto;
    private String fotoRecortada;
    private String arquivoFoto;
    private String arquivoFotoRecortada;
    private boolean exibeImagemCapturada;
    private ServletContext servletContext;

   /*getters e setters*/
    private String getNumeroRandomico() {
        int i = (int) (Math.random() * 10000);
        return String.valueOf(i);
    }

    private void criaArquivo(String arquivo, byte[] dados) {
        FileImageOutputStream imageOutput;
        try {
            imageOutput = new FileImageOutputStream(new File(arquivo));
            imageOutput.write(dados, 0, dados.length);
            imageOutput.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(PhotoController.class.getName()).log(Level.SEVERE, null, ex);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Caminho não encontrado!", "Erro"));
        } catch (IOException ex) {
            Logger.getLogger(PhotoController.class.getName()).log(Level.SEVERE, null, ex);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erro ao criar arquivo!", "Erro"));
        }
    }

    public void recortar() {
        verificaExistenciaArquivo(arquivoFotoRecortada);
        fotoRecortada = "fotoRecortada" + getNumeroRandomico() + ".png";
        arquivoFotoRecortada = servletContext.getRealPath(File.separator + "imagens" + File.separator + "tmp" + File.separator + fotoRecortada);
        criaArquivo(arquivoFotoRecortada, imagemRecortada.getBytes());
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Foto RECORTADA com sucesso!", "Informação"));
    }

    public void oncapture(CaptureEvent captureEvent) {
        verificaExistenciaArquivo(arquivoFoto);
        foto = "foto" + getNumeroRandomico() + ".png";
        arquivoFoto = servletContext.getRealPath(File.separator + "imagens" + File.separator + "tmp" + File.separator + foto);
        criaArquivo(arquivoFoto, captureEvent.getData());
        exibeImagemCapturada = true;
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Foto CAPTURADA com sucesso!", "Informação"));
    }

    private void verificaExistenciaArquivo(String arquivo) {
        if (arquivo != null) {
            File file = new File(arquivo);
            if (file.exists()) {
                file.delete();
            }
        }
    }

    public PhotoController() {
        exibeImagemCapturada = false;
        servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
    }

O método  recortar() é chamado sempre que recortamos a imagem na view e o oncapture() é acionado pelo componente photocam sempre que a função javascript capture() for chamada. Veja que uso nomes randomicos para as imagens criadas, este é um truque para evitar cache do imagecropper, já que não há esta propriedade neste componente.

Muito simples!

Abaixo o resultado:

Categorias:JSF
  1. Fabio Resplandes
    14/01/2012 às 22:16

    Benigno gostei muito do seu blog. Sou estudante de computação no IFRR, e estou desenvolvendo um sistema java web com primefaces, mas estou com dificuldade em trabalhar com photocam primefaces 3.0,
    peço a voçê que envias um projeto com este tema, vou divulgar seu blog aquí na região norte do brasil.

    Fábio, Boa Vista Roraima 14 de janeiro de 2012,
    Agradeco…

    • 15/01/2012 às 02:53

      Caro Fábio, posso enviar-lhe o projeto-base do post. Vou disponibilizar em um link para que todos possam realizar o download.

      • 24/09/2012 às 16:39

        Oi Benigno, você disponibilizou os fontes?
        []s

  2. William B.
    23/01/2012 às 12:36

    Seu blog é excelente, muito didático!
    Meus sinceros parabéns!

  3. Camillo Targas
    24/01/2012 às 16:12

    Tem como usar este recurso para digitalizar por exemplo um documento com o scanner?

    Existe para o jsf algum componente para scanner?

  4. yenayev
    30/01/2012 às 02:56

    Muy bueno tutorial, podrías mandarme EventoDAO.java, FotoDAO.java y ConnectionFactory.java.
    Muchas gracias

  5. Israel
    05/02/2012 às 08:39

    Olá Benigno!

    Parabéns pelo seu post! Seu blog está excelente!

    Bem, mas indo direto ao assunto: Hoje fui usar o componente photocam do primefaces, e tive problemas com a função javascript capture(). Quando executo esta função por meio do evento onlick executando a chamada “photoCam.capture()” tenho o erro javascript:

    webcam.capture is not a function

    Pesquisando por este erro, vi que você teve este mesmo problema registrado no forum do primefaces e consta como resolvido.

    Aqui verifiquei que este erro acontece no firefox (atualmente uso a versão 10, no linux). Abrindo a mesma página no Chromiun funciona perfeitamente.

    Estranho que a demostração deste componente no site primefaces funciona perfeitamente.

    Como resolveu este problema?

    Obrigado pela atenção,
    Israel

    • 05/02/2012 às 10:41

      Grande Israle, tudo bem? Coloquei resolvido porque até hoje nunca resolveram um problema que eu tenha postado naquele forum :D, acho que dão prioridade ao forum empresarial(os que pagam). Simplesmente desisti.

      Mas atualizando para a nova versão eu percebi que a frequencia do erro diminuiu.

      • Israel
        05/02/2012 às 12:30

        De qualquer forma obrigado pela resposta!

        Gostaria de aproveitar para passar uma dica: não é necessário passar o caminho completo para a imagem, o caminho relativo é o suficiente, ou seja, onde possui o código:

        image=”#{pageContext.servletContext.contextPath}/imagens/tmp/#{photoController.foto}”

        pode substituir tranquilamente para

        image=”/imagens/tmp/#{photoController.foto}”

        []’s

      • 05/02/2012 às 21:24

        Você testou usando template(facelets)? Ou alguma framework de reescrita de URL como PrettyFaces? Veja bem, eu recomendo usar da forma como ensino porque você pode usar em qualquer situação. Há um tempo atras eu havia testado os casos que falei e não funcionava, caso funcione agora, excelente.

  6. Israel
    05/02/2012 às 08:43

    Ops, só uma correção! Me enganei ao dizer que funciona no firefox pela demonstração do primefaces. Lá também não funciona.

  7. Israel
    05/02/2012 às 12:52

    Mais uma dúvida: Fiz um código semelhante a este, para testar o uso do photocam e imagecropper. No entanto, em um dado momento, o componente p:commandButtom para de invocar o método definido no action deste componente.

    Percebo que isto acontece quando capturo a imagem da câmera e a renderizo num p:panel, via ajax (comportamento normal). No entanto, após esta captura, ao tentar executar o crop (action de um commandButton), simplesmente o método não é invocado (não ocorre a chamada de forma alguma ao método do managed bean, verifico depurando o código).

    Percebi que antes de capturar a imagem (ou seja, antes de atualizar o panel com imagem capturada), ao clicar no botão que faz crop, o método é invocado.

    Não tenho certeza, mas me parece que algum evento ajax acaba interferindo no comportamento do botão e o mesmo passa a não funcionar caso eu capture a imagem.

    Não sei se a dúvida é devida a este post, mas se puder me ajudar e entender este comportamento.

    Não estou trabalhando com arquivo de imagem diretamente, e sim com o seu fluxo de bytes codificado em base64, acabo não precisando gerar o arquivo. Não acredito ser este o problema, pois já tive situações semelhantes em outros casos sem inclusive estar manipulando arquivos.

    Bem, se puder me ajudar, gostaria de trocar umas idéias contigo. Gostaria que visse meu código.

    []’s,
    Israel

    • 05/02/2012 às 21:27

      Como você deve saber o ciclo JSF tem várias fases e em uma delas, a de validação, ocorre antes da chamada da action. Muito provavelmente esteja ocorrendo algum erro de validação no formulário. Tente colocar um componente p:messages e no botão crop mande atualiza-lo. Caso aconteça algum erro na validação aparecerá no messages.

    • Israel
      05/02/2012 às 22:59

      Obrigado pelas respostas! Não estava exibindo mensagens de erro, e como ainda tenho pouca experiência com jsf, acabei não ficando atento a este detalhe. Pela mensagem exibida no p:messages, vi que o erro era por trabalhar com o formato em base64, consequentemente deu erro de conversão da imagem capturada para o crop. Ainda não resolvi o problema, mas entendendo o motivo, já ficou fácil resolver.

      • 05/02/2012 às 23:58

        Ok, mas veja bem… se estiver aparecendo um erro de conversão… tive um problema desses e era por conta do caminho da imagem, por isso indico que use da forma como ensinei. Veja esta postagem: http://stackoverflow.com/questions/5307882/primefaces-imagecropper-conversion-error-occur-croppedimage-is-null

      • Israel
        06/02/2012 às 08:29

        Bem, realmente o problema foi o caminho, mas não diretamente. Para meu caso usei a tag imageCropper basicamente da seguinte forma:

        Nada demais aí, só que a variável photoCamBean.imageEncoded é uma string codificada em Base64 e não um caminho. Então ela é algo como:

        photoCamBean.imageEncoded = “data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ…”

        E juntando o que me disse a esta informação … No precesso de validação essa string é convertida em um CroppedImage que necessita de um caminho para a imagem original, e como este valor não é um caminho válido, gera o erro.

        Não sei se é exatamente isto, então me corrija se estiver errado.

        Vi que posso criar um Converter, mas, pelo que percebi, de qualquer forma terei que criar um arquivo em disco, já que o objeto CroppedImage necessita disto.

        Então estarei usando como você mostrou aqui (especificando inclusive o caminho completo), é garantido e menos trabalhoso :). Pelo menos até amadurecer mais com os conceitos em jsf.

  8. Israel
    06/02/2012 às 08:33

    Ops … houve um corte no meu texto por usar as tags especiais aqui. Então esta é a forma que uso a tag imageCropper:

    p:imageCropper id=”croppedImage” value=”#{photoCamBean.imageCroped}” image=”#{photoCamBean.imageEncoded}”

  9. Oliver
    10/09/2012 às 17:37

    Onde encontro o link para dowload do exemplo?

    parabens! muito bom!

  10. 24/09/2012 às 16:10

    Benigno,
    Boa tarde!
    Não está aparecendo a codificação 2 nem a 3.
    Obrigada!

  11. 24/09/2012 às 16:36

    Gente, tem algum requisito para esse tutorial? Segui todos os passos, mas o meu está com vários erros. 😦

  12. Alexander
    06/11/2012 às 14:40

    Benigno, tudo bem??? Bem, primeiramente obrigado, seu blog esta me ajudando bastante, gostaria de saber se tem algum projeto que fez com gráfico em barras (barChat), pq tento fazer usando sua estrutura de pizza, da muito pau… O que posso fazer?

    • 06/11/2012 às 17:34

      nao tenho o projeto, mas posso te ajudar no que deu errado no seu. posta o codigo.

  13. Alexander
    06/11/2012 às 16:48

    E outra pergunta, é possível alimentar o gráfico com informações resgatadas de um banco MySql?

  14. Alexander
    07/11/2012 às 14:11

    Consegui solucionar o problema do gráfico de barras, agora como posso alimentar o gráfico com informações do banco, ou seja, não estática?? E outra coisa,na minha aplicação ao clicar em um checkbox preciso mostrar um valor “x” em um outro campo inputext, como fazê-lo?? Olha o código abaixo…. Obrigado

  15. Aurélio
    08/01/2013 às 14:24

    Parabéns, voce teria os fontes em algum lugar para dowload?

  16. Irlanilson
    09/01/2013 às 14:43

    Boa tarde Benigno! Teria como vc me enviar os fontes desse exemplo pra mim?

  17. YuE²noque
    23/03/2013 às 21:24

    Olá, estou a uns dias procurando sobre como implementar este componente e só no seu blog que consegui algo consistente. Poderia me passar os fontes desse exemplo, Aqui não está aparecendo todo o código. Desde já obrigado!

  18. Igo
    02/04/2013 às 15:35

    Boa tarde, também já procurei muito na net a implementação destes componentes e não encontrei muita coisa, poderia me informar onde pego os fontes deste exemplo? Obrigado!

  19. Wellington
    21/05/2013 às 21:01

    O triste é postar um excelente tutorial e não disponibilizar os fontes.

  20. felippelfcc
    26/06/2013 às 12:12

    Benigno excelente post, todavia teria como vc disponibilizar os fontes, ou acertar as exibições dos códigos acima pois não está aparecendo corretamente! Desde já agradeço!

  21. 02/07/2013 às 22:05

    Benigno agradeço por ter ajudado bastante com seu post. já consegui resolver tudo porém gostaria de mudar o width do photocam sabe me informar como?????

  22. Hudson Alves
    30/10/2013 às 10:49

    JSF 2 – PRIMEFACES – PHOTOCAM COM IMAGECROPPER

    teria como enviar por email os fontes desse projeto? Obrigado amigo

  23. HUDSON ALVES
    09/11/2013 às 15:38

    Só vim aqui agradecer a ajuda amigo.. peguei o seu exemplo e fiz uma adaptação para que a foto seja salvar num banco de dados em um campo do tipo Blob.. muito Obrigado pela ajuda.. Ajudou 100%..Valeu mesmo !!!

  24. aysegulP
    29/05/2014 às 08:04

    Can you share the source codes?

  25. 24/08/2017 às 09:02

    wow grate man 🙂 embedded two things

  1. 28/08/2013 às 05:54

Deixar mensagem para Israel Cancelar resposta