Как оригинальный писатель Dynamsoft Carcode Reader для Python ( PIP Установка DBR
), я предпочитаю использовать CPYthon и Dynamsoft C/C ++ Carcode SDK SDK, чтобы принести API для обнаружения штрих-кода для Python. Тем не менее, CTYPES Также стоит изучить. Это позволяет разработчикам вызывать функции C совместных библиотек в чистом виде Python. Статья проходит через шаги о том, как вызвать API на Dynamsoft C/C ++ Barcode API на Python Ctypes.
Попытка позвонить в функции C SDK Carcode SDK Dynamsoft в чистом Python
Предположим, вы скачали C/C ++ Пакеты , который содержит * .dll и * .so Файлы для Windows и Linux, с веб-сайта Dynamsoft. Мы копируем файлы * .dll и * .so в ту же папку нашего проекта Python.
В файле Python мы импортируем библиотеку Ctypes, а затем загрузите общую библиотеку DynamSoft:
import os import platform from ctypes import * dbr = None if 'Windows' in system: os.environ['path'] += ';' + os.path.join(os.path.abspath('.'), r'') dbr = windll.LoadLibrary('DynamsoftBarcodeReaderx64.dll') else: dbr = CDLL(os.path.join(os.path.abspath('.'), ' '))
Dynamsoftbarcodereaderx64.dll
. зависит от vcom110.dll
Отказ Если vcom110.dll
Пропущено, вы получите следующую ошибку:
Traceback (most recent call last): File ".\failure.py", line 80, indbr = windll.LoadLibrary('DynamsoftBarcodeReaderx64.dll') File "C:\Python37\lib\ctypes\__init__.py", line 442, in LoadLibrary return self._dlltype(name) File "C:\Python37\lib\ctypes\__init__.py", line 364, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 126] The specified module could not be found
Для Linux, путь libdynamsoftbarcodereader.so
достаточно.
Шаги для декодирования изображения штрих-кода с CTYPES
Чтобы понять функции вызова, вы можете обратиться к Dynamsoftbarcodereader.h
файл.
Шаг 1: Инициализируйте считыватель DynamSoft Barcode
DBR_CreateInstance = dbr.DBR_CreateInstance DBR_CreateInstance.restype = c_void_p instance = dbr.DBR_CreateInstance()
Шаг 2: Установите лицензионный ключ
DBR_InitLicense = dbr.DBR_InitLicense DBR_InitLicense.argtypes = [c_void_p, c_char_p] DBR_InitLicense.restype = c_int ret = DBR_InitLicense(instance, c_char_p('LICENSE-KEY'.encode('utf-8')))
Получить действительный Лицензионный ключ с веб-сайта Dynamsoft, а затем обновить C_CHAR_P («Лицензия-ключ'.encode ('utf-8'))
.
При преобразовании Python Строка
к Чар *
, вам нужно кодировать его на UTF-8
первый. В противном случае вы получите TypeError: BYTES или целочисленный адрес, ожидаемый вместо экземпляра CAR
Отказ
Шаг 3: Позвоните в API декодирования
DBR_DecodeFile = dbr.DBR_DecodeFile DBR_DecodeFile.argtypes = [c_void_p, c_char_p, c_char_p] DBR_DecodeFile.restype = c_int ret = DBR_DecodeFile(instance, c_char_p('test.png'.encode('utf-8')), c_char_p(''.encode('utf-8')))
Шаг 4: Получите результат штрих-кода
pResults = POINTER(TextResultArray)() DBR_GetAllTextResults = dbr.DBR_GetAllTextResults DBR_GetAllTextResults.argtypes = [c_void_p, POINTER(POINTER(TextResultArray))] DBR_GetAllTextResults.restype = c_int ret = DBR_GetAllTextResults(instance, byref(pResults)) print(ret) resultsCount = pResults.contents.resultsCount print(resultsCount) results = pResults.contents.results print(results) if bool(results): for i in range(resultsCount): result = results[i] if bool(result): print(result) print('Format: %s' % result.contents.barcodeFormatString.decode('utf-8')) print('Text: %s' % result.contents.barcodeText.decode('utf-8'))
Это самая жесткая часть всего процесса. Результатом является TextresUltarray
Структура, которая содержит список Textresult
структуры. Каждый Textresult
Структура содержит формат штрих-кода, текст штрих-кода и другую информацию. Чтобы получить доступ к результатам декодирования штрих-кода, нам нужно определить все соответствующие сооружения C в Python:
class SamplingImageData(Structure): _fields_ = [("bytes", POINTER(c_byte)), ("width", c_int), ("height", c_int)] class ExtendedResult(Structure): _fields_ = [("resultType", c_uint), ("barcodeFormat", c_uint), ("barcodeFormatString", c_char_p), ("barcodeFormat_2", c_uint), ("barcodeFormatString_2", c_char_p), ("confidence", c_int), ("bytes", POINTER(c_byte)), ("bytesLength", c_int), ("accompanyingTextBytes", POINTER(c_byte)), ("accompanyingTextBytesLength", c_int), ("deformation", c_int), ("detailedResult", c_void_p), ("samplingImage", SamplingImageData), ("clarity", c_int), ("reserved", c_char * 40), ] class LocalizationResult(Structure): _fields_ = [("terminatePhase", c_uint), ("barcodeFormat", c_uint), ("barcodeFormatString", c_char_p), ("barcodeFormat_2", c_uint), ("barcodeFormatString_2", c_char_p), ("x1", c_int), ("y1", c_int), ("x2", c_int), ("y2", c_int), ("x3", c_int), ("y3", c_int), ("x4", c_int), ("y4", c_int), ("angle", c_int), ("moduleSize", c_int), ("pageNumber", c_int), ("regionName", c_char_p), ("documentName", c_char_p), ("resultCoordinateType", c_uint), ("accompanyingTextBytes", POINTER(c_byte)), ("accompanyingTextBytesLength", c_int), ("confidence", c_int), ("reserved", c_char * 52), ] class TextResult(Structure): _fields_ = [("barcodeFormat", c_uint), ("barcodeFormatString", c_char_p), ("barcodeFormat_2", c_uint), ("barcodeFormatString_2", c_char_p), ("barcodeText", c_char_p), ("barcodeBytes", POINTER(c_byte)), ("barcodeBytesLength", c_int), ("localizationResult", POINTER(LocalizationResult)), ("detailedResult", c_void_p), ("resultsCount", c_int), ("results", POINTER(POINTER(ExtendedResult))), ("exception", c_char_p), ("isDPM", c_int), ("isMirrored", c_int), ("reserved", c_char * 44), ] class TextResultArray(Structure): _fields_= [("resultsCount",c_int), ("results", POINTER(POINTER(TextResult)))]
Шаг 5: Бесплатная память о результате штрих-кода
DBR_FreeTextResults = dbr.DBR_FreeTextResults DBR_FreeTextResults.argtypes = [POINTER(POINTER(TextResultArray))] if bool(pResults): DBR_FreeTextResults(byref(pResults))
Шаг 6: Уничтожьте Reader DynamSoft Barcode Reader
DBR_DestroyInstance = dbr.DBR_DestroyInstance DBR_DestroyInstance.argtypes = [c_void_p] DBR_DestroyInstance(instance)
Тестирование программы
До сих пор мы успешно реализовали читатель Python Barcode с CTYPES. Тем не менее, работает скрипт ничего. Количество результата отличное, чем ноль, но Bool (результаты)
Возвращает false, что означает, что результаты декодирования штрих-кода пусты. Это невозможно, по-видимому,. Но, к сожалению, я еще не разобрался, где есть ошибка. Вероятно, это вызвано копией памяти вложенных структур C. Чтобы избежать нарушения сегментации, лучше написать немного C-кода для упрощения Структур C, определенных в Python.
Написать немного C-кода, чтобы упростить вызовы ctypes
Мы создаем проект библиотеки CMAKE с именем мост
Для реализации двух методов dbr_get_results.
и dbr_free_results.
вместо Dbr_getalltextresults.
и Dbr_freetextresults
Отказ C-код написан в bridge.c
Отказ
Cmakelists.txt
Файл выглядит следующим образом:
cmake_minimum_required(VERSION 3.0.0) project(bridge VERSION 0.1.0) INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include") if (CMAKE_HOST_WIN32) LINK_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/lib/Windows") else() LINK_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/lib/Linux") endif() add_library(${PROJECT_NAME} SHARED bridge.c) if(CMAKE_HOST_WIN32) target_link_libraries (${PROJECT_NAME} "DBRx64") else() target_link_libraries (${PROJECT_NAME} "DynamsoftBarcodeReader") endif()
Для экспорта функций для Windows и Linux мы определяем макрос в bridge.h
:
#if !defined(_WIN32) && !defined(_WIN64) #define EXPORT_API #else #define EXPORT_API __declspec(dllexport) #endif
Кроме того, мы определяем структуры и функции C, которые будут использоваться Python Ctypes:
typedef struct { char* format; char* text; } ResultInfo; typedef struct { int size; ResultInfo** pResultInfo; } ResultList; EXPORT_API ResultList* dbr_get_results(void* barcodeReader); EXPORT_API void dbr_free_results(ResultList* resultList);
В bridge.c
мы добавляем реализацию dbr_get_results.
и dbr_free_results.
:
#include#include #include #include "bridge.h" ResultList* dbr_get_results(void* barcodeReader) { TextResultArray *pResults; int ret = DBR_GetAllTextResults(barcodeReader, &pResults); int count = pResults->resultsCount; TextResult **results = pResults->results; ResultInfo** pResultInfo = (ResultInfo**)malloc(sizeof(ResultInfo*) * count); ResultList* resultList = (ResultList*)malloc(sizeof(ResultList)); resultList->size = count; resultList->pResultInfo = pResultInfo; for (int i = 0; i < count; i++) { TextResult* pResult = results[i]; ResultInfo* pInfo = (ResultInfo*)malloc(sizeof(ResultInfo)); pInfo->format = NULL; pInfo->text = NULL; pResultInfo[i] = pInfo; pInfo->format = (char *)calloc(strlen(pResult->barcodeFormatString) + 1, sizeof(char)); strncpy(pInfo->format, pResult->barcodeFormatString, strlen(pResult->barcodeFormatString)); pInfo->text = (char *)calloc(strlen(pResult->barcodeText) + 1, sizeof(char)); strncpy(pInfo->text, pResult->barcodeText, strlen(pResult->barcodeText)); } DBR_FreeTextResults(&pResults); return resultList; } void dbr_free_results(ResultList* resultList) { int count = resultList->size; ResultInfo** pResultInfo = resultList->pResultInfo; for (int i = 0; i < count; i++) { ResultInfo* resultList = pResultInfo[i]; if (resultList) { if (resultList->format) free(resultList->format); if (resultList->text) free(resultList->text); free(resultList); } } if (pResultInfo) free(pResultInfo); }
Как только сборка библиотеки моста сделана, мы вернемся к сценарию Python. Новый файл библиотеки bridge.dll/bridge.so
готов к нагрузке:
dbr = None bridge = None if 'Windows' in system: os.environ['path'] += ';' + os.path.join(os.path.abspath('.'), r'bridge\lib\Windows') dbr = windll.LoadLibrary('DynamsoftBarcodeReaderx64.dll') bridge = windll.LoadLibrary(os.path.join(os.path.abspath('.'), r'bridge\build\Debug\bridge.dll')) else: dbr = CDLL(os.path.join(os.path.abspath('.'), 'bridge/lib/Linux/libDynamsoftBarcodeReader.so')) bridge = CDLL(os.path.join(os.path.abspath('.'), 'bridge/build/libbridge.so'))
Последовательность загрузки библиотеки жизненно важно для Linux: libdynamsoftbarcodereader.so
Во-первых, тогда libbridge.so.
. Если библиотека загружена в неправильном порядке, код Python не будет работать на Linux.
Структуры C теперь намного проще и очиститель, чем структуры, определенные на предыдущем шаге:
class ResultInfo(Structure): _fields_ = [("format", c_char_p), ("text", c_char_p)] class ResultList(Structure): _fields_ = [("size", c_int), ("pResultInfo", POINTER(POINTER(ResultInfo)))]
Поэтому кода Python для получения и уничтожения результатов декодирования штрих-кода меняется на:
# dbr_get_results dbr_get_results = bridge.dbr_get_results dbr_get_results.argtypes = [c_void_p] dbr_get_results.restype = c_void_p address = dbr_get_results(instance) data = cast(address, POINTER(ResultList)) size = data.contents.size results = data.contents.pResultInfo for i in range(size): result = results[i] print('Format: %s' % result.contents.format.decode('utf-8')) print('Text: %s' % result.contents.text.decode('utf-8')) # dbr_free_results dbr_free_results = bridge.dbr_free_results dbr_free_results.argtypes = [c_void_p] if bool(address): dbr_free_results(address)
Наконец, мы можем успешно запустить приложение декодирования штрих-кода Python.
Исходный код
https://github.com/yushulx/python-ctypes-barcode-shared-library
Оригинал: “https://dev.to/yushulx/python-ctypes-for-loading-and-calling-shared-libraries-49n7”