Server.MapPath

Last week, I created a WinForms signature capture panel and then rendered the data out to a webpage.  You can read about it here.  The problem is that I used Response.Write to write the image to the browser.  Even in a web control, the only thing shown in a browser is the image:

image

gives this:

image

 

I then decided that I should use a Web.UI.Image Control to render the image. 

image

The problem?  ImageUrl is the method you use to assign the image, and that only has 1 signature – 1 String that is the Url of the image that is, typically, located on the file system.

 

image

Without thinking too hard, I decided to put the image on the file system  and then point to the image in the code behind.

I wrote the following code:

private void LoadSignature()
{
    SignatureFactory signatureFactory = new SignatureFactory();
    String fileName = String.Format("~/images/Signature.bmp");

    using (Bitmap bitmap = new Bitmap(200, 100))
    {
        using (Graphics graphics = Graphics.FromImage(bitmap))
        {
            Signature signature = signatureFactory.LoadSignatureFromFileSystem(@"C:\Signatures\signature.xml");
            Pen pen = new Pen(Color.Black);

            SolidBrush solidBrush = new SolidBrush(Color.White);
            graphics.FillRectangle(solidBrush, 0, 0, 400, 50);

            foreach (Glyph glyph in signature.Glyphs)
            {
                foreach (Line line in glyph.Lines)
                {
                    graphics.DrawLine(pen, line.StartPoint.X, line.StartPoint.Y,
                        line.EndPoint.X, line.EndPoint.Y);
                }
            }
            bitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Bmp);
        }
    }
    this.signatureImage.ImageUrl = fileName;
}

When I ran it, I got the following exception:

image

Carp!  And no inner exception to boot!  When you Bing/Google/AskJeeves this exception, you get TONS of potential reasons (Security, Location, OOM, etc…) – basically, the managed wrapper for the CGI+ call didn’t implement any exceptions.  Without knowing anything about the implementation, I have to believe that HRESULT did return something, MSFT was just to lazy busy to send out meaningful exception message.

After screwing around for a bit, I would get the message to write to the file system by hard-coding the path like so:

//String fileName = String.Format("~/images/Signature.bmp");
String fileName = String.Format(@"C:\Users\Jamie\Desktop\Tff.SignatureCapture\Tff.SignatureCapture.WebForm\images\Signature.bmp");

The problem is that the Signature.ImageUrl now breaks:

image

It was coding after 8PM, so I immediately started throwing more gasoline on the fire by compounding my mistakes.  I thought, heck, I need need 2 strings for the file – 1 that the GDI+ uses to write and 1 that the ASP:Image control can read from like this:

It worked, so I went to

String readFileName = String.Format("~/images/Signature.bmp");
String writeFleName = String.Format(@"C:\Users\Jamie\Desktop\Tff.SignatureCapture\Tff.SignatureCapture.WebForm\images\Signature.bmp");

bed, safe in the knowledge that I created a great solution:

image


Around 2 in the morning I woke up.  “You idiot” I thought.  The ASP.NET framework already has a provision to resolve relative and absolute paths.  It is the Server.MapPath function:

bitmap.Save(Server.MapPath(fileName), System.Drawing.Imaging.ImageFormat.Bmp);

Sure enough, that did the trick.  Since I was up a 2:15AM with my computer on, I decided to look at the ASP Image.Control to see if I could extend it to have an ImageStream function.

image

Sure enough, it is not sealed.  that might be a fun project for next week.  I went back to sleep, in a better place….

Advertisements

Signature Capture

I was chatting with another member of TriNug last night and we talked about the best way to capture a user’s signature.  There are some pretty good articles out there, including this one.  I dove right in with a WinForm application and a Panel control and built something like this:

image

 

Visual Studio 2010 and WinForms made this a pretty straightforward task.  First, I built up my domain model starting with the points that are captured from the Panel.MouseMove event handler (MouseEventArgs) with the e.Location of type Point.

I created a Line class that has 2 points that make up the line:

[Serializable]
public class Line
{
    public Line()
    {

    }

    public Line(Point startPoint, Point endPoint)
    {
        this.StartPoint = startPoint;
        this.EndPoint = endPoint;
    }

    public Point StartPoint { get; set; }
    public Point EndPoint { get; set; }
}

I then created a Glyph class that is a collection of those lines:

[Serializable]
public class Glyph
{
    public Glyph()
    {
        this.Lines = new List<Line>();
    }
    public List<Line> Lines { get; set; }
}

I could have called this class “letter” but each glyph may or may not be a letter – it could be several letters strung together in cursive, a part of a letter (the dot of the i), or may not be any letter (like when R2D2 signs his name.  R2D2 is a boy, right?)

Anyway, I then created a Signature class that is a collection of glyphs:

[Serializable]
public class Signature
{
    public Signature()
    {
        this.Glyphs = new List<Glyph>();
    }

    public List<Glyph> Glyphs { get; set; }
}

If this was used in a real-world application, this class would have a uniqueId so you can relate it back to your people/user class.  It might have some other properties to allow easy comparison and analysis.

I then coded in my WinForm a way to capture the user’s mouse strokes and putting them into this signature graph.  First, I started with some form level variables:

Boolean IsCapturing = false;
private Point startPoint;
private Point endPoint;
Pen pen = new Pen(Color.Black);
Glyph glyph = null;
Signature signature = new Signature();
String fileName = @"signature.xml";

I then handled three events from the panel:

private void SignaturePanel_MouseMove(object sender, MouseEventArgs e)
{
    if (IsCapturing)
    {
        if (startPoint.IsEmpty && endPoint.IsEmpty)
        {
            endPoint = e.Location;
        }
        else
        {
            startPoint = endPoint;
            endPoint = e.Location;
            Line line = new Line(startPoint, endPoint);
            glyph.Lines.Add(line);
            DrawLine(line);
        }

    }
}
private void SignaturePanel_MouseUp(object sender, MouseEventArgs e)
{
    IsCapturing = false;
    signature.Glyphs.Add(glyph);
    startPoint = new Point();
    endPoint = new Point();

}

private void SignaturePanel_MouseDown(object sender, MouseEventArgs e)
{
    IsCapturing = true;
    glyph = new Glyph();
}

Basically, every time a user clicks down it starts capturing the points and turning them into lines.  When the user clicks up, all of those lines go into 1 glyph.  Capture…Rinse….Repeat.

There is 1 supporting function (DrawLine) that looks like this to render it to the screen:

private void DrawLine(Line line)
{
    using (Graphics graphic = this.SignaturePanel.CreateGraphics())
    {
        graphic.DrawLine(pen, line.StartPoint, line.EndPoint);
    }
}

A couple of notes on the code blocks above.

  • The Point struct has a convenience property called IsEmpty.  This resolves to X and Y equaling 0.
  • The Point Equals overload resolved to the X and Y values.   If you have 2 instances of a Point with the same X and Y, they are equal.

Once the signature is captured on the panel, I needed a way to save the signature.  Most people capture the image.  Me, I want the signature transformed into structured data for better down-steam analysis.  Therefore, I decided to put it into XML.  To that end, I marked all of the classes in the Signature graph as Serializable.  I then created two functions to push and pull the signature out of a XML file:

private void SerializeSignature()
{
    XmlSerializer serializer = new XmlSerializer(typeof(Signature));

    if (File.Exists(fileName))
    {
        File.Delete(fileName);
    }

    using (TextWriter textWriter = new StreamWriter(fileName))
    {
        serializer.Serialize(textWriter, signature);
        textWriter.Close();
    }
}

And

private void DeserializeSignature()
{
    XmlSerializer deserializer = new XmlSerializer(typeof(Signature));
    using (TextReader textReader = new StreamReader(fileName))
    {
        signature = (Signature)deserializer.Deserialize(textReader);
        textReader.Close();
    }
}

I then wired up the button clicks to save the signature:

private void ExportButton_Click(object sender, EventArgs e)
{
    SerializeSignature();
}

and to load it:

private void ImportButton_Click(object sender, EventArgs e)
{
    DeserializeSignature();
    ClearSignaturePanel();
    DrawSignature();

}

and these are the two other supporting methods:

private void ClearSignaturePanel()
{
    using (Graphics graphic = this.SignaturePanel.CreateGraphics())
    {
        SolidBrush solidBrush = new SolidBrush(Color.LightBlue);
        graphic.FillRectangle(solidBrush, 0, 0, SignaturePanel.Width, SignaturePanel.Height);
    }
    
}

and

private void DrawSignature()
{
    foreach (Glyph glyph in signature.Glyphs)
    {
        foreach (Line line in glyph.Lines)
        {
            DrawLine(line);
        }
    }

}

Sure enough, here is the XML in the file:

image

The problem is that this file is larger than a image file – but much more analyzable (and yes, that is a real word).  I then wanted to display the signature in a web browser.  To that end, I fired up a classic ASP.NET application and created a web control.  In the code, I rendered the points out of the XML file back into a graphic:

protected void Page_Load(object sender, EventArgs e)
{
    this.Response.ContentType = "image/gif";
    using (Bitmap bitmap = new Bitmap(200, 100))
    {
        using (Graphics graphics = Graphics.FromImage(bitmap))
        {
            SignatureFactory signatureFactory = new SignatureFactory();
            String fileName = @"C:\signature.xml";
            Signature signature = signatureFactory.LoadSignatureFromFileSystem(fileName);
            Pen pen = new Pen(Color.Red);
            foreach (Glyph glyph in signature.Glyphs)
            {
                foreach (Line line in glyph.Lines)
                {
                    graphics.DrawLine(pen, line.StartPoint.X, line.StartPoint.Y,
                        line.EndPoint.X, line.EndPoint.Y);
                }
            }

            bitmap.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif);
        }
    }
}

And the output on a web form:

image

According to WCPSS: Google > Bing

I went into a Wake County Library that is inside a local public high school.  I went to go to Bing via their WiFi and I got this:

Capture

 

I could get to Google.  I am surprised that my government was picking sides in the search engine wars – I mean it is not like either Google or Bing are different in any substantive way…

Kinect SDK

I purchased a Kinect last week so that I could start messing around with its API.

1) There are two versions of the Kinect.  The XBOX 360 one and the Windows one.  The only difference between the two that I could gather is that the Windows one pre-loads the SDK and allows you to distribute your software commercially.  Since I am just a hobbyist, I went with the XBOX one for $100 cheaper.

2) The Kinect for the XBOX360 requires an additional power cord for it to connect to your computer,  You don’t need to buy it though as it comes included.  I made that mistake (and compounded it by buying from the Microsoft store at a premium)

3) There are a couple different SDKs floating around out there.  There is the 1.0 SDK and the 1.5 SDK.  You will want to use the 1.5 one (because newer is always better) and there is a HUGE difference in the APIs between the two versions to the point that anything you wrote in 1.0 is useless.

4) I started digging into programming the Kinect with this book.  After reading the SDK samples and documentation, it really isn’t necessary.  The SDK is really well documented and is probably the best place to start to learn about the technology.

5) Once I dove into programming the Kinect, I realize that that this is no small task.  For C#, the amount of code you need to write and the complexity is higher than any other Microsoft technology I have seen.  You will need to know about bit shifts, the low-level details of graphical classes, and advanced data structures.  For example, here is an example from the Kinect Explorer solution:

// Converts a 16-bit grayscale depth frame which includes player indexes into a 32-bit frame
// that displays different players in different colors
private void ConvertDepthFrame(short[] depthFrame, DepthImageStream depthStream)
{
    int tooNearDepth = depthStream.TooNearDepth;
    int tooFarDepth = depthStream.TooFarDepth;
    int unknownDepth = depthStream.UnknownDepth;

    // Test that the buffer lengths are appropriately correlated, which allows us to use only one
    // value as the loop condition.
    if ((depthFrame.Length * 4) != this.depthFrame32.Length)
    {
        throw new InvalidOperationException();
    }

    for (int i16 = 0, i32 = 0; i32 < this.depthFrame32.Length; i16++, i32 += 4)
    {
        int player = depthFrame[i16] & DepthImageFrame.PlayerIndexBitmask;
        int realDepth = depthFrame[i16] >> DepthImageFrame.PlayerIndexBitmaskWidth;
        
        if (player == 0 && realDepth == tooNearDepth)
        {
            // white 
            this.depthFrame32[i32 + RedIndex] = 255;
            this.depthFrame32[i32 + GreenIndex] = 255;
            this.depthFrame32[i32 + BlueIndex] = 255;
        }
        else if (player == 0 && realDepth == tooFarDepth)
        {
            // dark purple
            this.depthFrame32[i32 + RedIndex] = 66;
            this.depthFrame32[i32 + GreenIndex] = 0;
            this.depthFrame32[i32 + BlueIndex] = 66;
        }
        else if (player == 0 && realDepth == unknownDepth)
        {
            // dark brown
            this.depthFrame32[i32 + RedIndex] = 66;
            this.depthFrame32[i32 + GreenIndex] = 66;
            this.depthFrame32[i32 + BlueIndex] = 33;
        }
        else
        {
            // transform 13-bit depth information into an 8-bit intensity appropriate
            // for display (we disregard information in most significant bit)
            byte intensity = (byte)(~(realDepth >> 4));

            // tint the intensity by dividing by per-player values
            this.depthFrame32[i32 + RedIndex] = (byte)(intensity >> IntensityShiftByPlayerR[player]);
            this.depthFrame32[i32 + GreenIndex] = (byte)(intensity >> IntensityShiftByPlayerG[player]);
            this.depthFrame32[i32 + BlueIndex] = (byte)(intensity >> IntensityShiftByPlayerB[player]);
        }
    }
}

My goal is to have enough to work with to present at TriNug’s code camp in November.  That might be a stretch…