O NeoMatrix Tech está de casa nova!

Você deverá ser redirecionado em 6 segundos. Se não, visite:
http://www.leonelfraga.com/neomatrixtech
e atualize seus favoritos.

Aviso IMPORTANTÍSSIMO!

Aviso aos navegantes:

O NeoMatrix Tech mudou de casa!!!

A partir de agora, acessem pelo novo endereço:

http://www.leonelfraga.com/neomatrixtech

Ué... mas é só o domínio mudou de lugar?

R: Na verdade, não é bem assim hehe. Este domínio que você acessa agora aponta para um blog hospedado no Blogger, enquanto no novo, aponta para um blog na plataforma Wordpress, hospedagem própria, muito mais rápida e com um layout mais agradável de ler ;)

Não vou fechar este domínio igual ao que eu fiz com o NM Light (que já está 100% na nova plataforma). Talvez beeeeeeem depois eu faça isso.

Todos os posts daqui se encontram lá, e novos posts serão colocados somente no novo endereço.
A única coisa que não consegui importar foram os comentários. Mas em breve vai ter um post contando sobre a epopéia que foi migrar o NeoMatrix Tech!

Somente vou fechar a área de comentários daqui. Caso queiram comentar, favor ver o post correspondente no "Novo NeoMatrix Tech" e comentem por lá. É bem melhor! (pena que os permalinks "amigáveis para SEO" não funcionam lá, dá erro 404 e não consigo fazer a configuração funcionar. E olha que eu já vi vários artigos falando desse assunto :( ).

Quem assina o feed, já está lendo o conteúdo do novo NeoMatrix Tech!

sábado, 17 de janeiro de 2009

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

Para tornar este artigo ainda mais interessante, escreva suas críticas (desde que construtivas e sem ofenças), elogios, sugestões, complementos, dúvidas, etc, etc, etc!!!

  © Blogger templates ProBlogger Template by Ourblogtemplates.com 2008 - Editado e configurado por Leonel F.

Voltar ao TOPO