Publicado em C#, MySQL, Programação, WPF

Manipulação de imagens associadas a um “Image Control” – Ficheiro> source>MySQL

trio3

Com este exemplo pretendo demonstrar algumas formas de manipular imagens no contexto de uma aplicação escrita na linguagem C# (WPF). Para o efeito vamos considerar a imagem quando armazenada num ficheiro de disco, a imagem carregada para o controlo Image e a imagem quando armazenada numa base de dados (MySQL).

Por uma questão de simplificação apenas vou considerar o formato JPEG.

Em síntese, com a aplicação aqui apresentada, pretendo dar resposta às seguintes questões:

  • Como carregar a imagem de um Resource Dictionary para um controlo Image?
  • Como carregar uma imagem armazenada em disco para um controlo Image?
  • Como carregar os dados da base de dados para a DataGrid, sendo um dos campos do tipo BLOB?
  • Como inserir um registo na base de dados, sendo um dos campos do tipo imagem (Blob)?
  • Como copiar uma imagem do registo selecionada na DataGrid para outra imagem (área de preview)?
  • Como guardar em disco uma imagem exibida num controlo Image?
  • Como guardar em disco uma imagem exibida num campo de uma DataGrid?
  • Como copiar a imagem exibida num campo de uma DataGrid para um controlo Image?

O Código completo pode ser descarregado aqui.

De forma a poder testar a aplicação é necessária uma base de dados “db“, a tabela “imagem” com a estrutura apresentada na imagem e, por fim, o utilizador “user” com a palavra-passe “123” e respetivos privilégios de acesso.

imagem

A forma mais simples de conseguir tudo isto num único passo será utilizando o ficheiro “db.mwb” que, depois de aberto utilizando o MySQL Workbench, facilmente executa estas tarefas recorrendo à opção “Forward Engineer…“.

dbfe

 

Uma vez preparada a base de dados, podemos testar as funcionalidades executando a aplicação. Este vídeo faz uma demonstração do funcionamento do programa.

Passemos então à resposta das questões formuladas.

Como carregar a imagem de um Resource Dictionary para um controlo Image?

Uma forma de organizar ficheiro gráficos no contexto da aplicação consiste em utilixzarum Resource Dictionary.

As duas imagens seguintes indicam a sua forma de configuração.

ptrscr01ptrscr02

Assim sendo, podemos carregar a imagem correspondente a uma moldura vazia, no arranque da aplicação, bastando para o efeito indicar a source da imagem a partir da designação utilizada no Resource Dictionary.

<Image x:Name="previewImage" Grid.Row="1" Source = "{StaticResource molduraImage}" />

Como carregar uma imagem armazenada em disco para um controlo Image?

Surge um diálogo que permite selecionar o ficheiro, sendo de seguida este carregado para a interface.

//Abre um imagem armazenada num ficheiro de disco carrega-a para a área de preview
private void AbrirImagemDiscoButton_Click(object sender, RoutedEventArgs e)
{
    OpenFileDialog ofdImage = new OpenFileDialog();
    ofdImage.Filter = "JPEG Files|*.jpg";
    ofdImage.DefaultExt = "jpg";
    ofdImage.FilterIndex = 1;
    if (ofdImage.ShowDialog() == true)
    {
        previewImage.Source = new BitmapImage(new Uri(ofdImage.FileName));
        nomeFicheiroWindowLabel2.Content = ofdImage.SafeFileName.ToString();
    }
}

Como carregar os dados da base de dados para a DataGrid, sendo um dos campos do tipo BLOB ?

A DataGrid em questão é a seguinte:

<DataGrid Grid.Row="0" AutoGenerateColumns="False" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Left" Name="dataGridImagem" ItemsSource="{Binding Path=carregarDados}" Margin="5" SelectionMode="Single" CanUserAddRows="False" CanUserDeleteRows="False" SelectedCellsChanged="dataGridImagem_SelectedCellsChanged" >
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Path=idImagem}" Header="Código" Width="Auto" IsReadOnly="True" />
        <DataGridTemplateColumn Header="Imagem"  IsReadOnly="True" Width="Auto">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Image Source="{Binding imagemImagem}" Width="10" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTextColumn Binding="{Binding Path=imagemDescricao}" Header="Imagem" Width="*" IsReadOnly="True" />
    </DataGrid.Columns>
    <DataGrid.RowDetailsTemplate>
        <DataTemplate>
            <Image Height="100" Source="{Binding imagemImagem}" />
        </DataTemplate>
    </DataGrid.RowDetailsTemplate>
</DataGrid>

Sempre que pretendemos carregar este controlo com os dado da tabela imagem invocamos o método seguinte:

//Carrega os dados da tabela imagem, da base de dados db, para a DataGrid
private bool carregarDados()
{
    bool status = false;
    try
    {
        ligacaoBD.Open();
        MySqlCommand comandoMySQL = new MySqlCommand("Select * from db.imagem", ligacaoBD);
        MySqlDataAdapter adp = new MySqlDataAdapter(comandoMySQL);
        DataSet ds = new DataSet();
        adp.Fill(ds, "carregarDados");
        dataGridImagem.DataContext = ds;
        status = true;
        dataGridImagem.SelectedIndex = 0;
    }
    catch (MySqlException ex)
    {
        MessageBox.Show(ex.ToString());
    }
    finally
    {
        ligacaoBD.Close();
    }
    return status;
}

Neste caso não temos que nos preocupar com a imagem, uma vez que os objetos das classe utilizados processam tudo de forma automática.

Como inserir um registo na base de dados, sendo um dos campos do tipo imagem (Blob)?

Assumindo que foi carregada uma imagem para a área de preview, para a inserir na base de dados executamos o código seguinte:

//Inserir na Base de Dados a imagem exibida na área de preview
private void inserirImagemDBButton_Click(object sender, RoutedEventArgs e)
{
    //Converter a imagem num byte array
    byte[] ImageData = getJPGFromImageControl(previewImage.Source as BitmapImage);
    try
    {
        //Inserir o registo na base de dados
        ligacaoBD.Open();
        MySqlCommand comandoMySQL = new MySqlCommand(string.Format("INSERT INTO `db`.`imagem` (`imagemImagem`, `imagemDescricao`) VALUES (?image, '{0}');", nomeFicheiroWindowLabel2.Content), ligacaoBD);
        MySqlParameter parImage = new MySqlParameter();
        parImage.ParameterName = "?image";
        parImage.MySqlDbType = MySqlDbType.LongBlob;
        parImage.Value = ImageData;
        comandoMySQL.Parameters.Add(parImage);
        comandoMySQL.ExecuteNonQuery();
    }
    catch (MySqlException ex)
    {
        MessageBox.Show(ex.ToString());
    }
    finally
    {
        ligacaoBD.Close();
        if (!carregarDados()) MessageBox.Show("Ocorreu um erro inesperado ...");
    }
}

Como copiar uma imagem do registo selecionada na DataGrid para outra imagem (área de preview)?

Nesta caso pretendemos copiar a imagem que corresponde ao registo selecionado na DataGrid para a source do controlo Image correspondente à área de preview.

//Exibir a imagem selecionada na DataGrid na área de preview
private void previewSelectedImage()
{
    if (dataGridImagem.SelectedIndex != -1)
    {
        DataRowView selectedRecord = (DataRowView)dataGridImagem.SelectedItem;
        var bytes = selectedRecord.Row.ItemArray[1] as byte[];
        var mStream = new MemoryStream(bytes);
        var image = new BitmapImage();
        image.BeginInit();
        image.StreamSource = mStream;
        image.EndInit();
        previewImage.Source = image;
        nomeFicheiroWindowLabel2.Content = selectedRecord.Row.ItemArray[2].ToString();
    }
    else
        dataGridImagem.SelectedIndex = 0;
}

Como guardar em disco uma imagem exibida num controlo Image?

Uma funcionalidade interessante consiste em poder gravar no disco as imagens exibidas num controlo Image.

O processo é relativamente simples:

//Criar um ficheiro no disco correspondente à imagem exibida na área de preview
private void guardarImagemDiscoDoPreviewButton_Click(object sender, RoutedEventArgs e)
{
    try
    {
        //Converter source da imagem num byte array
        byte[] ImageData = getJPGFromImageControl(previewImage.Source as BitmapImage);

        //Save As Dialog ...
        Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
        dlg.FileName = "imagem";
        dlg.DefaultExt = ".jpg";
        dlg.Filter = "Imagem JPEG|*.jpg";
        Nullable<bool> result = dlg.ShowDialog();

        //Gravar a imagem no disco
        using (Image image = Image.FromStream(new MemoryStream(ImageData)))
        {
            image.Save(dlg.FileName, ImageFormat.Jpeg);  // Ou Png ...
        }
    }
    catch
    {
        MessageBox.Show("Nenhuma imagem foi ainda carregada.", "ERRO!", MessageBoxButton.OK, MessageBoxImage.Error);

    }
}

Como guardar em disco uma imagem exibida num campo de uma DataGrid?

Muito semelhante ao exemplo anterior, mas desta vez a imagem corresponde a uma coluna do registo selecionado na DataGrid:

//Criar um ficheiro no disco correspondente à imagem exibida no registo actual da DataGrid
private void guardarImagemDiscoButton_Click(object sender, RoutedEventArgs e)
{
    //Save As Dialog ...
    Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
    dlg.FileName = "imagem";
    dlg.DefaultExt = ".jpg";
    dlg.Filter = "Imagem JPEG|*.jpg";
    Nullable<bool> result = dlg.ShowDialog();

    //Guardar a imagem relativa ao registo selecionado na DataGrid
    DataRowView selectedRecord = (DataRowView)dataGridImagem.SelectedItem;
    var bytes = selectedRecord.Row.ItemArray[1] as byte[];
    var myStream = new MemoryStream(bytes);
    Image img = System.Drawing.Image.FromStream(myStream);
    img.Save(dlg.FileName, ImageFormat.Jpeg);
}

Como copiar a imagem exibida num campo de uma DataGrid para um controlo Image??

Neste caso temos que recorrer a algumas operações de streaming de forma a transferir a imagem:

//Exibir a imagem selecionada na DataGrid na área de preview
private void previewSelectedImage()
{
    if (dataGridImagem.SelectedIndex != -1)
    {
        DataRowView selectedRecord = (DataRowView)dataGridImagem.SelectedItem;
        var bytes = selectedRecord.Row.ItemArray[1] as byte[];
        var mStream = new MemoryStream(bytes);
        var image = new BitmapImage();
        image.BeginInit();
        image.StreamSource = mStream;
        image.EndInit();
        previewImage.Source = image;
        nomeFicheiroWindowLabel2.Content = selectedRecord.Row.ItemArray[2].ToString();
    }
    else
        dataGridImagem.SelectedIndex = 0;
}

O código fonte ainda contém algumas funcionalidades que não foram aqui exploradas.

Bom trabalho!

 

Anúncios

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s