Code Sample: GDI+ that Adapts to Your Mobile Browser

I thought I’d follow up my post 10 great resources for learning GDI+ for ASP.NET 2.0 with the latest code I’ve rolled out from the AjaxNinja Laboratory. It’s called Adaptive GDI+ Rendering for Mobile Devices.

Abstract: Web browsers designed for embedded and mobile devices have to conserve memory, network bandwidth, and processing resources given how limited those resources are compared to full-fledged computers, thus all browsers for mobile devices (and even computers) carry “preference” information to help mobile websites optimize their output for that particular browser.

Some browsers can’t even support common image types; many mobile devices don’t even support the increasingly popular .png extension. Thus, sometimes it may be to our benefit to detect and anticipate these short comings and adapt to them.

AjaxNinja’s Solution: Using the lovely MobileCapabilities class from the System.Web.Mobile namespace we can detect the MIME type of the browser’s preferred image and automatically re-render an existing image or generate an existing image to that type! Of course we may lose a lot of image quality if we’re moving from a .png to a .gif but it’s better than the image not being available at all!

The Results:

Using the popular OpenWave mobile phone simulator (it’s image/gif)

OpenWave - Adaptive Rendering with GDI for Mobile Phones

Using Firefox 2.0

Firefox - Adaptive Image Rendering

Using Internet Explorer 6

Internet Explorer - Adaptive Rendering for Mobile Devices

Try it yourself at the AjaxNinja Mobile Lab – Adaptive GDI+ Rendering for Mobile Phones – Leave a reply or comment with your phone, browser, and results here if you’d like.

The Code:

The first piece of code we have is a static utilities class I wrote that takes an incoming string with MIME type information and translates that data into an ImageFormat object that the GDI+ drawing libraries can understand. This also does the reverse operation and provides the MIME type if you’d like… It’s not terribly hard to write.

namespace AjaxNinja.Mobile.Graphics
{
public static class MobileGDIUtility
{
public static ImageFormat getFormatPreference(MobileCapabilities mobCaps)
{
//Our return value (eventually)
ImageFormat result;
switch (mobCaps.PreferredImageMime) //Returns the MIME type of the preferred image
{
case “image/bmp”: //Bitmap
result = ImageFormat.Bmp;
break;
case “image/gif”: //GIF
result = ImageFormat.Gif;
break;
case “image/jpeg”: //JPEG
result = ImageFormat.Jpeg;
break;
case “image/png”: //PNG
result = ImageFormat.Png;
break;
case “image/tiff”: //TIFF
result = ImageFormat.Tiff;
break;
default:
//GIF is a good default value in case we have a fallthrough.
result = ImageFormat.Gif;
break;
}
return result;
} public static String getMIMEType(ImageFormat format)
{
if(format.Equals(ImageFormat.Bmp)) //Returns the MIME type of the preferred image
return “image/bmp”;
if(format.Equals(ImageFormat.Gif)) //GIF
return “image/gif”;
if(format.Equals(ImageFormat.Jpeg)) //JPEG
return “image/jpeg”;
if(format.Equals(ImageFormat.Png)) //PNG
return “image/png”;
if(format.Equals(ImageFormat.Tiff)) //TIFF
return “image/tiff”;
return “text/plain”; //If we fall all the way through, just return blank text
}
}
}

Now we have the MobileAdaptiveImage.ashx handler which does all of the real GDI+ work…

public void ProcessRequest (HttpContext context) {
MobileCapabilities mobCaps = (MobileCapabilities)context.Request.Browser;
context.Response.ContentType = mobCaps.PreferredImageMime;

//Because people will want to know who made this heinously easy demo!
String waterMark = “AjaxNinja”;

//Notice how I use the mobCaps.ScreenCharactersWidth attribute.. this is for LOWER bounding
//int screenSize = mobCaps.ScreenPixelsWidth > 300 ? 300 : mobCaps.ScreenCharactersWidth;
int screenSize = 144;

System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(screenSize, 100);
System.Drawing.Graphics grphx = System.Drawing.Graphics.FromImage(bmp);
System.Drawing.Font fnt = new System.Drawing.Font(”Verdana”, 12); //Verdana size 12

grphx.DrawString(mobCaps.PreferredImageMime, fnt, System.Drawing.Brushes.Yellow, 20, 10);
System.Drawing.Font wm = new System.Drawing.Font(”Tahoma”, 8); //Tahoma size 8
grphx.DrawString(waterMark, wm, System.Drawing.Brushes.White, 70, 80);
//Send the image out to the response stream
bmp.Save(context.Response.OutputStream, MobileGDIUtility.getFormatPreference(mobCaps));
wm.Dispose();
fnt.Dispose();
grphx.Dispose(); //Clean-up
bmp.Dispose();
}

Lastly we put it all together in mobileAdaptiveGDI1.aspx

<html xmlns=”http://www.w3.org/1999/xhtml” >
<body>
<mobile:Form id=”Form1″ runat=”server”>
This image is being rendered according to your mobile device’s preferences in real time. <br />
<mobile:Image Runat=”server” ImageUrl=”AdaptiveImage.ashx” />
<mobile:Link ID=”Link1″ Runat=”server” NavigateUrl=”~/Default.aspx”>Return to AjaxNinja Labs</mobile:Link>
</mobile:Form>
</body>
</html>

The line to take note of here is this one:

<mobile:Image Runat=”server” ImageUrl=”AdaptiveImage.ashx” />

This is what triggers our HTTPHandler written on the .ashx page to fire and render the image.

Download Source: Adaptive GDI+ Rendering Source Code

If you have any questions, comments, or suggestions, please leave them!

[Post to Twitter] 

If you enjoyed this post, make sure you subscribe to my RSS feed!

Post a Comment

Your email is never published nor shared. Required fields are marked *