sexta-feira, 8 de abril de 2016

Sobre Blob e Images

Carregar imagens diretamente no banco de dados é uma operação bastante interessante e prática utilizando os tipos Image e Blob no Genexus. Porém, quais as diferenças e até onde chegamos com esses dois recursos.

Parece até aquela briguinha manjada dos super heróis, aquela coisa meio armada das lutas de vale tudo dos anos 80. Falo isso porque os dois recursos são ótimos e não competem entre si, podem inclusive encontrar várias áreas em que se conectam, e cada um vai auxiliá-lo a desenvolver excelentes recursos.

Porém, antes de avançarmos, vamos revisar os artigos já apresentados sobre esses dois assuntos, aqui do Genexando.

Manipulando Imagens

  • http://www.genexando.com/2009/12/tratando-imagens.html
    Neste artigo chegamos a conclusão que o tipo Image nos ofereciam recursos que permitiam a carga da imagem, e principalmente sua posterior recuperação por meio do image.Link(), desta forma podemos ligar a imagem a um controle, ou programar o acesso por meio de <img src='...' >
  • http://www.genexando.com/2015_10_01_archive.html
    Neste artigo mais recente, falamos a respeito de resoluções, dimensões de imagens e também passamos rapidamente sobre o armazenamento com Blob e Image.

Manipulando Blob


O que devo escolher: Blob ou Image?

Apesar de diversos artigos ainda não tivemos um que respondesse definitivamente a respeito deste assunto. Ambos os tipos permitem armazenar dados binários no banco de dados. Então porque precisamos de dois tipos distintos? Qual é mais indicado em cada situação?

Image 

É destinado a armazernar e recuperar imagens, aceitando as extensões:  jpe, jpg, jpeg, gif, png, bmp, ico, svg, tif, tiff, ai, drw, pct, psp, xcf, psd, raw. Desta forma arquivos do tipo pdf, doc, xls, não serão aceitos.

É disponibilizado uma série de propriedades que facilitam a operação da imagem.


Image.FromURL()
Permite carregar uma imagem a partir de uma URL, bastando informar o local onde a mesma se encontra publicada, como por exemplo o logotipo do Genexando, que pode ser carregado em uma variável &image.

Event 'fromurl'
    &image.FromURL('http://1.bp.blogspot.com/-m1NiBb4VqsA/UXvcMgc9YpI/AAAAAAAAAsc/kUip66gYUGk/s1600/genexandologo.png')
Endevent


Image.FromImage()
Carrega uma imagem a partir de outra que já se encontra carregada na Kb, na área Customization - Images, como por exemplo a ActionExport, que representa um XLS.

Event 'fromimage'
    &image.FromImage(ActionExport)
Endevent


*** Inverti a ordem e coloquei uma URL em um FromImage e funcionou também, portanto, tanto FromImage como FromUrl aceitam imagens de URLs externas.


Image.ImageURI, Image.ImageName, Image.ImageType
Para quem precisa recuperar a imagem a partir de uma URL ou fisicamente no disco, é necessário compreender como a imagem carregada no BD se transforma novamente em um arquivo no servidor. Em nossa Kb temos uma pasta chamada PUBLICTEMPSTORAGE\MULTIMEDIA que é utilizada para construir os objetos temporários, como as imagens, por exemplo.

Image.ImageURI: devolve o caminho via servidor web até a imagem.
http://localhost/nomekb/PublicTempStorage/multimedia/nomekb_229a89cef51d48579586cdcf30d6ad85.png

Image.ImageName: devolve o nome da imagem, sem a extensão.
nomekb_229a89cef51d48579586cdcf30d6ad85

Image.ImageType: devolve o tipo ou extensão da imagem
png 
   
*** Se for necessário obter o caminho físico até a imagem, poderemos utilizar o caminho conhecido até a pasta PublicTempStorage\multimedia e acrescentar o ImageName e ImageType para completar.

Z:\Models\TESTE\EV3\Extensao\CSharpModel\web\PublicTempStorage\multimedia

*** Os valores ImageName, ImageType e ImageURI somente quando referenciarmos um atributo armazenado em uma tabela, isto devido a necessidade de se reconstruir a imagem em formato de arquivo físico novamente para ser devolvida para o navegador. Se a operação envolver apenas a carga de uma imagem em uma variável, a mesma ficará no somente no navegador, desta forma não teremos as informações até que ocorra a carga da imagem a partir do servidor, ou seja, a mesma for armazenada e posteriormente recuperada.

Blob

Blob é mais flexível em termos de carga pois aceitam qualquer tipo de arquivo, desde que se estabeleça um atributo para armazenar a extensão na propriedade File Type Attribute. Isto quer dizer se definirmos esta propriedade para um atributo do tipo Character(4), teremos a possibilidade de armazenar qualquer coisa, uma vez que para reconstruir o objeto a extensão será variável e recuperada deste atributo.

Assim como ocorre com as imagens os atributos do tipo Blob precisam se transformar novamente em arquivos físicos, para que possam ser enviados aos navegadores, e o mesmo é construido na pasta PUBLICTEMPSTORAGE. Com atributos do tipo Blob as informações não são tão explicitas quanto as definidas no tipo Image.

Blob.ToString() ou link(Blob)
A operação retorna o caminho físico até o arquivo reconstruído para ser devolvido ao navegador. Neste caso o nome do arquivo original não será mais considerado, sendo gerado novos arquivos aleatórios, abaixo um exemplo.

Z:\Models\TESTE\EV3\Extensao\CSharpModel\web\PublicTempStorage\usercontrol5863015.pdf

&URL = pathtourl(Blob)
Esta operação é meio obscura na documentação, mas muito importante pois devolve o link utilizado pelo navegador de internet para enviar o arquivo gerado pelo Genexus. Está documentada aqui http://wiki.genexus.com/commwiki/servlet/wiki?9563,PathToURL+function,. O resultado devolvido é algo semelhante ao apresentado a seguir.

http://localhost/nomekb/PublicTempStorage/usercontrol5863015.pdf



Tamanho do Blob: &File.GetLength()
Outra operação interessante que pode realizada no Blob e igualmente obscura na documentação é a obtenção da dimensão do Blob por meio de um tipo File, a operação GetLength() devolve a dimensão em bytes do arquivo. A documentação encontra-se aqui http://wiki.genexus.com/commwiki/servlet/wiki?6915,File+data+type,

&File.Source  = Blob.ToString()
&size = &File.GetLength()


Resultado:
12311

Tamanho do Blob: &File.GetName()
Utilizando o File também será possível obter o nome do arquivo gerado pelo Genexus. Com este nome também será possível chegar a URL da imagem.

&File.Source  = Blob.ToString()
&filename = &File.GetName()


Resultado:

usercontrol1740234.pdf

Base64 String

Os navegadores de internet conseguem entender um formato chamado Base64 String que representa uma imagem, porém codificada num chamado encode. Neste formato a imagem é gerada como uma string, no seguinte formato, apresentado de forma reduzida.

data:image/png;base64,iVBORw0KAACrQAAAmICA...WgA5ErkJggg==

O modelo foi implementado como uma maneira de reduzir a comunicação entre o servidor e o cliente, e não nos cabe aqui discutir o que é melhor ou pior, porque a imagem pode ser alcançada pela sua URI ou por uma string codificada no formato Base64.

A seguir alguma documentação sobre este tema:

Blob.FromBase64String()
Blob.ToBase64String()
Os Blobs incluem métodos que transformam uma string em Base64 em um Blob (Blob.FromBase64String()) ou um Blob em Base64 (Blob.ToBase64String()). Isso é interessante porque Image não possui este recurso, somente Blob.

Se for necessário uma Image neste formato é possível converter em Blob e utilizar o recurso da conversão Base64String().  Para isso será necessário que a Image e Blob sejam do mesmo tipo, ou seja, compartilhem do mesmo MIME type.

&Blob  = &Image
&string = &Blob.ToBase64String()

Ver documentação em http://wiki.genexus.com/commwiki/servlet/wiki?15204,Image+data+type

Redimensionamento?

Esta é uma boa pergunta, pois não temos como redimensionar a imagem quando realizamos o upload, e este é um fator muito importante visto que os aparelhos atuais geram imagens quase sempre desnecessariamente muito grandes. Imagens grandes muitas vezes não vão atender nossa necessidade na grande maioria dos casos, normalmente o que ser faz é reduzir a imagem a uma dimensão predeterminada.

Para smartdevices temos uma propriedade para escalar a imagem, Scale Type Property


Voltemos outra hora para tratarmos especificamente deste assunto.