QR-код (аббревиатура QR расшифровывается как «Quick Response», «Быстрый отклик») представляет собой способ кодирования текстовой и графической информации в матричной форме.
Если проводить аналогию со штрих-кодом, который является предшественником QR-кода, то первый – одномерный массив, а второй – двумерный. «Кем он придуман?», «зачем?» и тому подобные вопросы я отправляю на обработку поисковику, а сам перейду к концепту программы, которая распознает эти коды.
QR-код прежде всего удобен тем, что поддается быстрому распознаванию. К примеру, если взять мобильник (или любой другой девайс, содержащий камеру любого разрешения) и сфотографировать картинку, находящуюся выше (кстати, можно сделать банальный PrintScreen, но это выглядит менее эффектно) и пропустить через одну из программ распознавания QR-кодов, то в процессе всех этих манипуляций будет получена строка «http://defec.ru», которая, в свою очередь, была закодирована в эту картинку. Забавно. Однако авторы этих программ неохотно делятся секретами своих программных продуктов.
Японцами написана библиотека, в которой реализовано распознавание QR-кодов, и прикреплен к ней весьма скудный мануал ее использования (она триальная, поэтому выдаваемая информация искажается).
Приведу фрагмент кода (концепт), который использует библиотеку распознавания QR-кода:
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-кодов, а именно: всеядность программного обеспечения, распознающего эти коды.
2 comments
е*aнутый код! нативного разве ничего под c# нет?
Привет
Прочитал твою статеку в ][ и возник вопрос=)
У тебя нет случайно стандарта ISO/IEC 18004:2006 в пдф? А-то в свободном доступе не могу найти полную версию, а на стандартс.ру за нее просят аж семь с половиной тыщ О_о (http://www.standards.ru/document/3615257.aspx)