Разбираем матрицу: QR-код и чем его «едят» (C#).

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by c0n Difesa, 20 Feb 2009.

  1. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    QR-код (аббревиатура QR расшифровывается как «Quick Response», «Быстрый отклик») представляет собой способ кодирования текстовой и графической информации в матричной форме. Если проводить аналогию со штрих-кодом, который является предшественником QR-кода, то первый - одномерный массив, а второй – двумерный. «Кем он придуман?», «зачем?» и тому подобные вопросы TC отправляет на обработку поисковику, а сам перейдет к концепту программы, которая распознает эти коды.

    QR-код прежде всего удобен тем, что поддается быстрому распознаванию. К примеру, если взять мобильник (или любой другой девайс, содержащий камеру любого разрешения) и сфотографировать картинку из прилагающегося к материалу архива (кстати, можно сделать банальный PrintScreen, но это выглядит менее эффектно) и пропустить через одну из программ распознавания QR-кодов, то в процессе всех этих манипуляций будет получена строка «http://forum.antichat.ru», которая, в свою очередь, была закодирована в эту картинку. Забавно. Однако авторы этих программ неохотно делятся секретами своих программных продуктов.

    Японцами написана библиотека, в которой реализовано распознавание QR-кодов, и прикреплен к ней весьма скудный мануал ее использования (она триальная, поэтому выдаваемая информация искажается).

    Приведу фрагмент кода (концепт), который использует библиотеку распознавания QR-кода:

    Code:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Forms;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Runtime.InteropServices;
    namespace ConsoleApplication1
    {
        class Program
        {
            /*Image file reading/writing APIs and definitions */
            //DEFINES SECTION 
            public const int PT_IMAGERW_FAIL = 0x00000000; //An error occurred in an operation.
            public const int PT_IMAGERW_SUCCESS = 0x00000001; //An operation is successful.
            public const int PT_IMAGERW_ALLOC_ERROR = 0x00000100; //Error while allocating memory.
            public const int PT_IMAGERW_FORMAT_UNSUPPORTED = 0x00000101; //The format of image is unsupported. 
    
            //STRUCTURES SECTION
            unsafe public struct PTIMAGE
            {
                public int dwWidth;       //The width of the image in pixels.
                public int dwHeight;      //The height of the image in pixels.
                public byte* pBits;         //Pointer to the image data.
                public byte* pPalette;      //Pointer to the palette data (RGBQUAD)for 1,4,8 bits image.
                public short wBitsPerPixel; //Number of bits per pixel.
            }
    
            //FUNCTIONS SECTION	
            [DllImport("PtImageRW.dll", EntryPoint = "PtInitImage", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern void PtInitImage(ref PTIMAGE pImage);
    
            [DllImport("PtImageRW.dll", EntryPoint = "PtLoadImage", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern int PtLoadImage(string filename, ref PTIMAGE pImage, int FrameIndex);
    
            [DllImport("PtImageRW.dll", EntryPoint = "PtSaveImage", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern int PtSaveImage(string filename, ref PTIMAGE pImage);
    
            [DllImport("PtImageRW.dll", EntryPoint = "PtShowImage", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern void PtShowImage(ref PTIMAGE pImage, IntPtr hDC, int x, int y, float scale);
    
            [DllImport("PtImageRW.dll", EntryPoint = "PtCreateImage", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern int PtCreateImage(ref	PTIMAGE pImage, int ImageSize, int PaletteSize);
    
            [DllImport("PtImageRW.dll", EntryPoint = "PtFreeImage", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern void PtFreeImage(ref PTIMAGE pImage);
    
    
            /*The PTDECODEPARA structure is used to decide parameter when decoding barcodes from an image.*/
            public unsafe struct PTDECODEPARA
            {
                public int dwStartX;     //The start X-coordinate in pixels of the search window in the image to decode the symbol.
                public int dwStartY;     //The start Y-coordinate in pixels of the search window in the image to decode the symbol.
                public int dwEndX;       //The end X-coordinate in pixels of the search window in the image to decode the symbol.
                public int dwEndY;       //The end Y-coordinate in pixels of the search window in the image to decode the symbol.
                public int dwMaxCount;   //The maximal number of symbols to be searched. If it's set to 0 then search the all symbols.
            }  
            ;
    
    
            /*The PTBARCODEINFO structure contains a barcode information after decoding*/
            public unsafe struct PTBARCODEINFO
            {
                public int dwX1, dwY1;    //Four corners' coordinates in pixels of the barcode. 
                public int dwX2, dwY2;
                public int dwX3, dwY3;
                public int dwX4, dwY4;
                public byte* pData;         //Pointer to the buffer that contains the barcode's data.
                public int dwDataLen;     //The barcode data's length in bytes.
            }
            ;
    
    
            /*The PTTOTALBARCODEINFO structure contains all barcodes' information after decoding*/
            public unsafe struct PTTOTALBARCODEINFO
            {
                public PTBARCODEINFO* pInfoList;    //Pointer to the start address of the list of barcodes' info.  
                public int dwTotalCount; //The number of barcode that have been decoded.
            }
            ;
            /*QR Code symbol reading APIs and definitions*/
            /* Status of an operation */
            public const int PT_QRDECODE_FAIL = 0x00000000;//An error occurred in an operation.
            public const int PT_QRDECODE_SUCCESS = 0x00000001;//An operation is successful.
            public const int PT_QRDECODE_ALLOC_ERROR = 0x00000300;//Error while allocating the memory.
            public const int PT_QRDECODE_IMAGE_INVALID = 0x00000301;//The image to be decode is invalid. 
            public const int PT_QRDECODE_PARAMETERS_INVALID = 0x00000302;//The parameters input to a function are invalid.
    
            //FUNCTIONS SECTION
            [DllImport("PtQRDecode.dll", EntryPoint = "PtQRDecodeRegister", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern int PtQRDecodeRegister(string pKeyStr);
    
            [DllImport("PtQRDecode.dll", EntryPoint = "PtQRDecodeInit", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern void PtQRDecodeInit(ref PTTOTALBARCODEINFO pInfo);
    
            [DllImport("PtQRDecode.dll", EntryPoint = "PtQRDecode", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern int PtQRDecode(ref PTIMAGE pImage, ref PTDECODEPARA pPara, ref PTTOTALBARCODEINFO pInfo);
    
            [DllImport("PtQRDecode.dll", EntryPoint = "PtQRDecodeFromFile", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern int PtQRDecodeFromFile(string FileName, ref PTDECODEPARA pPara, ref PTTOTALBARCODEINFO pInfo);
    
            [DllImport("PtQRDecode.dll", EntryPoint = "PtQRDecodeFromBitmap", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern int PtQRDecodeFromBitmap(IntPtr hBitmap, ref PTDECODEPARA pPara, ref PTTOTALBARCODEINFO pInfo);
    
            [DllImport("PtQRDecode.dll", EntryPoint = "PtQRDecodeFree", SetLastError = true,
                 CharSet = CharSet.Ansi, ExactSpelling = true,
                 CallingConvention = CallingConvention.StdCall)]
            public static extern void PtQRDecodeFree(ref PTTOTALBARCODEINFO pInfo);
            static private PTIMAGE image;
            static private PTTOTALBARCODEINFO BarCodeInfo;
            static private PTDECODEPARA DecodePara;
            static private string FileName;
            [STAThreadAttribute]
            static void Main(string[] args)
            {
                PtQRDecodeRegister("12345678901234567890");//use the license key of demo version.
                PtInitImage(ref image);
                System.Windows.Forms.OpenFileDialog OpenFileDlg=new System.Windows.Forms.OpenFileDialog();
                OpenFileDlg.Filter = "Image File|*.bmp;*.jpg;*.tif;*.tiff;*.gif;*.png";
                if (OpenFileDlg.ShowDialog() == DialogResult.OK)
                {
                    if (OpenFileDlg.FileName != "")
                    {
                        FileName = OpenFileDlg.FileName;
                        DecodeQR();
                    }
                    else
                        MessageBox.Show("Неправельный файл");
                }
                else
                {
                    MessageBox.Show("Требуется нажатие кнопки ОК");
                }
            }
            static private void DecodeQR()
            {
                DecodePara.dwStartX = 0;
                DecodePara.dwStartY = 0;
                DecodePara.dwEndX = 0;
                DecodePara.dwEndY = 0;//search the whole image.
                DecodePara.dwMaxCount = 0;//search the all symbols in the image.
    
                PtQRDecodeInit(ref BarCodeInfo);
    
                if (PtLoadImage(FileName, ref image, 0) == PT_IMAGERW_SUCCESS)
                {
                    if (PtQRDecode(ref image, ref DecodePara, ref BarCodeInfo) != PT_QRDECODE_SUCCESS)
                        MessageBox.Show("An error occured while rocognition ");
                    else
                        ShowBarCodeInfo(ref BarCodeInfo);
                }
                PtFreeImage(ref image);
                PtQRDecodeFree(ref BarCodeInfo);
    
            }
            static public unsafe void ShowBarCodeInfo(ref PTTOTALBARCODEINFO BarCodeInfo)
            {
                if (BarCodeInfo.dwTotalCount <= 0)
                {
                    MessageBox.Show("No barcode was found");
                    return;
                }
    
                string str = "";
                PTBARCODEINFO* pInfoList = BarCodeInfo.pInfoList;
                for (int count = 0; count < BarCodeInfo.dwTotalCount; count++)
                {
                    str = str + "barcode " + Convert.ToString(count + 1) + ":\n";
                    byte[] byteArray = new byte[pInfoList->dwDataLen];
                    for (int i = 0; i < pInfoList->dwDataLen; i++)
                        byteArray[i] = pInfoList->pData[i];
                    str = str + Encoding.Default.GetString(byteArray);//Encoding.GetEncoding("GB2312").GetString
                    str = str + "\n\n";
                    pInfoList++;
                }
                str = str + '\0';
                MessageBox.Show(str);
            }
        }
    }
    
    Думаю, что интересующимся альтернативным кодированием информации, этот код будет весьма «кстати». Что делать с ним дальше – дело читателя, и свобода действий ограничена лишь количеством извилин в его голове. В качестве бонуса, выложен проект для Visual Studio 2008, который демонстрирует прелесть QR-кодов, а именно: всеядность программного обеспечения, распознающего эти коды.

    http://depositfiles.com/files/m217feydd (пароль: antichat.ru)

    (c) c0n Difesa (defec.ru)
     
    #1 c0n Difesa, 20 Feb 2009
    Last edited: 28 Nov 2009
    2 people like this.
  2. Maxidrom

    Maxidrom New Member

    Joined:
    4 Feb 2009
    Messages:
    12
    Likes Received:
    0
    Reputations:
    0
    Все это смахивает на стеганографию)
     
  3. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    Не думаю, что информацию удастся скрыть от человека, вооруженного камерой и знанием понятия QR-кода (и его наличием в передаваемом сообщении). QR-код не может использоваться как метод стеганографии напрямую, однако ему можно найти косвенные применения.
     
  4. procedure

    procedure Elder - Старейшина

    Joined:
    22 Dec 2007
    Messages:
    527
    Likes Received:
    257
    Reputations:
    46
    Я не разбираюсь в этих кодах. Поэтому такой вопрос, что лучше QR код или штих-код? И если QR почему все используют штрих код?

    И действительно в каких ситуациях они могут понадобится программисту?
     
  5. eLWAux

    eLWAux Elder - Старейшина

    Joined:
    15 Jun 2008
    Messages:
    860
    Likes Received:
    616
    Reputations:
    211
    кому интересно:
    [​IMG]
    http://en.wikipedia.org/wiki/QR_Code
    генератор: http://qrcode.kaywa.com/
     
  6. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    Ответ: QR-код, т.к. он позволяет хранить гораздо больше информации из-за особенности своей структуры (матричная форма хранения информации), и типом информации может выступать как текст (не многим более 4000 символов, что несомненно превышает объем хранимой информации в штрих-коде), так и картинка.

    Не все. В Японии, например, вследствие нехватки объема хранимой информации в штрих-коде, происходит достаточно быстрый переход на новый стандарт QR. Однако, Россия не спешит менять программное обеспечение, да и не за чем, ведь пока хватает «старичка» штрих-кода.

    С трудом понял вопрос, но попытаюсь перебрать несколько вариантов ответа. Программисту может понадобиться только SDK работы с ним…
    А вот что касается практического применения (относится не только к программистам), то тут уйма ситуаций:
    - если закодировать адрес электронной почты, ICQ, номер телефона и т.п. информацию в аватарке на сайте, то большинство спам-ботов идут «косить изюм»…
    - из предыдущего пункта пока актуальна защита от спам-ботов при регистрации на сайтах
    - объявления, реклама, приглашения, визитка и много другое можно закодировать в QR-код.
     
  7. Algol

    Algol New Member

    Joined:
    29 May 2002
    Messages:
    1,759
    Likes Received:
    4
    Reputations:
    0
    Посмотрел програмку распознавания.
    Из плюсов:
    1) Распознавание инвариантно положению картинки (хорошо распознает QR внутри произвольной картинки)
    2) Инвариантно масштабированию QR кода
    3) Инвариантно поворотам

    Из минусов:
    НЕ инвариантно любым преобразованиям с изменением соотнешения сторон QR кода.

    В результате:
    Хоршо распознаются на плоскости. Но в 3D, к сожалению - нет...
     
  8. zeppe1in

    zeppe1in Elder - Старейшина

    Joined:
    12 Jul 2006
    Messages:
    343
    Likes Received:
    66
    Reputations:
    18
    Триал у них одно название, если кому надо то вот дллки, что использовались, без триала)
    http://www.sendspace.com/file/uvw7ii
    кстати PtQRDecodeRegister, вызывать ненужно.
     
  9. Ivan1999

    Ivan1999 Member

    Joined:
    2 Jan 2009
    Messages:
    47
    Likes Received:
    13
    Reputations:
    1
    Подскажите где скачать генератор кода?
     
  10. ~*Trojan*~

    ~*Trojan*~ New Member

    Joined:
    22 Feb 2009
    Messages:
    0
    Likes Received:
    3
    Reputations:
    0
    http://qrcode.kaywa.com/
     
  11. Ivan1999

    Ivan1999 Member

    Joined:
    2 Jan 2009
    Messages:
    47
    Likes Received:
    13
    Reputations:
    1
    Я спросил где скачать,а не где сделать.
     
  12. Feonor

    Feonor Elder - Старейшина

    Joined:
    23 Jul 2008
    Messages:
    128
    Likes Received:
    52
    Reputations:
    19
    Как для 2005 студии адаптировать, не подскажешь? заинтересовала тема...
     
  13. zeppe1in

    zeppe1in Elder - Старейшина

    Joined:
    12 Jul 2006
    Messages:
    343
    Likes Received:
    66
    Reputations:
    18
    Ivan1999
    Feonor
    http://www.partitek.com/Download.htm
     
    1 person likes this.
  14. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    В силу своей специфики высокой степени распознаваемости, QR-коду можно найти 1000 и одно применение.

    Проходивший в этом году конкурс студентов-разработчиков «Imagine Cup» был посвящен теме глобальных проблем современного мира. Занявшая второе место на российском этапе (поясню: сначала команда проходит отбор среди других ВУЗовских команд своего региона, затем уже открывается доступ на этап России, после которого команда-победитель едет на этап мира в Каир) команда одного московского ВУЗа использовала в своем проекте как раз концепцию, основанную на QR-кодах. Идея состояла в следующем: расширить видимую реальность с помощью подручных средств, коими являются мобильные телефоны с камерой любого разрешения. Почему именно мобильники, не вижу смысла объяснять.

    Специально написанный фреймворк устанавливался на мобильный телефон. Далее обладатель телефона (предполагался индивид с ограниченными слуховыми способностями, что, в принципе не имеет особого значения), который интересовался, например, меню какого-либо ресторана (бара, кафе, закусочной и др. зданием, содержащим QR-код, который несет полезную информацию), при наведении камерой на здание мог спокойно увидеть в реальном времени на дисплее своего телефона меню или любую другую информацию, которую несет код.

    Код, размещенный на здании, так же мог отправить в фоновом режиме браузер телефона по ссылке на специальный сайт за детальной информацией.
     
  15. Qb1024

    Qb1024 New Member

    Joined:
    15 Jul 2009
    Messages:
    323
    Likes Received:
    4
    Reputations:
    0
    блин, а где бы найти программу для кодирования в QR, тока не онлайн. Или исходники на PHP
     
  16. neru

    neru New Member

    Joined:
    25 Nov 2008
    Messages:
    1
    Likes Received:
    1
    Reputations:
    0
    не принимает эти dll-ки
    [​IMG]
     
  17. zeppe1in

    zeppe1in Elder - Старейшина

    Joined:
    12 Jul 2006
    Messages:
    343
    Likes Received:
    66
    Reputations:
    18
    neru
    а оригинальные принимает? кинь пример с такой ошибкой посмотрю в чом дело.
     
  18. neru

    neru New Member

    Joined:
    25 Nov 2008
    Messages:
    1
    Likes Received:
    1
    Reputations:
    0
    проект который в первом посте http://depositfiles.com/files/m217feydd (пароль: antichat.ru) с оригинальными DLL-ками работает нормально. если DLL - ки заменить то начинает ругаться.