Question

I am using the Signature control in OpenNETCF. It works great for most everything I need.

However, I need a way invert the signature and load it back in.

It has a call to get the "bytes" for the signature (GetSignatureEx()). It returns a byte[] of the signature. This signature can then be loaded back in with LoadSignatureEx().

I can't seem to figure out the system for these bytes. I thought they may be coordinates, but it does not seem so now.

If anyone out there knows a way to invert the signature and load it back in, I would be grateful to hear it.


Note for others who may care:

These bytes seem to have the following structure (in order):

2 bytes to show Width  
2 bytes to show Height  
  -- This next part repeats till the end of the array  
  2 bytes to show How many points are in the next line  
    -- This next part repeats as many times as the previous line indicated  
    1 byte for the x coordinate of the point  
    1 byte for the y coordinate of the point  
    2 bytes for the width of the pen (I am not 100% sure on this one)  

I will post my final code once I have it done.


Later Note: Ok after tons of work, I found how easy it is to flip the view using the built in stuff (thanks MusiGenesis). That seems to be way less error prone a process to me.

Just in case someone else wants it, here is my unfinished code. (I was close but the stuff to advance to the next "line" does not work quite right.) (EDIT: I decided that I liked the way this worked a bit more. I have updated the code below. It will work as long as the width or height of the Signature control is not greater than 256. (See ctacke's answer below).)

But first, big thanks to MusiGenesis who helped me figure all this out. You are very helpful and I appreciate your efforts a lot!

Now the code:

private void InvertSignature(ref byte[] original)
{
    int currentIndex = 0;
    short width = BitConverter.ToInt16(original, 0);
    short height = BitConverter.ToInt16(original, 2);
    while (currentIndex < original.Length - 4)
    {
        // Move past the last iteration (or the width and hight for the first time through).
        currentIndex += 4;
        // Find the length of the next segment.
        short nextGroup = BitConverter.ToInt16(original, currentIndex);
        //Advance one so we get past the 2 byte group
        currentIndex += 2;
        // Find the actual index of the last set of coordinates for this segment.
        int nextNumberOfItems = ((nextGroup) * 4) + currentIndex;
        // Invert the coordinates
        for (int i = currentIndex; i < (nextNumberOfItems - 1); i += 4)
        {
            currentIndex = i;

            //Invert Horizontal
            int newHorzPoint = width - original[i] - 1;
            if (newHorzPoint <= 0)
                newHorzPoint = 0;
            else if (newHorzPoint >= width - 1)
                newHorzPoint = width - 1;
            original[i] = (byte)newHorzPoint;

            // Invert Vertical
            int newVertPoint = height - original[i + 1] - 1;
            if (newVertPoint <= 0)
                newVertPoint = 0;
            else if (newVertPoint >= height - 1)
                newVertPoint = height - 1;
            original[i + 1] = (byte)newVertPoint;
        }
    }
}
Was it helpful?

Solution

Completely-untested-code Golf:

public void InvertSignature(ref byte[] original, 
    bool invertHorizontal, bool invertVertical)
{
    for (int i = 0; i < original.Length; i += 2)
    {
        if ((original[i] != 0) && (original[i + 1] != 0))
        {
            if (invertHorizontal)
            {
                original[i] = 232 - original[i] - 1;
            }
            if (invertVertical)
            {
                original[i + 1] = 64 - original[i + 1] - 1;
            }
        }
    }
}

Or try this version, on the assumption that the first 4 bytes are used to store the width and height of the signature (2 byte short ints for each):

public void InvertSignature(ref byte[] original, 
    bool invertHorizontal, bool invertVertical)
{
    byte w = (byte)BitConverter.ToInt16(original, 0) - 1;
    byte h = (byte)BitConverter.ToInt16(original, 2) - 1;
    // TO DO: blow up if w or h are > 255
    for (int i = 4; i < original.Length; i += 2)
    {
        if ((original[i] != 0) && (original[i + 1] != 0))
        {
            if (invertHorizontal)
            {
                original[i] = w - original[i];
            }
            if (invertVertical)
            {
                original[i + 1] = h - original[i + 1];
            }
        }
    }
}

See: Converting OpenNetCF GetSignatureEx to Bitmap on Desktop

Update: Given your description of why you need to invert the signature, it might be easier for you to just invert the ScreenOrientation of your device by 180 degrees (and then back after the customer signs). This way you could also have labels that tell the customer what they're signing - otherwise they're going to be looking at a bunch of upside-down stuff (other than the signature control itself).

To do this, add a reference to Microsoft.WindowsCE.Forms to your project, then add using Microsoft.WindowsCE.Forms; to the top of your file.

To invert the screen by 180 degrees:

SystemSettings.ScreenOrientation = ScreenOrientation.Angle180;

To set back to normal:

SystemSettings.ScreenOrientation = ScreenOrientation.Angle0;

If you're running this in the emulator, your screen will still appear normally upright, but the skin gets flipped upside-down.

Update: one last shot at this, based on ctacke's answer (this should work for signatures with any dimensions):

public void InvertSignature(ref byte[] original, 
    bool invertHorizontal, bool invertVertical)
{
    short w = BitConverter.ToInt16(original, 0);
    short h = BitConverter.ToInt16(original, 2);
    int i = 4;
    while (i < original.Length)
    {
        if (invertHorizontal)
        {
            if (w < 256)
            {
                if (original[i] != 0)
                {
                    original[i] = (byte)w - original[i] - 1;
                }
                i++;
            }
            else
            {
                short val = BitConverter.ToInt16(original, i);
                if (val != 0)
                {
                    val = w - val - 1;
                    byte[] valbytes = BitConverter.GetBytes(val);
                    Buffer.BlockCopy(valbytes, 0, original, i, 2);
                }
                i += 2;
            }
        }
        else
        {
            i += (w < 256) ? 1 : 2;
        }
        if (invertVertical)
        {
            if (h < 256)
            {
                if (original[i] != 0)
                {
                    original[i] = (byte)h - original[i] - 1;
                }
                i++;
            }
            else
            {
                short val = BitConverter.ToInt16(original, i);
                if (val != 0)
                {
                    val = h - val - 1;
                    byte[] valbytes = BitConverter.GetBytes(val);
                    Buffer.BlockCopy(valbytes, 0, original, i, 2);
                }
                i += 2;
            }
        }
        else
        {
            i += (h < 256) ? 1 : 2;
        }
    }
}

OTHER TIPS

I might be a little late, but I'm looking at the code right now and here are some points worth noting.

  • The first 2 bytes are the width.
  • The next 2 bytes are the Height.
  • The remainder of the data are X,Y coordinates, however the storage format is deceptive and it can change. If the dimension (x or y) is < 256, we use one byte to store the value. If it's greater, we use 2 bytes. This means you might see vales stored as XYXY, XXYXXY or XYYXYY.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top