Desenvolvimento - Visual Basic

Como Armazenar Imagens no Banco de Dados

Crie uma maneira fácil de salvar e recuperar imagens no seu aplicativo VB e no banco de dados do Microsoft Access.

por Stan Schultes



Seja quais forem seus planos (incluir gráficos no programa, criar formulários de entrada de dados ou projetar um banco de dados para o seu site Web), a criação de um método fácil para modificar e adicionar imagens em um banco de dados dará maior flexibilidade e portabilidade aos seus aplicativos. No entanto, você precisa escolher com cuidado o método mais apropriado para o seu aplicativo. Nesta coluna, abordaremos as diferentes maneiras de manipular imagens como objetos ou ponteiros de arquivos no banco de dados do aplicativo.

Os clientes estão sempre pedindo dicas sobre como exibir o logotipo da empresa e outras imagens em diferentes locais no aplicativo. Da mesma forma, os projetos Web geralmente requerem que cada registro possua uma imagem associada aos dados. As imagens oferecem uma maneira fácil de associar visualmente um item aos dados do registro. O problema é que essas imagens mudam constantemente, e os clientes estão sempre adicionando imagens novas. O seu aplicativo deve ser capaz de dar aos clientes a flexibilidade de que necessitam.

O Visual Basic oferece várias maneiras de armazenar imagens (como, por exemplo, usar o controle ImageList), porém esses métodos requerem a recompilação do aplicativo e geralmente são restritos a um número limitado de imagens. A melhor maneira de armazenar imagens é incluí-las em um banco de dados. É possível fazer isso de duas maneiras: armazenando a imagem como um BLOB (Binary Large Object) em um campo do banco de dados ou armazenando um indicador, ou “ponteiro”, para a localização do arquivo no disco. Cada um desses métodos oferece vantagens e desvantagens.

Por exemplo, armazenar imagens como um BLOB pode aumentar muito o tamanho do banco de dados, embora as imagens fiquem armazenadas em uma localização central, única. Já o armazenamento de imagens como um ponteiro de arquivo permite diminuir consideravelmente o tamanho do banco de dados, mas por outro lado, faz com que qualquer arquivo inválido ou ausente cause problemas mais tarde.

Dependendo de sua preferência, você precisará pesar esses dois fatores (tamanho e eficiência) para decidir qual método será o mais indicado para um aplicativo específico. Descreveremos ambos os métodos usando ADO (Microsoft ActiveX Data Objects) para salvar e recuperar imagens em um banco de dados do Access 97. O código será idêntico se você quiser usar um banco de dados do Access 97, mas nesse caso será necessário fazer o download e a instalação do último pacote MDAC (Microsoft Data Access Components).

Como Criar Banco de Dados

Você criará um aplicativo simples para armazenar uma biblioteca de imagens elementar. Antes de iniciar o projeto VB, crie o banco de dados em que irá armazenar os dados. Inicie o Access e crie uma nova tabela, denominada ImageLibrary. Adicione os campos e propriedades necessários (consulte a Tabela 1).

Tabela 1: Criação da tabela ImageLibrary. Configure sua tabela no Access 97 ou 2000 com esses campos. Defina o campo ID como a chave primária (PrimaryKey).

Nome de campo Tipo de campo Tamanho
ID AutoNumber Long Integer
ImageTitle Text 100
ImagePath Text 255
ImageBLOB OLEObject n/d

Depois de criar o banco de dados, inicie o VB, escolha Project | References e selecione Microsoft ActiveX Data Objects 2.1 Library (ou use a biblioteca ADO 2.5, se estiver instalada). Nomeie o formulário padrão do projeto frmMain. Projete seu formulário de forma a atender a suas necessidades de armazenamento de imagens. O projeto da tabela ImageLibrary foi configurado para permitir que você selecione como desejará armazenar as imagens no banco de dados (consulte a Figura 1).

Aprimore sua imagem<br />
<p><strong>Figura 1:</strong> Aprimore sua imagem</p>
<p>Decidir como salvar as imagens no banco de dados é uma etapa importante. O exemplo de projeto permite que você teste ambos os métodos para decidir qual é o melhor para o seu aplicativo.</p>

<p>Você precisa adicionar as variáveis que fazem referência ao recordset e à conexão do banco de dados. Posteriormente, você usará essas variáveis para navegar no banco de dados e também para adicionar e editar registros. Adicione essas variáveis à seção Declaration do frmMain:</p>

<p>

Conn.ConnectionString = _

"Provider=Microsoft.Jet.OLEDB" & _

".3.51;Data Source=" & App.Path & _

"\ImageLib.mdb"

Conn.Open

"Abra o recordset

Set rs = New ADODB.Recordset

rs.Open "ImageLibrary", Conn, _

adOpenKeyset, adLockPessimistic, adCmdTable

Em seguida, você precisará estabelecer a conexão com o banco de dados e recordset. Certifique-se de que o arquivo ImageLib.mdb esteja no caminho do aplicativo e adicione esse código ao evento frmMain_Load:

Com o recordset aberto, é hora de começar a visualizar e modificar os dados no registro. O primeiro passo será aprender a salvar e recuperar a imagem real no banco de dados usando os métodos GetChunk e AppendChunk. Esses dois métodos podem ser usados para exibir um campo BLOB armazenado no banco de dados. No primeiro método, bastará apenas especificar as propriedades DataSource e DataField do controle Image para o campo BLOB e para o recordset já aberto:

Set imgDBImage.DataSource = rs

imgDBImage.DataField = "ImageBLOB"

Seguir esse método é geralmente a maneira mais fácil de começar a exibir as imagens armazenadas no banco de dados. No entanto, os arquivos maiores poderão pesar na memória do sistema quando o controle Image tentar carregar no banco de dados. Se espaço na memória for um problema para seu aplicativo devido a arquivos de imagens muito grandes, use o segundo método – o método GetChunk – para recuperar objetos binários do banco de dados. Esse método permite especificar o número de bytes (blocos) a serem recuperados do campo BLOB. Você poderá carregar o objeto armazenado nesses blocos menores (no caso das imagens maiores) ou em um único bloco:

strData = rs("ImageBLOB"). _

GetChunk(rs("ImageBLOB").ActualSize)

A desvantagem do método GetChunk: como a propriedade de figura do controle Image não pode ler o vetor de bytes carregado do banco de dados, você precisará antes salvar um arquivo temporário do campo de dados e, em seguida, ler esse arquivo com o método LoadPicture. Apesar dessa falha, o método GetChunk é na verdade mais rápido do que definir as propriedades de dados do controle Image.

Como Determinar o Melhor Método

Criamos uma tabela com 100 registros e fizemos um pequeno teste para determinar qual método era mais rápido. Cada registro continha dados binários de aproximadamente 50 K. Efetuamos um loop em todos os registros na tabela e visualizamos os dados armazenados em um controle Image. O método DataField foi concluído em 58 segundos, enquanto o método GetChunk levou apenas 27 segundos (com um tamanho de bloco de 100 bytes). Como essas imagens específicas não eram muito grandes, recuperamos o objeto todo em um único bloco. Esse método resultou no tempo mais rápido: 18 segundos. Ou seja, você precisa descobrir qual o melhor método a ser usado em seus aplicativos. Para acompanhar este artigo, use o método GetChunk com um tamanho de bloco de 100 bytes (consulte a Listagem 1).

Listagem 1: Recupere um registro do banco de dados e propague os campos no formulário.

Public Sub FillFields() 
"Preencha os campos com dados do registro 
Dim lngImageSize As Long 
Dim lngOffset As Long 
Dim bytChunk() As Byte 
Dim intFile As Integer 
Dim strTempPic As String Const conChunkSize = 100 
Dim strImage As String 
If Not (rs.BOF And rs.EOF) Then 
txtImageTitle.Text = rs.Fields("ImageTitle") 

If Trim$("" & rs.Fields("ImagePath")) = "" Then 
"Imagem foi salva como um BLOB 
txtImagePath.Text = "" 
optImageType(1).Value = True 

"Certifique-se de que o arquivo temporário 
"ainda não exista 
strTempPic = App.Path & "\TempPic.jpg" 
If Len(Dir(strTempPic)) > 0 Then 
Kill strTempPic 
End If 
"Abra o arquivo temporário para salvar o BLOB em 
intFile = FreeFile 
Open strTempPic For Binary As #intFile 

"Leia os dados binários contidos 
"no vetor da variável de byte 
lngImageSize = rs("ImageBLOB").ActualSize 
Do While lngOffset < lngImageSize 
bytChunk() = rs _ 
("ImageBLOB").GetChunk(conChunkSize)
Put #intFile, , bytChunk()
lngOffset = lngOffset + conChunkSize 
Loop 
Close #intFile 
"Depois de carregar a imagem, exclua 
"o arquivo temporário 
imgDBImage.Picture = LoadPicture(strTempPic) 
Kill strTempPic 
Else "Imagem foi salva como um ponteiro de arquivo 
txtImagePath.Text = rs.Fields("ImagePath") 
optImageType(0).Value = True 
If Not IsNull(rs.Fields ("ImagePath")) Then 
strImage = Trim$("" & rs.Fields("ImagePath")) 
If Len(Dir(strImage)) Then 
imgDBImage.Picture = LoadPicture(strImage) 
Else 
imgDBImage.Picture = LoadPicture() 
End If 
End If 
End If 
End If 
End Sub

Se o caminho da imagem estiver vazio, o programa deduzirá que a imagem foi armazenada como um BLOB. O procedimento presumirá que você abriu o recordset (rs) e posicionou-o no registro correto.

Assim como acontece no processo de recuperação de imagens armazenadas, salvar uma imagem no banco de dados também requer antes a conversão de imagem em um vetor de bytes. Uma vez feito isso, você poderá usar o método AppendChunk para gravar os bytes no campo do banco de dados. No código, grave os dados no campo em uma única etapa, atribuindo ao bloco o mesmo tamanho atribuído ao arquivo de imagem (consulte a Listagem 2).

Listagem 2: Salve o registro no banco de dados

Private Sub SaveToDB() 
Dim bytBLOB() As Byte 
Dim strImagePath As String 
Dim intNum As Integer 

"Salve o registro 
strImagePath = Trim$(txtImagePath.Text) 
With rs 
.Fields("ImageTitle") = _ 
Trim$(txtImageTitle.Text)

If (optImageType(0).Value) Then 
"Salve como um ponteiro de arquivo 
.Fields("ImagePath") = strImagePath 
Else
If (txtImagePath.Text <> "") Then 
"Abra o arquivo de imagens
intNum = FreeFile 
Open strImagePath For Binary As #intNum 
ReDim bytBLOB (FileLen(strImagePath)) "Leia os dados e feche o arquivo 
Get #intNum, , bytBLOB 
Close #1 

"Armazene o BLOB 
.Fields("ImagePath") = "" 
.Fields("ImageBLOB").AppendChunk bytBLOB 
End If 
End If 
.Update 
End With 
End Sub

. Dependendo do botão de opção selecionado, você salvará a imagem no banco de dados como um arquivo de ponteiro ou como um BLOB. O procedimento presumirá que você posicionou o recordset (rs) em um novo registro ou que está editando o registro atual (rs.Edit).he current record (rs.Edit).

No exemplo de projeto, apenas o primeiro caminho será armazenado no banco de dados se você escolher salvar a imagem como um ponteiro de arquivo, o que reduz o tamanho do banco de dados e aumenta a velocidade do aplicativo. O procedimento FillFields na Listagem 1 determina primeiro se o campo ImagePath contém um valor. Se você salvou um caminho com o registro, a imagem será armazenada como um ponteiro de arquivo. Caso contrário, a imagem será armazenada como um BLOB (consulte o método GetChunk descrito anteriormente). O ponteiro armazenado pode ser facilmente exibido usando-se o método LoadPicture do controle Image.

A vantagem de armazenar imagens como um arquivo de ponteiro é que apenas o caminho do arquivo é salvo. Isto significa que o banco de dados não crescerá tanto como cresceria se a imagem fosse armazenada em um campo BLOB. No exemplo descrito anteriormente, com 100 registros de imagens de 50 K armazenados em campos BLOB, o banco de dados alcançou 4 MB. O mesmo banco de dados, quando utilizou ponteiros de arquivo, não chegou a 100 K. Do ponto de vista da velocidade, o método de ponteiro de arquivo venceu, completando o teste em cinco segundos. Essas vantagens geralmente justificam a preferência pelo método de ponteiros de arquivos quando se fala em salvamento de imagens.

A principal desvantagem do método de ponteiro de arquivo é o fato de que, se houver alguma mudança nas localizações do arquivo, o seu aplicativo não poderá carregar a imagem. Outra desvantagem é a pouca portabilidade do aplicativo. Se você mover o aplicativo para outro local, precisará mover o banco de dados e todos os arquivos de imagem para os quais ele aponta. Uma maneira de amenizar esses problemas é salvar a UNC (Universal Naming Convention) do arquivo, em vez de sua localização real no disco (por exemplo, \\andyr\images\test.jpg em vez de c:\images\test\jpg). Evidentemente, se precisar enviar o aplicativo para clientes externos, estes provavelmente não terão acesso aos mesmos recursos que você (a não ser que você salve o ponteiro de arquivo como uma imagem na Internet, como em www.yoursite.com/images/test.jpg). Provavelmente, essa é a única situação em que seria recomendado salvar a imagem no banco de dados como um objeto binário. Ou seja, os ganhos em relação a velocidade e tamanho do arquivo só compensarão se você souber com antecedência que as mudanças na localização dos arquivos prejudicarão o aplicativo.

Por fim, você deve estar se perguntando se poderá usar esses métodos para armazenar imagens em bancos de dados SQL Server. Embora os métodos AppendChunk e GetChunk também funcionem nesses bancos de dados, a Microsoft desaconselha seu uso porque as colunas de BLOB nas tabelas SQL prejudicam o desempenho do servidor. No caso de tabelas SQL, a Microsoft recomenda armazenar um ponteiro para a localização do arquivo.

No início, você levará algum tempo até armazenar as imagens de todos os seus aplicativos no banco de dados, mas os resultados aparecerão rapidamente. Agora, você pode criar um formulário de entrada de dados para atualizar as imagens de seu site. Além disso, não precisará mais recompilar o aplicativo para alterar suas imagens gráficas. Tente usar um banco de dados de imagens em seu próximo projeto. Você verá a melhoria na portabilidade e na flexibilidade de seus usuários.

Sobre o Autor

Stan Schultes é gerente de projetos e desenvolve aplicativos para empresas de Web e VB em Sarasota, Fla. Stan é MCP em VB e fez uma palestra sobre desenvolvimento de VB na conferência DevDays na Microsoft.

Download do código referente a este artigo

Clique aqui para fazer o download. Clique aqui para fazer o download.
Stan Schultes

Stan Schultes