From b9cbf820d30b935fd86dceac899a1d4f21cac608 Mon Sep 17 00:00:00 2001 From: luoliangyi <87842688@qq.com> Date: Tue, 19 Jul 2022 11:48:38 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E8=A7=A3=E5=86=B3HGBase=5FWriteInfo?= =?UTF-8?q?=E5=B4=A9=E6=BA=83=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/base/HGInfo.cpp | 2 +- sdk/webservice/ManagerV2.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/base/HGInfo.cpp b/modules/base/HGInfo.cpp index 323f16bf..fcd051e5 100644 --- a/modules/base/HGInfo.cpp +++ b/modules/base/HGInfo.cpp @@ -28,7 +28,7 @@ HGResult HGAPIV HGBase_WriteInfo(HGUInt type, const HGChar* format, ...) char buf[1024] = { 0 }; va_list va; va_start(va, format); - vsprintf(buf, format, va); + vsnprintf(buf, 1024, format, va); va_end(va); return g_infoImpl->Write(type, buf); diff --git a/sdk/webservice/ManagerV2.cpp b/sdk/webservice/ManagerV2.cpp index ae95beb1..120300b5 100644 --- a/sdk/webservice/ManagerV2.cpp +++ b/sdk/webservice/ManagerV2.cpp @@ -4033,6 +4033,8 @@ namespace ver_2 } HGBase_EnterLock(p->m_lock); + if (NULL != p->m_saneEvent) + p->m_saneEvent(SANEEVENT_REMOVE, sane_dev->name, false, p->m_saneParam); for (int i = 0; i < (int)p->m_devNameList.size(); ++i) { if (0 == strcmp(sane_dev->name, p->m_devNameList[i].c_str())) @@ -4041,8 +4043,6 @@ namespace ver_2 break; } } - if (NULL != p->m_saneEvent) - p->m_saneEvent(SANEEVENT_REMOVE, sane_dev->name, false, p->m_saneParam); HGBase_LeaveLock(p->m_lock); } break; From 51590dfd88195dea17a69e3e04ff58fbe47d85e3 Mon Sep 17 00:00:00 2001 From: luoliangyi <87842688@qq.com> Date: Tue, 19 Jul 2022 11:51:00 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=A2=9E=E5=8A=A0HGScannerLib=E5=B7=A5?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/windows/HGScannerLib/HGScannerLib.def | 19 ++ .../windows/HGScannerLib/HGScannerLib.vcxproj | 179 ++++++++++++++++++ build/windows/HGSolution.sln | 15 ++ sdk/scannerlib/HGLibDeviceImpl.cpp | 127 +++++++++++++ sdk/scannerlib/HGLibDeviceImpl.hpp | 43 +++++ sdk/scannerlib/HGScannerLib.cpp | 155 +++++++++++++++ sdk/scannerlib/HGScannerLib.h | 179 ++++++++++++++++++ 7 files changed, 717 insertions(+) create mode 100644 build/windows/HGScannerLib/HGScannerLib.def create mode 100644 build/windows/HGScannerLib/HGScannerLib.vcxproj create mode 100644 sdk/scannerlib/HGLibDeviceImpl.cpp create mode 100644 sdk/scannerlib/HGLibDeviceImpl.hpp create mode 100644 sdk/scannerlib/HGScannerLib.cpp create mode 100644 sdk/scannerlib/HGScannerLib.h diff --git a/build/windows/HGScannerLib/HGScannerLib.def b/build/windows/HGScannerLib/HGScannerLib.def new file mode 100644 index 00000000..1c394345 --- /dev/null +++ b/build/windows/HGScannerLib/HGScannerLib.def @@ -0,0 +1,19 @@ +LIBRARY + +EXPORTS + +HGLib_LoadImage +HGLib_SaveImage +HGLib_ReleaseImage +HGLib_InitDevice +HGLib_DeinitDevice +HGLib_GetDeviceNameList +HGLib_ReleaseDeviceNameList +HGLib_OpenDevice +HGLib_CloseDevice +HGLib_SetDeviceParam +HGLib_GetDeviceParamGroupList +HGLib_ReleaseDeviceParamGroupList +HGLib_ResetDeviceParam +HGLib_StartDeviceScan +HGLib_StopDeviceScan \ No newline at end of file diff --git a/build/windows/HGScannerLib/HGScannerLib.vcxproj b/build/windows/HGScannerLib/HGScannerLib.vcxproj new file mode 100644 index 00000000..395b1c10 --- /dev/null +++ b/build/windows/HGScannerLib/HGScannerLib.vcxproj @@ -0,0 +1,179 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + 16.0 + Win32Proj + {62cad8e9-4461-49a1-8eb8-4cebe113fe02} + HGScannerLib + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;HGSCANNERLIB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + ../../../modules/base/;../../../modules/;../../../utility/;../../../../sdk/include/;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Windows + true + false + HGScannerLib.def + ../Debug/HGBase.lib;../Debug/HGImgFmt.lib;../Debug/HGImgProc.lib;../../../../sdk/lib/win/x86/Release/sane.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + WIN32;NDEBUG;HGSCANNERLIB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + MultiThreaded + + + Windows + true + true + true + false + HGScannerLib.def + + + + + Level3 + true + _DEBUG;HGSCANNERLIB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + MultiThreadedDebug + + + Windows + true + false + HGScannerLib.def + + + + + Level3 + true + true + true + NDEBUG;HGSCANNERLIB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + MultiThreaded + + + Windows + true + true + true + false + HGScannerLib.def + + + + + + \ No newline at end of file diff --git a/build/windows/HGSolution.sln b/build/windows/HGSolution.sln index 627f6c6e..dd480ddb 100644 --- a/build/windows/HGSolution.sln +++ b/build/windows/HGSolution.sln @@ -50,6 +50,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HGVersion", "HGVersion\HGVe {F85F4457-1B42-46E7-BA86-F088D6D5994F} = {F85F4457-1B42-46E7-BA86-F088D6D5994F} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HGScannerLib", "HGScannerLib\HGScannerLib.vcxproj", "{62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}" + ProjectSection(ProjectDependencies) = postProject + {F85F4457-1B42-46E7-BA86-F088D6D5994F} = {F85F4457-1B42-46E7-BA86-F088D6D5994F} + {5D85F2AC-FACD-436C-A67B-E13056DD0C03} = {5D85F2AC-FACD-436C-A67B-E13056DD0C03} + {4909ACEA-80FF-482E-9FA2-5E8534789A82} = {4909ACEA-80FF-482E-9FA2-5E8534789A82} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -130,6 +137,14 @@ Global {25D00B63-9385-4283-8955-92CAAEDBE68A}.Release|x64.Build.0 = Release|x64 {25D00B63-9385-4283-8955-92CAAEDBE68A}.Release|x86.ActiveCfg = Release|Win32 {25D00B63-9385-4283-8955-92CAAEDBE68A}.Release|x86.Build.0 = Release|Win32 + {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Debug|x64.ActiveCfg = Debug|x64 + {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Debug|x64.Build.0 = Debug|x64 + {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Debug|x86.ActiveCfg = Debug|Win32 + {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Debug|x86.Build.0 = Debug|Win32 + {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Release|x64.ActiveCfg = Release|x64 + {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Release|x64.Build.0 = Release|x64 + {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Release|x86.ActiveCfg = Release|Win32 + {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sdk/scannerlib/HGLibDeviceImpl.cpp b/sdk/scannerlib/HGLibDeviceImpl.cpp new file mode 100644 index 00000000..b1748fa5 --- /dev/null +++ b/sdk/scannerlib/HGLibDeviceImpl.cpp @@ -0,0 +1,127 @@ +#include "HGLibDeviceImpl.hpp" +#include "base/HGInc.h" +#include "base/HGInfo.h" +#include "HGString.h" + +HGLock HGLibDeviceImpl::m_lock = NULL; +HGLibDeviceHotPlugEventFunc HGLibDeviceImpl::m_hotPlugEventFunc = NULL; +HGPointer HGLibDeviceImpl::m_hotPlugEventParam = NULL; +HGBool HGLibDeviceImpl::m_init = HGFALSE; +std::vector HGLibDeviceImpl::m_devNameList; + +HGLibDeviceImpl::HGLibDeviceImpl() +{ + +} + +HGLibDeviceImpl::~HGLibDeviceImpl() +{ + +} + +HGBool HGLibDeviceImpl::Init(HGLibDeviceHotPlugEventFunc func, HGPointer param) +{ + if (m_init) + { + return HGFALSE; + } + + assert(NULL == m_lock); + HGBase_CreateLock(&m_lock); + assert(NULL == m_hotPlugEventFunc); + m_hotPlugEventFunc = func; + m_hotPlugEventParam = param; + + SANE_Int version_code = 0; + if (SANE_STATUS_GOOD != sane_init_ex(&version_code, sane_ex_callback, NULL)) + { + m_hotPlugEventFunc = NULL; + m_hotPlugEventParam = NULL; + HGBase_DestroyLock(m_lock); + m_lock = NULL; + return HGFALSE; + } + + m_init = HGTRUE; + return HGTRUE; +} + +HGBool HGLibDeviceImpl::Deinit() +{ + if (!m_init) + { + return HGFALSE; + } + + sane_exit(); + m_hotPlugEventFunc = NULL; + m_hotPlugEventParam = NULL; + HGBase_DestroyLock(m_lock); + m_lock = NULL; + m_init = HGFALSE; + return HGTRUE; +} + +HGChar** HGLibDeviceImpl::GetNameList() +{ + return NULL; +} + +HGBool HGLibDeviceImpl::ReleaseNameList(HGChar** deviceName) +{ + if (NULL == deviceName) + { + return HGFALSE; + } + + while (0 != *deviceName) + { + free(*deviceName); + ++deviceName; + } + + free(deviceName); + return HGTRUE; +} + +int HGLibDeviceImpl::sane_ex_callback(SANE_Handle hdev, int code, void* data, unsigned int* len, void* param) +{ + switch (code) + { + case SANE_EVENT_DEVICE_ARRIVED: + { + SANE_Device* sane_dev = (SANE_Device*)data; + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_DEVICE_ARRIVED, name=%s", Utf8ToStdString(sane_dev->name).c_str()); + + HGBase_EnterLock(m_lock); + m_devNameList.push_back(sane_dev->name); + HGBase_LeaveLock(m_lock); + + if (NULL != m_hotPlugEventFunc) + m_hotPlugEventFunc(HGLIB_DEVHOTPLUG_EVENT_ARRIVE, sane_dev->name, m_hotPlugEventParam); + } + break; + case SANE_EVENT_DEVICE_LEFT: + { + SANE_Device* sane_dev = (SANE_Device*)data; + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_DEVICE_LEFT, name=%s", Utf8ToStdString(sane_dev->name).c_str()); + + if (NULL != m_hotPlugEventFunc) + m_hotPlugEventFunc(HGLIB_DEVHOTPLUG_EVENT_REMOVE, sane_dev->name, m_hotPlugEventParam); + + HGBase_EnterLock(m_lock); + for (int i = 0; i < (int)m_devNameList.size(); ++i) + { + if (0 == strcmp(sane_dev->name, m_devNameList[i].c_str())) + { + m_devNameList.erase(m_devNameList.begin() + i); + break; + } + } + HGBase_LeaveLock(m_lock); + } + break; + } + + return 0; +} \ No newline at end of file diff --git a/sdk/scannerlib/HGLibDeviceImpl.hpp b/sdk/scannerlib/HGLibDeviceImpl.hpp new file mode 100644 index 00000000..7c938754 --- /dev/null +++ b/sdk/scannerlib/HGLibDeviceImpl.hpp @@ -0,0 +1,43 @@ +#ifndef __HGLIBDEVICEIMPL_HPP__ +#define __HGLIBDEVICEIMPL_HPP__ + +#include "HGScannerLib.h" +#include "base/HGLock.h" +#include "sane/sane_ex.h" +#include "sane/sane_option_definitions.h" +#include +#include + +class HGLibDeviceImpl +{ +public: + HGLibDeviceImpl(); + ~HGLibDeviceImpl(); + + static HGBool Init(HGLibDeviceHotPlugEventFunc func, HGPointer param); + static HGBool Deinit(); + static HGChar** GetNameList(); + static HGBool ReleaseNameList(HGChar** deviceName); + + HGBool Open(const HGChar* deviceName); + HGBool Close(); + HGBool SetParam(const HGLibDeviceSetParam* param, HGUInt count); + HGLibDeviceGetParamGroup* GetParamGroupList(HGUInt* count); + static HGBool ReleaseParamGroupList(HGLibDeviceGetParamGroup* paramGroup, HGUInt count); + HGBool ResetParam(); + HGBool StartScan(HGLibDeviceScanEventFunc eventFunc, HGPointer eventParam, + HGLibDeviceScanImageFunc imageFunc, HGPointer imageParam); + HGBool StopScan(); + +private: + static int sane_ex_callback(SANE_Handle hdev, int code, void* data, unsigned int* len, void* param); + +private: + static HGLock m_lock; + static HGLibDeviceHotPlugEventFunc m_hotPlugEventFunc; + static HGPointer m_hotPlugEventParam; + static HGBool m_init; + static std::vector m_devNameList; +}; + +#endif /* __HGLIBDEVICEIMPL_HPP__ */ \ No newline at end of file diff --git a/sdk/scannerlib/HGScannerLib.cpp b/sdk/scannerlib/HGScannerLib.cpp new file mode 100644 index 00000000..17e08b20 --- /dev/null +++ b/sdk/scannerlib/HGScannerLib.cpp @@ -0,0 +1,155 @@ +#include "HGScannerLib.h" +#include "base/HGInc.h" +#include "base/HGImage.h" +#include "imgfmt/HGImgFmt.h" +#include "imgproc/HGOcr.h" +#include "HGString.h" +#include "HGLibDeviceImpl.hpp" + +typedef struct +{ + HGUInt size; /* 结构体大小 */ + HGUInt jpegQuality; /* jpeg下有效, 0-100 */ + HGUInt tiffCompression; /* tiff下有效, HGLIB_TIFFCOMPRESSION_* */ + HGUInt tiffJpegQuality; /* tiff且HGLIB_TIFFCOMPRESSION_JPEG下有效, 0-100 */ + HGBool ocr; /* 是否OCR,pdf和ofd格式有效 */ +}HGLibSaveImageParam_V1; + +HGLibImage HGAPI HGLib_LoadImage(const HGChar* filePath) +{ + if (NULL == filePath) + { + return NULL; + } + + HGImage image = NULL; + HGImgFmt_LoadImage(Utf8ToStdString(filePath).c_str(), 0, NULL, 0, HGBASE_IMGORIGIN_TOP, &image); + return (HGLibImage)image; +} + +HGBool HGAPI HGLib_SaveImage(HGLibImage image, const HGChar* savePath, const HGLibSaveImageParam* saveParam) +{ + if (NULL == image || NULL == savePath) + { + return HGFALSE; + } + + HGUInt fmtType = 0; + HGImgFmt_GetImgFmtTypeFromFileName(Utf8ToStdString(savePath).c_str(), &fmtType); + if (fmtType < HGIMGFMT_TYPE_JPEG || fmtType > HGIMGFMT_TYPE_GIF) + { + return HGFALSE; + } + + if (NULL == saveParam) + { + return (HGBASE_ERR_OK == HGImgFmt_SaveImage((HGImage)image, fmtType, NULL, Utf8ToStdString(savePath).c_str())); + } + + if (saveParam->size == sizeof(HGLibSaveImageParam_V1)) + { + const HGLibSaveImageParam_V1* saveParamV1 = (const HGLibSaveImageParam_V1*)saveParam; + if ((HGIMGFMT_TYPE_PDF == fmtType || HGIMGFMT_TYPE_OFD == fmtType) && saveParamV1->ocr) + { + HGOCRMgr ocrMgr = NULL; + HGImgProc_CreateOCRMgr(&ocrMgr); + if (NULL == ocrMgr) + { + return HGFALSE; + } + + HGBool ret = (HGBASE_ERR_OK == HGImgProc_ImageOCRToFile(ocrMgr, (HGImage)image, 0, Utf8ToStdString(savePath).c_str())); + HGImgProc_DestroyOCRMgr(ocrMgr); + return ret; + } + + HGImgFmtSaveInfo saveInfo; + saveInfo.jpegQuality = saveParamV1->jpegQuality; + saveInfo.tiffCompression = 0; + if (HGLIB_TIFFCOMPRESSION_NONE == saveParamV1->tiffCompression) + saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_NONE; + else if (HGLIB_TIFFCOMPRESSION_CCITTFAX4 == saveParamV1->tiffCompression) + saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_CCITTFAX4; + else if (HGLIB_TIFFCOMPRESSION_LZW == saveParamV1->tiffCompression) + saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_LZW; + else if (HGLIB_TIFFCOMPRESSION_JPEG == saveParamV1->tiffCompression) + saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_JPEG; + saveInfo.tiffJpegQuality = saveParamV1->tiffJpegQuality; + + return (HGBASE_ERR_OK == HGImgFmt_SaveImage((HGImage)image, fmtType, &saveInfo, Utf8ToStdString(savePath).c_str())); + } + + return HGFALSE; +} + +HGBool HGAPI HGLib_ReleaseImage(HGLibImage image) +{ + if (NULL == image) + { + return HGFALSE; + } + + HGBase_DestroyImage((HGImage)image); + return HGTRUE; +} + +HGBool HGAPI HGLib_InitDevice(HGLibDeviceHotPlugEventFunc func, HGPointer param) +{ + return HGLibDeviceImpl::Init(func, param); +} + +HGBool HGAPI HGLib_DeinitDevice() +{ + return HGLibDeviceImpl::Deinit(); +} + +HGChar** HGAPI HGLib_GetDeviceNameList() +{ + return HGLibDeviceImpl::GetNameList(); +} + +HGBool HGAPI HGLib_ReleaseDeviceNameList(HGChar** deviceName) +{ + return HGLibDeviceImpl::ReleaseNameList(deviceName); +} + +HGLibDevice HGAPI HGLib_OpenDevice(const HGChar* deviceName) +{ + return NULL; +} + +HGBool HGAPI HGLib_CloseDevice(HGLibDevice device) +{ + return HGFALSE; +} + +HGBool HGAPI HGLib_SetDeviceParam(HGLibDevice device, const HGLibDeviceSetParam* param, HGUInt count) +{ + return HGFALSE; +} + +HGLibDeviceGetParamGroup* HGAPI HGLib_GetDeviceParamGroupList(HGLibDevice device, HGUInt* count) +{ + return NULL; +} + +HGBool HGAPI HGLib_ReleaseDeviceParamGroupList(HGLibDeviceGetParamGroup* paramGroup, HGUInt count) +{ + return HGFALSE; +} + +HGBool HGAPI HGLib_ResetDeviceParam(HGLibDevice device) +{ + return HGFALSE; +} + +HGBool HGAPI HGLib_StartDeviceScan(HGLibDevice device, HGLibDeviceScanEventFunc eventFunc, HGPointer eventParam, + HGLibDeviceScanImageFunc imageFunc, HGPointer imageParam) +{ + return HGFALSE; +} + +HGBool HGAPI HGLib_StopDeviceScan(HGLibDevice device) +{ + return HGFALSE; +} \ No newline at end of file diff --git a/sdk/scannerlib/HGScannerLib.h b/sdk/scannerlib/HGScannerLib.h new file mode 100644 index 00000000..94b61e17 --- /dev/null +++ b/sdk/scannerlib/HGScannerLib.h @@ -0,0 +1,179 @@ +#ifndef __HGSCANNERLIB_H__ +#define __HGSCANNERLIB_H__ + +#include "HGDef.h" + +HG_DECLARE_HANDLE(HGLibImage); +HG_DECLARE_HANDLE(HGLibDevice); + +/* TIFF压缩方式 */ +#define HGLIB_TIFFCOMPRESSION_NONE 1L +#define HGLIB_TIFFCOMPRESSION_CCITTFAX4 2L +#define HGLIB_TIFFCOMPRESSION_LZW 3L +#define HGLIB_TIFFCOMPRESSION_JPEG 4L + +/* 设备热拔插事件 */ +#define HGLIB_DEVHOTPLUG_EVENT_ARRIVE 1L +#define HGLIB_DEVHOTPLUG_EVENT_REMOVE 2L + +/* 设备扫描事件 */ +#define HGLIB_DEVSCAN_EVENT_BEGIN 1L +#define HGLIB_DEVSCAN_EVENT_END 2L +#define HGLIB_DEVSCAN_EVENT_INFO 3L + +/* 设备参数类型 */ +#define HGLIB_DEVPARAM_TYPE_INT 1L +#define HGLIB_DEVPARAM_TYPE_STRING 2L +#define HGLIB_DEVPARAM_TYPE_DOUBLE 3L +#define HGLIB_DEVPARAM_TYPE_BOOL 4L + +/* 设备参数取值范围类型 */ +#define HGLIB_DEVPARAM_RANDETYPE_INTLIST 1L +#define HGLIB_DEVPARAM_RANDETYPE_STRINGLIST 2L +#define HGLIB_DEVPARAM_RANDETYPE_DOUBLELIST 3L +#define HGLIB_DEVPARAM_RANDETYPE_INTRANGE 4L +#define HGLIB_DEVPARAM_RANDETYPE_DOUBLERANGE 5L + +typedef struct +{ + HGUInt size; /* 结构体大小,必须初始化为sizeof(HGLibSaveImageParam) */ + HGUInt jpegQuality; /* jpeg下有效, 0-100 */ + HGUInt tiffCompression; /* tiff下有效, HGLIB_TIFFCOMPRESSION_* */ + HGUInt tiffJpegQuality; /* tiff且HGLIB_TIFFCOMPRESSION_JPEG下有效, 0-100 */ + HGBool ocr; /* 是否OCR,pdf和ofd格式有效 */ +}HGLibSaveImageParam; + +typedef struct +{ + HGChar *title; /* 参数名, UTF8 */ + HGUInt type; /* 参数类型, 参见HGLIB_DEVPARAM_TYPE_* */ + union + { + HGInt intValue; + HGChar *stringValue; + HGDouble doubleValue; + HGBool boolValue; + }; +}HGLibDeviceSetParam; + +typedef struct +{ + HGInt* value; + HGUInt count; +}HGLibDeviceIntValueList; + +typedef struct +{ + HGChar** value; + HGUInt count; +}HGLibDeviceStringValueList; + +typedef struct +{ + HGDouble* value; + HGUInt count; +}HGLibDeviceDoubleValueList; + +typedef struct +{ + HGInt minValue; + HGInt maxValue; +}HGLibDeviceIntValueRange; + +typedef struct +{ + HGDouble minValue; + HGDouble maxValue; +}HGLibDeviceDoubleValueRange; + +typedef struct +{ + HGLibDeviceSetParam param; + HGUInt rangeType; /* 取值类型, 参见HGLIB_DEVPARAM_RANGETYPE_* */ + union + { + HGLibDeviceIntValueList intValueList; + HGLibDeviceStringValueList stringValueList; + HGLibDeviceDoubleValueList doubleValueList; + HGLibDeviceIntValueRange intValueRange; + HGLibDeviceDoubleValueRange doubleValueRange; + }; +}HGLibDeviceGetParam; + +typedef struct +{ + HGChar* groupName; + HGLibDeviceGetParam* param; + HGUInt paramCount; +}HGLibDeviceGetParamGroup; + +/* 设备热拔插回调 +* event: HGLIB_DEVHOTPLUG_EVENT_* +* deviceName: 设备名 +* param: 回调参数 +*/ +typedef void (*HGLibDeviceHotPlugEventFunc)(HGUInt event, const HGChar *deviceName, HGPointer param); + +/* 设备扫描事件回调 +* device: 设备句柄 +* event: HGLIB_DEVSCAN_EVENT_* +* err: 是否是错误信息, HGLIB_DEVSCAN_EVENT_INFO下有效 +* info: 扫描信息, HGLIB_DEVSCAN_EVENT_INFO下有效 +* param: 回调参数 +*/ +typedef void (*HGLibDeviceScanEventFunc)(HGLibDevice device, HGUInt event, HGBool err, const HGChar *info, HGPointer param); + +/* 设备扫描图像回调 +* device: 设备句柄 +* image: 图像句柄, 不要调用HGLib_ReleaseImage释放, 回调执行后会自动释放 +* param: 回调参数 +*/ +typedef void (*HGLibDeviceScanImageFunc)(HGLibDevice device, HGLibImage image, HGPointer param); + +/* 加载图像 */ +HGEXPORT HGLibImage HGAPI HGLib_LoadImage(const HGChar *filePath); + +/* 保存图像 */ +HGEXPORT HGBool HGAPI HGLib_SaveImage(HGLibImage image, const HGChar* savePath, const HGLibSaveImageParam* saveParam); + +/* 释放图像 */ +HGEXPORT HGBool HGAPI HGLib_ReleaseImage(HGLibImage image); + +/* 初始化扫描仪 */ +HGEXPORT HGBool HGAPI HGLib_InitDevice(HGLibDeviceHotPlugEventFunc func, HGPointer param); + +/* 反初始化扫描仪 */ +HGEXPORT HGBool HGAPI HGLib_DeinitDevice(); + +/* 获取扫描仪名称列表 */ +HGEXPORT HGChar** HGAPI HGLib_GetDeviceNameList(HGUInt *count); + +/* 销毁扫描仪名称列表 */ +HGEXPORT HGBool HGAPI HGLib_ReleaseDeviceNameList(HGChar** deviceName); + +/* 打开设备 */ +HGEXPORT HGLibDevice HGAPI HGLib_OpenDevice(const HGChar *deviceName); + +/* 关闭设备 */ +HGEXPORT HGBool HGAPI HGLib_CloseDevice(HGLibDevice device); + +/* 设置设备参数 */ +HGEXPORT HGBool HGAPI HGLib_SetDeviceParam(HGLibDevice device, const HGLibDeviceSetParam *param, HGUInt count); + +/* 获取设备参数 */ +HGEXPORT HGLibDeviceGetParamGroup* HGAPI HGLib_GetDeviceParamGroupList(HGLibDevice device, HGUInt *count); + +/* 销毁设备参数 */ +HGEXPORT HGBool HGAPI HGLib_ReleaseDeviceParamGroupList(HGLibDeviceGetParamGroup* paramGroup, HGUInt count); + +/* 重置设备参数 */ +HGEXPORT HGBool HGAPI HGLib_ResetDeviceParam(HGLibDevice device); + +/* 开始扫描 */ +HGEXPORT HGBool HGAPI HGLib_StartDeviceScan(HGLibDevice device, HGLibDeviceScanEventFunc eventFunc, HGPointer eventParam, + HGLibDeviceScanImageFunc imageFunc, HGPointer imageParam); + +/* 停止扫描 */ +HGEXPORT HGBool HGAPI HGLib_StopDeviceScan(HGLibDevice device); + +#endif /* __HGSCANNERLIB_H__ */ \ No newline at end of file From 42b22b84098fc215beb207c7f1e4ef3b4a022995 Mon Sep 17 00:00:00 2001 From: luoliangyi <87842688@qq.com> Date: Tue, 19 Jul 2022 17:09:52 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=AE=8C=E5=96=84HGScannerLib=E7=9A=84?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../windows/HGScannerLib/HGScannerLib.vcxproj | 8 + build/windows/HGSolution.sln | 1 + build/windows/HGTest/HGTest.vcxproj | 8 +- build/windows/HGTest/pch.cpp | 4 + build/windows/HGTest/pch.h | 1 + sdk/scannerlib/HGLibDeviceImpl.cpp | 236 +++++++++++++++++- sdk/scannerlib/HGLibDeviceImpl.hpp | 15 +- sdk/scannerlib/HGScannerLib.cpp | 52 +++- sdk/scannerlib/HGScannerLib.h | 2 +- sdk/webservice/ManagerV2.cpp | 4 +- 10 files changed, 307 insertions(+), 24 deletions(-) diff --git a/build/windows/HGScannerLib/HGScannerLib.vcxproj b/build/windows/HGScannerLib/HGScannerLib.vcxproj index 395b1c10..4210d846 100644 --- a/build/windows/HGScannerLib/HGScannerLib.vcxproj +++ b/build/windows/HGScannerLib/HGScannerLib.vcxproj @@ -125,6 +125,7 @@ NotUsing pch.h MultiThreaded + ../../../modules/base/;../../../modules/;../../../utility/;../../../../sdk/include/;%(AdditionalIncludeDirectories) Windows @@ -133,6 +134,8 @@ true false HGScannerLib.def + ../Release/HGBase.lib;../Release/HGImgFmt.lib;../Release/HGImgProc.lib;../../../../sdk/lib/win/x86/Release/sane.lib;%(AdditionalDependencies) + /LTCG %(AdditionalOptions) @@ -144,12 +147,14 @@ NotUsing pch.h MultiThreadedDebug + ../../../modules/base/;../../../modules/;../../../utility/;../../../../sdk/include/;%(AdditionalIncludeDirectories) Windows true false HGScannerLib.def + ../x64/Debug/HGBase.lib;../x64/Debug/HGImgFmt.lib;../x64/Debug/HGImgProc.lib;../../../../sdk/lib/win/x64/Release/sane.lib;%(AdditionalDependencies) @@ -163,6 +168,7 @@ NotUsing pch.h MultiThreaded + ../../../modules/base/;../../../modules/;../../../utility/;../../../../sdk/include/;%(AdditionalIncludeDirectories) Windows @@ -171,6 +177,8 @@ true false HGScannerLib.def + ../x64/Release/HGBase.lib;../x64/Release/HGImgFmt.lib;../x64/Release/HGImgProc.lib;../../../../sdk/lib/win/x64/Release/sane.lib;%(AdditionalDependencies) + /LTCG %(AdditionalOptions) diff --git a/build/windows/HGSolution.sln b/build/windows/HGSolution.sln index dd480ddb..73bae0bb 100644 --- a/build/windows/HGSolution.sln +++ b/build/windows/HGSolution.sln @@ -12,6 +12,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HGTest", "HGTest\HGTest.vcx {EFAE5F69-A4C2-4A07-8BE6-68714D86BCE2} = {EFAE5F69-A4C2-4A07-8BE6-68714D86BCE2} {4954F36B-A0A3-4550-9C4E-3B3D210F5CE4} = {4954F36B-A0A3-4550-9C4E-3B3D210F5CE4} {5D85F2AC-FACD-436C-A67B-E13056DD0C03} = {5D85F2AC-FACD-436C-A67B-E13056DD0C03} + {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02} = {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02} {4909ACEA-80FF-482E-9FA2-5E8534789A82} = {4909ACEA-80FF-482E-9FA2-5E8534789A82} EndProjectSection EndProject diff --git a/build/windows/HGTest/HGTest.vcxproj b/build/windows/HGTest/HGTest.vcxproj index 4de9d506..e2e500a7 100644 --- a/build/windows/HGTest/HGTest.vcxproj +++ b/build/windows/HGTest/HGTest.vcxproj @@ -93,7 +93,7 @@ true WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) pch.h - ../../../modules;%(AdditionalIncludeDirectories) + ../../../modules/base/;../../../modules;../../../sdk;%(AdditionalIncludeDirectories) Windows @@ -116,7 +116,7 @@ true _WINDOWS;_DEBUG;%(PreprocessorDefinitions) pch.h - ../../../modules;%(AdditionalIncludeDirectories) + ../../../modules/base/;../../../modules;../../../sdk;%(AdditionalIncludeDirectories) Windows @@ -141,7 +141,7 @@ true WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) pch.h - ../../../modules;%(AdditionalIncludeDirectories) + ../../../modules/base/;../../../modules;../../../sdk;%(AdditionalIncludeDirectories) Windows @@ -169,7 +169,7 @@ true _WINDOWS;NDEBUG;%(PreprocessorDefinitions) pch.h - ../../../modules;%(AdditionalIncludeDirectories) + ../../../modules/base/;../../../modules;../../../sdk;%(AdditionalIncludeDirectories) Windows diff --git a/build/windows/HGTest/pch.cpp b/build/windows/HGTest/pch.cpp index 06dc7ba6..70b6a20e 100644 --- a/build/windows/HGTest/pch.cpp +++ b/build/windows/HGTest/pch.cpp @@ -12,6 +12,7 @@ #pragma comment(lib, "../x64/Debug/HGTwainUser.lib") #pragma comment(lib, "../x64/Debug/HGSaneUser.lib") #pragma comment(lib, "../x64/Debug/HGVersion.lib") +#pragma comment(lib, "../x64/Debug/HGScannerLib.lib") #else #pragma comment(lib, "../x64/Release/HGBase.lib") #pragma comment(lib, "../x64/Release/HGImgFmt.lib") @@ -19,6 +20,7 @@ #pragma comment(lib, "../x64/Release/HGTwainUser.lib") #pragma comment(lib, "../x64/Release/HGSaneUser.lib") #pragma comment(lib, "../x64/Release/HGVersion.lib") +#pragma comment(lib, "../x64/Release/HGScannerLib.lib") #endif #else #ifdef _DEBUG @@ -28,6 +30,7 @@ #pragma comment(lib, "../Debug/HGTwainUser.lib") #pragma comment(lib, "../Debug/HGSaneUser.lib") #pragma comment(lib, "../Debug/HGVersion.lib") +#pragma comment(lib, "../Debug/HGScannerLib.lib") #else #pragma comment(lib, "../Release/HGBase.lib") #pragma comment(lib, "../Release/HGImgFmt.lib") @@ -35,5 +38,6 @@ #pragma comment(lib, "../Release/HGTwainUser.lib") #pragma comment(lib, "../Release/HGSaneUser.lib") #pragma comment(lib, "../Release/HGVersion.lib") +#pragma comment(lib, "../Release/HGScannerLib.lib") #endif #endif diff --git a/build/windows/HGTest/pch.h b/build/windows/HGTest/pch.h index 346e3393..c9162a8e 100644 --- a/build/windows/HGTest/pch.h +++ b/build/windows/HGTest/pch.h @@ -24,5 +24,6 @@ #include "twain_user/HGTwain.h" #include "sane_user/HGSane.h" #include "version/HGVersion.h" +#include "scannerlib/HGScannerLib.h" #endif //PCH_H diff --git a/sdk/scannerlib/HGLibDeviceImpl.cpp b/sdk/scannerlib/HGLibDeviceImpl.cpp index b1748fa5..e8885e87 100644 --- a/sdk/scannerlib/HGLibDeviceImpl.cpp +++ b/sdk/scannerlib/HGLibDeviceImpl.cpp @@ -1,6 +1,7 @@ #include "HGLibDeviceImpl.hpp" #include "base/HGInc.h" #include "base/HGInfo.h" +#include "base/HGImage.h" #include "HGString.h" HGLock HGLibDeviceImpl::m_lock = NULL; @@ -8,10 +9,18 @@ HGLibDeviceHotPlugEventFunc HGLibDeviceImpl::m_hotPlugEventFunc = NULL; HGPointer HGLibDeviceImpl::m_hotPlugEventParam = NULL; HGBool HGLibDeviceImpl::m_init = HGFALSE; std::vector HGLibDeviceImpl::m_devNameList; +std::map HGLibDeviceImpl::m_deviceList; HGLibDeviceImpl::HGLibDeviceImpl() { - + m_devHandle = NULL; + m_devName.clear(); + m_scanning = HGFALSE; + m_scanEvent = NULL; + m_eventFunc = NULL; + m_eventParam = NULL; + m_imageFunc = NULL; + m_imageParam = NULL; } HGLibDeviceImpl::~HGLibDeviceImpl() @@ -53,7 +62,13 @@ HGBool HGLibDeviceImpl::Deinit() return HGFALSE; } + if (!m_deviceList.empty()) + { + return HGFALSE; + } + sane_exit(); + m_devNameList.clear(); m_hotPlugEventFunc = NULL; m_hotPlugEventParam = NULL; HGBase_DestroyLock(m_lock); @@ -64,7 +79,23 @@ HGBool HGLibDeviceImpl::Deinit() HGChar** HGLibDeviceImpl::GetNameList() { - return NULL; + HGChar** nameList = NULL; + + HGBase_EnterLock(m_lock); + nameList = (HGChar **)malloc((m_devNameList.size() + 1) * sizeof(HGChar *)); + if (NULL != nameList) + { + nameList[m_devNameList.size()] = NULL; + for (int i = 0; i < (int)m_devNameList.size(); ++i) + { + nameList[i] = (HGChar *)malloc(m_devNameList[i].size() + 1); + if (NULL != nameList[i]) + strcpy(nameList[i], m_devNameList[i].c_str()); + } + } + HGBase_LeaveLock(m_lock); + + return nameList; } HGBool HGLibDeviceImpl::ReleaseNameList(HGChar** deviceName) @@ -74,16 +105,131 @@ HGBool HGLibDeviceImpl::ReleaseNameList(HGChar** deviceName) return HGFALSE; } - while (0 != *deviceName) + HGChar** p = deviceName; + while (0 != *p) { - free(*deviceName); - ++deviceName; + free(*p); + ++p; } free(deviceName); return HGTRUE; } +HGLibDeviceImpl* HGLibDeviceImpl::Open(const HGChar* deviceName) +{ + SANE_Handle devHandle = NULL; + sane_open(deviceName, &devHandle); + if (NULL == devHandle) + { + return NULL; + } + + HGLibDeviceImpl* deviceImpl = new HGLibDeviceImpl; + deviceImpl->m_devHandle = devHandle; + deviceImpl->m_devName = deviceName; + m_deviceList[devHandle] = deviceImpl; + return deviceImpl; +} + +HGBool HGLibDeviceImpl::Close() +{ + assert(NULL != m_devHandle); + assert(!m_devName.empty()); + + StopScan(); + sane_close(m_devHandle); + m_devHandle = NULL; + m_devName.clear(); + + std::map::iterator iter; + for (iter = m_deviceList.begin(); iter != m_deviceList.end(); ++iter) + { + if (iter->second == this) + { + m_deviceList.erase(iter); + break; + } + } + + delete this; + return HGTRUE; +} + +HGBool HGLibDeviceImpl::SetParam(const HGLibDeviceSetParam* param, HGUInt count) +{ + return HGFALSE; +} + +HGLibDeviceGetParamGroup* HGLibDeviceImpl::GetParamGroupList(HGUInt* count) +{ + return NULL; +} + +HGBool HGLibDeviceImpl::ReleaseParamGroupList(HGLibDeviceGetParamGroup* paramGroup, HGUInt count) +{ + return HGFALSE; +} + +HGBool HGLibDeviceImpl::ResetParam() +{ + return HGFALSE; +} + +HGBool HGLibDeviceImpl::StartScan(HGLibDeviceScanEventFunc eventFunc, HGPointer eventParam, + HGLibDeviceScanImageFunc imageFunc, HGPointer imageParam) +{ + if (m_scanning) + { + return HGFALSE; + } + + HGBase_CreateEvent(HGFALSE, HGFALSE, &m_scanEvent); + assert(NULL != m_scanEvent); + m_eventFunc = eventFunc; + m_eventParam = eventParam; + m_imageFunc = imageFunc; + m_imageParam = imageParam; + + SANE_Status status = sane_start(m_devHandle); + if (SANE_STATUS_GOOD != status) + { + m_eventFunc = NULL; + m_eventParam = NULL; + m_imageFunc = NULL; + m_imageParam = NULL; + HGBase_DestroyEvent(m_scanEvent); + m_scanEvent = NULL; + return HGFALSE; + } + + m_scanning = HGTRUE; + return HGTRUE; +} + +HGBool HGLibDeviceImpl::StopScan() +{ + if (!m_scanning) + { + return HGFALSE; + } + + sane_cancel(m_devHandle); + + assert(NULL != m_scanEvent); + HGBase_WaitEvent(m_scanEvent); + HGBase_DestroyEvent(m_scanEvent); + m_scanEvent = NULL; + + m_eventFunc = NULL; + m_eventParam = NULL; + m_imageFunc = NULL; + m_imageParam = NULL; + + m_scanning = HGFALSE; + return HGTRUE; +} + int HGLibDeviceImpl::sane_ex_callback(SANE_Handle hdev, int code, void* data, unsigned int* len, void* param) { switch (code) @@ -106,9 +252,6 @@ int HGLibDeviceImpl::sane_ex_callback(SANE_Handle hdev, int code, void* data, un SANE_Device* sane_dev = (SANE_Device*)data; HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_DEVICE_LEFT, name=%s", Utf8ToStdString(sane_dev->name).c_str()); - if (NULL != m_hotPlugEventFunc) - m_hotPlugEventFunc(HGLIB_DEVHOTPLUG_EVENT_REMOVE, sane_dev->name, m_hotPlugEventParam); - HGBase_EnterLock(m_lock); for (int i = 0; i < (int)m_devNameList.size(); ++i) { @@ -119,6 +262,83 @@ int HGLibDeviceImpl::sane_ex_callback(SANE_Handle hdev, int code, void* data, un } } HGBase_LeaveLock(m_lock); + + if (NULL != m_hotPlugEventFunc) + m_hotPlugEventFunc(HGLIB_DEVHOTPLUG_EVENT_REMOVE, sane_dev->name, m_hotPlugEventParam); + } + break; + case SANE_EVENT_WORKING: + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_WORKING, msg=%s", Utf8ToStdString((char*)data).c_str()); + + HGLibDeviceImpl* deviceImpl = m_deviceList[hdev]; + if (NULL != deviceImpl->m_eventFunc) + { + deviceImpl->m_eventFunc((HGLibDevice)deviceImpl, HGLIB_DEVSCAN_EVENT_BEGIN, + HGFALSE, NULL, deviceImpl->m_eventParam); + deviceImpl->m_eventFunc((HGLibDevice)deviceImpl, HGLIB_DEVSCAN_EVENT_INFO, + HGFALSE, (const char*)data, deviceImpl->m_eventParam); + } + } + break; + case SANE_EVENT_SCAN_FINISHED: + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_SCAN_FINISHED, msg=%s", Utf8ToStdString((char*)data).c_str()); + + HGLibDeviceImpl* deviceImpl = m_deviceList[hdev]; + if (NULL != deviceImpl->m_eventFunc) + { + deviceImpl->m_eventFunc((HGLibDevice)deviceImpl, HGLIB_DEVSCAN_EVENT_INFO, + (0 != *len), (const char*)data, deviceImpl->m_eventParam); + deviceImpl->m_eventFunc((HGLibDevice)deviceImpl, HGLIB_DEVSCAN_EVENT_END, + HGFALSE, NULL, deviceImpl->m_eventParam); + } + + HGBase_SetEvent(deviceImpl->m_scanEvent); + } + break; + case SANE_EVENT_STATUS: + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_STATUS, msg=%s", Utf8ToStdString((char*)data).c_str()); + } + break; + case SANE_EVENT_ERROR: + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_ERROR, msg=%s", Utf8ToStdString((char*)data).c_str()); + } + break; + case SANE_EVENT_IMAGE_OK: + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_IMAGE_OK"); + + SANE_Image* sane_img = (SANE_Image*)data; + + HGLibDeviceImpl* deviceImpl = m_deviceList[hdev]; + if (NULL != deviceImpl->m_imageFunc) + { + HGUInt imgType = 0; + if (sane_img->header.format == SANE_FRAME_GRAY) + { + if (1 == sane_img->header.depth) + imgType = HGBASE_IMGTYPE_BINARY; + else if (8 == sane_img->header.depth) + imgType = HGBASE_IMGTYPE_GRAY; + } + else if (sane_img->header.format == SANE_FRAME_RGB) + imgType = HGBASE_IMGTYPE_RGB; + + HGByte* data = sane_img->data; + HGImageInfo imgInfo = { (HGUInt)sane_img->header.pixels_per_line, (HGUInt)sane_img->header.lines, + imgType, (HGUInt)sane_img->header.bytes_per_line, HGBASE_IMGORIGIN_TOP }; + + HGImage img = NULL; + HGBase_CreateImageFromData(data, &imgInfo, NULL, 0, HGBASE_IMGORIGIN_TOP, &img); + if (NULL != img) + { + deviceImpl->m_imageFunc((HGLibDevice)deviceImpl, (HGLibImage)img, deviceImpl->m_imageParam); + HGBase_DestroyImage(img); + } + } } break; } diff --git a/sdk/scannerlib/HGLibDeviceImpl.hpp b/sdk/scannerlib/HGLibDeviceImpl.hpp index 7c938754..8cb0d6ff 100644 --- a/sdk/scannerlib/HGLibDeviceImpl.hpp +++ b/sdk/scannerlib/HGLibDeviceImpl.hpp @@ -3,9 +3,11 @@ #include "HGScannerLib.h" #include "base/HGLock.h" +#include "base/HGEvent.h" #include "sane/sane_ex.h" #include "sane/sane_option_definitions.h" #include +#include #include class HGLibDeviceImpl @@ -19,7 +21,7 @@ public: static HGChar** GetNameList(); static HGBool ReleaseNameList(HGChar** deviceName); - HGBool Open(const HGChar* deviceName); + static HGLibDeviceImpl* Open(const HGChar* deviceName); HGBool Close(); HGBool SetParam(const HGLibDeviceSetParam* param, HGUInt count); HGLibDeviceGetParamGroup* GetParamGroupList(HGUInt* count); @@ -38,6 +40,17 @@ private: static HGPointer m_hotPlugEventParam; static HGBool m_init; static std::vector m_devNameList; + static std::map m_deviceList; + + + SANE_Handle m_devHandle; + std::string m_devName; + HGBool m_scanning; + HGEvent m_scanEvent; + HGLibDeviceScanEventFunc m_eventFunc; + HGPointer m_eventParam; + HGLibDeviceScanImageFunc m_imageFunc; + HGPointer m_imageParam; }; #endif /* __HGLIBDEVICEIMPL_HPP__ */ \ No newline at end of file diff --git a/sdk/scannerlib/HGScannerLib.cpp b/sdk/scannerlib/HGScannerLib.cpp index 17e08b20..9dade41e 100644 --- a/sdk/scannerlib/HGScannerLib.cpp +++ b/sdk/scannerlib/HGScannerLib.cpp @@ -115,41 +115,77 @@ HGBool HGAPI HGLib_ReleaseDeviceNameList(HGChar** deviceName) HGLibDevice HGAPI HGLib_OpenDevice(const HGChar* deviceName) { - return NULL; + return (HGLibDevice)HGLibDeviceImpl::Open(deviceName); } HGBool HGAPI HGLib_CloseDevice(HGLibDevice device) { - return HGFALSE; + if (NULL == device) + { + return HGFALSE; + } + + HGLibDeviceImpl* deviceImpl = (HGLibDeviceImpl*)device; + return deviceImpl->Close(); } HGBool HGAPI HGLib_SetDeviceParam(HGLibDevice device, const HGLibDeviceSetParam* param, HGUInt count) { - return HGFALSE; + if (NULL == device) + { + return HGFALSE; + } + + HGLibDeviceImpl* deviceImpl = (HGLibDeviceImpl*)device; + return deviceImpl->SetParam(param, count); } HGLibDeviceGetParamGroup* HGAPI HGLib_GetDeviceParamGroupList(HGLibDevice device, HGUInt* count) { - return NULL; + if (NULL == device) + { + return NULL; + } + + HGLibDeviceImpl* deviceImpl = (HGLibDeviceImpl*)device; + return deviceImpl->GetParamGroupList(count); } HGBool HGAPI HGLib_ReleaseDeviceParamGroupList(HGLibDeviceGetParamGroup* paramGroup, HGUInt count) { - return HGFALSE; + return HGLibDeviceImpl::ReleaseParamGroupList(paramGroup, count); } HGBool HGAPI HGLib_ResetDeviceParam(HGLibDevice device) { - return HGFALSE; + if (NULL == device) + { + return HGFALSE; + } + + HGLibDeviceImpl* deviceImpl = (HGLibDeviceImpl*)device; + return deviceImpl->ResetParam(); } HGBool HGAPI HGLib_StartDeviceScan(HGLibDevice device, HGLibDeviceScanEventFunc eventFunc, HGPointer eventParam, HGLibDeviceScanImageFunc imageFunc, HGPointer imageParam) { - return HGFALSE; + if (NULL == device) + { + return HGFALSE; + } + + HGLibDeviceImpl* deviceImpl = (HGLibDeviceImpl*)device; + return deviceImpl->StartScan(eventFunc, eventParam, imageFunc, imageParam); } HGBool HGAPI HGLib_StopDeviceScan(HGLibDevice device) { - return HGFALSE; + if (NULL == device) + { + return HGFALSE; + } + + HGLibDeviceImpl* deviceImpl = (HGLibDeviceImpl*)device; + return deviceImpl->StopScan(); } \ No newline at end of file diff --git a/sdk/scannerlib/HGScannerLib.h b/sdk/scannerlib/HGScannerLib.h index 94b61e17..7d04e2f2 100644 --- a/sdk/scannerlib/HGScannerLib.h +++ b/sdk/scannerlib/HGScannerLib.h @@ -146,7 +146,7 @@ HGEXPORT HGBool HGAPI HGLib_InitDevice(HGLibDeviceHotPlugEventFunc func, HGPoint HGEXPORT HGBool HGAPI HGLib_DeinitDevice(); /* 获取扫描仪名称列表 */ -HGEXPORT HGChar** HGAPI HGLib_GetDeviceNameList(HGUInt *count); +HGEXPORT HGChar** HGAPI HGLib_GetDeviceNameList(); /* 销毁扫描仪名称列表 */ HGEXPORT HGBool HGAPI HGLib_ReleaseDeviceNameList(HGChar** deviceName); diff --git a/sdk/webservice/ManagerV2.cpp b/sdk/webservice/ManagerV2.cpp index 120300b5..ae95beb1 100644 --- a/sdk/webservice/ManagerV2.cpp +++ b/sdk/webservice/ManagerV2.cpp @@ -4033,8 +4033,6 @@ namespace ver_2 } HGBase_EnterLock(p->m_lock); - if (NULL != p->m_saneEvent) - p->m_saneEvent(SANEEVENT_REMOVE, sane_dev->name, false, p->m_saneParam); for (int i = 0; i < (int)p->m_devNameList.size(); ++i) { if (0 == strcmp(sane_dev->name, p->m_devNameList[i].c_str())) @@ -4043,6 +4041,8 @@ namespace ver_2 break; } } + if (NULL != p->m_saneEvent) + p->m_saneEvent(SANEEVENT_REMOVE, sane_dev->name, false, p->m_saneParam); HGBase_LeaveLock(p->m_lock); } break; From 451cf97416ec06950dbc08d805167240081d309d Mon Sep 17 00:00:00 2001 From: luoliangyi <87842688@qq.com> Date: Tue, 19 Jul 2022 17:12:20 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0HGScannerLib=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/scannerlib/鏂扮増dll鎺ュ彛璇存槑.doc | Bin 0 -> 72704 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/scannerlib/鏂扮増dll鎺ュ彛璇存槑.doc diff --git a/doc/scannerlib/鏂扮増dll鎺ュ彛璇存槑.doc b/doc/scannerlib/鏂扮増dll鎺ュ彛璇存槑.doc new file mode 100644 index 0000000000000000000000000000000000000000..13d5cd168811c67f7087dc3ecc7a1f649e5a5d44 GIT binary patch literal 72704 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

!9`Y|2)yIk?rLgHZEc3{UfL0N_Y0T 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 literal 0 HcmV?d00001