Imagem em JPanel

Aí, galera…
Consegui recuperar uma imagem gravada num campo binário do banco de dados para apresentação num jLabel…
O problema é que, quando a imagem se recupera, é apresentada em seu tamanho real, ou seja, as imagens mudam o tamanho do jLabel na área visível do formulário… Já tentei todos os métodos de redimensionamento do jLabel e até redimensionar a imagem, mas sem sucesso… Então pensei que pudesse jogar o array de bytes da imagem direto para um jPanel, como faço com o arquivo de imagem selecionado num JFileChooser…
Faço assim…
Tenho uma classe extendida de JPanel…

[code]package sigpbones;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

/**
*

  • @author lindoélio
    */

public class JImagePanel extends JPanel {
BufferedImage background = null;

public JImagePanel(BufferedImage img) {
    if (img == null)
        throw new NullPointerException("Sem imagem para processar!");
    this.background = img;
}

public JImagePanel(File imgSrc) throws IOException {
    this(ImageIO.read(imgSrc));
}

public JImagePanel(String fileName) throws IOException {
    this(new File(fileName));
}

protected void paintComponent(Graphics g) {        
super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g.create();
    g2d.drawImage(background, 0, 0, this.getWidth(), this.getHeight(), null);
    g2d.dispose();        
}

}[/code]
E então implemento o ActionPerformed do botão de procurar o arquivo de imagem…

private void btnProcurarActionPerformed(java.awt.event.ActionEvent evt) { if (fd.showOpenDialog(this) == JFileChooser.CANCEL_OPTION) return; try{ JImagePanel quadroImagem = new JImagePanel(fd.getSelectedFile()); painelImagem.add(quadroImagem,BorderLayout.CENTER); painelImagem.validate(); } catch (IOException ex) { JOptionPane.showMessageDialog(this, "Não foi possível ler a imagem!"); } }
E a imagem é então visualizada no painelImagem, respeitando a dimensão do JPanel…
Como eu faço para exibir o array de bytes recuperado do banco de dados para um JPanel???

Valeu!!!

Esse array de bytes era uma imgaem em que formato?

Se fosse jpg, imagino que dá pra azer o seguinte:
1-Obter esses bytes.
2-Criar um arquivo temporário (tem um método estático da classe File que faz isso) chamado “imagem.jpg”, por exemplo
3-Escrever esses bytes no arquito temporário acima com algum objeto que escreva array de bytes em arquivos (dá uma olhada em FileWriter, se nãp me engano é esse).
4-sobrescreve o método paintComponent de um JPanel, desenhando este arquivo de imagem…

Teoricamente funciona :wink:

Já deu uma olhada no JImagePanel?
http://www.guj.com.br/posts/list/56248.java

[quote=eclipso]Esse array de bytes era uma imgaem em que formato?

Se fosse jpg, imagino que dá pra azer o seguinte:
1-Obter esses bytes.
2-Criar um arquivo temporário (tem um método estático da classe File que faz isso) chamado “imagem.jpg”, por exemplo
3-Escrever esses bytes no arquito temporário acima com algum objeto que escreva array de bytes em arquivos (dá uma olhada em FileWriter, se nãp me engano é esse).
4-sobrescreve o método paintComponent de um JPanel, desenhando este arquivo de imagem…

Teoricamente funciona ;-)[/quote]
Fera, vou te explicar o que fiz…
Criei um método onde converto as imagens adicionadas através de um JFileChooser (swing) ao JPanel dentro de um JDialog em um array de bytes e gravo esses bytes dentro de um campo do tipo BLOB do banco de dados. Ou seja, tenho um preview, vamos dizer assim, da imagem que selecionei no formulário, onde visualizo a imagem dentro de um JPanel redimensionada ao tamanho dele…
O problema é que quando vou visualizar a imagem gravada no banco, recuperando o array de bytes, só consigo jogar essa imagem num JLabel, e o JLabel se redimensiona ao tamanho da imagem ao invés da imagem se redimensionar ao tamanho do JLabel…
Então modifiquei meu código para mostrar no JPainel, mas não está funcionando direito… As vezes aparece, se o arquivo for bem pequeno, outras vezes aparesce só um pedacinho…
Dá uma olhada no que fiz…

[code] private void recuperarImagem() {
Image img;
try {
conexao.conectar();
stmt = conexao.con.createStatement();
rs = stmt.executeQuery("Select Imagem_Log from Logomarcas where Cod_Log = "+codLogo);
if (rs.next()){
img = Toolkit.getDefaultToolkit().createImage(rs.getBytes(“Imagem_Log”));
//labelImagem.setIcon(new javax.swing.ImageIcon(img)); // Mostrava no JLabel…

            // Modifiquei aqui para mostrar no JPainel (painelImagem) a imagem resgatada do banco...
            painelImagem.removeAll();
            JImagePanel quadroImagem = new JImagePanel(img);
            painelImagem.add(quadroImagem,BorderLayout.CENTER);
            painelImagem.validate();
        }
        rs.close();
        stmt.close();
    }
    catch (SQLException e) {
        e.printStackTrace();
    }
    finally {
        conexao.desconectar();
    }
}[/code]

Daí, na classe JImagePanel, que já havia criado para visualizar a imagem selecionada através do JFileChooser, alterei o tipo “BufferedImage” para “Image” e ela continuou funcionando aparentemente normal…

Podem me ajudar???

[quote=Ratao]Já deu uma olhada no JImagePanel?
http://www.guj.com.br/posts/list/56248.java[/quote]
Aí, fera…
JImagePanel é uma classe, repassada pelo ViniGodoy, e é exatamente ela que estou implementando…
Sabe me dizer como resolver esse problema implementando essa classe?

Valeu!

Tlz te ajude:

Como redimensionar uma imagem

public static ImageIcon redimensionar(Image image, int width, int height, boolean aumentar){
        // Calculos necessários para manter as proporções da imagem, conhecido
        // como "aspect ratio"
        double imageWidth = (double) image.getWidth(null);
        double imageHeight = (double) image.getHeight(null);
        
        double thumbRatio = (double) width / (double) height;
        double imageRatio = imageWidth / imageHeight;
        
        if( imageWidth > width || imageHeight > height || aumentar){
            if (thumbRatio < imageRatio) {
                height = (int) (width / imageRatio);
            } else {
                width = (int) (height * imageRatio);
            }
        }
        else{
            width = image.getWidth(null);
            height = image.getHeight(null);
        }
        
        // Fim do cálculo
        
        BufferedImage thumbImage = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        
        Graphics2D graphics2D = thumbImage.createGraphics();
        
        graphics2D.drawImage(image, 0, 0, width, height, null);
        return (new ImageIcon((Image)thumbImage));
    }

Nem precisa de tanta complicação. Existe um segundo drawImage que recebe também o tamanho da imagem de destino, que será desenhada. Use-o.


public abstract boolean drawImage(Image img,
int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2,
ImageObserver observer)

Em dx1, dy1, dx2, dy você passa as dimensões da imagem de destino, que são as dimensões do painel. Em sx1, sy1, sx2, sy2 você passa as dimensões da imagem original.
Problema resolvido. Você também poderia ter visto isso lá no JImagePanel. Eu disponibilizei o código. :wink:

Um detalhe interessante. Passando os valores de x invertidos você faz um flip horizontal na imagem. Se passar y invertido, faz um flip vertical.

[quote=ViniGodoy]Nem precisa de tanta complicação. Existe um segundo drawImage que recebe também o tamanho da imagem de destino, que será desenhada. Use-o.


public abstract boolean drawImage(Image img,
int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2,
ImageObserver observer)

Em dx1, dy1, dx2, dy você passa as dimensões da imagem de destino, que são as dimensões do painel. Em sx1, sy1, sx2, sy2 você passa as dimensões da imagem original.
Problema resolvido. Você também poderia ter visto isso lá no JImagePanel. Eu disponibilizei o código. :wink:

Um detalhe interessante. Passando os valores de x invertidos você faz um flip horizontal na imagem. Se passar y invertido, faz um flip vertical.[/quote]
Aí, brother ViniGodoy… Mais uma vez, você!!!
Primeiramente, obrigado pela tamanha disposição em ajudar…
Não entendi direito como fazer isso… Achei num outro post da segunda implementação daquela classe que você repassou no GUJ onde implementou a possibilidade de redimensionar a imagem, centralizar ou repetí-la colocando lado-a-lado…
Será que poderia dizer mais detalhes?
Estou ralando pra conseguir isso…
Consigo visualizar no JPanel quando seleciono a imagem através de um JFileChooser, mas, mesmo usando a mesma classe e métodos não consigo mostrar satisfatoriamente a imagem quando a recupero do banco de dados…
Aguardo… E desde já, grato.
Um abraço!

Ah, brother ViniGodoy, aproveitando, para não desviar a discução deste post criei outro perguntando sobre as diferenças do BufferedImage e do Image, porque na classe JImagePanel mudei de BufferedImage para Image afim de conseguir processar a imagem recuperada do banco nesse tipo e continuou funcionando da mesma forma que antes…
Será que tem como você dar uma olhadinha? Ou mesmo me dizer como vou recuperar uma imagem do banco de dados em bytes para o tipo BufferedImage ao invés de Image? Imagino que isso esteja contribuindo para o fracasso nessa operação… Mas só consigo recuperar para o tipo Image com Toolkit…

Image img = Toolkit.getDefaultToolkit().createImage(rs.getBytes("Imagem")); // onde "rs" é o meu ResultSet...
Tentei fazer o casting para BufferedImage, assim:

BufferedImage img = (BufferedImage) Toolkit.getDefaultToolkit().createImage(rs.getBytes("Imagem"));

E quando executo dá erro nessa linha…
Faz idéia???

[quote=ivo costa]Tlz te ajude:

Como redimensionar uma imagem

[code]
public static ImageIcon redimensionar(Image image, int width, int height, boolean aumentar){
// Calculos necessários para manter as proporções da imagem, conhecido
// como "aspect ratio"
double imageWidth = (double) image.getWidth(null);
double imageHeight = (double) image.getHeight(null);

    double thumbRatio = (double) width / (double) height;
    double imageRatio = imageWidth / imageHeight;
    
    if( imageWidth > width || imageHeight > height || aumentar){
        if (thumbRatio < imageRatio) {
            height = (int) (width / imageRatio);
        } else {
            width = (int) (height * imageRatio);
        }
    }
    else{
        width = image.getWidth(null);
        height = image.getHeight(null);
    }
    
    // Fim do cálculo
    
    BufferedImage thumbImage = new BufferedImage(width, height,
            BufferedImage.TYPE_INT_RGB);
    
    Graphics2D graphics2D = thumbImage.createGraphics();
    
    graphics2D.drawImage(image, 0, 0, width, height, null);
    return (new ImageIcon((Image)thumbImage));
}

[/code][/quote]
Aí, fera, valeu pela dica!!!
Vou testar aqui e ver no que posso aproveitar…
Muito obrigado mesmo…
Quando implementar volto a dizer no que deu, rsrsr…
Um abraço!

Qual é a dificuldade?
A área de destino é o painel. Logo, a imagem de destino tem o tamanho do painel.
A área de origem é a própria imagem.

Seu código vai ficar assim:

protected void paintComponent(Graphics g) {           
   super.paintComponent(g);   
   Graphics2D g2d = (Graphics2D)g.create();   
   g2d.drawImage(
      background, 0, 0, getWidth(), getHeight(),  //Tamanho destino = tamanho do painel
      0, 0, background.getWidth(), background.getHeight(), //Tamanho da origem = própria imagem
      null);   
   g2d.dispose();           
}   

Me diz uma coisa… como você está fazendo para gravar e recuperar do banco de dados?
Você já conseguiu alguma vez mostrar a imagem corretamente, mesmo em escala natural?

Então, brother…
A questão das dimensões eu entendi depois de analisar o que tinha me dito e de olhar na documentação que me enviara…
Então dei uma mexida e consegui fazer a imagem aparecer…
O problema é que só aparece corretamente na primeira vez… Quando eu seleciono outro registro o panel fica piscando a imagem anterior e a nova imagem, como se tivesse dando um refresh muito rápido, e as duas imagens ficam fundidas e piscando, numa confusão geral…
Eu consegui gravar como array de bytes em um campo LONGBLOG; o campo BLOB não conseguiu armazenar o array…
Eu consigo recuperar a imagem para um JLabel facilmente, mas ela fica em tamanho natural, redimensionando o JLabel…
Segue detalhes dos processos de gravar, recuperar e visualizar…

[code] private void incluirLogomarca() {
try {
conexao.conectar();
PreparedStatement pstmt = conexao.con.prepareStatement("+
“Insert into Logomarcas (Identificacao_Log, Imagem_Log, Observacoes_Log)” +
“Values (?, ?, ?)”);

        ByteArrayOutputStream byteSaida = new ByteArrayOutputStream();
        BufferedImage imagemBuffer = ImageIO.read(new File(editArquivo.getText()));
        ImageIO.write((BufferedImage)imagemBuffer, "jpg", byteSaida);
        byteSaida.flush();
        byte[] byteArray = byteSaida.toByteArray();
        byteSaida.close();
        
        pstmt.setString(1, editIdentificacao.getText());
        pstmt.setBytes(2, byteArray);
        pstmt.setString(3, editObservacoes.getText());
        pstmt.executeUpdate();
        pstmt.close();
    }
    catch (IOException ex) {
        Logger.getLogger(Logomarcas.class.getName()).log(Level.SEVERE, null, ex);
        JOptionPane.showMessageDialog(this, "Não foi possível processar a imagem!");
    }
    catch (SQLException e) {
        e.printStackTrace();
        JOptionPane.showMessageDialog(this, "Falha na inclusão do registro!\n\nMensagem de erro:\n"+e.getMessage());
    }
    finally {
        conexao.desconectar();
    }
}[/code]

E então o registro é incluído com sucesso…
Daí eu recupero o array de bytes do tipo jpg e visualizo…

[code] private void visualizarRegistroSelecionado() {
Image img = null;
identLogo = (String) tabelaLogomarcas.getValueAt(tabelaLogomarcas.getSelectedRow(), 0);
try {
conexao.conectar();
stmt = conexao.con.createStatement();
rs = stmt.executeQuery(“Select * from Logomarcas where Identificacao_Log = '”+identLogo+"’");
if (rs.next()) {
codLogo = rs.getInt(“Cod_Log”);
identLogo = rs.getString(“Identificacao_Log”);
obsLogo = rs.getString(“Observacoes_Log”);
editIdentificacao.setText(identLogo);
editObservacoes.setText(obsLogo);

            img = Toolkit.getDefaultToolkit().createImage(rs.getBytes("Imagem_Log"));
            //labelImagem.setIcon(new javax.swing.ImageIcon(img)); // mostrava num JLabel...

            JImagePanel quadroImagem = new JImagePanel(img);
            painelImagem.add(quadroImagem);
            painelImagem.validate();
            // já tentei um monte de métodos por aqui mas sem sucesso...
        }
        rs.close();
        stmt.close();
    }
    catch (SQLException e){
        e.printStackTrace();
    }
    finally {
        conexao.desconectar();
    }
}[/code]

E a classe JImagePanel ficou assim…

[code]public class JImagePanel extends JPanel {
Image background = null;
// note que eu tive que mudar de BufferedImage para Image para aceitar a imagem criada pelo Toolkit
// quando recupero a imagem do array de bytes…

public JImagePanel(Image img) {
    if (img == null)
        throw new NullPointerException("Sem imagem para processar!");
    this.background = img;
}

public JImagePanel(File imgSrc) throws IOException {
    this(ImageIO.read(imgSrc));
}

public JImagePanel(String fileName) throws IOException {
    this(new File(fileName));
}

protected void paintComponent(Graphics g) {
super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g.create();
    g2d.drawImage(background, 0, 0, getWidth(), getHeight(), null);
    g2d.dispose();
    repaint(); // sem esse repaint não aparece nenhuma imagem no panel...
}

}[/code]
Faz ideia???
Aguardo…

Ahhh, outro detalhe…
Tentei adicionar as dimensões que você disse

g2d.drawImage(background, 0, 0, getWidth(), getHeight(), 0, 0, background.getWidth(), background.getHeight(), null);

Porém dá erro porque mudei de BufferedImage para Image e pelo o que entendi não deve aceitar mesmo…

Estranho, aquele repaint ali dentro do paintComponent está completamente errado. Se você fizer isso, vai fazer com que a imagem fique sendo repintada sempre.
Afinal, o repaint faz com que o swing chame o paintComponent e quando ele chega lá, você força um repaint novamente.

No lugar, chame o método invalidate() só no construtor do seu JImagePanel (e sempre que a imagem for substituída).

Quanto ao método de draw, vc pode continuar usando o de assinatura mais simples mesmo. Ele redimensiona a imagem original de acordo com o tamanho que vc passou.
Eu me confundi, o outro é só se vc quiser pegar uma porção da imagem original.

Fera, entendi então o porque das imagens ficarem piscando; era por causa do repaint se repetindo no paintComponent()…
No entanto, o problema apenas se modificou…
Sem o repaint() lá dentro a imagem não é visualizada…
Ocorre o seguinte:
Quando recupero a imagem pra visualiza-la não aparece nada no JPanel, daí, quando seleciono outro registro a imagem anterior aparece no JPanel e fica lá… O JPanel não se atualiza mais e fica mostrando sempre a mesma imagem…
Não tem como eu remover a imagem e atualizar o JPanel quando eu quiser???
Fiz assim:

JImagePanel quadroImagem = new JImagePanel(img); painelImagem.add(quadroImagem); painelImagem.repaint();
Tentei painelImagem.remove(quadroImagem);
Tentei painelImagem.removeAll();
Tentei painelImagem.invalidate();
Tentei painelImagem.validate(); antes de repaint, no lugar do repaint, depois do repaint…
Tentei painelImagem.revalidate();
E nada!!!
Caramba, que canseira!!!
O que mais eu posso fazer???

Ahhh, outra pergunta…
Você não sabe como eu posso recuperar o array de bytes para um BufferedImage ao invés de Image???
Estou fazendo assim…

Image img = Toolkit.getDefaultToolkit().createImage(rs.getBytes("Imagem_Log"));

Queria obter uma BufferedImage…
Valeu!

Use o método ImageIo.read, ao invés do Toolkit. Ele vai ler a imagem como um BufferedImage.
Você chegou a chamar o invalidate() depois que trocou a imagem como eu falei?

Cara, não adianta!
Já havia colocado o invalidate()…
Mas tb não funfou…
Não sei como implementar esse ImageIo.read()…
Já tentei um monte de parafernalias…
O que eu façoooooooooooooo???
Estou entrando em desespero, kkkkk…

Brother, desculpe estar enchendo tanto as paciências, mas dá uma olhada…

BufferedImage imagem = new BufferedImage(painelImagem.getWidth(), painelImagem.getHeight(), BufferedImage.TYPE_INT_RGB); JImagePanel quadroImagem = new JImagePanel(imagem);
Só que no painel aparece tudo preto! Então eu acho que seja porque não passei nenhuma imagem do tipo Image para o “new BufferedImage(…)”, não é mesmo?
Imagina como eu possa passar a imagem que recuperei do banco do tipo Image???