Dec 24 2008

Signature Converter

Category: Software DevelopmentJeff @ 07:27

For a mobile application I'm working on, I needed a simple signature capture control. I found just such a control at the Code Project (http://www.codeproject.com/KB/mobile/SignatureCapture_PocketPC.aspx). The code will capture a signature and actually convert it into bitmap coordinates. This will allow me to store much less data rather than full images. But at some point I'm going to want to convert these bitmap coordinates back into an image. And unfortunately, the signature capture project only provides Java code for performing this process.

Well, if anyone else is interested, here is the Java code ported to C#. My next step will be to extend this class so that it isn't directly dependent on File System IO. But this should be enough to get anyone started who'd like to use the Signature Capture control from CodeProject, but wants to use .NET and C# to convert the bitmap coordinates back into an image.

using System;

using System.Collections;

using System.Collections.Generic;

using System.IO;

using System.Drawing;

using System.Drawing.Imaging;

namespace Agilification

{

    public class SignatureConverter

    {

        const int baseX = 25; const int baseY = 25;

 

        public static void Convert(String inputTxtFile, String outputGraphicsFile)

        {

            List<String[]> v = readFile(inputTxtFile); Hashtable ht = getMinMax(v); int minX = (Int32)ht["minX"]; int maxX = (Int32)ht["maxX"]; int minY = (Int32)ht["minY"]; int maxY = (Int32)ht["maxY"]; int width = maxX - minX + baseX; int height = maxY - minY + baseY; Image image = new Bitmap(width, height); Graphics g2d = Graphics.FromImage(image); var b = new SolidBrush(Color.White); g2d.FillRectangle(b, 0, 0, width, height); drawImage(g2d, v, minX, minY); g2d.Dispose(); image.Save(outputGraphicsFile, ImageFormat.Jpeg);

        }

 

        private static void drawImage(Graphics g2d, List<String[]> v, int minX, int minY)

        {

            for (int j = 0; j < v.Count; j++)

            {

                String[] points = (String[])v[j]; int x1 = 0; int y1 = 0; int x2 = 0; int y2 = 0; for (int i = 0; i < 4; i++)

                {

                    x1 = Int32.Parse(points[0]) - minX + (baseX / 2); x2 = Int32.Parse(points[2]) - minX + (baseX / 2); y1 = Int32.Parse(points[1]) - minY + (baseY / 2); y2 = Int32.Parse(points[3]) - minY + (baseY / 2);

                }

                var p = new Pen(Color.Black); g2d.DrawLine(p, x1, y1, x2, y2);

            }

        }

 

        private static Hashtable getMinMax(List<String[]> v)

        {

            Hashtable ht = new Hashtable(); int minX = 9999; int maxX = 0; int minY = 9999; int maxY = 0; for (int j = 0; j < v.Count; j++)

            {

                String[] points = (String[])v[j]; for (int i = 0; i < 4; i++)

                {

                    minX = (Int32.Parse(points[0]) < minX) ? Int32.Parse(points[0]) : minX; minX = (Int32.Parse(points[2]) < minX) ? Int32.Parse(points[2]) : minX; maxX = (Int32.Parse(points[0]) > maxX) ? Int32.Parse(points[0]) : maxX; maxX = (Int32.Parse(points[2]) > maxX) ? Int32.Parse(points[2]) : maxX; minY = (Int32.Parse(points[1]) < minY) ? Int32.Parse(points[1]) : minY; minY = (Int32.Parse(points[3]) < minY) ? Int32.Parse(points[3]) : minY; maxY = (Int32.Parse(points[1]) > maxY) ? Int32.Parse(points[1]) : maxY; maxY = (Int32.Parse(points[3]) > maxY) ? Int32.Parse(points[3]) : maxY;

                }

            }

            ht.Add("minX", minX); ht.Add("maxX", maxX); ht.Add("minY", minY); ht.Add("maxY", maxY); return ht;

        }

 

        private static List<String[]> readFile(String fileName)

        {

            List<String[]> v = new List<String[]>(); var reader = new StreamReader(fileName); String record = null; while ((record = reader.ReadLine()).Trim().Length > 0)

            {

                String[] points = new String[4]; points = record.Split(' '); v.Add(points);

            }

            return v;

        }

 

        [MTAThread]

        static void Main(String[] args)

        {

            try

            {

                String inputTextFile = ".\\Sign.txt"; String outputImageFile = ".\\Sign.jpg"; Convert(inputTextFile, outputImageFile);

            }

            catch (Exception ex)

            {

                Console.WriteLine(" exception: " + ex.ToString());

            }

        }

    }

}


Tags: ,

Nov 22 2008

Dependency Injection for the Compact Framework, Part 2

Category: Software DevelopmentJeff @ 00:18

Last week I wrote about my need for Dependency Injection for the Compact Framework.  Many DI frameworks do not support the Compact Framework, so I identified four options:

  1. Don't use IoC and dependency injection
  2. Continue to "roll-my-own" dependency injection tool
  3. Pray that Jeremy Miller ports StructureMap to the Compact Framework
  4. Use Ninject

Well, there is a fifth option that I hadn't considered: finding an open source project that does what I need.  Germán Schuager pointed me to a project he created on Google Code called Compact Container. It is lightweight, clean and simple.  After reviewing Germán's code, I found that it would support most of my needs, short of a couple of nice-to-have features.

  1. Marking the injectable constructor with an attribute
  2. Setting a default object life cycle for a container (rather than having to pass in the life cycle every time a type is registered with the container)
  3. Ability to resolve concrete types that have not yet been registered with the container

In the spirit of open-source, I created the necessary code and sent it back to Germán for inclusion in the project.  As of this posting, he's included the constructor attribution feature in the source repository, and hopefully he'll also add the other features as well.

My struggle with Ninject came down to the fact that it operates in a fashion quite distinct from other DI frameworks. I must admit that the Ninject DSL is quite appealing, but certain things that I'm comfortable doing with StructureMap are difficult if not impossible to attain using Ninject without creating a bunch of direct dependencies on the Ninject assemblies.  So it looks like Compact Container is the winner at this point.  We'll see if it sticks.

 

Tags: , , , ,

Nov 14 2008

T4 Templates For The .NET Compact Framework

Category: Software DevelopmentJeff @ 22:48

I first learned about the Text Template Transformation Toolkit (T4) about a month ago when reading some blog posts from Rob Conery and Scott Hanselman. T4 is a code generation tool that comes with Visual Studio 2008 (there's also an add-in for VS 2005).  Rob likes T4 so much, that he's rewriting his SubSonic data access layer builder to use T4 template generation (check out his second preview of SubSonic 3.0).

As I wrote about a few days ago (Dependency Injection for the Compact Framework), I've recently returned to the world of building Smart Device applications using the .NET Compact Framework.  I've been working on building the basic foundations of the domain model and I started running into some situations where code generation could make my team more productive.  So, I tried adding a T4 template to my Compact Framework project (a file with a ".tt" file extension) and *boom*!  Three errors crop up:

  1. Compiling transformation: The type or namespace name 'CompilerError' does not exist in the namespace 'System.CodeDom.Compiler' (are you missing an assembly reference?)
  2. Compiling transformation: The type 'System.CodeDom.Compiler.CompilerErrorCollection' is defined in an assembly that is not referenced. You must add a reference to assembly 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
  3. Compiling transformation: 'System.CodeDom.Compiler.CompilerErrorCollection' does not contain a definition for 'Add'

Why doesn't this work?  Because Visual Studio is attempting to use the Compact Framework assemblies in order to process the T4 template file.  But the Compact Framework assemblies don't include the System.CodeDom namespace. 

I don't think Microsoft is ever going to add the CodeDom namespace to the Compact Framework.  But there is a way to get T4 templates working in a Compact Framework project.  You basically start off by creating two separate projects, one targeting the full .NET Framework, and another targeting the Compact Framework.  Then, combine these projects into the same folder so they can share files between them.  Finally, you can add .tt files to the full .NET Framework project and include the generated .cs files in your Compact Framework project.  Voila!  Templates for the Compact Framework.

I've created a quick-start document to walk you through the process: T4 Templates for the .NET Compact Framework

Happy code generating!

Tags: , ,

Nov 12 2008

Dependency Injection for the Compact Framework

Category: Software DevelopmentJeff @ 08:03

I've spent the last 2 years developing WinForms and ASP.Net MVC applications, so it's been a while since I've worked on a .NET Compact Framework project.  In case you haven't heard of it, the .NET Compact Framework is a compact sub-set of the .NET framework that can run on devices with limited resources (like phones, blackberries, barcode scanners, etc.).  As I began working on the project, I decided up front that I would use the same SOLID principles I use on any other application.  I almost hit a roadblock, however, when it came to choosing a Dependency Injection framework.

I began with just a simple roll-your-own dependency resolver.  But this solution doesn't work well once you need to inject multiple layers of dependencies and build up your object hierarchies in a more complex fashion.  So I did some research into which (if any) DI frameworks support the Compact Framework.  It turns out that only one DI framework supports the Compact Framework: Ninject.  Typically StructureMap has been my DI container of choice, and recently I've spent some time evaluating the Unity container from Microsoft, but neither of these support the Compact Framework.  So I guess I've got a limited number of choices:

  1. Don't use IoC and dependency injection
  2. Continue to "roll-my-own" dependency injection tool
  3. Pray that Jeremy Miller ports StructureMap to the Compact Framework
  4. Use Ninject

Option 1 is not even a real option.  There are too many benefits to be gained from loose coupling and depending on abstractions rather than details.  Option 2 seemed feasible at first, until I needed more complicated object hierarchies.  I can't hold my breath and wait on something that may never happen, so Option 3 isn't a real option either.  So, it looks like I'm going to be heading to Ninja school!  I'll let you know how it goes and what I discover along the way.

Tags: , , , ,