Gerando Thumbnails em .NET (Upload em ASP.NET com jqModal e Efeitos Ajax Pt. 4)
Lembra do tutorial de Upload de fotos com AJAX, aquele onde fazemos o upload e exibimos as fotos em um gridview. Para você não se sentir perdido em alguns pontos deste artigo, sugiro a leitura dos artigos anteriores sobre esse assunto ;-)
Bem no final do artigo foi comentado de que poderíamos gerar um thumbnail a partir da imagem que vem do Banco de Dados. Vamos fazer isso agora?
O código completo pode ser obtido no link no final do artigo :-)
No artigo original, definimos hard-coded o tamanho das fotos que irão aparecer no gridview. Veja a declaração abaixo:
1: <img runat="server" id="foto" src='<%#Bind("FotoID","visImagem.aspx?fid={0}")%>' alt="foto" width="50" height="50" />
Esta linha foi retirada do gridview da página Default.aspx do projeto original. E qual a desvantagem desta abordagem, já que o tamanho da foto vai ser reduzido?
Sim, mas de que tamanho estamos falando? Estamos falando das dimensões da foto, e não do seu tamanho em bytes!
A redução das dimensões será feita pelo navegador após o download das fotos. Uma foto de grandes dimensões, maior será seu tamanho em bytes, mais tempo leva para download, mais franquia de download gasta-se do provedor (caso o seu provedor tenha limite de download...).
Então, o que vamos fazer aqui, é recuperar a foto do BD, reduzir as suas dimensões, gerando um novo arquivo com dimensões reduzidas na memória do servidor, e enviando este novo arquivo para o usuário.
Para isso, acrescentei na classe TCadastroClsConn um método chamado GetThumbnail, que retorna um array de bytes com o novo arquivo e recebe como parâmetros as dimensões do novo arquivo.
Veja o código deste método:
1: public byte[] GetThumbnail(int TamX, int TamY)
2: {
3: //Obtendo a foto original do BD
4: MemoryStream sImgOriginal = new MemoryStream();
5: BinaryWriter bw = new BinaryWriter(sImgOriginal);
6: bw.Write(this.Foto);
7: bw.Flush();
8:
9: //Cria a miniatura
10: Image Original = Image.FromStream(sImgOriginal, true);
11: Image Thumbnail = Original.GetThumbnailImage(TamX, TamY, new Image.GetThumbnailImageAbort(ThumbCallback), IntPtr.Zero);
12:
13: //Saída para Array de Bytes
14: MemoryStream sOutput = new MemoryStream();
15: Thumbnail.Save(sOutput, ImageFormat.Jpeg);
16:
17: byte[] bOutput = new byte[sOutput.Length];
18: sOutput.Position = 0;
19: sOutput.Read(bOutput, 0, (int)sOutput.Length);
20:
21: sImgOriginal.Dispose();
22: Original.Dispose();
23: Thumbnail.Dispose();
24: return bOutput;
25: }
26:
27: protected bool ThumbCallback()
28: {
29: return false;
30: }
Antes, acrescentamos a referência do assembly System.Drawing ao projeto da biblioteca de classes, e além disso acrescentamos os namespaces System.Drawing e System.Drawing.Imaging na cláusula using.
Carregamos a propriedade Foto, que irá recuperar a foto do banco de dados, em um MemoryStream chamado sImgOriginal. Fazemos isso através de um BinaryWriter, que irá efetivamente escrever o conteúdo da propriedade Foto no stream.
Após isso, criamos um objeto do tipo Image, chamado Original, que inicializamos com o conteúdo da imagem no stream sImgOriginal, feito através do método estático FromStream da classe Image, que recebe como parâmetros o stream onde a imagem se encontra e um booleano que indica se será utilizado o gerenciamento de cores que está no arquivo original.
Criamos também outro objeto do tipo Image, o qual chamamos Thumbnail, que é inicializado com a saída do método GetThumbnailImage do objeto Image, que no nosso caso é a variável Original.
O método GetThumbnailImage gera uma miniatura da imagem contida em um objeto Image, e pede como parâmetros a largura, altura (inteiros), um delegate (olha ele aí) que aponta para um método de callback que representa o abort da função de geração de imagens, e a constante IntPtr.Zero.
Eu disse acima que a função GetThumbnailImage pede como um dos parâmetros um delegate, e vimos no artigo sobre Eventos que um delegate é um ponteiro para um método, não é?
Dentro da classe Image, temos o delegate Image.GetThumbnailImageAbort, que tem como assinatura o retorno de um booleano sem parâmetros. No seu construtor, informamos uma função que retorna um booleano.
No nosso caso, já que precisamos somente da referência da função, criamos a função TumbCallback, retornando false e não exigindo nenhum parâmetro. Apenas isso é o suficiente.
Pronto, geramos o thumbnail da imagem que veio do BD, e agora precisamos transformar esse novo bitmap em um array de bytes, para que possamos aproveitar todo o código restante, com pouquíssimas alterações.
Primeiramente criamos um MemoryStream para salvar o objeto Image em um Stream. Isto é feito pelo método Save() do objeto Image, que pede como parâmetros em uma das sobrecargas o stream de saída e o formato do arquivo, que é representado pela classe ImageFormat. Iremos no nosso caso utilizar o JPEG.
Com isso, criamos o nosso array de bytes que será o retorno do método, a variável bOutput. Feito isso, escrevemos o conteúdo do MemoryStream sOutput no nosso array de bytes, utilizando o método Read(), que em uma das sobrecargas recebe o array de bytes onde os dados serão escritos, a posição inicial e a quantidade de bytes a ser escrita.
Como o método Read() pede a quantidade de bytes como um inteiro, e a propriedade Length do stream nos retorna um long, precisamos fazer um cast.
Feito isso, liberamos os objetos da memória e retornamos o array de bytes com o thumbnail gerado.
Agora, na classe TCadastroClsConn temos a propriedade Foto que retorna o arquivo original e o método GetThumbnail() que retorna com dimensões personalizadas. Veja agora como ficou a linha do gridiview da página Default.aspx:
1: <img runat="server" id="foto" src='<%#Bind("FotoID","visImagem.aspx?fid={0}&thumb=1")%>' alt="foto" />
Na querystring da página visImagem.aspx (a que carrega a foto, lembra?), acrescentamos o parâmetro thumb. Se existir esse parâmetro, ele chama a função GetThumbnail ao invés da propriedade Foto. Veja o código da página visImagem.aspx neste ponto:
1: BinaryWriter bw = new BinaryWriter(Response.OutputStream);
2: if (Request.Params["thumb"] == null)
3: {
4: bw.Write(cad.Foto);
5: }
6: else
7: {
8: bw.Write(cad.GetThumbnail(120, 120));
9: }
10: bw.Flush();
11: bw.Close();
Somente foi acrescentado o if, mais nada!
Simples, não foi?
Exemplo Upload com Ajax + Thumbnail (229 KB)
Um abraço a todos :-)
0 comentários:
Postar um comentário