I took a little bit of time today to make a few minor changes to the blog here and added some enhancements to the comments section here. One of the additions is support for Gravatars which is a very simple REST based mechanism that lets you show an avatar image. Gravatar is implemented by quite a few sites these days (SubText, DasBlog and Community Server all support it for example), so if you access any of these sites you can get your image shown on those sites.
This is nothing new really (especially given that the above engines have had it for a while), but I thought it makes a nice change of pace on this blog to talk about something that's straight forward for a change <g>...
Gravatar is a very simple mechanism: The user signs up with a site with his or her email addresss and uploads an image. The image is resized into a square and displayed as a gravatar of up to 80 x 80 pixels (determined by the link). Gravatar is purely REST based and works by the calling site embedding an image link that contains an encrypted URL querystring that references the image URL. It's all very simple and can be accomplished literally with a few lines of code.
For fun here's how it works. First there's the Gravatar implementation the details of which you can find on the Gravatar site. The concept is basically that you embed an image URL into your site and the image is then served by Gravatar. The image is referenced via an MD5 hash and HexBin encoding of the email address. Here's my quick and dirty implementation:
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
namespace Westwind.Weblog
{
/// <summary>
/// Implements the Gravatar API for retrieving a Gravatar image to display
/// </summary>
public class Gravatar
{
public const string GravatarBaseUrl = "http://www.gravatar.com/avatar.php?";
/// <summary>
/// Returns a Gravatar URL only
/// </summary>
/// <param name="Email"></param>
/// <param name="Size"></param>
/// <param name="Rating"></param>
public static string GetGravatarLink(string Email, int Size, string Rating, string DefaultImageUrl)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] Hash = md5.ComputeHash(Encoding.ASCII.GetBytes(Email));
StringBuilder sb = new System.Text.StringBuilder();
for (int x = 0; x < Hash.Length; x++)
{
sb.Append(Hash[x].ToString("x2"));
}
if (!string.IsNullOrEmpty(DefaultImageUrl))
DefaultImageUrl = "&default=" + DefaultImageUrl;
else
DefaultImageUrl = "";
return string.Format("{0}?gravatar_id={1}&size={2}&rating={3}{4}",
Gravatar.GravatarBaseUrl, sb.ToString(), Size, Rating, DefaultImageUrl);
}
/// <summary>
/// Returns a Gravatar Image Tag that can be directly embedded into
/// an HTML document.
/// </summary>
/// <param name="Email"></param>
/// <param name="Size"></param>
/// <param name="Rating"></param>
/// <param name="ExtraImageAtributes"></param>
/// <returns></returns>
public static string GetGravatarImage(string Email, int Size, string Rating,
string ExtraImageAttributes,string DefaultImageUrl)
{
string Url = GetGravatarLink(Email, Size, Rating, DefaultImageUrl);
return string.Format("<img src='{0}' {1}>",Url,ExtraImageAttributes,DefaultImageUrl);
}
/// <summary>
/// Return a full Html img tag for a GravatarBaseUrl
/// </summary>
/// <param name="Email"></param>
/// <param name="ExtraImageAttributes"></param>
/// <returns></returns>
public static string GetGravatarImage(string Email, string ExtraImageAttributes)
{
return GetGravatarImage(Email, 80, "G", ExtraImageAttributes, string.Empty);
}
}
}
Nothing complicated here. MD5 encoding is built into .NET and the HexBin conversion is easy to do. HexBin is basically just a hex representation of each character by converting the character into its two character hex representation.
There are two static methods - one that generates only the URL and one that generates the full image which is likely the most common scenario. A couple of things that I like to do with the Gravatar. First off if the user didn't leave an email address I prefer not to show an image and if the entry happens to be not a blog entry but trackback too it shouldn't actually show a gravatar.
So here's how it gets called off a repeater in the page:
<asp:Repeater runat="server" ID="repFeedback" OnItemCommand="repFeedBack_ItemCommand" EnableViewState="false">
<ItemTemplate>
<div class="<%# (string) Eval("Author") == App.Configuration.WebLogAuthor ? "comment commentauthor" : "comment" %>" >
<%# WebUtils.GravatarLink( Container.DataItem as System.Data.DataRowView ) %>
<b><%# Eval("Title") %></b><br />
<small> by
<%# string.IsNullOrEmpty( Eval("Url") as string) ? Eval("Author") as string : wwUtils.Href( Eval("Author") as string,Eval("Url") as string,"_WebLog",null) %> <%# WebUtils.WebLogDateString( (DateTime) Eval("Entered"),true ) %>
<%# string.IsNullOrEmpty( Eval("Body") as string ) ? "" : "<br /><br />" + (Eval("Body") as string) %>
<asp:LinkButton runat="server" ID="lnkRemoveComment" visible="<%# this.IsAdmin %>"
CommandName="RemoveComment" CommandArgument='<%# Eval("pk") %>'><br />Remove Comment</asp:LinkButton>
</small>
</div>
</ItemTemplate>
</asp:Repeater>
Note rather than directly linking the Gravatar link it calls off into a static utility method (primarily because this link is used in several places). The method needs to check a few things so rather than pass a slew of Eval() parameters I instead pass the Dataitem as whole and so give the method access to all the fields from this query.
/// <summary>
/// Generate a gravatar link
/// </summary>
/// <param name="Email"></param>
/// <returns></returns>
public static string GravatarLink(DataRowView Row)
{
// *** Only add gravatar to comments
if ((int)Row["EntryType"] != 3)
return "";
string Email = (string)Row["Email"];
if (string.IsNullOrEmpty(Email))
return "";
return Gravatar.GetGravatarImage(Email,"style='opacity:.75;filter:alpha(opacity=\"75\");' align='right' hspace='5'");
}
In general I'm a big fan of calling page level methods or (in this case) generic static methods if more than one or two operations need to be set because of the hideousnous that otherwise ensues in the ASP.NET HTML markup. Compare this simple method eval even to the relatively simple conditional Author logic above trying to figure out which Css Class to display on the div for example. <s>
Anyway. After playing around with new technology in R & D modes for the last few weeks, sometimes it's nice to come back to some simple code that produces results in just a few minutes of work instead of days <s>...
Other Posts you might also like