Запрос распознавания текста
Приложение вызывает функцию MappingRecognizeText для запроса распознавания текста из определенной службы ELS. Служба должна быть обнаружена при предыдущем вызове MappingGetServices, как описано в разделе Перечисление и освобождение служб.
Примечание
Платформа может обрабатывать вызовы MappingRecognizeText синхронно или асинхронно.
MappingRecognizeText обрабатывает следующие типы текста:
- Распознавание языка Майкрософт. UTF-16, форма нормализации C, текст, для которого определяется язык.
- Обнаружение скриптов Майкрософт. Текст UTF-16, для которого необходимо определить диапазоны скриптов.
- Службы транслитерации. Текст UTF-16, написанный в исходном скрипте (система записи).
Использование синхронного распознавания текста
В этом разделе приведены инструкции по нескольким способам синхронного распознавания текста.
Синхронное распознавание текста с помощью службы распознавания языка (Майкрософт)
В следующем примере показано использование MappingRecognizeText со службой распознавания языка Майкрософт и выводится все результаты, полученные службой. Формат выходных данных этой службы представляет собой одну структуру MAPPING_DATA_RANGE с элементом pData , указывающим на массив строк в формате реестра в Юникоде с двойным завершением NULL. Каждая строка массива заканчивается null, а для указания конца массива используется пустая строка. Содержимое массива — это имена языков, отсортированные по достоверности.
#include <windows.h>
#include <stdio.h>
#include <elscore.h>
#include <elssrvc.h>
#define USER_TEXT ( \
L"Skip This is a simple sentence. " \
L"\x0422\x0445\x0438\x0441 \x0438\x0441 \x0415\x043d\x0433\x043b\x0438\x0441\x0445.")
#define USER_TEXT_SKIP (5)
int __cdecl main();
HRESULT CallMappingRecognizeText(PMAPPING_SERVICE_INFO pService);
void PrintAllResults(PMAPPING_PROPERTY_BAG pBag);
int __cdecl main()
{
MAPPING_ENUM_OPTIONS EnumOptions;
PMAPPING_SERVICE_INFO prgServices = NULL;
DWORD dwServicesCount = 0;
HRESULT hResult;
ZeroMemory(&EnumOptions, sizeof (MAPPING_ENUM_OPTIONS));
EnumOptions.Size = sizeof (MAPPING_ENUM_OPTIONS);
// Using the Language Auto-Detection GUID to enumerate LAD only:
EnumOptions.pGuid = (GUID *)&ELS_GUID_LANGUAGE_DETECTION;
hResult = MappingGetServices(&EnumOptions, &prgServices, &dwServicesCount);
if (SUCCEEDED(hResult))
{
hResult = CallMappingRecognizeText(&prgServices[0]);
if (SUCCEEDED(hResult))
{
printf("Calling the service %ws has succeeded!\n",
prgServices[0].pszDescription);
}
else
{
printf("Calling the service %ws has failed, failure = 0x%x!\n",
prgServices[0].pszDescription, hResult);
}
MappingFreeServices(prgServices);
}
return 0;
}
HRESULT CallMappingRecognizeText(PMAPPING_SERVICE_INFO pService)
{
MAPPING_PROPERTY_BAG bag;
HRESULT hResult;
ZeroMemory(&bag, sizeof (MAPPING_PROPERTY_BAG));
bag.Size = sizeof (MAPPING_PROPERTY_BAG);
// MappingRecognizeText's dwIndex parameter specifies the first
// index inside the text from where the recognition should start.
// We pass USER_TEXT_SKIP, thus skipping the "Skip " part
// of the input string.
// Calling without MAPPING_OPTIONS:
hResult = MappingRecognizeText(pService, USER_TEXT, wcslen(USER_TEXT), USER_TEXT_SKIP, NULL, &bag);
if (SUCCEEDED(hResult))
{
printf("Results from service: %ws\n", pService->pszDescription);
PrintAllResults(&bag);
hResult = MappingFreePropertyBag(&bag);
}
return hResult;
}
void PrintAllResults(PMAPPING_PROPERTY_BAG pBag)
{
WCHAR * p;
// The return format of the Language Auto-Detection is a
// double null-terminated registry-formatted array of strings.
// Every string of the array is null-terminated and there's an
// empty string specifying the end of the array.
for (p = (WCHAR *)pBag->prgResultRanges[0].pData; *p; p += wcslen(p) + 1)
{
printf("%ws\n", p);
}
}
Синхронное распознавание текста с помощью службы обнаружения сценариев (Майкрософт)
В следующем примере показано использование MappingRecognizeText со службой обнаружения сценариев (Майкрософт) и выводится все полученные результаты. Формат выходных данных этой службы представляет собой массив MAPPING_DATA_RANGE структур, каждая из которых указывает текст, написанный в одном скрипте. Общие символы (Zyyy) добавляются к предыдущему диапазону или к следующему диапазону, если предыдущий диапазон не существует. Элемент pData каждой структуры указывает на строку в Юникоде с пустым завершением, содержащую стандартное имя Юникода скрипта для определенного диапазона.
Примечание
В Windows 7 служба обнаружения сценариев (Майкрософт) соответствует Юникоду 5.1.
#include <windows.h>
#include <stdio.h>
#include <elscore.h>
#include <elssrvc.h>
#define USER_TEXT ( \
L"Skip This is a simple sentence. " \
L"\x0422\x0445\x0438\x0441 \x0438\x0441 \x0415\x043d\x0433\x043b\x0438\x0441\x0445.")
#define USER_TEXT_SKIP (5)
int __cdecl main();
HRESULT CallMappingRecognizeText(PMAPPING_SERVICE_INFO pService);
void PrintAllResults(PMAPPING_PROPERTY_BAG pBag);
int __cdecl main()
{
MAPPING_ENUM_OPTIONS EnumOptions;
PMAPPING_SERVICE_INFO prgServices = NULL;
DWORD dwServicesCount = 0;
HRESULT hResult;
ZeroMemory(&EnumOptions, sizeof (MAPPING_ENUM_OPTIONS));
EnumOptions.Size = sizeof (MAPPING_ENUM_OPTIONS);
// Using the Script Detection GUID to enumerate SD only:
EnumOptions.pGuid = (GUID *)&ELS_GUID_SCRIPT_DETECTION;
hResult = MappingGetServices(&EnumOptions, &prgServices, &dwServicesCount);
if (SUCCEEDED(hResult))
{
hResult = CallMappingRecognizeText(&prgServices[0]);
if (SUCCEEDED(hResult))
{
printf("Calling the service %ws has succeeded!\n",
prgServices[0].pszDescription);
}
else
{
printf("Calling the service %ws has failed, failure = 0x%x!\n",
prgServices[0].pszDescription, hResult);
}
MappingFreeServices(prgServices);
}
return 0;
}
HRESULT CallMappingRecognizeText(PMAPPING_SERVICE_INFO pService)
{
MAPPING_PROPERTY_BAG bag;
HRESULT hResult;
ZeroMemory(&bag, sizeof (MAPPING_PROPERTY_BAG));
bag.Size = sizeof (MAPPING_PROPERTY_BAG);
// MappingRecognizeText's dwIndex parameter specifies the first
// index inside the text from where the recognition should start.
// We pass USER_TEXT_SKIP, thus skipping the "Skip " part
// of the input string.
// Calling without MAPPING_OPTIONS:
hResult = MappingRecognizeText(pService, USER_TEXT, wcslen(USER_TEXT), USER_TEXT_SKIP, NULL, &bag);
if (SUCCEEDED(hResult))
{
printf("Results from service: %ws\n", pService->pszDescription);
PrintAllResults(&bag);
hResult = MappingFreePropertyBag(&bag);
}
return hResult;
}
void PrintAllResults(PMAPPING_PROPERTY_BAG pBag)
{
DWORD dwRangeIndex;
for (dwRangeIndex = 0; dwRangeIndex < pBag->dwRangesCount; ++dwRangeIndex)
{
if (dwRangeIndex > 0)
{
printf(" ----\n");
}
printf("Range from %u to %u\n",
(unsigned)pBag->prgResultRanges[dwRangeIndex].dwStartIndex,
(unsigned)pBag->prgResultRanges[dwRangeIndex].dwEndIndex);
printf("Data size in WCHARs: %u\n",
(unsigned)pBag->prgResultRanges[dwRangeIndex].dwDataSize / 2);
printf("\"%ws\"\n", (WCHAR *)pBag->prgResultRanges[dwRangeIndex].pData);
}
}
Синхронное распознавание текста с помощью службы транслитерации (Майкрософт) с кириллицей на латиницу
В следующем примере показано использование MappingRecognizeText со службой транслитерации кириллицы и латиницы (Майкрософт) и вывод полученных результатов. Обратите внимание на два разных способа перечисления этой службы: по GUID или по категориям и входному скрипту.
Формат выходных данных одинаков для всех доступных служб транслитерации. Это одна структура MAPPING_DATA_RANGE с элементом pData , указывающим на массив символов Юникода, представляющих исходный текст, транслитерированный в выходной скрипт, применяя только правила конкретной службы транслитерации. Эта служба не завершает выходные данные со значением NULL, если входные данные не содержат завершающего символа NULL.
#include <windows.h>
#include <stdio.h>
#include <elscore.h>
#include <elssrvc.h>
#define USER_TEXT (L"Skip The russian word for 'yes' is transliterated to Latin as '\x0434\x0430'.")
#define USER_TEXT_SKIP (5)
int __cdecl main();
HRESULT CallMappingRecognizeText(PMAPPING_SERVICE_INFO pService);
void PrintAllResults(PMAPPING_PROPERTY_BAG pBag);
int __cdecl main()
{
MAPPING_ENUM_OPTIONS EnumOptions;
PMAPPING_SERVICE_INFO prgServices;
DWORD dwServicesCount;
HRESULT hResult;
// 1. Enumerate by GUID:
prgServices = NULL;
dwServicesCount = 0;
ZeroMemory(&EnumOptions, sizeof (MAPPING_ENUM_OPTIONS));
EnumOptions.Size = sizeof (MAPPING_ENUM_OPTIONS);
// Use the Cyrl->Latn Transliteration GUID to enumerate only this service:
EnumOptions.pGuid = (GUID *)&ELS_GUID_TRANSLITERATION_CYRILLIC_TO_LATIN;
hResult = MappingGetServices(&EnumOptions, &prgServices, &dwServicesCount);
if (SUCCEEDED(hResult))
{
hResult = CallMappingRecognizeText(&prgServices[0]);
if (SUCCEEDED(hResult))
{
printf("Calling the service %ws has succeeded!\n",
prgServices[0].pszDescription);
}
else
{
printf("Calling the service %ws has failed, failure = 0x%x!\n",
prgServices[0].pszDescription, hResult);
}
MappingFreeServices(prgServices);
}
printf("--\n");
// 2. Enumerate by input script and category:
prgServices = NULL;
dwServicesCount = 0;
ZeroMemory(&EnumOptions, sizeof (MAPPING_ENUM_OPTIONS));
EnumOptions.Size = sizeof (MAPPING_ENUM_OPTIONS);
EnumOptions.pszCategory = L"Transliteration";
EnumOptions.pszInputScript = L"Cyrl";
hResult = MappingGetServices(&EnumOptions, &prgServices, &dwServicesCount);
if (SUCCEEDED(hResult))
{
hResult = CallMappingRecognizeText(&prgServices[0]);
if (SUCCEEDED(hResult))
{
printf("Calling the service %ws has succeeded!\n",
prgServices[0].pszDescription);
}
else
{
printf("Calling the service %ws has failed, failure = 0x%x!\n",
prgServices[0].pszDescription, hResult);
}
MappingFreeServices(prgServices);
}
return 0;
}
HRESULT CallMappingRecognizeText(PMAPPING_SERVICE_INFO pService)
{
MAPPING_PROPERTY_BAG bag;
HRESULT hResult;
ZeroMemory(&bag, sizeof (MAPPING_PROPERTY_BAG));
bag.Size = sizeof (MAPPING_PROPERTY_BAG);
// MappingRecognizeText's dwIndex parameter specifies the first
// index inside the text from where the recognition should start.
// We pass USER_TEXT_SKIP, thus skipping the "Skip " part
// of the input string.
// Calling without MAPPING_OPTIONS:
// We want the result to be null-terminated for display.
// That's why we will also pass the input null terminator:
hResult = MappingRecognizeText(pService, USER_TEXT, wcslen(USER_TEXT) + 1, USER_TEXT_SKIP, NULL, &bag);
if (SUCCEEDED(hResult))
{
printf("Results from service: %ws\n", pService->pszDescription);
PrintAllResults(&bag);
hResult = MappingFreePropertyBag(&bag);
}
return hResult;
}
void PrintAllResults(PMAPPING_PROPERTY_BAG pBag)
{
printf("\"%ws\"\n", (WCHAR *)pBag->prgResultRanges[0].pData);
}
Синхронное распознавание текста с вызовом всех доступных служб
В следующем примере показано использование MappingRecognizeText со всеми доступными службами и выводится полученный результат для всех служб. В этом примере показана хорошая иллюстрация работы каждой службы. Просмотрев выходные данные примера приложения, можно легко узнать, что происходит внутри служб. В этом примере также показано, что почти весь код, используемый для вызова любой из служб ELS, одинаков.
#include <windows.h>
#include <stdio.h>
#include <elscore.h>
#define USER_TEXT ( \
L"Skip This is a simple sentence. " \
L"\x0422\x0445\x0438\x0441 \x0438\x0441 \x0415\x043d\x0433\x043b\x0438\x0441\x0445.")
#define USER_TEXT_SKIP (5)
int __cdecl main();
HRESULT CallMappingRecognizeText(PMAPPING_SERVICE_INFO pService);
void PrintAllResults(PMAPPING_PROPERTY_BAG pBag);
int __cdecl main()
{
PMAPPING_SERVICE_INFO prgServices = NULL;
DWORD dwServicesCount = 0;
HRESULT hResult;
DWORD i;
// Get all installed ELS services:
hResult = MappingGetServices(NULL, &prgServices, &dwServicesCount);
if (SUCCEEDED(hResult))
{
for (i = 0; i < dwServicesCount; ++i)
{
// Do something with each service:
// ... prgServices[i] ...
if (i > 0)
{
printf("--\n");
}
hResult = CallMappingRecognizeText(&prgServices[i]);
if (SUCCEEDED(hResult))
{
printf("Calling the service %ws has succeeded!\n",
prgServices[i].pszDescription);
}
else
{
printf("Calling the service %ws has failed, failure = 0x%x!\n",
prgServices[i].pszDescription, hResult);
}
}
MappingFreeServices(prgServices);
}
return 0;
}
HRESULT CallMappingRecognizeText(PMAPPING_SERVICE_INFO pService)
{
MAPPING_PROPERTY_BAG bag;
HRESULT hResult;
ZeroMemory(&bag, sizeof (MAPPING_PROPERTY_BAG));
bag.Size = sizeof (MAPPING_PROPERTY_BAG);
// MappingRecognizeText's dwIndex parameter specifies the first
// index inside the text from where the recognition should start.
// We pass USER_TEXT_SKIP, thus skipping the "Skip " part
// of the input string.
// Calling without MAPPING_OPTIONS:
hResult = MappingRecognizeText(pService, USER_TEXT, wcslen(USER_TEXT), USER_TEXT_SKIP, NULL, &bag);
if (SUCCEEDED(hResult))
{
printf("Results from service: %ws\n", pService->pszDescription);
PrintAllResults(&bag);
hResult = MappingFreePropertyBag(&bag);
}
return hResult;
}
void PrintAllResults(PMAPPING_PROPERTY_BAG pBag)
{
DWORD dwRangeIndex;
DWORD dwDataIndex;
WCHAR c;
for (dwRangeIndex = 0; dwRangeIndex < pBag->dwRangesCount; ++dwRangeIndex)
{
if (dwRangeIndex > 0)
{
printf(" ----\n");
}
printf("Range from %u to %u\n",
(unsigned)pBag->prgResultRanges[dwRangeIndex].dwStartIndex,
(unsigned)pBag->prgResultRanges[dwRangeIndex].dwEndIndex);
// Currently, we can treat all results as arrays of unicode WCHAR
// characters, but there can be services in the future
// that use different formatting, i.e. XML, HTML, etc.
printf("Data size in WCHARs: %u\n",
(unsigned)pBag->prgResultRanges[dwRangeIndex].dwDataSize / 2);
printf("\"");
for (dwDataIndex = 0; dwDataIndex < pBag->prgResultRanges[dwRangeIndex].dwDataSize / 2; ++dwDataIndex)
{
c = ((WCHAR *)pBag->prgResultRanges[dwRangeIndex].pData)[dwDataIndex];
if (c >= 32 && c < 128 && c != '"') printf("%wc", c);
else printf("#%x", (unsigned)c);
}
printf("\"\n");
}
}
void CallRecognizeText(LPCWSTR Category, LPCWSTR Text)
{
HRESULT Result;
PMAPPING_SERVICE_INFO rgServices;
DWORD ServicesCount;
MAPPING_ENUM_OPTIONS options = {sizeof(MAPPING_ENUM_OPTIONS), (LPWSTR) Category, 0};
Result = MappingGetServices(&options, &rgServices, &ServicesCount);
if (Result == S_OK && ServicesCount > 0)
{
MAPPING_PROPERTY_BAG bag = { sizeof(MAPPING_PROPERTY_BAG), 0};
Result = MappingRecognizeText(&rgServices[0], Text, wcslen(Text), 0, NULL, &bag);
if (Result == S_OK)
{
MappingFreePropertyBag(&bag);
}
MappingFreeServices(rgServices);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
CallRecognizeText(L"Language Detection", L"Text to be recognized");
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
return 0;
}
Использование асинхронного распознавания текста
В следующем примере показано использование MappingRecognizeText для асинхронного распознавания текста. При использовании обратного вызова приложение должно убедиться, что контейнер свойств, входной текст, параметры и служба действительны до завершения обратного вызова.
Приложение должно вызывать MappingFreePropertyBag сразу после использования контейнера функцией обратного вызова. Дополнительные сведения см. в статье Предоставление обратных вызовов для служб ELS.
#include <windows.h>
#include <stdio.h>
#include <elscore.h>
#include <elssrvc.h>
#define USER_TEXT ( \
L"Skip This is a simple sentence. " \
L"\x0422\x0445\x0438\x0441 \x0438\x0441 \x0415\x043d\x0433\x043b\x0438\x0441\x0445.")
#define USER_TEXT_SKIP (5)
int __cdecl main();
HRESULT CallMappingRecognizeText(PMAPPING_SERVICE_INFO pService);
void RecognizeCallback(PMAPPING_PROPERTY_BAG pBag, LPVOID data, DWORD dwDataSize, HRESULT Result);
int __cdecl main()
{
MAPPING_ENUM_OPTIONS EnumOptions;
PMAPPING_SERVICE_INFO prgServices = NULL;
DWORD dwServicesCount = 0;
HRESULT hResult;
ZeroMemory(&EnumOptions, sizeof (MAPPING_ENUM_OPTIONS));
EnumOptions.Size = sizeof (MAPPING_ENUM_OPTIONS);
// Using the Language Auto-Detection GUID to enumerate LAD only:
EnumOptions.pGuid = (GUID *)&ELS_GUID_LANGUAGE_DETECTION;
hResult = MappingGetServices(&EnumOptions, &prgServices, &dwServicesCount);
if (SUCCEEDED(hResult))
{
hResult = CallMappingRecognizeText(&prgServices[0]);
if (SUCCEEDED(hResult))
{
printf("Calling the service %ws has succeeded!\n",
prgServices[0].pszDescription);
}
else
{
printf("Calling the service %ws has failed, failure = 0x%x!\n",
prgServices[0].pszDescription, hResult);
}
MappingFreeServices(prgServices);
}
return 0;
}
HRESULT CallMappingRecognizeText(PMAPPING_SERVICE_INFO pService)
{
MAPPING_PROPERTY_BAG bag;
MAPPING_OPTIONS Options;
HRESULT hResult;
HANDLE SyncEvent;
DWORD dwWaitResult;
SyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (SyncEvent == NULL)
{
hResult = E_FAIL;
}
else
{
ZeroMemory(&bag, sizeof (MAPPING_PROPERTY_BAG));
bag.Size = sizeof (MAPPING_PROPERTY_BAG);
ZeroMemory(&Options, sizeof (MAPPING_OPTIONS));
Options.Size = sizeof (MAPPING_OPTIONS);
Options.pfnRecognizeCallback = (PFN_MAPPINGCALLBACKPROC)RecognizeCallback;
Options.pRecognizeCallerData = &SyncEvent;
Options.dwRecognizeCallerDataSize = sizeof (HANDLE);
// MappingRecognizeText's dwIndex parameter specifies the first
// index inside the text from where the recognition should start.
// We pass USER_TEXT_SKIP, thus skipping the "Skip " part
// of the input string.
hResult = MappingRecognizeText(pService, USER_TEXT, wcslen(USER_TEXT), USER_TEXT_SKIP, &Options, &bag);
if (SUCCEEDED(hResult))
{
// We are using an event to synchronize our waiting for the call to end,
// because some objects have to be valid till the end of the callback call:
// - the input text
// - the property bag
// - the options
// - the service
dwWaitResult = WaitForSingleObject(SyncEvent, INFINITE);
if (dwWaitResult != WAIT_OBJECT_0)
{
hResult = E_FAIL;
}
}
CloseHandle(SyncEvent);
}
return hResult;
}
void RecognizeCallback(PMAPPING_PROPERTY_BAG pBag, LPVOID data, DWORD dwDataSize, HRESULT Result)
{
HANDLE SyncEvent;
WCHAR * p;
UNREFERENCED_PARAMETER(dwDataSize);
if (SUCCEEDED(Result))
{
for (p = (WCHAR *)pBag->prgResultRanges[0].pData; *p; p += wcslen(p) + 1)
{
printf("%ws\n", p);
}
MappingFreePropertyBag(pBag);
}
SyncEvent = *((HANDLE *)data);
SetEvent(SyncEvent);
}
Связанные темы