# Friday, July 23, 2010

I've been working on a new control this week that depends a whole lot on transparency and the alpha channel.  The Compact Framework's Bitmap class is actually really, really bad and it's made for all sorts of swearing. 

The design of the control requires me to regularly create a "transparent" background.  We know that you can't create a transparent bitmap directly (which is the fundamental thing that is killing me) so I end up using a TransparentClearBitmap method that first appeared in Project Resistance that does a LockBits and walks the image setting transparency.  This is slow (600ms for my bitmap on the emulator).

I needed to draw on top of this Bitmap to assemble my control layout. The issue is that every time I repainted the control due to a change, I need a new transparent Bitmap and had to pay the 600ms piper.  Needless to say this gave for a really bad user experience.  Well how about just caching the transparent bitmap and returning a copy of it when necessary?  That should be simple, right?

I tried to use the Bitmap constructor to make a copy:

var bmp = new Bitmap(m_transparentBitmap);

Of course it failed. The new Bitmap lost all transparency data.

Well maybe the Clone method would do what I want, after all that's what I needed - an exact clone:

var bmp = m_transparentBitmap.Clone;

Again, all transparency data was lost. Joy.

So it was off to the drawing board to re-implement what should have already been working.  Here's the result - a TransparentBitmap that you can clone and actually keep the transparency info:

public class TransparentBitmap
{
    private Bitmap m_bmp;

    public int Width { get; private set; }
    public int Height { get; private set; }

    public TransparentBitmap(int width, int height)
    {
        Width = width;
        Height = height;
        m_bmp = new Bitmap(width, height, (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

        GraphicTools.TransparentClearBitmap(m_bmp);
    }

    private TransparentBitmap(Bitmap image)
    {
        m_bmp = image;
        Width = image.Width;
        Height = image.Height;
    }

    public static implicit operator Bitmap(TransparentBitmap t)
    {
        return t.m_bmp;
    }

    public TransparentBitmap Clone()
    {
        var clone = new Bitmap(Width, Height, (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

        var dest = clone.LockBits(
                new Rectangle(0, 0, Width, Height),
                ImageLockMode.WriteOnly,
                (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

        try
        {
            var src = m_bmp.LockBits(
                    new Rectangle(0, 0, Width, Height),
                    ImageLockMode.ReadOnly,
                    (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

            try
            {
                int bytes = src.Width * src.Height * 4;
                memcpy(dest.Scan0, src.Scan0, bytes);
            }
            finally
            {
                m_bmp.UnlockBits(src);
            }
        }
        finally
        {
            clone.UnlockBits(dest);
        }

        return new TransparentBitmap(clone);
    }

    [DllImport("coredll.dll", SetLastError = true)]
    private static extern IntPtr memcpy(IntPtr to, IntPtr from, int count);
}

The Clone takes only about 4ms to run instead of 600ms to create new, so it certainly improved things.

Friday, July 23, 2010 4:02:06 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, July 21, 2010

I'm working on a new control and I ran into the need to know if a pixel in an image is transparent or not (essentially I want to ignore clicks on the control if the underlying color is transparent).  My first reaction was that I'd simply call GetPixel on the underlying Bitmap and look at the Color's A (alpha) value.  Unfortunately, the Compact Framework's implementation always appears to return 0xff (fully opaque) for teh A channel.

Next I figured I'd call LockBits and look at the pixel data manually.  Once again the CF tried to thwart me because the supported PixelFormat enumeration values in the Compact Framework don't include anything with Alpha support.

Instead I decided to try to "fool" the framework by creeating my own PixelFormat enumeration that contained all of the actual possible values, not just the three exposed in the CF:

enum PixelFormat
{
    Indexed = 0x00010000, // Indexes into a palette
    GDI = 0x00020000, // Is a GDI-supported format
    Alpha = 0x00040000, // Has an alpha component
    PAlpha = 0x00080000, // Pre-multiplied alpha
    Extended = 0x00100000, // Extended color 16 bits/channel
    Canonical = 0x00200000,

    Undefined = 0,
    DontCare = 0,

    F1bppIndexed = (1 | (1 << 8) | Indexed | GDI),
    F4bppIndexed = (2 | (4 << 8) | Indexed | GDI),
    F8bppIndexed = (3 | (8 << 8) | Indexed | GDI),
    F16bppRGB555 = (5 | (16 << 8) | GDI),
    F16bppRGB565 = (6 | (16 << 8) | GDI),
    F16bppARGB1555 = (7 | (16 << 8) | Alpha | GDI),
    F24bppRGB = (8 | (24 << 8) | GDI),
    F32bppRGB = (9 | (32 << 8) | GDI),
    F32bppARGB = (10 | (32 << 8) | Alpha | GDI | Canonical),
    F32bppPARGB = (11 | (32 << 8) | Alpha | PAlpha | GDI),
    F48bppRGB = (12 | (48 << 8) | Extended),
    F64bppARGB = (13 | (64 << 8) | Alpha | Canonical | Extended),
    F64bppPARGB = (14 | (64 << 8) | Alpha | PAlpha | Extended),
    Max = 15,
}

Since an enum is really just a number, you can directly cast this to a System.Drawing.Imaging.PixelFormat. Nicely (and fortunately), the CF implementation of LockBits doesn't check to ensure that the value you pass in is one of the defined PixelFormat values and it readly accepts this cast value.  Even more interesting is that it returns a set of data with the proper alpha channel data. 

Gettting the Alpha data, then is as easy as this (I don't return a Color because there is no easy way to create a Color class that contains Alpha data in the CF either):

private byte GetPixelAlpha(Bitmap image, Point point)
{
    var d = image.LockBits(new Rectangle(0, 0, this.Width, this.Height),
            System.Drawing.Imaging.ImageLockMode.ReadOnly,
            (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

    try
    {
        // the CF's GetPixel method will always return 0xff (full opaque) for the alpha channel
        // so we have to resort to unsafe shenanigans
        unsafe
        {
            int offset = (d.Width * point.Y * 4) + (point.X * 4);
            byte* p = (byte*)d.Scan0;
            p += offset;

            return *(p + 3);
        }
    }
    finally
    {
        image.UnlockBits(d);
    }
}

Wednesday, July 21, 2010 3:50:57 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, July 20, 2010

Codeplex recently updated the server hosting the IoC project to TFS10.  Since we still have to use Studio 2008 for device development, I had to do some client changes for bindings to get to the server.  TFS 2010 added the concept of a "Team Project Collection", which Codeplex is using - but Studio 2008's Team Explorer dialog has no provision for it.  It took me a while with a search engine to figure out how to actually attach - basically you have to manually type the full path into the connection dialog in Team Explorer like so:

http://<serverName>:<port>/<vdir>/<collectionName>

So for the new TFS10 on Codeplex, it looks like this:

https://tfs.codeplex.com:443/tfs/tfs10

Tuesday, July 20, 2010 10:46:45 AM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, July 12, 2010

One drawback to the OpenNETCF.IoC framework was the difficulty in making object generation loosely coupled.  This is especially true when object types you want to create change depending on your runtime environment.  For example let's say we have an interface IAccelerometerService.  Different devices have different implementations, and the emulator and your integration tests don't even have hardware so they need a simulator.  So you create some classes that derive from the interface like this:

public interface IAccelerometerService
{
}

public class DeviceAAccelerometer : IAccelerometerService
{
// handles the accelerometer by using APIs for device A
}

public class DeviceBAccelerometer : IAccelerometerService
{
// handles the accelerometer by using APIs for device B
}

public class SimulatedAccelerometer : IAccelerometerService
{
// simulates an accelerometer (emulator, test use, etc)
}

That's all well and good, but let's say we have a generic infrastructure module that does the object creation and injection.  We don't want it to have to know about the concrete class types. They might be in separate assemblies that may not even exist - you certainly don't need (or want) to ship emulator implementation for your hardware. 

How would you handle this? The IoC framework doesn't like the following construct:

RootWorkItem.Items.AddNew<IAccelerometerService>();

Because it has no idea what concrete type you want it to create.  In this case it will throw an IOCException.

Today I added a "registration" process to the framework.  You now can do the following:

RootWorkItem.RegisterType(typeof(SimulatedAccelerometer), typeof(IAccelerometerService));

This tells the RootWorkItem that when you call to create an item of type IAccelerometerService, it should actually create an object of type SimulatedAccelerometer.

Each ManagedObjectCollection (so Items, WorkItems, SmartParts and Workspaceas) keeps track of its own Dictionary of type mappings and calling RegisterType on a given WorkItem calls the registration for each.  You can explicitly call RegisterType on any one of the collections directly and "override" an existing registration.  This means that you could have Items create one type and SmartParts create another type for the same interface.  I'm not sure when you'd ever want to do that, but I've provided for it.

Hopefully this makes the IoC framework a little more friendly, especially for testing (which is already painful enough for devices), and helps you, as a developer, develop your solutions faster without having to think about the underlying framework.

Monday, July 12, 2010 5:37:14 PM (Central Daylight Time, UTC-05:00)  #     | 

Codeplex is in the process of upgrading their servers to TFS2010.  It isn't very clear, however, how to attach to the upgraded servers from older versions of Studio (like Studio 2008, which is required for all device development).  The answer is that you have to install a "forward compatibility update".

Monday, July 12, 2010 11:58:02 AM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, June 30, 2010

I've written about your DWR before.   While deleting code is certainly a way to increase it, it's not really the entire point.  The real point is that you should be writing less code.  I'm a huge fan of writing less code - especially less of the redundant, mind-numbing, why-can't-I-hire-an-intern-to-write-this code.  You know what I'm talking about - all of that data access layer garbage that we churn out to get our class data into and out of our relational databases.

If your job is primarily working on one application, you probably don't do this a whole lot, but when you are frequently starting new projects, you find yourself getting into this tedious stuff frequently, and I really, really hate doing it.  Not only is it torture, it's highly prone to errors since it's typically a copy, paste and adjust-the-names process.  How often have you have to write code to generate your database?  Does code like this look familiar?

public Book[] GetAllBooks()
{
  var books = new List<Book>();

  using (SqlCeCommand cmd = new SqlCeCommand("SELECT * FROM Book", Connection))
  {
    using (var results = cmd.ExecuteResultSet(ResultSetOptions.Insensitive))
    {
      while (results.Read())
      {
        if (m_bookOrdinals.Count == 0)
        {
          for (int i = 0; i < results.FieldCount; i++)
          {
            m_bookOrdinals.Add(results.GetName(i), i);
          }
        }

        books.Add(new Book
        {
          BookID = results.GetInt32(m_bookOrdinals["BookID"]),
          AuthorID = results.GetInt32(m_bookOrdinals["AuthorID"]),
          Title = results.GetString(m_bookOrdinals["Title"])
        });
      }
    }
  }

  return books.ToArray();
}

Well, I finally got tired of it and decided to spend some time writing code that would free me from having to do that stuff any longer.  The result is a new, open-source project called the OpenNETCF.ORM Framework.  It's a simple, lightweight ORM that helps take care of this tedium.  For example, the above block of code now looks like this:

public Book[] GetAllBooks()
{
  return Store.Select<Book>();
}

And it pulls all of the books from the underlying SQLCE database. Yes, it's that simple.  Of course getting it to do that requires a little infrastructure work.  For this one the Book class has to look like this:

[Entity]
public class Book
{
  [Field(IsIdentity=true, IsPrimaryKey=true)]
  public int BookID { get; set; }

  [Field]
  public int AuthorID { get; set; }

  [Field]
  public string Title { get; set; }

  [Field(SearchOrder=FieldSearchOrder.Ascending)]
  public BookType BookType { get; set; }
}

But that's a small price to pay in my book.  We went from 11 lines of code (not counting brackets) to one.  Multiply that out by the number of entities, filtering logic, paging logic and all the other code you typoically write and you'd greatly decreased your LOC count.

Now I'm not saying that OpenNETCF.ORM does everything that something like the Entity Framework does.  Remember, this is a small scale framework (the core is only 14k and the SqlCE implementation adds 17k) designed for mobile and embedded systems.  It's also put together by a team of one and as a side project while doing other work.

What it does have, though, is performance. It's actually faster than using direct SQL calls in many cases because it avoid the query processor whenever it can).  It has extensibility. The source code has a full implementation for SQL CE but I've also included the skeleton for an XML implementation for anyone who wants to try their hand at it, and it would be pretty easy to do a MySQL or SQLite implementation as well.  Most important, though, is that it has my commitment.  Like the IoC framework, I've already rolled ORM into a production application.  That means that as I find problems, they are going to get fixed.  As I find features that are missing that would help me get my job done, I'm going to add them.  Bottom line is that this is not a science project that I'm doing purely for fun and that will get abandoned when I get bored with it.

So if you're as tired of writing DAL code as I am, give it a try.  If you like it, let me know, or better yet update the docs or a new implementation.

If you're ready to get started, pull down the latest code (there are no releases quite yet) and look at the test project.  There should be enough to get you going on how to use it, but if you have questions, feel free to post them.

Wednesday, June 30, 2010 10:54:38 AM (Central Daylight Time, UTC-05:00)  #     |