Контрольный вопрос для подписи OpenNETCF

Я использую элемент управления «Подпись» в OpenNETCF. Он отлично работает почти со всем, что мне нужно.

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

У него есть вызов для получения «байтов» для подписи (GetSignatureEx()). Он возвращает byte[] подписи. Затем эту подпись можно загрузить обратно с помощью LoadSignatureEx().

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

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


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

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

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)  

Я отправлю свой последний код, как только он будет готов.


Позднее примечание: Хорошо, после тонны работы я обнаружил, насколько легко перевернуть представление, используя встроенные средства (спасибо 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;
        }
    }
}

person Vaccano    schedule 17.04.2010    source источник
comment
Предположительно подпись может быть представлена ​​строкой UTF8. Возможно, так оно и есть.   -  person Oded    schedule 17.04.2010
comment
Я только что подумал: какого черта вам нужно инвертировать подпись?   -  person MusiGenesis    schedule 18.04.2010
comment
Хороший вопрос. Я делаю портативное приложение, в котором задействованы курьеры, которые забирают посылки. Я показываю экран с подсчетом того, что было забрано, а затем я хочу, чтобы клиент, который раздает пикапы, расписался за то, сколько вещей они отдали курьеру. Будет проще, если я могу перевернуть весь экран вверх ногами и позволить им подписать, а затем перевернуть обратно. В противном случае курьер должен передать клиенту наши устройства с символами стоимостью 1800 долларов. (Для удобства, времени и безопасности устройства мы бы хотели избежать этого, если сможем.)   -  person Vaccano    schedule 18.04.2010
comment
Ага, это даже хуже, чем я думал! Хорошая детективная работа, по крайней мере, до этого добралась.   -  person MusiGenesis    schedule 18.04.2010
comment
Не принято, поэтому я могу дать чаевые автору. См .: meta.stackexchange .com / questions / 36567 /. Не утруждайтесь ответами на этот вопрос, так как он перейдет в MusiGenesis. @MusiGenesis   -  person Vaccano    schedule 19.04.2010


Ответы (2)


Полностью непроверенный код 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;
            }
        }
    }
}

Или попробуйте эту версию, предполагая, что первые 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;
        }
    }
}
person MusiGenesis    schedule 17.04.2010
comment
Хорошо, это действительно впечатляет и очень близко. Изображение было перевернуто, но часть его была сдвинута с верхней части планшета для подписи и добавлено несколько вертикальных линий. (Когда я сделал вертикальный переворот). Вы можете объяснить, как работает ваш код? Вы явно кое-что знаете о том, что означают байты. Например, почему текущий не может быть равен 0 или следующий? Почему 232 по горизонтали и 64 по вертикали? Я буду продолжать возиться с кодом, но любые ссылки или объяснения будут потрясающими! - person Vaccano; 17.04.2010
comment
Немного покопавшись, я обнаружил, что 64 управляет вертикальным смещением перевернутого изображения, и вертикальные линии отображаются, когда перевернутое изображение уходит с экрана. Так что я думаю, мне просто нужно набирать обороты, пока я не найду подходящую золотую середину. (Если нет каких-либо расчетов, которые я могу сделать на основе высоты элемента управления подписью?) - person Vaccano; 17.04.2010
comment
Я предполагаю, что нечетные и четные байты предназначены для горизонтальных и вертикальных координат? (Просто приблизительное предположение). Я до сих пор не знаю, что такое нулевые значения. - person Vaccano; 17.04.2010
comment
@Vaccano: мой код был основан на ответе на вопрос об изменении пола эксперта (прокрутите ссылку вниз, чтобы увидеть фактические ответы, не обращая внимания на запросы денег): expert-exchange.com/OS/Microsoft_Operating_Systems/Windows/ - person MusiGenesis; 18.04.2010
comment
Массив байтов из GetSignatureEx отформатирован (я думаю) так, что каждая пара байтов представляет координаты x и y серии точек, составляющих линию. Использование байтов для координат ограничивает вас областью 255 x 255, и похоже, что ребята из OpenNetCF выбрали в качестве области 232 x 64, потому что это хороший размер для поля подписи на экране шириной 240 пикселей. Если выполнение горизонтального инвертирования работает нормально, то я правильно угадал ширину 232. Если я ошибаюсь насчет высоты 64, вы, вероятно, получите те результаты, которые описываете - вертикальные линии почти наверняка связаны с ... - person MusiGenesis; 18.04.2010
comment
... неправильно инвертированные значения y странным образом оборачиваются. Я бы рекомендовал поэкспериментировать с значениями, превышающими 64, пока вы не получите то, что работает правильно. Я не нашел почти никакой документации по этому поводу, что, как я подозреваю, связано с тем, что этот формат байтов никогда не предназначался для внешних манипуляций, а вместо этого предназначен просто как способ экономии места для сохранения и воссоздания подписи. - person MusiGenesis; 18.04.2010
comment
Крис Тэке из OpenNetCF является постоянным посетителем StackOverflow, и он обязательно направит вас, как только увидит это. Лично я бы рекомендовал просто сохранить подпись как Bitmap даже на устройстве Windows Mobile. 232 x 64 - это всего лишь около 60 КБ (и хорошо сжимается) в качестве растрового изображения 32bpp, и вы также можете использовать для этого более компактные форматы. - person MusiGenesis; 18.04.2010
comment
Несколько лет назад я написал элемент управления сигнатуры, который работал практически так же (только у меня каждая координата хранилась как пара short целых чисел, а не как пара байтов). Юрист нашей компании рекомендовал (не основываясь на каких-либо серьезных знаниях) вместо этого хранить подписи в виде стандартных растровых изображений, поскольку их законность как формы электронной подписи будет сложнее подвергнуть сомнению в судебной ситуации. - person MusiGenesis; 18.04.2010
comment
И последнее, что касается проверки на 0 в обеих координатах: код в ответе ExpertSexChange рисует линию только в том случае, если все 4 задействованных значения (x1, y1, x2 и y2) не равны нулю. Я понял, что это означает, что значение координаты (0, 0) используется для обозначения конца одного непрерывного отрезка линии и начала другого (поскольку большинство сигнатур состоят из более чем одной извилистой линии). Поэтому инвертирующий код должен просто игнорировать эти пары координат. - person MusiGenesis; 18.04.2010
comment
Кроме того, какова фактическая высота элемента управления подписью, когда вы помещаете его в форму? Я предполагаю, что ширина составляет 232 (может быть, на 2 пикселя из-за границы?), И независимо от высоты элемента управления, вы должны указать, какое значение использовать в методе инвертирования. - person MusiGenesis; 18.04.2010
comment
Мне пришло в голову, что высоту и ширину элемента управления подписью можно регулировать в дизайнере (вами), поэтому вы можете знать, какую высоту и ширину использовать в методе инвертирования. Кстати, я думаю, что формат может фактически использовать первые 8 байтов для хранения высоты и ширины элемента управления (как два 4-байтовых целых числа), а затем сохраняет данные как по 1 байту для каждого x и y, если высота и ширина оба меньше 255 или по 4 байта для x и y в противном случае. Если первые 4 двухбайтовых пары координат дают вам странные, ошибочные точки, вероятно, поэтому. - person MusiGenesis; 18.04.2010
comment
Не принято, поэтому я могу дать чаевые автору. См .: meta.stackexchange .com / questions / 36567 /. - person Vaccano; 19.04.2010

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

  • Первые 2 байта - это ширина.
  • Следующие 2 байта - это высота.
  • Остальные данные представляют собой координаты X, Y, однако формат хранения обманчив и может измениться. Если размер (x или y) равен ‹256, мы используем один байт для хранения значения. Если больше, мы используем 2 байта. Это означает, что вы можете видеть значения, сохраненные как XYXY, XXYXXY или XYYXYY.
person ctacke    schedule 19.04.2010
comment
Ага, где ты был? Я потратил на это пару часов. :) - person MusiGenesis; 19.04.2010
comment
Спасибо за информацию. Я поместил свой код поворота на 180 градусов выше. Я думаю, что до тех пор, пока размер элемента управления не превышает 256 в любом направлении, он должен работать нормально. Поскольку я не планирую превышать этот предел, я не собираюсь беспокоиться об этой части. - person Vaccano; 19.04.2010
comment
Никогда не говори никогда! Я перехожу на устройство VGA и превысил 256 в обоих измерениях. Этот пост сэкономит мне много времени, когда я буду чесать затылок! Спасибо! - person Vaccano; 05.10.2010