Friday, July 31, 2009

How to code the signature

How to code the signature

Here, we'll be focusing on a lot of interesting features of the .NET Framework. Just to enumerate some: web requests, web handlers, graphics, caching, section handlers etc. My purpose was to create a solution that can be easily customized and extended by others.
Looking at the prerequisites

By having such a purpose, I have decided to provide most of the settings in the "web.config" file, as follows:



allowLocation="true" allowDefinition="Everywhere"
restartOnExternalChanges="true" />





As you might have noticed I have created a custom section handler. The sample code includes the handler and is pretty much self explanatory, so we will not get into further details on this. However, I would like to explain the structure of the section. It contains a title and exception node that describes how to draw the title, and respectively the exception in case it occurs. It also contains an items node, which acts as a collection; it provides us the possibility to specify how to draw unlimited posts (if they exist) on the surface of the image. I have chosen to draw only the latest three. Note that the structure is similar with the RSS 2.0 standard.





drawFont="Verdana, 10.5pt" <br /> drawColor="194, 71, 11" <br /> drawBorder="false" /> <br /> <!-- Exception --> <br /> <exception drawRectangle="5, 5, 118, 246" <br /> drawFont="Verdana, 9pt" <br /> drawColor="255, 0, 0" <br /> drawBorder="false" /> <br /> <!-- Items --> <br /> <items> <br /> <clear/> <br /> <add Name="1" <br /> drawRectangle="5, 110, 117, 28" <br /> drawFont="Verdana, 8pt" <br /> drawColor="255, 55, 0" <br /> drawBorder="false"> <br /> <pubDate MoreText="Published on: " <br /> drawRectangle="5, 140, 117, 12" <br /> drawFont="Verdana, 6pt" <br /> drawColor="0, 0, 0" <br /> drawBorder="false"/> <br /> </add> <br /> <add Name="2" <br /> drawRectangle="5, 155, 117, 28" <br /> drawFont="Verdana, 8pt" <br /> drawColor="255, 55, 0" <br /> drawBorder="false"> <br /> <pubDate MoreText="Published on: " <br /> drawRectangle="5, 185, 117, 12" <br /> drawFont="Verdana, 6pt" <br /> drawColor="0, 0, 0" <br /> drawBorder="false"/> <br /> </add> <br /> <add Name="3" <br /> drawRectangle="5, 200, 117, 28" <br /> drawFont="Verdana, 8pt" <br /> drawColor="255, 55, 0" <br /> drawBorder="false"> <br /> <pubDate MoreText="Published on: " <br /> drawRectangle="5, 230, 117, 12" <br /> drawFont="Verdana, 6pt" <br /> drawColor="0, 0, 0" <br /> drawBorder="false"/> <br /> </add> <br /> <!--<remove Name="2"/>--> <br /> </items> <br /> </Channel> <br /> </RSSGraphics> <br /> <br /> The RSS Feed URL can also be easily modified by the following lines of code: <br /> <br /> <appSettings> <br /> <clear/> <br /> <add key="RSSFeedURL" value="http://msdn.microsoft.com/rss.xml"/> <br /> </appSettings> <br /> <br />The basic and exception images are provided as resources in "WebResources.resx" and are linked at compile time. <br /> <br />Coding the task <br /> <br />By collecting all these prerequisites, we now have everything we need to get started. We begin by creating a new ASP.NET Web Site. The task is to respond to a request with an image (our own dynamic image). It may seem a little odd at the first glance, but it can be achieved by using a Generic Handler. The Generic Handler is built upon a basic asynchronous handler, which is standard, and we'll be focusing only on the asynchronous task. <br /> <br />The following code represents the header of the asynchronous procedure and the declarations within, which are going to be used throughout the procedure. <br /> <br />Visual C# <br /> <br /> HttpRequest objRequest = MyContext.Request; <br /> HttpResponse objResponse = MyContext.Response; <br /> Cache objCache = MyContext.Cache; <br /> NameValueCollection objAppSettings = null; <br /> GeneralSectionHandler objConfig = null; <br /> <br /> Bitmap objImage = null; <br /> objResponse.ContentType = "image/png"; <br /> objResponse.Clear(); <br /> <br />Visual Basic <br /> <br /> Private Sub StartAsyncTask(ByVal workItemState As [Object]) <br /> Dim objRequest As HttpRequest = MyContext.Request <br /> Dim objResponse As HttpResponse = MyContext.Response <br /> Dim objCache As Cache = MyContext.Cache <br /> Dim objAppSettings As NameValueCollection = Nothing <br /> Dim objConfig As RSSGraphics.GeneralSectionHandler = Nothing <br /> Dim objImage As Bitmap = Nothing <br /> objResponse.ContentType = "image/png" <br /> objResponse.Clear() <br /> <br />The featured line requires attention in the sense that it specifies the type of response, which is an image in PNG format. <br /> <br />Visual C# <br /> <br />try <br /> { <br /> if (objCache["BitmapCache"] == null) <br /> { <br /> <br />Visual Basic <br /> <br />Try <br /> If objCache.Item("BitmapCache") Is Nothing Then <br /> <br />In order to serve many simultaneous requests, I have used the cache to insert and retrieve the image, which I must say it increases the performance quite a bit. In the case that the image is not found in the cache, or it may have expired, a new request to the RSS Feed URL is made, and the xml document is loaded. Next, the basic image is loaded from the resources, and drawn on the surface of it using smooth anti-alias (just to get a nice looking response). At the end, the image is saved into the cache in order to be retrieved from it by the next request, if it happens within 15 minutes. <br /> <br />Visual C# <br /> <br /> objAppSettings = <br /> System.Web.Configuration. <br /> WebConfigurationManager.AppSettings; <br /> objConfig = <br /> (GeneralSectionHandler)System.Configuration. <br /> ConfigurationManager.GetSection("RSSGraphics/Channel"); <br /> <br /> string RSSFeedURL = objAppSettings["RSSFeedURL"]; <br /> <br /> HttpWebRequest rssFeed = <br /> (HttpWebRequest)WebRequest.Create(RSSFeedURL); <br /> XmlDocument rssDocument = new XmlDocument(); <br /> rssDocument.Load(rssFeed.GetResponse().GetResponseStream()); <br /> <br /> objImage = Resources.WebResources.RSS_Basic; <br /> Graphics objGraphics = Graphics.FromImage(objImage); <br /> objGraphics.SmoothingMode = SmoothingMode.AntiAlias; <br /> objGraphics.TextRenderingHint = <br /> System.Drawing.Text.TextRenderingHint.AntiAlias; <br /> <br /> DrawChannel(rssDocument, objGraphics, objConfig); <br /> DrawItems(rssDocument, objGraphics, objConfig); <br /> objGraphics.Dispose(); <br /> <br /> //Insert bitmap in cache for 15 minutes <br /> objCache.Insert("BitmapCache", objImage, <br /> null, Cache.NoAbsoluteExpiration, new TimeSpan(0, 15, 0)); <br /> } <br /> else <br /> { <br /> //Retrieve bitmap from cache <br /> objImage = (Bitmap)objCache["BitmapCache"]; <br /> } <br /> } <br /> catch (Exception ex) <br /> { <br /> <br />Visual Basic <br /> <br /> objAppSettings = Web.Configuration.WebConfigurationManager.AppSettings <br /> objConfig = System.Configuration.ConfigurationManager.GetSection("RSSGraphics/Channel") <br /> Dim RSSFeedURL As String = objAppSettings.Item("RSSFeedURL") <br /> Dim rssFeed As HttpWebRequest = DirectCast(WebRequest.Create(RSSFeedURL), HttpWebRequest) <br /> Dim rssDocument As XmlDocument = New XmlDocument <br /> rssDocument.Load(rssFeed.GetResponse.GetResponseStream()) <br /> objImage = CType(Resources.WebResources.RSS_Basic, Bitmap) <br /> Dim objGraphics As Graphics = Graphics.FromImage(objImage) <br /> With objGraphics <br /> .SmoothingMode = SmoothingMode.AntiAlias <br /> .TextRenderingHint = Text.TextRenderingHint.AntiAlias <br /> End With <br /> DrawChannel(rssDocument, objGraphics, objConfig) <br /> DrawItems(rssDocument, objGraphics, objConfig) <br /> objGraphics.Dispose() <br /> 'Insert bitmap in cache for 15 minutes <br /> objCache.Insert("BitmapCache", objImage, Nothing, NoAbsoluteExpiration, New TimeSpan(0, 15, 0)) <br /> Else <br /> 'Retrieve bitmap from cache <br /> objImage = CType(objCache.Item("BitmapCache"), Bitmap) <br /> End If <br /> Catch ex As Exception 'Exception <br /> <br />If an exception occurs, an image containing details about the exception is returned. The code that caches the exception is simple and similar. <br /> <br />Visual C# <br /> <br /> objImage = Resources.WebResources.RSS_Exception; <br /> Graphics objGraphics = Graphics.FromImage(objImage); <br /> objGraphics.SmoothingMode = SmoothingMode.AntiAlias; <br /> objGraphics.TextRenderingHint = <br /> System.Drawing.Text.TextRenderingHint.AntiAlias; <br /> DrawException(ex, objGraphics, objRequest, objConfig); <br /> if (objGraphics != null) <br /> { <br /> objGraphics.Dispose(); <br /> } <br /> <br /> } <br /> <br />Visual Basic <br /> <br /> objImage = CType(Resources.WebResources.RSS_Exception, Bitmap) <br /> Dim objGraphics As Graphics = Graphics.FromImage(objImage) <br /> With objGraphics <br /> .SmoothingMode = SmoothingMode.AntiAlias <br /> .TextRenderingHint = Text.TextRenderingHint.AntiAlias <br /> End With <br /> DrawException(ex, objGraphics, objRequest, objConfig) <br /> If Not objGraphics Is Nothing Then objGraphics.Dispose() <br /> End Try <br /> <br />At this moment, no matter what, we have a response. All that is left to do is return it by writing the contents of the bitmap to a stream, in PNG format. Because PNG format cannot be written to a non-seekable stream, an intermediate memory stream object (which is seekable) is used. <br /> <br />Visual C# <br /> <br /> MemoryStream objMemoryStream = new MemoryStream(); <br /> objImage.Save(objMemoryStream, ImageFormat.Png); <br /> objMemoryStream.WriteTo(objResponse.OutputStream); <br /> objMemoryStream.Dispose(); <br /> objResponse.Flush(); <br /> MyCompleted = true; <br /> MyCallback(this); <br /> <br />Visual Basic <br /> <br /> Dim objMemoryStream As MemoryStream = New MemoryStream <br /> objImage.Save(objMemoryStream, ImageFormat.Png) <br /> objMemoryStream.WriteTo(objResponse.OutputStream) <br /> objMemoryStream.Dispose() <br /> objResponse.Flush() <br /> MyCompleted = True <br /> MyCallback(Me) <br />End Sub 'StartAsyncTask <br /> <br />Drawing the task <br /> <br />Now we'll start painting using brushes, and we'll not get dirty; we are going to achieve this by code. Basically we have three procedures that are going to handle this task: one that is going to draw the exception details on the exception image; and two procedures that are going to draw the title and the latest posts on the basic image. <br /> <br />The first procedure is the one that draws the exception. Due to security issues, the exception message is drawn only if the request is made from the same computer where the solution resides; else a friendly message is displayed. A lot of conversions are made here from string to rectangle, font, color, etc. Be sure to enter them correctly in the "web.config", or else an exception is raised. <br /> <br />Visual C# <br /> <br />private void DrawException(Exception ex, Graphics drawGraphics, <br /> HttpRequest objRequest, GeneralSectionHandler objConfig) <br />{ <br /> try <br /> { <br /> string drawString = "Exception: "; <br /> <br /> if (objRequest.IsLocal) <br /> { <br /> drawString += ex.Message; <br /> } <br /> else <br /> { <br /> drawString += "We are unable to serve your request."; <br /> } <br /> <br /> //Rectangle <br /> RectangleConverter drawRectangleConverter = <br /> new RectangleConverter(); <br /> Rectangle drawRectangle = new Rectangle(); <br /> drawRectangle = <br /> (Rectangle)drawRectangleConverter.ConvertFrom( <br /> objConfig.Exception.drawRectangle); <br /> <br /> //Font <br /> FontConverter drawFontConverter = new FontConverter(); <br /> Font drawFont; <br /> drawFont = <br /> (Font)drawFontConverter.ConvertFromString( <br /> objConfig.Exception.drawFont); <br /> <br /> //Brush <br /> ColorConverter drawColorConverter = new ColorConverter(); <br /> Color drawColor = new Color(); <br /> drawColor = <br /> (Color)drawColorConverter.ConvertFrom( <br /> objConfig.Exception.drawColor); <br /> SolidBrush drawBrush = new SolidBrush(drawColor); <br /> <br /> //String format <br /> StringFormat drawStringFormat = new StringFormat(); <br /> drawStringFormat.Alignment = StringAlignment.Near; <br /> drawStringFormat.LineAlignment = StringAlignment.Center; <br /> drawStringFormat.Trimming = StringTrimming.EllipsisWord; <br /> <br /> //Border <br /> if (Convert.ToBoolean(objConfig.Exception.drawBorder)) <br /> { <br /> drawGraphics.DrawRectangle(Pens.Black, drawRectangle); <br /> } <br /> drawGraphics.DrawString( <br /> drawString, drawFont, drawBrush, <br /> drawRectangle, drawStringFormat); <br /> } <br /> catch <br /> { <br /> drawGraphics = null; <br /> } <br />} <br /> <br />Visual Basic <br /> <br />Private Sub DrawException(ByVal ex As Exception, ByRef drawGraphics As Graphics,_ <br /> ByVal objRequest As HttpRequest, _ <br /> ByVal objConfig As RSSGraphics.GeneralSectionHandler) <br /> Try <br /> Dim drawString As String = "Exception: " <br /> If objRequest.IsLocal Then <br /> drawString += ex.Message.ToString <br /> Else <br /> drawString += "We are unable to serve your request." <br /> End If <br /> With objConfig.Exception <br /> 'Rectangle <br /> Dim drawRectangleConverter As New RectangleConverter <br /> Dim drawRectangle As New Rectangle <br /> drawRectangle = drawRectangleConverter.ConvertFrom(.drawRectangle) <br /> 'Font <br /> Dim drawFontConverter As New FontConverter <br /> Dim drawFont As Font <br /> drawFont = drawFontConverter.ConvertFromString(.drawFont) <br /> 'Brush <br /> Dim drawColorConverter As New ColorConverter <br /> Dim drawColor As New Color <br /> drawColor = drawColorConverter.ConvertFrom(.drawColor) <br /> Dim drawBrush As New SolidBrush(drawColor) <br /> 'String format <br /> Dim drawStringFormat As StringFormat = New StringFormat() <br /> With drawStringFormat <br /> .Alignment = StringAlignment.Near <br /> .LineAlignment = StringAlignment.Center <br /> .Trimming = StringTrimming.EllipsisWord <br /> End With <br /> 'Border <br /> If CType(.drawBorder, Boolean) Then _ <br /> drawGraphics.DrawRectangle(Pens.Black, drawRectangle) <br /> drawGraphics.DrawString(drawString, drawFont, drawBrush, <br /> drawRectangle, drawStringFormat) <br /> End With <br /> Catch ex2 As Exception <br /> drawGraphics = Nothing <br /> End Try <br />End Sub <br /> <br />The second procedure is the one that draws the channel title, which is read from the XML document and then painted inside the rectangle with the specified font and color; simple and can be easily understood. In the case that the text will not fit in the given rectangle, a text trimming will occur. The rectangle border is drawn only if required attribute is set to true. Also, a lot of conversions are made, as in the previous sample, so be sure to enter them correctly. <br /> <br />Visual C# <br /> <br />private void DrawChannel(XmlDocument rssDocument, <br /> Graphics drawGraphics, GeneralSectionHandler objConfig) <br />{ <br /> XmlNode rssChannel = <br /> rssDocument.SelectSingleNode("rss/channel"); <br /> string drawString = rssChannel["title"].InnerText; <br /> <br /> //Rectangle <br /> RectangleConverter drawRectangleConverter = <br /> new RectangleConverter(); <br /> Rectangle drawRectangle = new Rectangle(); <br /> drawRectangle = <br /> (Rectangle)drawRectangleConverter.ConvertFrom( <br /> objConfig.Title.drawRectangle); <br /> <br /> //Font <br /> FontConverter drawFontConverter = new FontConverter(); <br /> Font drawFont; <br /> drawFont = <br /> (Font)drawFontConverter.ConvertFromString( <br /> objConfig.Title.drawFont); <br /> <br /> //Brush <br /> ColorConverter drawColorConverter = new ColorConverter(); <br /> Color drawColor = new Color(); <br /> drawColor = <br /> (Color)drawColorConverter.ConvertFrom( <br /> objConfig.Title.drawColor); <br /> SolidBrush drawBrush = new SolidBrush(drawColor); <br /> <br /> //String format <br /> StringFormat drawStringFormat = new StringFormat(); <br /> drawStringFormat.Alignment = StringAlignment.Near; <br /> drawStringFormat.LineAlignment = StringAlignment.Center; <br /> drawStringFormat.Trimming = StringTrimming.EllipsisWord; <br /> <br /> //Border <br /> if (Convert.ToBoolean(objConfig.Title.drawBorder)) <br /> { <br /> drawGraphics.DrawRectangle(Pens.Black, drawRectangle); <br /> } <br /> <br /> drawGraphics.DrawString( <br /> drawString, drawFont, drawBrush, <br /> drawRectangle, drawStringFormat); <br />} <br /> <br />Visual Basic <br /> <br />Private Sub DrawChannel(ByVal rssDocument As XmlDocument,_ <br /> ByRef drawGraphics As Graphics,_ <br /> ByVal objConfig As RSSGraphics.GeneralSectionHandler) <br /> Dim rssChannel As XmlNode = rssDocument.SelectSingleNode("rss/channel") <br /> Dim drawString As String = rssChannel.Item("title").InnerText <br /> With objConfig.Title <br /> 'Rectangle <br /> Dim drawRectangleConverter As New RectangleConverter <br /> Dim drawRectangle As New Rectangle <br /> drawRectangle = drawRectangleConverter.ConvertFrom(.drawRectangle) <br /> 'Font <br /> Dim drawFontConverter As New FontConverter <br /> Dim drawFont As Font <br /> drawFont = drawFontConverter.ConvertFromString(.drawFont) <br /> 'Brush <br /> Dim drawColorConverter As New ColorConverter <br /> Dim drawColor As New Color <br /> drawColor = drawColorConverter.ConvertFrom(.drawColor) <br /> Dim drawBrush As New SolidBrush(drawColor) <br /> 'String format <br /> Dim drawStringFormat As StringFormat = New StringFormat() <br /> With drawStringFormat <br /> .Alignment = StringAlignment.Near <br /> .LineAlignment = StringAlignment.Center <br /> .Trimming = StringTrimming.EllipsisWord <br /> End With <br /> 'Border <br /> If CType(.drawBorder, Boolean) Then _ <br /> drawGraphics.DrawRectangle(Pens.Black, drawRectangle) <br /> drawGraphics.DrawString(drawString, drawFont, drawBrush,_ <br /> drawRectangle, drawStringFormat) <br /> <br /> End With <br />End Sub <br /> <br />The third procedure is the one that draws the items. The drawing procedures are very similar, but in addition to the previous sample, I have used two enumerators, one containing items from the xml document and one containing the graphic description on how to draw them. In the case one gets to the end, then both of them will stop. The code draws only the title and the publication date of a post, but can be easily extended to also draw other properties of a post. <br /> <br />Visual C# <br /> <br />private void DrawItems(XmlDocument rssDocument, <br /> Graphics drawGraphics, GeneralSectionHandler objConfig) <br />{ <br /> XmlNodeList rssItems = <br /> rssDocument.SelectNodes("rss/channel/item"); <br /> IEnumerator rssItemsEnum = rssItems.GetEnumerator(); <br /> <br /> ItemsConfigElemColl rssGraphicItems = objConfig.Items; <br /> IEnumerator rssGraphicItemsEnum = <br /> rssGraphicItems.GetEnumerator(); <br /> <br /> while ((rssItemsEnum.MoveNext()) && <br /> (rssGraphicItemsEnum.MoveNext())) <br /> { <br /> XmlNode rssItem = (XmlNode)rssItemsEnum.Current; <br /> <br /> string drawString = <br /> rssItem.SelectSingleNode("title").InnerText; <br /> DateTime drawDate = <br /> DateTime.Parse(rssItem.SelectSingleNode( <br /> "pubDate").InnerText); <br /> <br /> ItemConfigElem cItem = <br /> (ItemConfigElem)rssGraphicItemsEnum.Current; <br /> //Rectangle <br /> RectangleConverter drawRectangleConverter = <br /> new RectangleConverter(); <br /> Rectangle drawRectangle = new Rectangle(); <br /> drawRectangle = <br /> (Rectangle)drawRectangleConverter.ConvertFrom( <br /> cItem.drawRectangle); <br /> <br /> Rectangle drawRectangle2 = new Rectangle(); <br /> drawRectangle2 = <br /> (Rectangle)drawRectangleConverter.ConvertFrom( <br /> cItem.pubDate.drawRectangle); <br /> <br /> //Font <br /> FontConverter drawFontConverter = new FontConverter(); <br /> Font drawFont; <br /> drawFont = <br /> (Font)drawFontConverter.ConvertFromString(cItem.drawFont); <br /> <br /> Font drawFont2; <br /> drawFont2 = <br /> (Font)drawFontConverter.ConvertFromString( <br /> cItem.pubDate.drawFont); <br /> <br /> //Brush <br /> ColorConverter drawColorConverter = new ColorConverter(); <br /> Color drawColor = new Color(); <br /> drawColor = <br /> (Color)drawColorConverter.ConvertFrom(cItem.drawColor); <br /> SolidBrush drawBrush = new SolidBrush(drawColor); <br /> <br /> Color drawColor2 = new Color(); <br /> drawColor2 = <br /> (Color)drawColorConverter.ConvertFrom( <br /> cItem.pubDate.drawColor); <br /> SolidBrush drawBrush2 = new SolidBrush(drawColor2); <br /> <br /> //String format <br /> StringFormat drawStringFormat = new StringFormat(); <br /> drawStringFormat.Alignment = StringAlignment.Near; <br /> drawStringFormat.LineAlignment = StringAlignment.Center; <br /> drawStringFormat.Trimming = StringTrimming.EllipsisWord; <br /> <br /> //Border <br /> if (Convert.ToBoolean(cItem.drawBorder)) <br /> { <br /> drawGraphics.DrawRectangle(Pens.Black, drawRectangle); <br /> } <br /> if (Convert.ToBoolean(cItem.pubDate.drawBorder)) <br /> { <br /> drawGraphics.DrawRectangle(Pens.Black, drawRectangle2); <br /> } <br /> <br /> drawGraphics.DrawString( <br /> drawString, drawFont, drawBrush, <br /> drawRectangle, drawStringFormat); <br /> drawGraphics.DrawString( <br /> cItem.pubDate.MoreText + drawDate.Date.ToString(), <br /> drawFont2, drawBrush2, drawRectangle2, drawStringFormat); <br /> } <br />} <br /> <br />Visual Basic <br /> <br />Private Sub DrawItems(ByVal rssDocument As XmlDocument,_ <br /> ByRef drawGraphics As Graphics,_ <br /> ByVal objConfig As RSSGraphics.GeneralSectionHandler) <br /> Dim rssItems As XmlNodeList = rssDocument.SelectNodes("rss/channel/item") <br /> Dim rssItemsEnum As IEnumerator = rssItems.GetEnumerator() <br /> Dim rssGraphicItems As RSSGraphics.ItemsConfigElemColl = objConfig.Items <br /> Dim rssGraphicItemsEnum As IEnumerator = rssGraphicItems.GetEnumerator <br /> While rssItemsEnum.MoveNext And rssGraphicItemsEnum.MoveNext <br /> Dim rssItem As XmlNode = CType(rssItemsEnum.Current, XmlNode) <br /> Dim drawString As String = rssItem.SelectSingleNode("title").InnerText <br /> Dim drawDate As DateTime = CType(rssItem.SelectSingleNode("pubDate").InnerText,_ <br /> DateTime) <br /> Dim cItem As RSSGraphics.ItemConfigElem = rssGraphicItemsEnum.Current <br /> With cItem <br /> 'Rectangle <br /> Dim drawRectangleConverter As New RectangleConverter <br /> Dim drawRectangle As New Rectangle <br /> drawRectangle = drawRectangleConverter.ConvertFrom(.drawRectangle) <br /> Dim drawRectangle2 As New Rectangle <br /> drawRectangle2 = drawRectangleConverter.ConvertFrom(.pubDate.drawRectangle) <br /> 'Font <br /> Dim drawFontConverter As New FontConverter <br /> Dim drawFont As Font <br /> drawFont = drawFontConverter.ConvertFromString(.drawFont) <br /> Dim drawFont2 As Font <br /> drawFont2 = drawFontConverter.ConvertFromString(.pubDate.drawFont) <br /> 'Brush <br /> Dim drawColorConverter As New ColorConverter <br /> Dim drawColor As New Color <br /> drawColor = drawColorConverter.ConvertFrom(.drawColor) <br /> Dim drawBrush As New SolidBrush(drawColor) <br /> Dim drawColor2 As New Color <br /> drawColor2 = drawColorConverter.ConvertFrom(.pubDate.drawColor) <br /> Dim drawBrush2 As New SolidBrush(drawColor2) <br /> 'String format <br /> Dim drawStringFormat As StringFormat = New StringFormat() <br /> With drawStringFormat <br /> .Alignment = StringAlignment.Near <br /> .LineAlignment = StringAlignment.Center <br /> .Trimming = StringTrimming.EllipsisWord <br /> End With <br /> 'Border <br /> If CType(.drawBorder, Boolean) Then_ <br /> drawGraphics.DrawRectangle(Pens.Black, drawRectangle) <br /> If CType(.pubDate.drawBorder, Boolean) Then_ <br /> drawGraphics.DrawRectangle(Pens.Black, drawRectangle2) <br /> drawGraphics.DrawString(drawString, drawFont, drawBrush,_ <br /> drawRectangle, drawStringFormat) <br /> drawGraphics.DrawString(CType(.pubDate.MoreText, String) & drawDate.Date,_ <br /> drawFont2,drawBrush2, drawRectangle2, drawStringFormat) <br /> <br /> End With <br /> End While <br />End Sub <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/14975877370038939364' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/14975877370038939364' rel='author' title='author profile'> <span itemprop='name'>Sarasoft Technologies</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='http://jambunathan.blogspot.com/2009/07/how-to-code-signature_31.html' itemprop='url'/> <a class='timestamp-link' href='http://jambunathan.blogspot.com/2009/07/how-to-code-signature_31.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2009-07-31T10:52:00+05:30'>10:52 AM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=1320183059559628213&postID=1794562446763199806' title='Email Post'> <img alt='' class='icon-action' height='13' src='https://resources.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-2026303505'> <a href='https://www.blogger.com/post-edit.g?blogID=1320183059559628213&postID=1794562446763199806&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> <div class='comments' id='comments'> <a name='comments'></a> <h4>No comments:</h4> <div id='Blog1_comments-block-wrapper'> <dl class='avatar-comment-indent' id='comments-block'> </dl> </div> <p class='comment-footer'> <a href='https://www.blogger.com/comment.g?blogID=1320183059559628213&postID=1794562446763199806' onclick=''>Post a Comment</a> </p> </div> </div> </div></div> </div> <div class='blog-pager' id='blog-pager'> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='http://jambunathan.blogspot.com/2010/01/dotnet-interview-questions.html' id='Blog1_blog-pager-newer-link' title='Newer Post'>Newer Post</a> </span> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='http://jambunathan.blogspot.com/2009/07/how-to-code-signature.html' id='Blog1_blog-pager-older-link' title='Older Post'>Older Post</a> </span> <a class='home-link' href='http://jambunathan.blogspot.com/'>Home</a> </div> <div class='clear'></div> <div class='post-feeds'> <div class='feed-links'> Subscribe to: <a class='feed-link' href='http://jambunathan.blogspot.com/feeds/1794562446763199806/comments/default' target='_blank' type='application/atom+xml'>Post Comments (Atom)</a> </div> </div> </div></div> </div> </div> <div class='column-left-outer'> <div class='column-left-inner'> <aside> </aside> </div> </div> <div class='column-right-outer'> <div class='column-right-inner'> <aside> <div class='sidebar section' id='sidebar-right-1'><div class='widget Profile' data-version='1' id='Profile1'> <h2>About Me</h2> <div class='widget-content'> <a href='https://www.blogger.com/profile/14975877370038939364'><img alt='My photo' class='profile-img' height='80' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG0bGUrYzjB_YtroxQnftqqFKHoQHNUWtZHoKoqscdcYY5wdqPLeByLbhJZgWP7rKXgGOZORdU8JfBfQpytRoocBwiOPAIM1rUcSBjS7wu4oqMHjhuBPn-tvPO0Y1oCw/s220/jambu.JPG' width='53'/></a> <dl class='profile-datablock'> <dt class='profile-data'> <a class='profile-name-link g-profile' href='https://www.blogger.com/profile/14975877370038939364' rel='author' style='background-image: url(//www.blogger.com/img/logo-16.png);'> Sarasoft Technologies </a> </dt> <dd class='profile-textblock'>Sarasoft Technologies is an emerging global IT solutions provider. We offer a complete range of uncompromising quality and value added IT products and services with focus on specific vertical segments. We provide End-to-end solutions by engaging industry experts and cutting edge technologies. Our aim is to deliver optimal solutions that help our customers achieve their business goals. Contact:- Jambunathan B.Tech[Information Technology]. Mail: vjambunathanbtech@yahoo.com Ph: +91-9944889339.</dd> </dl> <a class='profile-link' href='https://www.blogger.com/profile/14975877370038939364' rel='author'>View my complete profile</a> <div class='clear'></div> </div> </div><div class='widget Followers' data-version='1' id='Followers1'> <h2 class='title'>Viewers</h2> <div class='widget-content'> <div id='Followers1-wrapper'> <div style='margin-right:2px;'> <div><script type="text/javascript" src="https://apis.google.com/js/platform.js"></script> <div id="followers-iframe-container"></div> <script type="text/javascript"> window.followersIframe = null; function followersIframeOpen(url) { gapi.load("gapi.iframes", function() { if (gapi.iframes && gapi.iframes.getContext) { window.followersIframe = gapi.iframes.getContext().openChild({ url: url, where: document.getElementById("followers-iframe-container"), messageHandlersFilter: gapi.iframes.CROSS_ORIGIN_IFRAMES_FILTER, messageHandlers: { '_ready': function(obj) { window.followersIframe.getIframeEl().height = obj.height; }, 'reset': function() { window.followersIframe.close(); followersIframeOpen("https://www.blogger.com/followers.g?blogID\x3d1320183059559628213\x26colors\x3dCgt0cmFuc3BhcmVudBILdHJhbnNwYXJlbnQaByMyMjIyMjIiByNjYzY2MTEqByNmZmZmZmYyByMwMDAwMDA6ByMyMjIyMjJCByNjYzY2MTFKByM5OTk5OTlSByNjYzY2MTFaC3RyYW5zcGFyZW50\x26pageSize\x3d21\x26postID\x3d1794562446763199806\x26origin\x3dhttp://jambunathan.blogspot.com/"); }, 'open': function(url) { window.followersIframe.close(); followersIframeOpen(url); }, 'blogger-ping': function() { } } }); } }); } followersIframeOpen("https://www.blogger.com/followers.g?blogID\x3d1320183059559628213\x26colors\x3dCgt0cmFuc3BhcmVudBILdHJhbnNwYXJlbnQaByMyMjIyMjIiByNjYzY2MTEqByNmZmZmZmYyByMwMDAwMDA6ByMyMjIyMjJCByNjYzY2MTFKByM5OTk5OTlSByNjYzY2MTFaC3RyYW5zcGFyZW50\x26pageSize\x3d21\x26postID\x3d1794562446763199806\x26origin\x3dhttp://jambunathan.blogspot.com/"); </script></div> </div> </div> <div class='clear'></div> </div> </div></div> <table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'> <tbody> <tr> <td class='first columns-cell'> <div class='sidebar no-items section' id='sidebar-right-2-1'></div> </td> <td class='columns-cell'> <div class='sidebar no-items section' id='sidebar-right-2-2'></div> </td> </tr> </tbody> </table> <div class='sidebar section' id='sidebar-right-3'><div class='widget BlogSearch' data-version='1' id='BlogSearch1'> <h2 class='title'>Search This Blog</h2> <div class='widget-content'> <div id='BlogSearch1_form'> <form action='http://jambunathan.blogspot.com/search' class='gsc-search-box' target='_top'> <table cellpadding='0' cellspacing='0' class='gsc-search-box'> <tbody> <tr> <td class='gsc-input'> <input autocomplete='off' class='gsc-input' name='q' size='10' title='search' type='text' value=''/> </td> <td class='gsc-search-button'> <input class='gsc-search-button' title='search' type='submit' value='Search'/> </td> </tr> </tbody> </table> </form> </div> </div> <div class='clear'></div> </div></div> </aside> </div> </div> </div> <div style='clear: both'></div> <!-- columns --> </div> <!-- main --> </div> </div> <div class='main-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <footer> <div class='footer-outer'> <div class='footer-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left footer-fauxborder-left'> <div class='fauxborder-right footer-fauxborder-right'></div> <div class='region-inner footer-inner'> <div class='foot no-items section' id='footer-1'></div> <table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'> <tbody> <tr> <td class='first columns-cell'> <div class='foot no-items section' id='footer-2-1'></div> </td> <td class='columns-cell'> <div class='foot no-items section' id='footer-2-2'></div> </td> </tr> </tbody> </table> <!-- outside of the include in order to lock Attribution widget --> <div class='foot section' id='footer-3' name='Footer'><div class='widget Attribution' data-version='1' id='Attribution1'> <div class='widget-content' style='text-align: center;'> Simple theme. Powered by <a href='https://www.blogger.com' target='_blank'>Blogger</a>. </div> <div class='clear'></div> </div></div> </div> </div> <div class='footer-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </footer> <!-- content --> </div> </div> <div class='content-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <script type='text/javascript'> window.setTimeout(function() { document.body.className = document.body.className.replace('loading', ''); }, 10); </script> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/4290687098-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY7vb64KxDcKrosBA6ISRihyUfR8mw:1714751797331';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d1320183059559628213','//jambunathan.blogspot.com/2009/07/how-to-code-signature_31.html','1320183059559628213'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '1320183059559628213', 'title': 'Sarasoft Technologies', 'url': 'http://jambunathan.blogspot.com/2009/07/how-to-code-signature_31.html', 'canonicalUrl': 'http://jambunathan.blogspot.com/2009/07/how-to-code-signature_31.html', 'homepageUrl': 'http://jambunathan.blogspot.com/', 'searchUrl': 'http://jambunathan.blogspot.com/search', 'canonicalHomepageUrl': 'http://jambunathan.blogspot.com/', 'blogspotFaviconUrl': 'http://jambunathan.blogspot.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': false, 'httpsEnabled': true, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': true, 'analyticsAccountNumber': '', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Sarasoft Technologies - Atom\x22 href\x3d\x22http://jambunathan.blogspot.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Sarasoft Technologies - RSS\x22 href\x3d\x22http://jambunathan.blogspot.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Sarasoft Technologies - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/1320183059559628213/posts/default\x22 /\x3e\n\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Sarasoft Technologies - Atom\x22 href\x3d\x22http://jambunathan.blogspot.com/feeds/1794562446763199806/comments/default\x22 /\x3e\n', 'meTag': '', 'adsenseClientId': 'ca-pub-4996366113739067', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': true, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/a26ecadc30bb77e6', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'Twitter', 'key': 'twitter', 'shareMessage': 'Share to Twitter', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'item', 'postId': '1794562446763199806', 'pageName': 'How to code the signature', 'pageTitle': 'Sarasoft Technologies: How to code the signature'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'Simple', 'localizedName': 'Simple', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': false, 'variant': 'bold', 'variantId': 'bold'}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'How to code the signature', 'description': 'How to code the signature\r \r Here, we\x27ll be focusing on a lot of interesting features of the .NET Framework. Just to enumerate some: web req...', 'url': 'http://jambunathan.blogspot.com/2009/07/how-to-code-signature_31.html', 'type': 'item', 'isSingleItem': true, 'isMultipleItems': false, 'isError': false, 'isPage': false, 'isPost': true, 'isHomepage': false, 'isArchive': false, 'isLabelSearch': false, 'postId': 1794562446763199806}}]); _WidgetManager._RegisterWidget('_NavbarView', new _WidgetInfo('Navbar1', 'navbar', document.getElementById('Navbar1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'lightboxEnabled': true, 'lightboxModuleUrl': 'https://www.blogger.com/static/v1/jsbin/1666805145-lbx.js', 'lightboxCssUrl': 'https://www.blogger.com/static/v1/v-css/13464135-lightbox_bundle.css'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_ProfileView', new _WidgetInfo('Profile1', 'sidebar-right-1', document.getElementById('Profile1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_FollowersView', new _WidgetInfo('Followers1', 'sidebar-right-1', document.getElementById('Followers1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogSearchView', new _WidgetInfo('BlogSearch1', 'sidebar-right-3', document.getElementById('BlogSearch1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_AttributionView', new _WidgetInfo('Attribution1', 'footer-3', document.getElementById('Attribution1'), {}, 'displayModeFull')); </script> </body> </html>