Problemas com BufferedImage

19 respostas
A

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!!

19 Respostas

ViniGodoy

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

seu código aqui

Como você está carregando esse vetor do banco?

A

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;
            }
        }
ViniGodoy

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.

A

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.

ViniGodoy

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

A

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.
ViniGodoy

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
A

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

ViniGodoy

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.

A

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!!!

ViniGodoy

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.

A

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.

A

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.

davidbuzatto

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.

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

A

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

A

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

davidbuzatto

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

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

A

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 é  colocar o diretório no parametro de destino do método: 
FileUtils.copyFile(file1, file2);
A

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 ?

Criado 25 de janeiro de 2010
Ultima resposta 1 de fev. de 2010
Respostas 19
Participantes 3