Вопрос контроля подписи OpenNETCF

Я использую элемент управления Signature в OpenNETCF. Это прекрасно работает для большинства всего, что мне нужно.

Однако мне нужен способ инвертировать подпись и загрузить ее обратно.

Есть вызов для получения "байтов" для подписи (GetSignatureEx()). Возвращает byte[] подписи. Эта подпись затем может быть загружена обратно с LoadSignatureEx(),

Я не могу понять систему для этих байтов. Я думал, что они могут быть координатами, но сейчас это не так.

Если кто-нибудь знает способ инвертировать подпись и загрузить ее обратно, я был бы рад услышать это.


Примечание для тех, кто может заботиться:

Эти байты имеют следующую структуру (по порядку):

2 байта, чтобы показать ширину  
2 байта для отображения высоты  
  - Эта следующая часть повторяется до конца массива  
  2 байта, чтобы показать, сколько точек в следующей строке  
    - Эта следующая часть повторяется столько раз, сколько указано в предыдущей строке  
    1 байт для координаты x точки  
    1 байт для координаты y точки  
    2 байта для ширины пера (в этом я не уверен на 100%) 

Я опубликую свой окончательный код, как только я это сделаю.


Позже примечание: хорошо, после тонны работы, я обнаружил, как легко перевернуть изображение, используя встроенные функции (спасибо MusiGenesis). Это, кажется, гораздо меньше ошибок для меня.

На всякий случай, если кто-то еще захочет, вот мой незаконченный код. (Я был близок, но материал для перехода к следующей "линии" не работает совершенно правильно.) (РЕДАКТИРОВАТЬ: я решил, что мне больше понравилось, как это работает. Я обновил код ниже. Он будет работать до тех пор, пока ширина или высота элемента управления Signature не превышает 256. (См. Ответ ctacke ниже).)

Но сначала большое спасибо MusiGenesis, который помог мне разобраться во всем этом. Вы очень полезны, и я высоко ценю ваши усилия!

Теперь код:

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;
        }
    }
}

2 ответа

Решение

Полностью непроверенный код Гольф:

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;
            }
        }
    }
}

Или попробуйте эту версию, исходя из предположения, что первые 4 байта используются для хранения ширины и высоты подписи (2 байта коротких целых для каждого):

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];
            }
        }
    }
}

См.: Преобразование OpenNetCF GetSignatureEx в растровое изображение на рабочем столе.

Обновление: учитывая ваше описание того, почему вам нужно инвертировать подпись, вам может быть проще просто инвертировать ScreenOrientation вашего устройства на 180 градусов (а затем обратно после того, как клиент подпишет). Таким образом, у вас также могут быть ярлыки, которые сообщают клиенту о том, что они подписывают, иначе они будут смотреть на кучу перевернутых вещей (кроме самого элемента управления подписью).

Для этого добавьте ссылку на Microsoft.WindowsCE.Forms в свой проект, затем добавьте using Microsoft.WindowsCE.Forms; в начало вашего файла.

Чтобы перевернуть экран на 180 градусов:

SystemSettings.ScreenOrientation = ScreenOrientation.Angle180;

Чтобы вернуться к нормальной жизни:

SystemSettings.ScreenOrientation = ScreenOrientation.Angle0;

Если вы запускаете это в эмуляторе, ваш экран все равно будет выглядеть нормально, но кожа переворачивается вверх ногами.

Обновление: последний выстрел, основанный на ctackeответ (это должно работать для подписей с любыми измерениями):

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;
        }
    }
}

Возможно, я немного опоздал, но сейчас я смотрю на код, и вот некоторые моменты, на которые стоит обратить внимание.

  • Первые 2 байта являются шириной.
  • Следующие 2 байта - это высота.
  • Остальные данные представляют собой координаты X, Y, однако формат хранения обманчив и может измениться. Если размерность (x или y) < 256, мы используем один байт для хранения значения. Если оно больше, мы используем 2 байта. Это означает, что вы можете увидеть вейлы, хранящиеся как XYXY, XXYXXY или XYYXYY.
Другие вопросы по тегам