Imagens

Olá pessoal!

Vocês sabem o que devo fazer para salvar uma imagem no banco de dados MySql? Eu presisava redimensiona-la antes para salvar num tamanho estipulado. Na verdade funciona assim:
O usuario carrega a imagem (filechooser) e ela é visualizada num label da tela, na hora de salvar, o programa deveria pegar a imagem do label (imageIcon que ja tem um tamanho limitado que eu defini) em vez de pegar de novo.

Como fazer isso? Creio que algum de vocês ja tenha salvo imagens no banco.

obs: salvar numa pasta e gravar o path da imagem não resolve para o meu caso, questão de segurança.

Agradeço a todos. :thumbup: :thumbup: :thumbup:

acho que é assim:
seulabel.getIcon();//pegar imagem

agora para salvar no banco mysql voce terá que trabalhar com o tipo tinyblob ou similares, que são tipos para armazenar imagens no banco.

pesquise sobre isso no google que voce acha.

Pegar a imagem do label eu sei… :? O que quero saber é como salvar no BD.

package img;
import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Teste extends JFrame{

	{
		//Set Look & Feel
		try {
			javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	private JButton btAbrir;
	private JLabel lbFoto;
	private JButton btSalvar;
	private JPanel paBotoes;
	public static ImageIcon icon;
	public static String arquivo;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Teste t = new Teste();
		t.setVisible(true);
		//setTitle("Testando Imagens em MySql");

	}
	public Teste()
	{
		setBounds(0,0,500,500);
		setLocationRelativeTo(null);
		setResizable(false);
		GridBagLayout thisLayout = new GridBagLayout();
		setTitle("Inserir imagem no Banco");
		thisLayout.rowWeights = new double[] {0.0, 0.1, 0.0, 0.1};
		thisLayout.rowHeights = new int[] {18, 7, 358, 7};
		thisLayout.columnWeights = new double[] {0.0, 0.0, 0.0, 0.1};
		thisLayout.columnWidths = new int[] {16, 104, 356, 7};
		getContentPane().setLayout(thisLayout);
		{
			lbFoto = new JLabel();
			getContentPane().add(lbFoto, new GridBagConstraints(1, 1, 2, 2, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
			lbFoto.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, new java.awt.Color(0,0,0)));
			//lbFoto.setText("|");
		}
		{
			paBotoes = new JPanel();
			FlowLayout paBotoesLayout = new FlowLayout();
			paBotoesLayout.setVgap(30);
			paBotoes.setLayout(paBotoesLayout);
			getContentPane().add(paBotoes, new GridBagConstraints(0, 3, 4, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
			paBotoes.setOpaque(false);
			{
				btAbrir = new JButton();
				paBotoes.add(btAbrir);
				btAbrir.setText("Abrir imagem");
			}
			{
				btSalvar = new JButton();
				paBotoes.add(btSalvar);
				btSalvar.setText("Salvar Imagem");
//// OLHE AQUI ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////				
				btSalvar.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent evt) {
						
						try{
						
						byte[] fileBlob;
						java.io.File f1;
						java.io.FileInputStream fis;
						int fileLength = 0;

						f1  = new java.io.File(arquivo);

						fis = new java.io.FileInputStream(f1);
						fileLength  = (int)f1.length() + 1;
						fileBlob    = new byte[fileLength];
						fis.read(fileBlob);
						fis.close();
						
						if (BD.getConnectionAccess())
						{
							String sql = "insert into img values('"+fileBlob+"')";
							BD.runSQL(sql);
							BD.close();
						}
						}
						catch(Exception ex){ex.printStackTrace();}

					}
				});
//// ACABA AQUI ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////		
			}
		}
		btAbrir.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				boolean imagemValida = false;
				
				while(imagemValida==false)
				{
					try
					{
						JFileChooser fileChooser = new JFileChooser();
						fileChooser.setDialogTitle("Localizar imagem");
						int a = fileChooser.showOpenDialog(null);
						// Se a for igual a zero e porque o usuario clicou em salvar, se for 1 e porque clicou em cancelar
						if (a==0)
						{	
							//[460, 367]
							arquivo = fileChooser.getSelectedFile().getAbsolutePath();// Aqui estou pegando o nome do arquivo e o endereco dele	
							System.out.println(arquivo);//Imprimindo o caminho e o nome do arquivo
							File f = new File(arquivo);
							BufferedImage src = ImageIO.read(f);
							BufferedImage dest = new BufferedImage(460,367,
									BufferedImage.TYPE_INT_RGB);
							Graphics2D g = dest.createGraphics();
							AffineTransform at = AffineTransform.getScaleInstance(
									(double)460/src.getWidth(),
									(double)367/src.getHeight());
							g.drawRenderedImage(src,at);
							//dest agora tem 460x367 pixels e com a imagem redimensionada.


							//ImageIcon icon = new javax.swing.ImageIcon(arquivo);
							icon = new javax.swing.ImageIcon(dest);
							System.out.println("Comprimento da imagem: "+icon.getIconWidth()+"\nAltura da imagem: "+icon.getIconHeight());
							imagemValida = true;
							lbFoto.setIcon(icon);
							}
							
						else
							imagemValida = true;
					}
					catch(Exception ex)
					{
						JOptionPane.showMessageDialog(null, "Este arquivo n\u00E3o \u00E9 uma imagem v\u00E1lida", "Erro", JOptionPane.ERROR_MESSAGE);
						ex.printStackTrace();
					}
				}
			}			
		});
	}

}

Esse é o exemplo.

[code]

package img;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Statement;

public class BD {

public static Connection connection = null;

public static Statement statement = null;

public static ResultSet resultSet = null;

public static String banco;

//public static String host;

//public static Connection conn = null;

public static boolean status;



public static void main(String args[]) {

	getConnectionAccess();

	close();

}



/**

 * metodo que faz conexao com o banco de dados MySql

 * retorna true se houver sucesso, ou false em caso negativo

 */



public static boolean getConnectionAccess() {

	status = false;

	banco=("jdbc:mysql://localhost/imagens?user=root&password=123");

	try {

         Class.forName("com.mysql.jdbc.Driver");

        connection= DriverManager.getConnection( banco );

         status=true;

         System.out.println("++CONECTOU");

        

         

    } catch(ClassNotFoundException e) {

         System.out.println("excessão Classe não encontrada");

         e.printStackTrace();

     } catch(SQLException e) {

         System.out.println("SQL Exception... Não conectado");

         e.printStackTrace();

     }

     

     

	return status;

}





/**

 * Fecha ResultSet, Statement e Connection

 */

public static void close() {

	 try {

         connection.close();

         status=false;

         System.out.println("++DESCONECTOU");

     } catch(SQLException erro) {

         System.out.println("Erro no fechamento");

         //erro.printStackTrace();

     }

}



/**

 * Carrega o resultSet com o resultado do script SQL

 */

public static void setResultSet(String sql) {

	try {

		statement= connection.createStatement();

        resultSet= statement.executeQuery(sql);        

        status = true;    

    } catch(SQLException e) {

        status = false;

        System.out.print("Erro ao executar Query!");

        e.printStackTrace();

    }  

}



/**

 * Executa um script SQL de atualizacao

 * retorna um valor inteiro contendo a quantidade de linhas afetadas

 */

public static int runSQL(String sql) {

	int quant = 0;

	try {

		statement= connection.createStatement();

		quant = statement.executeUpdate(sql);

	} catch(SQLException erro) {

		erro.printStackTrace();

	}

	return quant;

}

}[/code]
Essa é a classe genérica que uso para conectar ao banco.

Tentei fazer esse exemplo em cima do que achei na internet, desta forma eu precisaria pegar a imagem de novo e o tamanho era preservado. E afinal nem dessa forma esse exemplo funciona, ele salva uns dez caracteres só (uma imagem virar dez caracteres :? :?: ) e cada vez que salvo a mesma imagem ele salva um código diferente.

o banco chama imagens e tem só uma tabela chamda img com um campo blob chamado imagem.

qual o tipo de dado que voce colocou na mysql para armazenar a imagem!

na hora em que voce for trazer denovo para sua aplicacao voce tem que retransforma-la em imagem, no banco a armazenagem são uns códigos doidos mesmo.

sei que vai armazenar codigos… o mysql não armazena imagens inteiras (obvio :? ) mas do jeito que quero fazer eu não sei e desse modo não funciona e também não atende as minhas necessidades.

mas entao qual é a sua necessidade?

Você rodou o exemplo? É uma tela com uma área de preview (label) e dois botões (abrir e salvar)
Você seleciona a sua imagem e ela aparece no label só que redimensionada, quando eu clicar em salvar preciso salvar a imagem que está no label (inclusive o tamanho) sem ter a necessidade de pegar atravez da url outra vez. Preciso converter num vetor de byte para salvar num campo blob

A imagem deve ser salva com as dimensões o usuário previsualizou no label, senão ele vai querer salvar uma imagem para colocar num outdor :? :? :?

vi aqui voce ja esta convertendo em um vetor de bytes e ja esta salvando no banco

Não basta saltvar o objeto redimensionado, dest, no banco?

Vinicius, não sei se entendi muito bem mas você recomendou salvar o dest? Ele acaba salvando isto:

ge@716cb7: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 460 height = 367 #Bands = 3 xOff = 0 yOff =
0] 0 |

Sim, mas vc não vai salvar o toString da imagem no banco.

E sim, usar o ImageIO.write para salvar os bytes da imagem no seu campo BLOB. Talvez seja necessário uma coluna extra para salvar também o tipo do dado.

Vinicius… desculpa a ignorância… li a api e não entendi quase nada… achei algo para gravação de imagem mas grava em um diretório… teria como vc mostrar um exemplo?

desculpa a burrice :oops: e obrigado pela ajuda :thumbup:

Primeiro você terá que alterar o seu método runSQL. Ele não usa o PreparedStatement, o que é péssimo, pois pode sofrer SQL Injection e não suporta BLOBs. Deixe ele assim:

[code]public static int runSQL(String sql, Object… values) {
try {
PreparedStatement ps = connection.prepareStatement(sql);
for (int i = 0; i < values.length; i++) {
if (values[i] instanceof Number) {
ps.setInt(i + 1, ((Number) values[i]).intValue());
} else if (values[i] instanceof String) {
ps.setString(i + 1, (String) values[i]);
} else if (values[i] instanceof RenderedImage) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write((RenderedImage) values[i], "png", bos);
ps.setBlob(i + 1, new ByteArrayInputStream(bos.toByteArray()));
}
}

    return ps.executeUpdate();
} catch (SQLException erro) {
    // Péssima prática. Você está ignorando o erro.
    erro.printStackTrace();

} catch (IOException e) {
    e.printStackTrace();
}

return -1;

}[/code]

E então use assim (por exemplo):

String nomeImagem = &quot;teste.png&quot;; BufferedImage imagem = ImageIO.read(new File(nomeImagem)); BD.runSql(&quot;INSERT INTO Image(nome, imagem) VALUES(?, ?)&quot;, nomeImagem, imagem);

PS: Você pode simplificar muito esse código usando o Spring. Ele já tem suporte a um método muito similar a esse runSql, que recebe um array de objetos. Mas ele já implementa boas práticas, como manter a conexão fechada, suporte a pool de conexões, tratamento adequado de exceções e garantir que seus statements sejam fechados num bloco finally (coisa que vc não fez em lugar nenhum, e certamente você esbarrará em falta de memória no futuro).

Por que você não pode salvar apenas o path?
Creio que não seja por segurança, nesse caso tanto faz salvar no banco ou em diretorio.
Se salvar em diretorio você também pode restringir acesso com no banco.
Se alguém descobrir sua senha de acesso ao diretorio também pode descobrir sua senha de acesso ao banco.