Thursday, July 10, 2008

Developing for Surface


We got a surface in the office! I can't really talk about the project I'm working on, but I will say that I'm determined to get some version of the satellite tracker on it - It offers a very interesting interaction model that could be a fun way to visualize and interact with orbits. 

One problem is that the SDK is under wraps so when you run into problems there's really not much of a community to turn to. The MS Surface developer's blog offers little in the way of hard examples, offering more of a list of cool stuff they're working on and why this thing is going to be cool when the masses get a hold of them.

I'd love to offer up some more info, but am under an NDA! Here's a little peek at our developer station until I can talk more.

#    Comments [0] |
 Tuesday, May 20, 2008

Hacking the Nike SportBand

The Nike SportBand came out. Really, it's no more than a glorified pedometer, but it stores a lot more data about your running. Now it's finally no bigger than you would expect. Previously you had to carry around an Ipod Nano.

With both versions, the only real way to get to the data is to upload it to the Nike website. With the Ipod, you could pull the files directly off. I don't really like the idea of Nike's website being the only way to really use the data, and would have come up with a way to use the Ipod data if I had one.

I was hoping that the SportBand worked similarly, but unfortunately, that's not the case. It is a USB device, but the computer sees it as a USB Human Interface Device (a keyboard or mouse, really) instead of a flash drive.

I've done a little research into accessing HIDs with the .NET framework, and though it appears possible - with thanks to Jan Axelson, I haven't yet figured out how to actually read the data off the device. If anyone knows more about this, I'd love to hear about it. Once I have the data, it should be easy enough to build a nice WPF app to display your run data.

Anyway, as a start, the initial critical data for the Nike+ USB device is:

Vendor ID: 11AC
Product ID: 4269

When I use the HID tester though I get the following message:

Device Detected: 
- Vendor ID: 11AC
- Product ID: 4269
The attempt to write an Output report has failed.
The attempt to read an Input report has failed.
The attempt to write a Feature report has failed.
The attempt to read a Feature report has failed.

Well, maybe more later if I can figure some more out.
#    Comments [0] |
 Saturday, April 26, 2008

Silverlight Fun

Primarily for the experience, I've been migrating my GDI/command-line based satellite tracking software to a web service and Silverlight application. Ultimately, it's nowhere near as useful since it's not going to be able to control your tracking hardware, but it's a fun excercise. Ultimately, the GDI version would go away and be replaced with a WPF version.

You'd think that building a WPF application and Silverlight application might produce a lot of code that is reusable. Ultimately, there is very little that's reusable primarily due to the constraints that MS put on Silverlight's library and what is available. They removed seemingly random features from Silverlight that, if you were writing a rich application in WPF, you would no doubt use. This means that, at this point, Silverlight is sufficiently handicapped to make code migration between WPF and Silverlight almost pointless. Below are some particular problems I've run across...

Viewport: There is no viewport in Silverlight. The viewport manages auto-sizing, zooming, and scrolling a canvas. This would be ideal for a map application such as the satellite tracker where you sometimes would like to display only a portion of the world view. Unfortunately it doesn't exist and all such presentation magic needs to be handled manually using Transforms on the canvas in question.

Mouse and Keyboard Events: Wouldn't it be nice to be able to tell if the shift key were pressed when a left-click even is caught? Wouldn't it be nice to tell if a right click event happened? The simple things in life are the most important! Really, I'm having to watch shift-key up and down events, toggling a state variable, and checking that variable when a left mousedown even occurs. This is even more complicated by the fact that there's no right-click! so I'm watching various combinations of ctrl-alt-shift keypresses during the mouse events. WHY?

Image Sizes: For some reason, I can't download an image larger than 3000 pixels wide. I'm sure the exact width isn't the true issue, but my world map needs to be 6000 pixels at 5x zoom factor, and it just isn't happening. I'm not sure why, but it's really irritating. [UPDATE 4/26] It looks like this was a problem with Firefox. The images wouldn't load directly in the browser either. Seems that restarting it worked. Makes sense since Silverlight, like flash, is running within the context of the browser and obtains all of its external funtionality through the browser.

Font Hinting: I'm all for this new vector-based rendering engine. I don't understand why that removes any requirements for font hinting. We still have to render fonts at sub 10px heights, and with hinting, the FONTS decide how they look best, not some random coder from Redmond. Sure, one day, we'll be dealing with magical 1200dpi screens, but now I'm still working at not much greater than the good ol' 72dpi resolution.

There are a lot of similar complaints on various blogs from various developers. It's very hard to decode which version of the runtime and development environment people are talking about when they make these complaints. Some features were around in 1.1 which have dissapeared in 2.0, and visa versa. Some people are complaining that some feature is broken or not implemented which should have been. I've noticed that in some cases it seems that folks are mistaken  - generally looking for features as they were in WinForms or GDI whereas they've simply been moved (or obfuscated) in WPF/Silverlight.

One such feature in particular is marshalling calls across threads primarily for GUI updates. I've determined that it is possible, but is implemented using each control's Dispatcher property instead of a Control.Invoke() call as was the case in WinForms. Silverlight fully supports spooling up a thread, doing some work, and invoking method calls back on the GUI thread. I was really worried when I read more than one post from folks who hadn't figured that out and were saying it wasn't supported.

You can see the progress of the app here.
#    Comments [0] |
 Saturday, January 26, 2008

Satellite Tracking Software

I wasn't extremely happy with the PC satellite control software out there, so I decided to do something about it. The process was quite a learning experience - it's my first true multi-threaded GUI app (as opposed to the web apps I'm usually building) and I learned a lot about basic satellite prediction.

It's based on bits and pieces of other open-source software out there, but architected using a more modular approach with decoupling done through a series of event handlers set up as a bi-directional message bus. I release the code on Google Code and wrote an article for the AMSAT Journal (122.55 KB).

#    Comments [0] |
 Thursday, May 17, 2007

Loren Ipsum library for .NET

It's QA Time in my world now... Just finished implementing a TeamSite/ASP.NET Intranet with a nice framework that allows TS to really only manage the content and metadata as XML and ASP.NET manages the presentation layer. The data access layer is defined by some XML that generates not only .NET access classes (using XML deserialization, of course), but helps us build all of the DCTs for the content entry.

Anyway, it's time to stress test this thing, and we're going to need a lot of data to really simulate what Intranets and Corportate websites can get like after a couple of years of abuse... That's more than my stubby fingers can type, and I dare say more than I can even copy/paste from www.lipsum.com. I figured it was high time to just make a library... Since they kindly provide an XML feed, it's super easy to just generate a request and pull the text out of it. I took it a small step further and blew out the API about as fully as possible.

Anyway, generating random content is now as easy as:
LipsumResponse r = Generator.Get(new LipsumRequest(20, LipsumRequest.RequestType.WORDS, false));
Console.WriteLine(r.Lipsum);
Here's links to the source, binaries, and documentation:

Documentation
Source
Binaries

#    Comments [0] |
 Wednesday, November 15, 2006

Quick and easy passwords for ASP.NET

There are quite a few samples on the net which will provide alternate password protection schemes for ASP.NET. There are also built in authentication and authorization mechanisms which are great at what they do, are robust, proven, and super flexible. Occasionally, however, you need something a little simpler.

In my case, I generally need to provide a basic password protection for simple admin/reporting tools or development environments I want to keep away from prying eyes. The optimal solution for me would be something that I can simply set up in web.config and forget about.

This article will outline the basics of getting something as simple as that set up and how you'd configure your web application once the code is running.

Setting up browser-based authentication involves the following steps:

  • Derive from the HttpModule base class
  • Interpret the appropriate HTTP Headers
  • Validate against a configuration or data store
  • Modify the appropriate HTTP Headers based on the result

Code

In setting up our HttpModule, the event that we are most interested in is Application.AuthenticateRequest. We need to setup a handler for it in the HttpModule.Init() method.

Once that's done, we can handle the bulk of the HTTP work that needs to be done. This little bit of code sets up the variables and tests to see if we can even handle this request.

HttpApplication app = (HttpApplication)source;
string authStr = app.Request.Headers["Authorization"];

/* If there's nothing in the header, then it's an anonymous request */
if (authStr == null || authStr.Length == 0)  return;

/* If the authtype isn't Basic, then assume someone else will handle it. */
authStr = authStr.Trim();
if (authStr.IndexOf("Basic",0) != 0) return;

Next, we need to interpret the header information which is stored in Base64 for basic authentication.

string encodedCredentials = authStr.Substring(6);
byte[] decodedBytes = Convert.FromBase64String(encodedCredentials);

string s = new ASCIIEncoding().GetString(decodedBytes);
string[] userPass = s.Split(new char[] {":"});
string username = userPass[0];
string password = userPass[1];

Finally, authenticate the user using the credentials we were presented with and modify the headers to reflect the results. If we are successful, give the current context a Principal based on our credentials in case that information is needed further down the line.

if (AuthenticateUser(app, username, password, out roles))
{
    string realm = "dieselrover";
    app.Context.User = new GenericPrincipal(new GenericIdentity(username, realm),
roles);
}
else
{
    DenyAccess(app);
}

The AuthenticateUser method simply checks the credentials against some settings in the web.config. If you are interested in seeing that, just download the project and browse through it. You can easily override that method with your own if you want a more complicated data store for usernames and passwords, but I would strongly suggest evaluting a more robust solution if you need "real" authentication.

Configuration

Now lets look at how to set this up and get it running. For those of you not interested in how it really works, you can just download the binary, put it in your bin folder, and edit the web.config file.

First, set up the configuration handler:

<configSections>
   <section name="MonoSite.Authentication"
type
="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
/>
</configSections>

Second, configure the authentication settings by setting the username, password, and realm. The realm is used by the client to organize saved passwords.

<MonoSite.Authentication>
  <add key="username" value="admin" />
  <add key="password" value="admin1234" />
  <add key="realm" value="dieselrover" />
</MonoSite.Authentication>

Third, setup the HttpModule.

<httpModules>
  <add name="Authentication"
type
="MonoSite.Http.AuthenticationModule,MonoSite.Http.Authentication" />
</httpModules>

Lastly, tell ASP.NET that you want there to be some sort of authentication.

<system.web>
 <authorization>
  <deny users="?"/>
 </authorization>
</system.web>

If you want to only password protect certain subfolders of your application, you can do that easily by using the location tag.

<location path="admin">
 <system.web>
  <authorization>
   <deny users="?"/>
  </authorization>
 </system.web>
</location>

Source code and binaries

#    Comments [0] |
 Monday, April 10, 2006

Smooth Alpha Layers with GDI+ [Part III]

Previously, I had applied an RGB Euclidean distance vector to the alpha channel of a jpeg and ended up with better results than Bitmap's MakeTransparent. There was, however, still a slight halo around the opaque parts of the image and I promised to show you a way that you might be able to improve upon that.

The plan to help get rid of the halo is to truncate the map at a lower an upper threshold and rescale the values in between. In other words, we know that there are lots of colors close to white that we want to throw away, and there's only a few colors around blue that we want to keep.

I chose to scale my thresholds to 8 bits instead of making the user guess (or know) the range of possible values for the distance map. Here's the code to truncate and rescale:

public static void SetThreshold(Bitmap bm, double[][] distanceMap, int limit1,
int limit2)
{
double maxDistance = GetMaxDistance(bm);
double lim1 = Scale255ToDouble(limit1, maxDistance);
double lim2 = Scale255ToDouble(limit2, maxDistance);

for (int x = 0; x < distanceMap.Length; x++)
{
for (int y = 0; y < distanceMap[x].Length; y++)
{
distanceMap[x][y] = ScaleDistanceToRange(distanceMap[x][y],
maxDistance, lim1, lim2);
}
}
}

private static double ScaleDistanceToRange(double val, double maxVal,
double lim1, double lim2)
{
if (val <= lim1) return 0;
if (val >= lim2) return maxVal;

return ((val - lim1) / (lim2 - lim1)) * maxVal;
}

And here's the results... (Again, this doesn't work fully in IE because it won't make PNGs transparent!)

Original:

Original with alpha channel:

This is about as good as you can expect, however, I haven't tried with a wider array of colors. I have a feeling that with more colors, it might be worth transforming the image to CSV and processing based on one or more of those channels.

#    Comments [0] |
 Saturday, April 08, 2006

Smooth Alpha Layers with GDI+ [Part II]

As I was saying before, I need to make an image with a smooth transparency. In other words, pick a transparent color and base an alpha layer on that with smooth edges.

The basic process is to base each pixel's alpha value on its euclidean distance from the transparent color. You could do that directly to the 8-bit alpha channel of a 32bpp ARGB image, but I forsaw a little more math down the line, so I chose to do the processing to a 2 dimensional array of doubles the same size as the image.

Here's the code to generate the map:

public static double[][] GetDistanceMap(Bitmap bm, Color c)
{
double[][] distanceMap = new double[bm.Width][];

for (int x = 0; x < bm.Width; x++)
{
distanceMap[x] = new double[bm.Height];
for (int y = 0; y < bm.Height; y++)
{
distanceMap[x][y] = GetEuclideanDistance(c, bm.GetPixel(x, y));
}
}

return distanceMap;
}

private static double GetEuclideanDistance(Color c1, Color c2)
{
int r1 = Convert.ToInt32(c1.R);
int g1 = Convert.ToInt32(c1.G);
int b1 = Convert.ToInt32(c1.B);
int r2 = Convert.ToInt32(c2.R);
int g2 = Convert.ToInt32(c2.G);
int b2 = Convert.ToInt32(c2.B);
return Math.Sqrt(((r1 * r1) - (r2 * r2)) +
((g1 * g1) - (g2 * g2)) +
((b1 * b1) - (b2 * b2)));
}

If you wanted to apply this directly to an image's alpha channel, you would certainly get improved results over GDI+'s MakeTransparent method which just finds a color and turns a pixel on or off. This, on the otherhand, will turn pixels more opaque the farther they are away from the chosen transparent color.

In order to apply our double precision values to an 8-bit (256 value) channel of an image, we're going to need to scale the numbers to the theoretical maximum Euclidean distance. We can calculate that if we know the number of bits per color (not pixel) which were used in our source image. For now, I'm going to assume that we'll be working with 24 bit RGB images and anything that is not will be converted beforehand.

     Dmax = SQRT(2552 + 2552 + 2552)

And here's the code we'll use to apply a distance map to an image:

public static Bitmap ApplyDistanceMap(Bitmap sourcebm, double[][] distanceMap)
{
Bitmap bm = new Bitmap(sourcebm.Width, sourcebm.Height,
PixelFormat.Format32bppArgb);
double maxDistance = GetMaxDistance(bm);

for (int x = 0; x < bm.Width; x++)
{
for (int y = 0; y < bm.Height; y++)
{
Color c = sourcebm.GetPixel(x, y);
int val = ScaleDoubleTo255(distanceMap[x][y], maxDistance);
bm.SetPixel(x, y, Color.FromArgb(val, c));
}
}

return bm;
}

This will turn the following image with a white background into the one with the red background. NOTE: You can't see the transparent layer of the PNG unless your browser supports it. You're out of luck, IE users. Go get Firefox.

Original:

Original with alpha channel:

Not bad. The transparency is smooth, but there's still a halo of white around it. Next time I'll show how to improve on that just a tad.

#    Comments [0] |
 Friday, April 07, 2006

Smooth Alpha Layers with GDI+

I'm working on a project with a Flash programmer friend, Jack. In one of those seemingly innocuous discussions that inevitably start with the phrase "Shouldn't you be able to...". and end up with me furiously flipping through books or googling for algorithms.

Jack needs to be able to upload an image in any reasonable format (gif, jpeg, tiff, png) and have it converted to a png. That's easy enough, but then he needs to be able to supply an x,y coordinate and have the color of that pixel be made transparent. Again, that's not so difficult in and of itself, but to make it look GOOD, you need to make sure that you grab not only that color, but a range of colors.

That's all well and good, but by the time someone is uploading an image, it's most likely got some anti-aliasing between the color you want to be transparent and the colors you want to keep. That will certainly cause some artifacts that we want to try to avoid...

So here's my plan of attack:

1. Calcualte the Euclidean distance of each of the pixels from the color to be made transparent. There are a number of good websites with information about this. The formula is:

     d = SQRT((R1 - R2)2 + (G1 - G2)2 + (B1 - B2)2)

This will effectively make a grayscale bitmap whose pixels are black if the colors are exactly the same as the target color and get lighter as they stray away.

2. The next step is similar to what you do when you tweak the histogram of an image in Photoshop. Any pixel whose value is less than a given threshold will be made completely transparent (alpha value of 0%). Any pixel whose value is greater than another number becomes fully opaque (alpha 100%). In between, the values are weighted to a scale from 0-100%

3. Producing a transparent PNG from there is a simple matter of applying that grayscale image to the alpa channel of the original image! Getting that image into Flash 7 is another matter. (But that's another show)

What about Bitmap.MakeTransparent(Color c) I hear you say? I'll be it works great on images you have full control over and started off as bitmaps, but what about jpegs which need to be supplied by anyone and their dog? Here's what MakeTransparent does to a jpeg: (NOTE: this sample doesn't work with IE because it doesn't properly display alpha channels for PNGs)

Original:

Original with MakeTransparent(Color.White):

#    Comments [0] |

-