November 15, 2004 12:11 AM

Improve Your Image(s)

Master Image Processing and Management
DevConnections
Rating: (0)

Control Freak

LANGUAGES:VB.NET

ASP.NETVERSIONS: 1.x | 2.0

 

Improve Your Image(s)

Master Image Processing and Management

 

 

A picture is worth a thousand words ? and in some cases,they?re worth quite a few dollars too. Content is king on the Internet. Scatteredthroughout company hard drives everywhere are marketing materials, scanneddocumentation, artwork, charts containing sensitive data, and other valuableimages that can do wonders in the right hands ? or horrors in the wrong hands. Consolidatingthese materials into one central system is a common optimization of corporatedollars these days, and these systems usually must provide some way to get atfiles from across the Internet. Security is rightly a top concern in mostdocument management systems.

 

In some basic cases you can configure IIS to manage thefiles and their permissions for you, but often a more customized system isnecessary. As you?re probably aware, a standard Image control is defined withthe following ASPX code:

 

<asp:Image ID="Image1" Runat="server"

ImageUrl="SomeImage.jpg" />

 

When the page is output to the browser, the resulting HTMLwill consist of a standard <img> tag similar to this:

 

<img ID="Image1" src="SomeImage.jpg" />

 

A key point here is that the image is not really part ofthe page from the server?s point of view. Therefore, you can?t really do anycustom image processing (such as cropping, resizing, or adding annotations)within the page itself. Rather, the image file name is all that?s written tothe page (inside the image tag). As the browser interprets the HTML, itdownloads the image from the Web server as a completely separate request.

 

Now consider the following code:

 

<asp:Image ID="Image1" Runat="server"

ImageUrl="GenImage1.aspx" />

 

This Image control declaration illustrates that, insteadof pointing directly to an image file, you can point an Image control toward aseparate ASP.NET page where you can do any fancy dynamic image processing thatis needed.

 

In this example, GenImage1.aspx doesn?t contain any HTMLbecause its sole purpose is to output an image for inclusion in another page. Theonly code in the Page_Load event calls the procedure listed in Figure 1.

 

DisplayImage(NewBitmap("C:\PrivateDir\TopSecret.jpg")))

 

Private Sub DisplayImage(ByVal bmp As Bitmap)

   WithHttpContext.Current

    'Clear any existingpage content

    .Response.Clear()

 

    'Set the content type

    .Response.ContentType= "image/jpeg"

 

    'Output the image tothe OutputStream object

    bmp.Save(.Response.OutputStream, _

        Imaging.ImageFormat.Jpeg)

 

    'Ensure the image isthe only thing that is output

    .Response.End()

  End With

End Sub

Figure 1: ASPXpages don?t have to output HTML. This example outputs an image, so that imagecontrols on other pages can reference this page instead of pointing directly toa static image file.

 

You might choose to add authentication code to a page suchas GenImage1 to ensure only proper individuals see the image. You?re alsolikely to sprinkle in some code to make this simple example more versatile byaccepting an image as a url parameter or some other mechanism to serve out avariety of image files instead of a single hard-coded one.

 

For an ASP.NET application to effectively manage files, itmust have permission to access these files. By default, ASP.NET runs under auser account (intuitively) named ASPNET. This user account has very limitedpermissions. It will not be able to interact with most of the server?s filesystem by default, and it won?t have access to any network shares, either. Therefore,you?ll want to give the ASPNET user account the folder permissions it needs, orhave ASP.NET use a different user account that does have the necessarypermissions.

 

You can adjust the user account from within IIS, or youcan configure Impersonation in the web.config file or the machine.config file. Forinitial experimentation and debugging I?d suggest having ASP.NET run under youruser account because you know what files you have permission to access:

 

<!-- Web.config file. -->

<identity impersonate="true"/>

<identity impersonate="true" userName=

 "Redmond\BillG"password="Melinda"/>

 

If the images aren?t stored in a file system, but insteadare stored in a SQL Server database, then the code behind for GenImage1.aspxmight look more like that shown in Figure 2.

 

Dim dr As System.Data.SqlClient.SqlDataReader

cmdGetFile.Parameters("@File_ID").Value = _

 Request("AttachmentID").ToString

dbConn.Open()

dr = cmdGetFile.ExecuteReader

If dr.Read Then

 Response.Clear()

 Response.ContentType =dr("ContentType").ToString

 Response.OutputStream.Write(CType(dr("FileData"), _

     Byte()), 0,CInt(dr("FileSize")))

 Response.AddHeader("Content-Disposition", _

 "inline;filename=" + dr("FileName").ToString())

End If

Figure 2: You cangrab the image data from a database and write the raw file data directly intothe Output Stream just before it?s sent to the browser.

 

This technique shows how you can dump a file directly froma database into the Response.OutputStream. ADO.NET is used to extract thebinary data from a SQL Server image field, the data is then converted into abyte array, and, finally, it?s written to the output stream along with adescriptive header to help the browser better interpret the resulting file. Formore details on this technique, see EasyUploads.

 

Custom Image Generation

By using the functionality included in the System.Drawingnamespace, your image manipulation capabilities are limitless. As if that weren?tenough power for a single developer to wield, there are also dozens of third-partycomponents available under such categories as charting, reporting, and imageprocessing libraries. Additionally, you can build your own image processingobject models either from scratch or by building on existing technologies. Hopefullyby now you?re beginning to realize the full power that can really lie behindthe seemingly humble image control.

 

The previous techniques are great for distributingpre-existing images, but if you need to dynamically create an image fromscratch (or modify an existing image on the fly,) then the System.Drawingnamespace will become quite familiar to you. Using the classes within thisnamespace you could create dynamic charts, graphs, or other useful output. However,that?s soooo boring! The next example will focus on less tangible corporateenhancements, such as improved morale.

 

Smiles can be infectious, and the next example willgenerate as many as you?d like. Call the subroutine shown in Figure 3 to createa randomly generated smiley face.

 

Private Sub DrawSmiley(ByVal g As Graphics, _

 ByVal Width As Integer,ByVal Height As Integer, _

 ByVal rand As Random)

 Dim SmileyWidth AsInteger = rand.Next(Width / 2)

 Dim SmileyHeight AsInteger = rand.Next(Height / 2)

 'Draw the head (a bigcircle)

 Dim x As Integer =rand.Next(Width - SmileyWidth)

 Dim y As Integer =rand.Next(Height - SmileyHeight)

 Dim PenWidth As Integer =rand.Next(5)

 Dim RandomColor As Color= _

     Color.FromArgb(rand.Next(255), _

     rand.Next(255),rand.Next(255))

 Dim Pen As NewPen(RandomColor, PenWidth)

 g.DrawEllipse(Pen, x, y,SmileyWidth, SmileyHeight)

 'Draw the Nose (in thecenter of the head)

 Dim NoseRect As System.Drawing.RectangleF

 NoseRect.Width =CInt(SmileyWidth / 50)

 NoseRect.Height =CInt(SmileyHeight / 50)

 NoseRect.X = CInt(x +(SmileyWidth / 2) - _

    (NoseRect.Width / 2))

 NoseRect.Y = CInt(y +(SmileyHeight / 2) - _

    (NoseRect.Height / 2))

 g.DrawEllipse(Pen,NoseRect)

 g.FillEllipse(Brushes.Green, NoseRect)

 'Draw the Left Eye

 Dim EyeRect AsSystem.Drawing.RectangleF

 EyeRect.Width =CInt(SmileyWidth / 30)

 EyeRect.Height =CInt(SmileyHeight / 30)

 EyeRect.X = CInt(x +(SmileyWidth / 2) - _

    (EyeRect.Width / 2) -(SmileyWidth / 4))

 EyeRect.Y = CInt(y +(SmileyHeight / 3) - _

    (EyeRect.Height / 2))

 g.DrawEllipse(NewPen(Color.Blue, PenWidth), EyeRect)

 g.FillEllipse(Brushes.Blue, EyeRect)

 'Draw the Right Eye

 EyeRect.Width =CInt(SmileyWidth / 30)

 EyeRect.Height =CInt(SmileyHeight / 30)

 EyeRect.X = CInt(x +(SmileyWidth / 2) - _

    (EyeRect.Width / 2) +(SmileyWidth / 4))

 EyeRect.Y = CInt(y +(SmileyHeight / 3) - _

    (EyeRect.Height / 2))

 g.DrawEllipse(New Pen(Color.Blue,PenWidth), EyeRect)

 g.FillEllipse(Brushes.Blue, EyeRect)

 'Draw the smile

 Dim points(2) AsSystem.Drawing.PointF

 points(0) = NewSystem.Drawing.PointF(CInt(x + _

    (SmileyWidth / 2) -(EyeRect.Width / 2) - _

    (SmileyWidth / 4)), y +(SmileyHeight / 2))

 points(1) = NewSystem.Drawing.PointF(CInt(x + _

    (SmileyWidth / 2)), y +(SmileyHeight / 2) + _

    (SmileyHeight / 4))

 points(2) = NewSystem.Drawing.PointF(CInt(x + _

    (SmileyWidth / 2) -(EyeRect.Width / 2) + _

    (SmileyWidth / 4)), y +(SmileyHeight / 2))

 g.DrawCurve(Pen, points,1)

End Sub

Figure 3: By usingthe classes within the System.Drawing namespace, nearly any illustrationimaginable can be generated at run time, including a bunch of smiley faces.

 

The first parameter is a Graphics object, which is thecanvas on which this masterpiece will be painted. The height and width of thecanvas are also passed along, to help ensure no smileys get abruptly cut off atthe edges of the canvas. Finally, a Random object is passed along, which willbe used to mix things up a bit.

 

Using the Random object, a random height and width aregenerated for the current smiley face and the head is drawn within thisbounding rectangle. A pen is created of random thickness and color. This penwill be used to draw most features of the face. The DrawEllipse method createsa circle, which is used in concert with the FillEllipse method to fill it withcolor. Three smaller circles are then drawn within the head to represent thenose and two eyes. Finally, the smile is drawn by passing an array of points tothe DrawCurve method of the Graphics object. All of the mathematical formulasthroughout the example are there simply to calculate the position and size ofeach facial feature.

 

The final piece of this image generation puzzle is thecode that will fill the Page_Load event of GenImage1.aspx and call theDrawSmiley routine. This Page_Load code is listed in Figure 4.

 

Dim g As Graphics

Dim rand As New Random 'random number generator

Dim bmp As Bitmap 'to hold the picture

Dim Width As Integer = 200 'image height

Dim Height As Integer = 200 'image width

Dim NumberOfSmileys As Integer = 3

 

'Grab parameters from the querystring (if any)

If Not IsNothing(Request.QueryString("NumSmileys"))Then

   NumberOfSmileys = _

   Int32.Parse(Request.QueryString("NumSmileys"))

End If

If Not IsNothing(Request.QueryString("Width")) Then

   Width = _

     CType(Request.QueryString("Width"), Integer)

End If

If Not IsNothing(Request.QueryString("Height")) Then

   Height = _

     CType(Request.QueryString("Height"), Integer)

End If

 

'Create a new bitmap of the specified size

bmp = New Bitmap(Width, Height, _

   Drawing.Imaging.PixelFormat.Format16bppRgb565)

 

'Get the underlying Graphics object

g = Graphics.FromImage(bmp)

 

'Specify a white background

g.FillRectangle(Brushes.White, g.ClipBounds)

 

'Smooth out curves

g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

 

'Generate random smileys

For i As Integer = 1 To NumberOfSmileys

   DrawSmiley(g, Width,Height, rand)

Next

 

DisplayImage(bmp)

Figure 4: Thiscode goes in the Page_Load event of GenImage1.aspx, which can be referenced bythe ImageURL property of a standard image control placed on any other page.

 

First, a few variables are declared with some default valuesspecifying the size of the image and the number of smiley faces that will bedrawn. Then the querystring is examined for optional parameters, which willreplace the defaults. A blank bitmap is then created with a white background. Antialiasingis turned on to create smoother looking curves for rounded shapes, such ascircles and smiles.

 

The main loop is then entered, iterating once for eachsmiley face to be drawn by calling the DrawSmiley subroutine mentioned earlier.Finally, the completed image is output by the DisplayImage subroutine in Figure1.

 

To see the code in action, create a new WebForm and dropan Image control onto it. Then simply set the ImageURL property of that Imagecontrol to point to the GenImage1.aspx page. The result will look a lot likeFigure 5.

 


Figure 5: The humble Image controlcan turn into a powerful tool once you?ve mastered the art of creating dynamic,configurable images at run time.

 

Conclusion

You should now have enough knowledge to manage andmanipulate images in all kinds of complex ways. The graphical possibilities areendless with these tools at your disposal. You can expand on these ideas in allkinds of ways. For example, you could create image buttons and other graphicalpage elements on demand to keep your Web site feeling constantly fresh and new.Look for a future article about manipulating existing images at run time, suchas: resizing, optimizing, cropping, rotating, adding borders, altering colorsand brightness, etc.

 

The techniques outlined in this article are the foundationfor virtually every modern third-party graphing component available on themarket today. You could also create your own, if so inclined. Let yourimagination wander and let me know what kinds of image creation tools youproduce as a result.

 

The sample code inthis article is available for download to asp.netPRO subscribers.

 

Steve C. Orr is anMCSD and a Microsoft MVP in ASP.NET. He?s been developing software solutionsfor leading companies in the Seattlearea for more than a decade. When he?s not busy designing software systems orwriting about such activities, he can often be found loitering at local usergroups and habitually lurking in the ASP.NET newsgroup. Find out more about himat http://Steve.Orr.netor e-mail him at mailto:Steve@Orr.net.

 

 

 

Add a Comment

There are no comments to display. Be the first one!
You must log on before posting a comment.

Are you a new visitor? Register Here

advertisement




Comments from the DevConnections Community

Join our community of development pros.

Windows problem

I all, I have a problem on my Windows Vista that began afetr the purchase of an external Hard Disk Freecom. A few days afetr the purchase I discon...

Most Recent Posts

GOOGLE LINKS
SPONSORED LINKS
FEATURED LINKS