Translate this page now :



»Programação
»Programação.NET
»Banco de Dados
»Webdesign
»Office
» Certificações Microsoft 4
»Treinamentos4
»Programação 4
»Webdesign«
»Office & User Tips«
»Grupos de Usuários
»Células Acadêmicas«
intcontpiada : 118
Os 3 Porquinhos
Você já está cadastrado e participa do grupo de usuários de sua cidade ? Se não, comente o porque.
 
 
Faça um pequeno teste com 10 questões de VB
.:.
Teste seus conhecimentos em Visual Basic, SQL Server e ASP 3.0 com nossas provas on-line
.:.
Aprimore seus conhecimentos em programação com nosso treinamento on-line de lógica de programação
.:.
Veja nosso calendário de treinamentos
Gostou da Página?
Então

para um amigo!
 







Pesquisa personalizada
Pesquisar Dicas:

 







Quer saber mais?
Não deixe escapar essa oportunidade!
A Búfalo Informática tem os cursos certos para você:
::Treinamento para Asp.Net::
::Treinamento para VB.Net ::

Criando e manipulando imagens com ASP.NET

Entre seus recursos, uma das grandes novidades do framework.net (e consequentemente do ASP.NET) é o fato dele expor a biblioteca de API's GDI (Graphical Development Interface) do Windows através do namespace system.Drawing.

Com isso podemos facilmente manipular imagens existentes ou criar novas imagens. Vamos ver um exemplo de como isso funciona.

No banco Northwind, que vem como exemplo no SQL Server, temos registro de vendas de produtos de várias categorias. Com a seguinte query, podemos obter um total de vendas por categoria :

select categoryname,count(*) total from [order details] a, products b,categories c
where a.productid=b.productid and b.categoryid=c.categoryid group by c.categoryname
order by total desc


(Não levei a quantidade em consideração para simplificar a query)

Vamos então utilizar essa query no ASP.NET para montarmos um gráfico de vendas de cada categoria.

Devemos iniciar uma nova WebApplication através do Visual Studio.NET e podemos configurar os objetos Connection e Command utilizando RAD, ou seja, visualmente. Até ai não há nenhum mistério em relação ao que você já conhece de ASP.NET.

Quanto aos objetos de imagem, existem 2 principais : BitMap e Graphics.

O objeto BitMap é a imagem em si. Podendo ter sido criada ou carregada de uma imagem pré-existente. Já o objeto Graphics é uma classe quer permite realizarmos desenho sobre o objeto BitMap. É através da classe Graphics que faremos o desenho de nosos gráfico e este estará sendo desenhado no objeto BitMap.

Todo o processo, em nosso exemplo, foi realizado no Page_load. Por isso temos muitas variáveis definidas nesta sub. Vamos analisar uma por uma, veja primeiro o trecho de declarações dentro desta sub :

 Dim dr As OleDbDataReader
     Dim b As New Drawing.Bitmap(600, 600, Imaging.PixelFormat.Format24bppRgb)
     Dim g As Graphics = Graphics.FromImage(b)
     Dim pen As Pen
     Dim pincel As New SolidBrush(Color.White)
     Dim icnt As Integer
     Dim cores() As Color = {Color.Black, Color.Yellow, Color.Green, Color.Aqua,      Color.Coral, Color.Gold, Color.AliceBlue, Color.Aquamarine}
     Dim rect As Rectangle
     Dim f As New Font(FontFamily.Families(3), 14, GraphicsUnit.Point)
     Dim penblack As New SolidBrush(Color.Black)


Eis as variáveis declaradas :

DR : OLEDBDataReader utilizado para manipular os dados resultantes da query. Lembre-se que o DataReader é um cursor apenas forward only e read only.

b : BitMap. Observe que o bitmap é criado na mesma linha em que é definido, com o tamanho 600x600

g : Graphics. Observe que esta variável também é criada na mesma linha em que é definida, mas com o método FromImage tendo como parâmetro o bitmap criado. Isso determina que todo desenho que fizermos sobre a variável g será na verdade armazenado na variável b

pen : Objeto Pen, utilizado para a definição das linhas de desenho no gráfico

Pincel : Objeto Brush, mas de sua subclasse SolidBrush, utilizado para fazer preenchimentos no gráfico. Observe que inicialmente ele é definido como white (há um bom motivo para isso, veremos depois), mas será redefinido várias vezes no código.

icnt : Um contador utilizado durante a navegação pelos registros

cores : Um vetor do tipo Color com um total de 8 cores. Sabemos que a query que foi feita só nos devolve 8 registros, estamos trabalhando de forma fixa. Deixaremos detalhes mais avançados, como a generalização deste artigo, para mais tarde.

rect : Um retângulo. É utilizado exatamente para isso - desenhar um retângulo.

f : Font. Utilizado para determinar a fonte para escrita no gráfico.

penBlack : Outro objeto do tipo SolidBrush, este já definido previamente como black.


Podemos dividir o código do page_Load em várias etapas. Primeiramente precisamos definir o fundo do bitmap. Por default é preto, o que não fica muito bem para um gráfico. Então vamos preencher o fundo do bitmap de branco. Para fazermos isso vamos utilizar um retângulo, veja :

 rect = New Rectangle(0,      0, 600, 600)
     pen = New Pen(Color.White)
     g.FillRectangle(pincel, rect)
     g.DrawRectangle(pen, rect)


Definimos o retângulo de tamanho 600x600, definimos o objeto Pen com cor branca, preenchemos então o retângulo com o método FillRectangle da classe Graphics (lembre-se que pincel é um solidbrush já definido como branco) e por último inserimos o retângulo no desenho através do método Drawrectangle do objeto Graphics (g).

O próximo passo é obtermos os dados do servidor de dados. Isso é muito fácil, já temos o objeto de conexão e o command, então precisamos de apenas 2 linhas :

 cn.Open()
     dr = cmd.ExecuteReader(CommandBehavior.SingleResult)

Nestas linhas abrimos a conexão e utilizamos o ExecuteReader para executar o command devolvendo um dataReader como resposta.

Precisamos então fazer um loop através do datareader para realizarmos o desenho do gráfico. Podemos dividir este loop em 3 etapas :

Desenhar a barra do gráfico
Escrever a legenda da barra (seu valor)
Escrever a legenda do gráfico (legenda de cores)

Vamos ver, por partes, cada uma das etapas :

 icnt = 0
     Do While dr.Read
     pen = New Pen(cores(icnt))
     pincel = New SolidBrush(cores(icnt))
     rect = New Rectangle((icnt * 40), 580 - dr.Item(1), 30, dr.Item(1))
     g.FillRectangle(pincel, rect)
     g.DrawRectangle(pen, rect)


Observe que nesta etapa, a primeira do laço, temos o inicio do laço e a inicialização do ICNT como 0. A condição do laço é a resposta do método Read do DataReader. Talvez você já tenha usado laços assim, mas caso não tenha vale citar algumas de suas características :

O método Read funciona como um movenext e é executado exatamente na linha do laço.
Este método devolve um booleano indicando se realmente há um próximo registro ou não.
O dataReader, quando é iniciado, não está posicionado em registro algum, sendo necessário uma primeira execução do método Read para posiciona-lo no 1o registro. Por isso o laço não só pode como deve ser do tipo que testa suas condições no inicio da execução e não no final (do while/loop x do/loop while).

Logo no inicio do laço devemos definir a PEN (que define a linha a ser usada no desenho) e o Pincel (que define o preenchimento do desenho). Observe que para garantir a variação de cores conforme os itens do gráfico utilizamos como parâmetro para criação tanto da pen como do pincel uma das cores do vetor, indexando o vetor de nosso contador, icnt.

Em seguida temos que desenhar os retângulos referentes ao item sendo inserido no gráfico. Os dois primeiros parâmetros para o desenho do retângulo são a posição x e y para inicio do desenho. A questão é que estas posições precisam ser calculadas : x, posição horizontal, calculada de acordo com o item sendo preenchido, enquanto que y, posição vertical, calculada de acordo com o valor do item, ou seja, o comprimento que se planeja ter para a barra.

Cada barra tem largura de 30 pixels e planeja-se uma utilização de 10 pixels como espaço entre as barras. Como o ICNT identifica a barra que está sendo exibida, fazendo o cálculo ICNT*40 encontramos a posição horizontal para imprimirmos a barra.

Já a posição vertical precisa ser calculada com base no valor da barra. Queremos o gráfico posicionado de baixo para cima, portanto a posição inferior será o limite inferior da área do bitmap (seria 600, 580 apenas para termos uma margem de segurança. Então para encontrarmos o limite superior faz-se o cálculo 580 - dr.item(1) ou seja, estamos fazendo 580 - o campo total do select. É claro que você observará que se o valor da barra for superior a 580 esse gráfico não funcionará, mas como citei antes, é apenas um exemplo, não vou inserir um cálculo complexo já neste primeiro artigo.

Em seguida inserimos a largura e altura do gráfico, estes simples : 30 de largura e dr.item(1) (o total) de altura.

Com o retângulo definido, fazemos seu preenchimento com o pincel que criamos e o inserimos no gráfico com a Pen que criamos. Podemos então passar para a etapa seguinte, montar a lengenda das barras, esta bem simples.

 g.DrawString(dr.Item(1),      f, penblack, (icnt * 40), 540 - dr.Item(1))

Utilizando o método DrawString para imprimir uma string no gráfico, a questão é determinarmos corretamente a posição de impressão. A posição x é exatamente a mesma, mas o cálculo da posição y foi um pouco alterado para que os valores apareçam um pouco acima de cada barra. No parâmetro string a ser impresso nós passamos o DR.ITEM(1), que é o valor da barra, enquanto que nos parâmetros seguintes passamos f (a fonte de letra a ser utilizada) e PenBlack (o pincel - preto - a ser usado para escrever o texto).

Já na etapa seguinte, da legenda, dividimos a legenda em 2 colunas, para melhor organiza-la. É uma questão simples : já que sabemos que temos 8 registros e icnt conta de 0 a 7, então de 0 a 3 fica em uma coluna enquanto que de 4 a 7 fica em outra. Como pode observar, uma determinação fixa, mas, como venho dizendo, não vamos complicar por enquanto. Veja :

 If icnt < 4 Then
     rect = New Rectangle(200, icnt * 30, 10, 20)
     g.FillRectangle(pincel, rect)
     g.DrawRectangle(pen, rect)
     g.DrawString(dr.Item(0), f, penblack, 215, icnt * 30)
Else
     rect = New Rectangle(400, (icnt - 4) * 30, 10, 20)
     g.FillRectangle(pincel, rect)
     g.DrawRectangle(pen, rect)
     g.DrawString(dr.Item(0), f, penblack, 415, (icnt - 4) * 30)
 End If
 icnt = icnt + 1
     Loop


Em ambos os casos desenha-se um pequeno retângulo, com altura de 20 e largura de 10 pixels, pintados com a mesma cor que a barra (pincel e pen continuam com as mesmas instâncias de objetos). O que precisa ser calculado é a posição da legenda : posição horizontal fixa, 200 para a primeira e 400 para a 2a, mas a posição vertical precisa ser calculada de acordo com o ICNT : No primeiro caso basta multiplicar icnt por 30, a altura do retângulo + 10 pixels de distância entre eles. Já no 2o caso precisamos subtrair 4 do icnt para fazer a multiplicação, já que reiniciamos a impressão em outra coluna de legendas.

Esse trecho de código inclui também a soma de +1 no ICNT e o término do loop.

Feito tudo isso precisamos apenas garantir a impressão da imagem na página web, veja :

 Response.ContentType      = "image/jpeg"
     b.Save(Response.OutputStream, ImageFormat.Jpeg)
     b.Dispose()
     dr.Close()
     cmd.Dispose()
     cn.Close()
     cn.Dispose()


Com essas instruções utilizamos o objeto Response para alterar o contentType, informando que a página retornará uma imagem, não HTML. Com o método Save do objeto B (BitMap) "salvamos" a imagem dentro do objeto response, propriedade outputstream, determinando assim que a imagem seja jogada como resposta da página e estamos ai determinando também o formato (JPEG). Depois o que encontramos é apenas o fechamendo e dispose dos objetos.

Veja como fica o código completo :

 Private Sub Page_Load(ByVal      sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
     'Put user code to initialize the page here
     Dim dr As OleDbDataReader
     Dim b As New Drawing.Bitmap(600, 600, Imaging.PixelFormat.Format24bppRgb)
     Dim g As Graphics = Graphics.FromImage(b)
     Dim pen As Pen
     Dim pincel As New SolidBrush(Color.White)
     Dim icnt As Integer
     Dim cores() As Color = {Color.Black, Color.Yellow, Color.Green, Color.Aqua,      Color.Coral, Color.Gold, Color.AliceBlue, Color.Aquamarine}
     Dim rect As Rectangle
     Dim f As New Font(FontFamily.Families(3), 14, GraphicsUnit.Point)
     Dim penblack As New SolidBrush(Color.Black)
 rect = New Rectangle(0,      0, 600, 600)
     pen = New Pen(Color.White)
     g.FillRectangle(pincel, rect)
     g.DrawRectangle(pen, rect)
 cn.Open()
     dr = cmd.ExecuteReader(CommandBehavior.SingleResult)
 icnt = 0
     Do While dr.Read
     pen = New Pen(cores(icnt))
     pincel = New SolidBrush(cores(icnt))
     rect = New Rectangle((icnt * 40), 580 - dr.Item(1), 30, dr.Item(1))
     g.FillRectangle(pincel, rect)
     g.DrawRectangle(pen, rect)
 g.DrawString(dr.Item(1),      f, penblack, (icnt * 40), 540 - dr.Item(1))
 If icnt < 4 Then
     rect = New Rectangle(200, icnt * 30, 10, 20)
     g.FillRectangle(pincel, rect)
     g.DrawRectangle(pen, rect)
     g.DrawString(dr.Item(0), f, penblack, 215, icnt * 30)
     Else
     rect = New Rectangle(400, (icnt - 4) * 30, 10, 20)
     g.FillRectangle(pincel, rect)
     g.DrawRectangle(pen, rect)
     g.DrawString(dr.Item(0), f, penblack, 415, (icnt - 4) * 30)
 End If
 icnt = icnt + 1
     Loop
 Response.ContentType      = "image/jpeg"
     b.Save(Response.OutputStream, ImageFormat.Jpeg)
     b.Dispose()
     dr.Close()
     cmd.Dispose()
     cn.Close()
     cn.Dispose()
 End Sub


Com este primeiro artigo sobre os recursos gráficos do ASP.NET demonstramos a criação de um gráfico, mas como muitos devem ter observado, de forma pouco versátil. Os recursos destes nameSpace são muito variados e precisaremos de muitos artigos para demonstra-los.


Dennes Torres
MCSD,MCSE,MCDBA


� Búfalo Informática, Treinamento e Consultoria - Rua Álvaro Alvim, 37 Sala 920 - Cinelândia - Rio de Janeiro / RJ
Tel.: (21)2262-1368 (21) 9240-5134 (21) 9240-7281 e-Mail:
contato@bufaloinfo.com.br