Coletando assinaturas em WPF e Windows Forms - André Alves de Lima
Nos últimos anos, principalmente devido às questões ambientais, o assunto "eliminação de papel" ganhou um certo destaque. E no que isso afeta a nós, programadores, desenvolvedores de software? Isso nos afeta diretamente, pois, muito provavelmente, durante o planejamento de aplicativos de negócios, a questão de eliminação de papel será lançada. Como podemos eliminar a impressão de relatórios nos nossos sistemas? Uma maneira muito interessante de alcançarmos esse objetivo é coletarmos assinaturas diretamente nos nossos aplicativos. E no artigo de hoje aprenderemos a coletar assinaturas em WPF e Windows Forms.
A questão de coleta de assinaturas em aplicativos é um assunto muito amplo. Basicamente, antes de adicionar a capacidade de coletar assinaturas na sua aplicação, você deve pensar pelo menos nestes quatro detalhes:
1 – Como coletar as assinaturas: dependendo da tecnologia que você estiver utilizando para desenvolver o seu aplicativo, você terá que utilizar controles diferentes para fazer a coleta das assinaturas. Neste artigo, veremos como coletar assinaturas em WPF e Windows Forms
2 – Como proteger as assinaturas coletadas: como assinaturas são informações sensíveis, muito provavelmente você terá que pensar em uma forma de criptografá-las
3 – Como armazenar as assinaturas: uma vez coletadas e protegidas, devemos pensar em como armazenar as assinaturas (se é que devemos armazená-las)
4 – Como reconhecer que a assinatura pertence a uma pessoa: dependendo dos requerimentos da sua aplicação, você terá que fazer um reconhecimento na assinatura para identificar se ela realmente pertence àquela pessoa que assinou
Uma vez que você tenha pensado nesses quatro pontos, você está pronto para começar a coletar assinaturas no seu aplicativo. Como você deve ter percebido, o tema de coleta de assinaturas é bem extenso. Nesse artigo abordarei principalmente a questão da coleta das assinaturas.
Coletando assinaturas em WPF
Coletar assinaturas no WPF é ridiculamente simples. O controle InkCanvas possibilita que desenhemos na tela, o que o torna candidato perfeito para fazermos coleta de assinaturas. Para vermos o quão simples é a utilização desse controle, crie um novo projeto do tipo "WPF Application" e altere o layout da MainWindow de forma que ela fique parecida com a imagem abaixo:
Confira abaixo o XAML correspondente ao Grid dessa MainWindow:
<TextBlock>Assine dentro do bloco abaixo:</TextBlock>
<InkCanvas x:Name="AssinaturaCanvas"
Height="110" />
<Button x:Name="LimparButton"
Click="LimparButton_Click"
Margin="2">Limpar</Button>
<Button x:Name="SalvarButton"
Click="SalvarButton_Click"
Margin="2">Salvar</Button>
O único detalhe importante nesse código é que colocamos o InkCanvas dentro de um Border. Temos que fazer isso pois, devido a vários relatos encontrados durante a minha pesquisa, se não tivermos a Border, ao salvarmos a imagem do InkCanvas, pedaços dos controles à sua volta podem ser salvos na imagem, e esse não é o resultado que estamos querendo.
Agora vá para o code-behind da MainWindow e adicione o handler para o evento "Click" do botão "Limpar", que dispensa comentários:
private void LimparButton_Click(object sender, RoutedEventArgs e)
AssinaturaCanvas.Strokes.Clear();
Já o código do evento "Click" do botão "Salvar" é um pouco mais extenso, mas, nada muito complicado:
private void SalvarButton_Click(object sender, RoutedEventArgs e)
using (System.IO.FileStream fs = new System.IO.FileStream("assinatura.png", System.IO.FileMode.Create))
RenderTargetBitmap rtb = new RenderTargetBitmap((int)AssinaturaCanvas.ActualWidth, (int)AssinaturaCanvas.ActualHeight, 96d, 96d, PixelFormats.Default);
rtb.Render(AssinaturaCanvas);
O trecho de código acima apresenta o código típico para salvarmos qualquer controle no WPF em formato imagem. Primeiramente criamos um RenderTargetBitmap utilizando as informações do controle e depois chamamos o método Render passando o controle a ser renderizado. Depois, criamos uma instância do encoder desejado (no nosso caso um PngBitmapEncoder, para salvarmos a imagem no formato "png"), adicionamos o frame no encoder e salvamos o resultado dentro de uma Stream (no nosso caso uma FileStream apontando para o arquivo "assinatura.png", que será criado ou substituído).
Coletando assinaturas em Windows Forms
A coleta de assinaturas no Windows Forms não é idêntica à maneira utilizada no WPF, mas, é um tanto quanto parecida. A principal diferença é que, no Windows Forms, não temos a facilidade de contarmos com um controle nativo com suporte a Ink. Nesse caso, temos que recorrer a uma biblioteca disponível no próprio .NET Framework (que está, porém, muito bem escondida!).
Para vermos como coletar assinaturas em Windows Forms, vamos começar criando um projeto do tipo "Windows Forms Application". No Form criado pelo Visual Studio, altere o seu layout de forma que ele fique parecido com a imagem abaixo:
Basicamente adicionamos um Label, um Panel (com Foreground configurado com a cor branca) e dois botões. Feito isso, vamos adicionar a referência à biblioteca que precisamos para desenharmos no Panel com Ink. Essa biblioteca é a Microsoft.Ink, e está muito bem escondida em algum lugar do diretório "C:\Windows\WinSxS". A minha, por exemplo, estava neste diretório:
Faça uma busca por "Microsoft.Ink.dll" e você vai achar onde essa dll está instalada no seu computador.
Uma vez adicionada a referência, podemos inicializar o suporte ao Ink no nosso Panel. Fazemos isso criando uma instância de InkCollector passando o Panel no construtor e configurando a propriedade Enabled como "true". Devemos separar a inicialização do InkCollector em um método, pois utilizaremos esse mesmo método para limpar o conteúdo da assinatura:
Microsoft.Ink.InkCollector inkCollector;
public FormAssinatura()
InicializarInkCollector();
private void InicializarInkCollector()
inkCollector = new Microsoft.Ink.InkCollector(assinaturaPanel);
Para limpar a assinatura, temos que primeiramente limpar o Panel (preenchendo-o totalmente com um retângulo branco) e reinicializarmos o InkCollector. Se não reinicializarmos o InkCollector, ao salvarmos a assinatura, o resultado será uma mistura de todas as assinaturas realizadas no Panel (e não somente a última assinatura). Veja o resultado abaixo:
private void limparButton_Click(object sender, EventArgs e)
var graphics = assinaturaPanel.CreateGraphics();
graphics.FillRectangle(new SolidBrush(Color.White), assinaturaPanel.ClientRectangle);
inkCollector.Enabled = false;
Finalmente, para salvarmos a assinatura, não podemos simplesmente salvar a imagem do Panel (se tentarmos fazer isso, o resultado será uma imagem vazia). A maneira correta de salvarmos a assinatura é utilizarmos o método Save da propriedade Ink do InkCollector. Esse método retornará um array de bytes com o resultado da imagem. Com esse array de bytes em mãos, chamamos o método WriteAllBytes da classe File e salvamos a imagem em um arquivo:
System.IO.File.WriteAllBytes("assinatura.gif", inkCollector.Ink.Save(Microsoft.Ink.PersistenceFormat.Gif));
Note que o único formato de imagem suportado é o "gif". Porém, caso necessário, é muito fácil converter entre os formatos de imagens em C#.
Armazenamento, proteção e reconhecimento de assinaturas
Nesse artigo, aprendemos a coletar as assinaturas e armazená-las em um arquivo no diretório da aplicação. Se você quiser aprender a salvar essas imagens no banco de dados, confira o artigo onde eu mostro como salvar imagens no banco de dados utilizando C#.
Como mencionei no início desse artigo, é recomendado que façamos a proteção das assinaturas com algum tipo de criptografia. Não vou abordar esse assunto aqui, pois ele é muito extenso. Quando eu escrever sobre criptografia com C# eu volto aqui e atualizo esse artigo.
Além disso, também não vou escrever sobre o reconhecimento de assinaturas, pois esse é um tópico totalmente à parte. Talvez algum dia eu escreva um artigo explicando o seu funcionamento.
Por enquanto, caso você se interesse por proteção e reconhecimento das assinaturas coletadas, sugiro que você dê uma olhada neste artigo.
Neste artigo você aprendeu a coletar e armazenar em disco assinaturas digitalizadas, tanto em WPF quanto em Windows Forms. Espero que as dicas apresentadas aqui te ajudem caso essa funcionalidade se encaixe no escopo do seu aplicativo. Se esse for o caso, utilize essas dicas, incremente-as e depois nos conte o resultado nos comentários!
Para ficar por dentro das novidades deste site, assine a minha newsletter. Além de saber em primeira mão os artigos que serão publicados, você recebe dicas exclusivas que eu só compartilho por e-mail! Assine aqui ou através do formulário logo abaixo.
Image by Sebastien Wiertz used under Creative Commons
https://www.flickr.com/photos/wiertz/4563720850/
Férias na Itália 2015 Implementando uma janela de login com Windows Forms ou WPF
6 thoughts on "Coletando assinaturas em WPF e Windows Forms"
Bons textos André!!!
Estou usando o seu site como referência nos meus projetos.
Dúvida. Estou usando o Win10, tentei procurar a DLL citada. Eu encontrei ela nos diretórios que vc comentou (parecidos, só trocando a versão), porém, ao adicioná-la no projeto, recebo a seguinte mensagem: Não é possível adicionar uma referência a … Assegure-se que o arquivo está acessível, que é um assembly válido ou um componente COM.
Sabe me dizer do que se trata? E como eu posso resolver?
Existe alguma outra forma de habilitar tais funcionalidades no meu projeto?
Só tem uma pasta com algo relacionado a "Microsoft.Ink.dll" dentro da pasta "C:\Windows\WinSxs" do seu computador? No meu computador com Windows 10, tenho três pastas que têm algo relacionado a Microsoft.Ink.. Ao tentar adicionar a referência utilizando a primeira pasta, eu recebi o mesmo erro que você recebeu.. Porém, com a dll das outras duas pastas, a referência funcionou sem problema nenhum..
Não. Existem várias pastas (em torno de 4) com a DLL dentro. inclusive notei que algumas se tratavam de x86 e outras eram x64.