Problemas com BufferedImage

Olá pessoal tudo bem!!!

Estou tentando gravar arquivos jpg no Banco de Dados MySQL, eu acredito que já consegui grava-lo mas o meu problema esta sendo em capiturar a imagem no banco

public BufferedImage getBufferedImage(byte[] vetor){

        BufferedImage bi = null;

        try{
            bi = ImageIO.read(new ByteArrayInputStream(vetor));

        }
        catch(IOException e){
            JOptionPane.showMessageDialog(null,"Erro ao converter o vetor " +
                    "de Bytes[] em BufferedImage"+e.getMessage());
            e.printStackTrace();
        }
        finally{
            
            return bi;
        }
    }

Estou usando o método acima para inserir o vetor de bytes lido do banco em uma BufferedImage, para que depois eu mostre a imagem na tela, mas o problema esta
nessa linha de código:

bi = ImageIO.read(new ByteArrayInputStream(vetor));

Quando chego no final do método o objeto bi ainda está null, ou seja não está convertendo bytes[] to BufferedImage

Eu vejo esses dados quando visualizo o campo blob no MySQL:

Binary

5B 42 40 31 |66 61 63 38 |35 32

[B@1FAC852

Caso alguém possa me ajudar ficarei grato!!

Oi. Ao postar códigos, utilize a tag code:

  seu código aqui

Como você está carregando esse vetor do banco?

Obrigado pela dica da tag!!!

Estou capturando o arquivo com esse método:

 private void JBBuscarArquivoActionPerformed(java.awt.event.ActionEvent evt) {                                                

        try{
        JFileChooser fc = new JFileChooser();
        fc.setCurrentDirectory(new File("C:\Imagens"));
        fc.setDialogTitle("Carregar foto do Carro");
        fc.showOpenDialog(this);
        setFotoCarro(ImageIO.read(new File(fc.getSelectedFile().getAbsolutePath())));
        jlfoto.setIcon(new ImageIcon(getFotoCarro()));
        JOptionPane.showMessageDialog(null,getFotoCarro());



        
        }catch(Exception e){
            JOptionPane.showMessageDialog(null,"Erro ao buscar a foto");
        }
    }                

Utilizo uma classe Carro, um de seus atributos é private BufferedImage fotoCarro. Leio o arquivo com o método acima e atualizo o atributo fotoCarro com o retorno do
método ImageIO.read e passo o objeto Carro para a classe CarroBD.

public boolean gravaCarro(Carro car) throws ErroBD{

            boolean gravou = false;

              criaConexao();
              Statement comando = null;

              
              try{
                  
                      //criar o comando sql a ser realizado
                      comando = conexao.createStatement();

                      comando.executeUpdate("insert into Carro (placa, tipo, modelo, ano, cor, " +
                   "chassis, quilometragem, diaria, disponibilidade, fotoCarro)"+
                   "value ('"+car.getPlaca()+"','" +
                    car.getTipo()+"','"+
                   car.getModelo()+"','"+
                   car.getAno()+"','"+
                   car.getCor()+"','"+
                   car.getChassis()+"',"+
                   car.getQuilometragem()+","+
                   car.getDiaria()+",'"+
                   car.isDisponibilidade()+"','"+
                   converteToBytes(car)+"')");

                   gravou = true;

                   
                   comando.close();
              }catch(SQLException erro){
                  erro.printStackTrace();
                  throw new ErroBD("erro na inserção do Carro");
              }
              finally{
                fechaConexao();
                return gravou;
              }
	  }

 public byte[] converteToBytes(Carro car){

             byte[] byteArray = null;
             

            try{
                ByteArrayOutputStream bytesImg = new ByteArrayOutputStream();
                ImageIO.write((BufferedImage)car.getFotoCarro(), "jpg", bytesImg);
                bytesImg.flush();
                byteArray = bytesImg.toByteArray();
                bytesImg.close();
                
                


            }catch(IOException e){
                JOptionPane.showMessageDialog(null,"Erro ao converter a imagem"+e.getMessage());
                e.printStackTrace();
            }
            finally{
                return byteArray;
            }
        }

acima é o método para gravar no Banco e o método para converter BufferedImage em um array de bytes

public ListaCarro listarCarro() throws ErroBD{

            
            ResultSet resultado = null;
            criaConexao();
            PreparedStatement comando = null;
            Carro car = null;
            ListaCarro listacarro = null;

            try {
                    listacarro = new ListaCarro();
                    
                    // criar o comando sql a ser realizado
                    comando = conexao.prepareStatement("select * from carro");
                    //executar a consulta e obter as tuplas selecionadas
                    resultado = comando.executeQuery();

                    //obter cada informação e armazenar na coleção

                    while(resultado.next()){

                        car = new Carro();
                        car.setPlaca(resultado.getString(1));
                        car.setTipo(resultado.getString(2));
                        car.setModelo(resultado.getString(3));
                        car.setAno(resultado.getString(4));
                        car.setCor(resultado.getString(5));
                        car.setChassis(resultado.getString(6));
                        car.setQuilometragem(resultado.getDouble(7));
                        car.setDiaria(resultado.getDouble(8));
                        car.setDisponibilidade(resultado.getString(9));
                        car.setFotoCarro(getBufferedImage(resultado.getBytes(10)));
            
                        


                        listacarro.adicionaCarro(car);
                        
                   }
                    

                    resultado.close();
                    comando.close();
                    return listacarro;
            } catch (SQLException erro) {
                throw new ErroBD("erro ao realizar consulta");
            }

            finally{
                fechaConexao();
                

            }
         }

acima o método para buscar os dados no banco. ListaCarro é uma classe que contém uma Collection para armazenas os Objetos de Carro.

E o método public BufferedImage getBufferedImage(byte[] vetor) para converter o array de bytes[] em uma BufferedImage está abaixo:

 public BufferedImage getBufferedImage(byte[] vetor){

            
            BufferedImage bi = null;

            try{
                bi = ImageIO.read(new ByteArrayInputStream(vetor));
          
            }
            catch(IOException e){
                JOptionPane.showMessageDialog(null,"Erro ao converter o vetor " +
                        "de Bytes[] em BufferedImage"+e.getMessage());
                e.printStackTrace();
            }
            finally{
                
                return bi;
            }
        }

Bom, esse comando aqui:
converteToBytes(car)

Retorna um array de bytes. Mas concatena-lo com uma string, como você faz no seu insert, vai chamar o toString() do array de bytes, que retornará o que você está vendo. Essa não é a forma correta de se manipular blobs.

Use o PreparedStatement, no lugar do Statement. Além de ser mais correto do que você está fazendo, pois gera uma sintaxe mais limpa e impede ataques de sql injection, lá você encontra o método )"]setBytes(), que aceita um array inteiro e o grava.

Outra coisa, na hora de ler os dados, ao invés de índices, use o nome do campo. É muito mais claro ver um getString(“placa”) do que um getString(2). Fora que, se a estrutura da sua tabela mudar, ou o SQL inserir algum campo, você não terá problemas depois.

Muito obrigado pela dica!!

Está funcionando perfeitamente, o código abaixo mostra as modificações:


public boolean gravaCarro(Carro car) throws ErroBD{

            boolean gravou = false;

              criaConexao();
              PreparedStatement comando = null;

              
              try{
                  
                   String sql = "insert into Carro (placa, tipo, modelo, ano, cor, " +
                   "chassis, quilometragem, diaria, disponibilidade, fotoCarro)"+
                   "value (?,?,?,?,?,?,?,?,?,?) ";
                   comando = conexao.prepareStatement(sql);

                   comando.setString(1,car.getPlaca());
                   comando.setString(2,car.getTipo());
                   comando.setString(3,car.getModelo());
                   comando.setString(4,car.getAno());
                   comando.setString(5,car.getCor());
                   comando.setString(6,car.getChassis());
                   comando.setDouble(7,car.getQuilometragem());
                   comando.setDouble(8,car.getDiaria());
                   comando.setString(9,car.isDisponibilidade());
                   comando.setBytes(10,converteToBytes(car));

                   gravou = comando.executeUpdate() > 0;
                   comando.close();
                   
              }catch(SQLException erro){
                  erro.printStackTrace();
                  throw new ErroBD("erro na inserção do Carro");
              }
              finally{
                fechaConexao();
                return gravou;
              }
	  }

Aproveitando a conversa o que vc me recomenda para visualizar na tela a imagem, no momento estou usando o seguinte comando:
jlfoto.setIcon(new ImageIcon(getFotoCarro()));

Mas estou tendo problemas com o tamanho da imagem, tenho um tamanho prédefino para o JLabel mas quando tenho uma imagem maior que ela aparece parcialmente

Como posso aprender a mudar o tamanho do JLabel de acordo com a imagem e como posso alterar a imagem para o tamanho do JLabel ?

Acredito ser interessante aprender as duas maneira porque dependendo da aplicação posso ter a necessidade de usar uma ou outra.

Dá uma olhada:
http://www.guj.com.br/posts/list/56248.java#295271

Consegui exibir as imagens gravadas no banco, mas estou tendo problemas com imagens com resolução de 3664 X 2748 de tamanho em média de
1,50 MB , com imagens de resolução baixa tipo 480 x 640 estão exibindo perfeitamente.

Na minha JFrame tenho JButton que está com o seguinte código:


private void JBBuscarArquivoActionPerformed(java.awt.event.ActionEvent evt) { 
  
   try{
        JFileChooser fc = new JFileChooser();
        fc.setCurrentDirectory(new File("C:\Imagens"));
        fc.setDialogTitle("Carregar foto do Carro");
        fc.showOpenDialog(this);

        setFotoCarro(ImageIO.read(new File(fc.getSelectedFile().getAbsolutePath())));
        // O problemas esta ocorrendo neste comando acima quando tento buscar fotos com resolução alta.
        // Quando peço para exibir na primeira vez ocorre tudo bem, mas quando clico na segunda vez 
        // ocorre um erro e as mensagens do Catch não são acionadas.   
        // Observação: O erro só ocorre quando peço para exibir imagens de alta resolução a partir da 2° vez
        // Com imagens menores exibe perfeitamente.
        JTNomeFoto.setText(fc.getSelectedFile().getName());
        exibeFoto(getFotoCarro());
      
        }catch(IOException e){
            e.getMessage();
            JOptionPane.showMessageDialog(null,"Erro ao buscar a foto");
        }
        catch(IllegalArgumentException e){
            JOptionPane.showMessageDialog(null,"Erro ao buscar a foto");
            e.getMessage();
        }
        catch(SecurityException e){
            JOptionPane.showMessageDialog(null,"Erro ao buscar a foto");
            e.getMessage();
        }

         

Mas esta mesagem aparece no NetBeans


Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
        at java.awt.image.DataBufferByte.<init>(DataBufferByte.java:58)
        at java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:397)
        at java.awt.image.Raster.createWritableRaster(Raster.java:938)
        at javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1169)
        at javax.imageio.ImageReader.getDestination(ImageReader.java:2879)
        at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:943)
        at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:915)
        at javax.imageio.ImageIO.read(ImageIO.java:1422)
        at javax.imageio.ImageIO.read(ImageIO.java:1282)
        at Telas.Cad_Veiculos.JBBuscarArquivoActionPerformed(Cad_Veiculos.java:768)
        at Telas.Cad_Veiculos.access$1500(Cad_Veiculos.java:33)
        at Telas.Cad_Veiculos$16.actionPerformed(Cad_Veiculos.java:415)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
        at java.awt.Component.processMouseEvent(Component.java:6041)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
        at java.awt.Component.processEvent(Component.java:5806)
        at java.awt.Container.processEvent(Container.java:2058)
        at java.awt.Component.dispatchEventImpl(Component.java:4413)
        at java.awt.Container.dispatchEventImpl(Container.java:2116)
        at java.awt.Component.dispatchEvent(Component.java:4243)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4322)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3986)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3916)
        at java.awt.Container.dispatchEventImpl(Container.java:2102)
        at java.awt.Window.dispatchEventImpl(Window.java:2440)
        at java.awt.Component.dispatchEvent(Component.java:4243)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)

Este é o método Exibe

public void exibeFoto(BufferedImage image){

        ImagePanel panel = new ImagePanel(image);

        JFrame frame = new JFrame();
        frame.getContentPane().add(panel);
        frame.pack();
        frame.setVisible(true);

    }

Apesar de vc ter me indicado uma classe para exibir imagens, acabei usando outra que encontrei na net e fiz uma pequena modificação


public class ImagePanel extends JPanel{


    private Image img,menor;

	  public ImagePanel(String img) {
	    this(new ImageIcon(img).getImage());
	  }

	  public ImagePanel(Image img) {
	    this.img = img;
            boolean flag = getTamanhoImage( img.getWidth(null), img.getHeight(null));

            if(flag == false)
                menor = img;
            else
             menor = new ImageIcon(img).getImage().getScaledInstance(800,600,Image.SCALE_DEFAULT);
            
	    Dimension size = new Dimension(menor.getWidth(null),menor.getHeight(null));
	    setPreferredSize(size);
	    setMinimumSize(size);
	    setMaximumSize(size);
	    setSize(size);
	    setLayout(null);
	  }

          public boolean getTamanhoImage(int x, int y){

              boolean flag = false;

              if(x > 800 && y > 600){
                  flag = true;
              }
              return flag;

          }

	  public void paintComponent(Graphics g) {
	    g.drawImage(menor, 0, 0, null);
	  }
}

O que tentei fazer nela foi que quando ela recebesse uma imagem com uma altura e largura muito grande eu mudo a Dimensão dela
para 800x600 , pois haviam imagens que nem cabiam na tela, mas outras eram interessante manter o tamanho original por serem pequenas.

O que não entendo mesmo é o porque daquele erro apenas com imagens de resolução alta que citei acima.

Você realmente não entende por que de um “Out of memory” error?
Simplesmente pq com a imagem muito grande, faltou memória. Simples assim.

Se sua imagem é um jpg, png ou qualquer outro formato compactado, carrega-la vai facilmente gerar um arquivo enorme. Essa sua imagem, por exemplo, vai ficar no mínimo com 38 MB, sozinha. A memória heap padrão do Java tem apenas 64MB. É natural que entre carrega-la e exibi-la (quando vc redesenha a imagem na tela), sua memória vá para o espaço.

Para corrigir o problema, dê o parâmetro -Xmx512m quando for executar seu programa. Isso permitirá que a VM ocupe até 512 megas de memória.

java -Xmx512m seuPrograma

Funcionou!!!

Fui no NetBeans em Propriedades do meu Projeto, Executar digitei: -mx512m em opções da VM.

O que eu não lembrava foi que existem Errors e Exception.

Exception são de resposabilidade do Programador e Errors da JVM

Mas beleza o que importa foi que o problema foi solucionado e se tornou um aprendizado.

Uma pergunta para vc ViniGodoy.

Numa situação em que realizamos um Cadastro e nele temos que armazenar diversas imagens, ou seja o usuário
irá gravar, alterar e excluir imagens a todo momento. Vc acha melhor armazenar as imagens no Banco de Dados
ou o caminho delas ? Por que se temos que armazenar o caminho da imagem teremos que gerenciar a pasta do
System File, porque senão com o tempo teremos uma pasta com um monte de imagens e nem saberemos mais
o que pode ser excluido nela.

Mas quando imagens são ilustrações na tela com a finalidade de melhorar a aparencia da Tela acredito que seja melhor
indicar o caminho delas.

O que acha sobre isso ?

E mais uma vez muito obrigado pela ajuda!!

valewww

Essa é uma pergunta difícil, porque depende…

Bom, isso pode estar mais relacionado a política da sua empresa e a importância da informação.
Geralmente, backups são feitos com mais frequencia em BDs do que no sistema de arquivos. E espaço em BD costuma a ser caríssimo.

Por outro lado, a informação no BD fica muito mais organizada, pode ser acessada mais rapidamente e, como você falou, pode evitar duplicações.

Passei o parametro para a JVM como descrevi acima, mas funcionou bem apenas com o programa rodando pelo NetBeans,
quando executo o .jar da pasta dist do meu projeto o problema continua.

Eu tentei do modo que vc mencionou digitando pelo Executar do Windows mas não houve alteração.

Caso vc saiba uma solução, ficarei grato!!!

Você digitou assim?

java -Xmx512m -jar seuJar.jar

Esses parâmetros deveriam funcionar pela linha de comando também, se não funcionou, é pq vc digitou alguma coisa errada.

java -Xmx512m -jar Locadora_de_Veiculos.jar

A dúvida fica a seguinte eu estou considerando que no diretório:

D:\NetBeans\Locadora de Veiculos\Locadora de Veiculos\dist

Esta o arquivo.jar do meu projeto então copiei o nome e colei no lugar
do “seuJar”.

A única mudança que houve foi quando eu fiz a modificação diretamente no netBeans
, mas mudou apenas quando executo o projeto pelo NetBeans.

Problema resolvido!!!

Entrei no site do java.com e fiz o download da versão recomendada. Depois executei o comando que vc
citou acima e deu certo!!!

Caso eu fosse gravar apenas o caminho da imagem como posso apagar um arquivo e um diretório do Windows
atavés do código java ? É possivel criar um diretório.

[quote=aversi]Problema resolvido!!!

Entrei no site do java.com e fiz o download da versão recomendada. Depois executei o comando que vc
citou acima e deu certo!!!

Caso eu fosse gravar apenas o caminho da imagem como posso apagar um arquivo e um diretório do Windows
atavés do código java ? É possivel criar um diretório.

[/quote]

Vini, vou me entrometer :wink:
Você consegue manipular arquivos dentro do código Java sim. Uma alternativa ao invés de usar as classes padrão do JDK seria vc usar o apache commons IO (http://commons.apache.org/io/). A classe FileUtils (http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html) tem um monte de métodos muito úteis para trabalhar com arquivos. No pacote existem várias outras clases úteis para manipular arquivos. Dê uma olhada no javadoc http://commons.apache.org/io/api-release/index.html.

[]´s

Gostei bastante da classe, mas tentei importar ela no netBeans e não consegui então imaginei que eu teria que realizar o download
do pacote org.apache.commons.

Realizei o download desses dois arquivos:

commons-io-1.4-bin
commons-io-1.4-src

Mas não sei o que fazer com eles e também não tenho certeza se esse é o caminho para que eu possa conseguir o pacote.

Caso vc possa me ajudar ficarei grato

Problema resolvido sobre como importar o pacote org.apache.commons

No NetBeans fui em propriedades do meu projeto
Adicionar JAR/pasta
Selecionei o commons-io-1.4.jar

E agora estou conseguindo importar a classe FileUtils

[quote=aversi]Problema resolvido sobre como importar o pacote org.apache.commons

No NetBeans fui em propriedades do meu projeto
Adicionar JAR/pasta
Selecionei o commons-io-1.4.jar

E agora estou conseguindo importar a classe FileUtils[/quote]

Legal aversi. Você pode também criar uma biblioteca dentro do netbeans para organizar os .jar externos, bem como fazer com que essa biblioteca fique empacotada dentro do seu projeto.

[]´s

Então encontrei os método que eu estava procurando

import org.apache.commons.io.*;

//Para salvar
FileUtils.copyFile(file1, file2);

//Para deletar
FileUtils.forceDelete(file2);


//Para exportar em um local escolhido pelo usuário

//Modifico o modo de seleção para apenas Diretórios
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

//Caso o usuário queira exportar a imagem do sistema e um diretório que deseja
//o método: fc.showSaveDialog(this) selecionará apenas o diretório
//Depois é só colocar o diretório no parametro de destino do método: 
FileUtils.copyFile(file1, file2);

No caso do sistemas seja acessado em apenas uma maquina, então eu teria que colocar um restrição
na pasta onde o sistema irá guardar as imagens.

Qual seria a melhor maneria de restringir o acesso a esta pasta e de que modo ?