#include "HGSaneImpl.hpp" #include "../base/HGInc.h" HGSaneManagerImpl::HGSaneManagerImpl() { } HGSaneManagerImpl::~HGSaneManagerImpl() { } HGResult HGSaneManagerImpl::Create() { return HGBASE_ERR_OK; } HGResult HGSaneManagerImpl::Destroy() { if (!m_listSourceImpl.empty()) { return HGBASE_ERR_FAIL; } return HGBASE_ERR_OK; } HGResult HGSaneManagerImpl::GetSourceCount(HGUInt *count) { if (NULL == count) { return HGBASE_ERR_INVALIDARG; } *count = (HGUInt)m_vSource.size(); return HGBASE_ERR_OK; } HGResult HGSaneManagerImpl::GetSourceName(HGUInt index, HGChar* name, HGUInt maxLen) { if (index >= (HGUInt)m_vSource.size() || NULL == name || 0 == maxLen) { return HGBASE_ERR_INVALIDARG; } if (maxLen < m_vSource[index].first.size() + 1) return HGBASE_ERR_FAIL; strcpy(name, m_vSource[index].first.c_str()); return HGBASE_ERR_OK; } HGResult HGSaneManagerImpl::OpenSource(HGUInt index, class HGSaneSourceImpl **sourceImpl) { if (index >= (HGUInt)m_vSource.size() || NULL == sourceImpl) { return HGBASE_ERR_INVALIDARG; } HGSaneSourceImpl *newSourceImpl = new HGSaneSourceImpl(this); HGResult ret = newSourceImpl->Open(m_vSource[index].first.c_str(), m_vSource[index].second.c_str()); if (HGBASE_ERR_OK != ret) { delete newSourceImpl; return ret; } m_listSourceImpl.push_back(newSourceImpl); *sourceImpl = newSourceImpl; return HGBASE_ERR_OK; } HGResult HGSaneManagerImpl::OpenSelectedSource(HGWindow parent, class HGSaneSourceImpl **sourceImpl) { if (NULL == sourceImpl) { return HGBASE_ERR_INVALIDARG; } HGDll dll = NULL; f_sane_init fInit = NULL; f_sane_exit fExit = NULL; SANEAPI saneAPI; char manuName[256]; if (-2 == show_srclist_ui(parent, &dll, &fInit, &fExit, &saneAPI, manuName, 256)) { return HGBASE_ERR_NOTSUPPORT; } if (NULL == dll) { return HGSANE_ERR_FAIL; } HGSaneSourceImpl* newSourceImpl = new HGSaneSourceImpl(this); HGResult ret = newSourceImpl->Init(manuName, dll, fInit, fExit, &saneAPI); if (HGBASE_ERR_OK != ret) { delete newSourceImpl; HGBase_DestroyDll(dll); return ret; } m_listSourceImpl.push_back(newSourceImpl); *sourceImpl = newSourceImpl; return HGBASE_ERR_OK; } void HGSaneManagerImpl::RemoveSource(class HGSaneSourceImpl* sourceImpl) { std::list::iterator iter; for (iter = m_listSourceImpl.begin(); iter != m_listSourceImpl.end(); ++iter) { if (*iter == sourceImpl) { m_listSourceImpl.erase(iter); delete sourceImpl; break; } } } HGSaneSourceImpl::HGSaneSourceImpl(HGSaneManagerImpl *managerImpl) { m_managerImpl = managerImpl; m_manuName.clear(); m_dll = NULL; m_f_sane_init = NULL; m_f_sane_exit = NULL; memset(&m_saneApi, 0, sizeof(SANEAPI)); } HGSaneSourceImpl::~HGSaneSourceImpl() { } HGResult HGSaneSourceImpl::Init(const HGChar* saneManu, HGDll dll, f_sane_init fInit, f_sane_exit fExit, const SANEAPI *saneAPI) { assert(NULL == m_dll); if (NULL == dll || NULL == fInit || NULL == fExit || NULL == saneAPI) { return HGBASE_ERR_INVALIDARG; } if (NULL == saneAPI->sane_open_api || NULL == saneAPI->sane_close_api || NULL == saneAPI->sane_start_api || NULL == saneAPI->sane_read_api || NULL == saneAPI->sane_cancel_api || NULL == saneAPI->sane_get_devices_api || NULL == saneAPI->sane_get_option_descriptor_api || NULL == saneAPI->sane_control_option_api || NULL == saneAPI->sane_get_parameters_api || saneAPI->sane_set_io_mode_api || NULL == saneAPI->sane_strstatus_api || NULL == saneAPI->sane_io_control_api) { return HGBASE_ERR_INVALIDARG; } if (SANE_STATUS_GOOD != fInit(NULL, NULL)) { return HGSANE_ERR_FAIL; } m_manuName = saneManu; m_dll = dll; m_f_sane_init = fInit; m_f_sane_exit = fExit; memcpy(&m_saneApi, saneAPI, sizeof(SANEAPI)); return HGBASE_ERR_OK; } HGResult HGSaneSourceImpl::Open(const HGChar* saneManu, const HGChar* sanePath) { assert(NULL == m_dll); if (NULL == saneManu || 0 == *saneManu || NULL == sanePath || 0 == *sanePath) { return HGBASE_ERR_INVALIDARG; } HGResult ret = HGBase_CreateDll(sanePath, &m_dll); if (HGBASE_ERR_OK != ret) { return ret; } ret = FindFunctions(saneManu); if (HGBASE_ERR_OK != ret) { HGBase_DestroyDll(m_dll); m_dll = NULL; return ret; } if (SANE_STATUS_GOOD != m_f_sane_init(NULL, NULL)) { HGBase_DestroyDll(m_dll); m_dll = NULL; return HGSANE_ERR_FAIL; } m_manuName = saneManu; return HGBASE_ERR_OK; } HGResult HGSaneSourceImpl::Close() { assert(NULL != m_dll); if (!m_listDeviceImpl.empty()) { return HGBASE_ERR_FAIL; } m_f_sane_exit(); HGBase_DestroyDll(m_dll); m_dll = NULL; m_managerImpl->RemoveSource(this); return HGBASE_ERR_OK; } HGResult HGSaneSourceImpl::GetName(HGChar* name, HGUInt maxLen) { if (NULL == name || 0 == maxLen) { return HGBASE_ERR_INVALIDARG; } if (maxLen < m_manuName.size() + 1) return HGBASE_ERR_FAIL; strcpy(name, m_manuName.c_str()); return HGBASE_ERR_OK; } HGResult HGSaneSourceImpl::GetDeviceCount(HGUInt* count) { if (NULL == count) { return HGBASE_ERR_INVALIDARG; } const SANE_Device** device_list; if (SANE_STATUS_GOOD != m_saneApi.sane_get_devices_api(&device_list, SANE_TRUE)) { return HGSANE_ERR_FAIL; } *count = 0; const SANE_Device** p; for (p = device_list; *p != NULL; ++p) ++(*count); return HGBASE_ERR_OK; } HGResult HGSaneSourceImpl::GetDeviceName(HGUInt index, HGChar* name, HGUInt maxLen) { if (NULL == name || 0 == maxLen) { return HGBASE_ERR_INVALIDARG; } const SANE_Device** device_list; if (SANE_STATUS_GOOD != m_saneApi.sane_get_devices_api(&device_list, SANE_TRUE)) { return HGSANE_ERR_FAIL; } HGUInt count = 0; const SANE_Device** p; for (p = device_list; *p != NULL; ++p) ++count; if (index >= count) return HGBASE_ERR_INVALIDARG; if (NULL == device_list[index]->name) return HGBASE_ERR_FAIL; if (maxLen < strlen(device_list[index]->name) + 1) return HGBASE_ERR_FAIL; strcpy(name, device_list[index]->name); return HGBASE_ERR_OK; } HGResult HGSaneSourceImpl::OpenDevice(HGUInt index, HGSaneDeviceImpl** deviceImpl, HGChar* errInfo, HGUInt errInfoLen) { if (NULL == deviceImpl) { return HGBASE_ERR_INVALIDARG; } const SANE_Device** device_list; if (SANE_STATUS_GOOD != m_saneApi.sane_get_devices_api(&device_list, SANE_TRUE)) { return HGSANE_ERR_FAIL; } HGUInt count = 0; const SANE_Device** p; for (p = device_list; *p != NULL; ++p) ++count; if (index >= count) return HGBASE_ERR_INVALIDARG; HGSaneDeviceImpl* newDeviceImpl = new HGSaneDeviceImpl(this); HGResult ret = newDeviceImpl->Open(device_list[index]->name, errInfo, errInfoLen); if (HGBASE_ERR_OK != ret) { delete newDeviceImpl; return ret; } m_listDeviceImpl.push_back(newDeviceImpl); *deviceImpl = newDeviceImpl; return HGBASE_ERR_OK; } HGResult HGSaneSourceImpl::OpenSelectedDevice(HGWindow parent, class HGSaneDeviceImpl** deviceImpl) { if (NULL == deviceImpl) { return HGBASE_ERR_INVALIDARG; } SANE_Handle handle = NULL; char devName[256] = {0}; if (-2 == show_devlist_ui(&m_saneApi, parent, &handle, devName, 256)) { return HGBASE_ERR_NOTSUPPORT; } if (NULL == handle) { return HGSANE_ERR_FAIL; } HGSaneDeviceImpl* newDeviceImpl = new HGSaneDeviceImpl(this); HGResult ret = newDeviceImpl->Init(devName, handle); if (HGBASE_ERR_OK != ret) { delete newDeviceImpl; m_saneApi.sane_close_api(handle); return ret; } m_listDeviceImpl.push_back(newDeviceImpl); *deviceImpl = newDeviceImpl; return HGBASE_ERR_OK; } HGResult HGSaneSourceImpl::FindFunctions(const HGChar* saneManu) { HGResult ret = HGBASE_ERR_OK; do { HGChar funcName[256]; sprintf(funcName, "sane_%s_init", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_f_sane_init); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_exit", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_f_sane_exit); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_get_devices", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_get_devices_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_open", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_open_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_close", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_close_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_start", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_start_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_read", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_read_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_cancel", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_cancel_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_set_io_mode", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_set_io_mode_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_strstatus", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_strstatus_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_get_parameters", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_get_parameters_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_get_option_descriptor", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_get_option_descriptor_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_control_option", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_control_option_api); if (HGBASE_ERR_OK != ret) break; sprintf(funcName, "sane_%s_io_control", saneManu); ret = HGBase_GetDllProcAddress(m_dll, funcName, (HGPointer*)&m_saneApi.sane_io_control_api); if (HGBASE_ERR_OK != ret) break; } while (0); return ret; } void HGSaneSourceImpl::RemoveDevice(class HGSaneDeviceImpl* deviceImpl) { std::list::iterator iter; for (iter = m_listDeviceImpl.begin(); iter != m_listDeviceImpl.end(); ++iter) { if (*iter == deviceImpl) { m_listDeviceImpl.erase(iter); delete deviceImpl; break; } } } HGSaneDeviceImpl::HGSaneDeviceImpl(HGSaneSourceImpl* sourceImpl) { m_sourceImpl = sourceImpl; m_devName.clear(); m_devHandle = NULL; m_buffer = NULL; m_bufferSize = 0; m_dpi = 0; m_eventFunc = NULL; m_eventParam = NULL; m_imageFunc = NULL; m_imageParam = NULL; m_stopThread = HGFALSE; m_thread = NULL; } HGSaneDeviceImpl::~HGSaneDeviceImpl() { } HGResult HGSaneDeviceImpl::Init(const HGChar* devName, SANE_Handle handle) { assert(NULL == m_devHandle); if (NULL == devName || NULL == handle) { return HGBASE_ERR_INVALIDARG; } m_devName = devName; m_sourceImpl->m_saneApi.sane_set_io_mode_api(handle, SANE_FALSE); m_devHandle = handle; return HGBASE_ERR_OK; } HGResult HGSaneDeviceImpl::Open(const HGChar* devName, HGChar* errInfo, HGUInt errInfoLen) { assert(NULL == m_devHandle); if (NULL == devName) { return HGBASE_ERR_INVALIDARG; } SANE_Handle handle = NULL; SANE_Status stat = m_sourceImpl->m_saneApi.sane_open_api(devName, &handle); if (SANE_STATUS_GOOD != stat) { if (NULL != errInfo) { const char* err = m_sourceImpl->m_saneApi.sane_strstatus_api(stat); if (NULL != err && errInfoLen >= strlen(err) + 1) { strcpy(errInfo, err); } } return HGSANE_ERR_FAIL; } m_devName = devName; m_sourceImpl->m_saneApi.sane_set_io_mode_api(handle, SANE_FALSE); m_devHandle = handle; return HGBASE_ERR_OK; } HGResult HGSaneDeviceImpl::Close() { assert(NULL != m_devHandle); Stop(); m_sourceImpl->m_saneApi.sane_close_api(m_devHandle); m_devHandle = NULL; m_devName.clear(); m_sourceImpl->RemoveDevice(this); return HGBASE_ERR_OK; } HGResult HGSaneDeviceImpl::GetName(HGChar* name, HGUInt maxLen) { if (NULL == name || 0 == maxLen) { return HGBASE_ERR_INVALIDARG; } if (maxLen < m_devName.size() + 1) return HGBASE_ERR_FAIL; strcpy(name, m_devName.c_str()); return HGBASE_ERR_OK; } HGResult HGSaneDeviceImpl::ShowSettingDlg(HGWindow parent) { if (NULL != m_thread) { return HGBASE_ERR_FAIL; } if (-2 == show_setting_ui(&m_sourceImpl->m_saneApi, m_devHandle, m_devName.c_str(), parent)) { return HGBASE_ERR_NOTSUPPORT; } return HGBASE_ERR_OK; } HGResult HGSaneDeviceImpl::Start(HGSane_DeviceEventFunc eventFunc, HGPointer eventParam, HGSane_DeviceImageFunc imageFunc, HGPointer imageParam, HGChar* errInfo, HGUInt errInfoLen) { if (NULL != m_thread) { return HGBASE_ERR_FAIL; } SANE_Parameters params; memset(¶ms, 0, sizeof(SANE_Parameters)); SANE_Status stat = m_sourceImpl->m_saneApi.sane_get_parameters_api(m_devHandle, ¶ms); if (SANE_STATUS_GOOD != stat) { if (NULL != errInfo) { const char* err = m_sourceImpl->m_saneApi.sane_strstatus_api(stat); if (NULL != err && errInfoLen >= strlen(err) + 1) { strcpy(errInfo, err); } } return HGSANE_ERR_FAIL; } m_bufferSize = 5000 * 4000; m_buffer = (HGByte *)malloc(m_bufferSize); if (NULL == m_buffer) { return HGBASE_ERR_OUTOFMEMORY; } m_dpi = GetDpi(); stat = m_sourceImpl->m_saneApi.sane_start_api(m_devHandle); if (SANE_STATUS_GOOD != stat) { if (NULL != errInfo) { const char* err = m_sourceImpl->m_saneApi.sane_strstatus_api(stat); if (NULL != err && errInfoLen >= strlen(err) + 1) { strcpy(errInfo, err); } } m_dpi = 0; free(m_buffer); m_buffer = NULL; m_bufferSize = 0; return HGSANE_ERR_FAIL; } m_eventFunc = eventFunc; m_eventParam = eventParam; m_imageFunc = imageFunc; m_imageParam = imageParam; m_stopThread = HGFALSE; HGBase_OpenThread(ThreadFunc, this, &m_thread); return HGBASE_ERR_OK; } HGResult HGSaneDeviceImpl::Stop() { if (NULL == m_thread) { return HGBASE_ERR_FAIL; } m_stopThread = HGTRUE; m_sourceImpl->m_saneApi.sane_cancel_api(m_devHandle); HGBase_CloseThread(m_thread); m_thread = NULL; m_eventFunc = NULL; m_eventParam = NULL; m_imageFunc = NULL; m_imageParam = NULL; m_dpi = 0; free(m_buffer); m_buffer = NULL; m_bufferSize = 0; return HGBASE_ERR_OK; } HGResult HGSaneDeviceImpl::StartWithUI(HGWindow parent, HGSane_DeviceImageFunc imageFunc, HGPointer imageParam) { if (NULL != m_thread) { return HGBASE_ERR_FAIL; } m_dpi = GetDpi(); m_imageFunc = imageFunc; m_imageParam = imageParam; if (-2 == show_scan_ui(&m_sourceImpl->m_saneApi, m_devHandle, m_devName.c_str(), parent, ShowScanImageCallback, this)) { return HGBASE_ERR_NOTSUPPORT; } return HGBASE_ERR_OK; } HGUInt HGSaneDeviceImpl::GetDpi() { HGUInt dpi = 0; SANE_Int num_dev_options = 0; m_sourceImpl->m_saneApi.sane_control_option_api(m_devHandle, 0, SANE_ACTION_GET_VALUE, &num_dev_options, NULL); for (int i = 1; i < num_dev_options; ++i) { const SANE_Option_Descriptor* desp = m_sourceImpl->m_saneApi.sane_get_option_descriptor_api(m_devHandle, i); if (nullptr == desp) continue; if (SANE_TYPE_INT == desp->type) { SANE_Int value = 0; m_sourceImpl->m_saneApi.sane_control_option_api(m_devHandle, i, SANE_ACTION_GET_VALUE, &value, NULL); if (0 == strcmp(desp->name, "resolution")) { dpi = (HGUInt)value; break; } } } return dpi; } void HGAPI HGSaneDeviceImpl::ThreadFunc(HGThread thread, HGPointer param) { HGSaneDeviceImpl* p = (HGSaneDeviceImpl*)param; while (!p->m_stopThread) { SANE_Parameters params; memset(¶ms, 0, sizeof(SANE_Parameters)); SANE_Status stat1 = p->m_sourceImpl->m_saneApi.sane_get_parameters_api(p->m_devHandle, ¶ms); SANE_Int readSize = 0; SANE_Status stat2 = SANE_STATUS_GOOD; while (readSize < p->m_bufferSize) { SANE_Int len = 0; stat2 = p->m_sourceImpl->m_saneApi.sane_read_api(p->m_devHandle, p->m_buffer + readSize, p->m_bufferSize - readSize, &len); readSize += len; if (SANE_STATUS_GOOD != stat2) { break; } } if (SANE_STATUS_GOOD == stat2) { // m_bufferSize空间不够 if (NULL != p->m_eventFunc) p->m_eventFunc((HGSaneDevice)p, HGSANE_ERR_FAIL, p->m_sourceImpl->m_saneApi.sane_strstatus_api(SANE_STATUS_INVAL), p->m_eventParam); break; } else if (SANE_STATUS_EOF == stat2) { if (0 == readSize) { if (NULL != p->m_eventFunc) p->m_eventFunc((HGSaneDevice)p, HGBASE_ERR_OK, NULL, p->m_eventParam); break; } else if (SANE_STATUS_GOOD != stat1 || readSize != params.bytes_per_line * params.lines) { if (NULL != p->m_eventFunc) p->m_eventFunc((HGSaneDevice)p, HGSANE_ERR_FAIL, p->m_sourceImpl->m_saneApi.sane_strstatus_api(SANE_STATUS_INVAL), p->m_eventParam); break; } } else if (SANE_STATUS_CANCELLED == stat2) { break; } else { if (NULL != p->m_eventFunc) p->m_eventFunc((HGSaneDevice)p, HGSANE_ERR_FAIL, p->m_sourceImpl->m_saneApi.sane_strstatus_api(stat2), p->m_eventParam); break; } if (NULL != p->m_imageFunc) { HGUInt imgType = 0; if (params.format == SANE_FRAME_GRAY) { if (1 == params.depth) imgType = HGBASE_IMGTYPE_BINARY; else if (8 == params.depth) imgType = HGBASE_IMGTYPE_GRAY; } else if (params.format == SANE_FRAME_RGB) { imgType = HGBASE_IMGTYPE_RGB; } HGImageInfo imgInfo = { (HGUInt)params.pixels_per_line, (HGUInt)params.lines, imgType, (HGUInt)params.bytes_per_line, HGBASE_IMGORIGIN_TOP }; HGImage img = NULL; HGBase_CreateImageWithData(p->m_buffer, &imgInfo, &img); if (NULL != img) { HGBase_SetImageDpi(img, p->m_dpi, p->m_dpi); p->m_imageFunc((HGSaneDevice)p, img, p->m_imageParam); HGBase_DestroyImage(img); } } } } void HGSaneDeviceImpl::ShowScanImageCallback(const SANE_Parameters* imageFormat, const SANE_Byte* imageData, void* callbackParam) { HGSaneDeviceImpl* p = (HGSaneDeviceImpl*)callbackParam; if (NULL != p->m_imageFunc) { HGUInt imgType = 0; if (imageFormat->format == SANE_FRAME_GRAY) { if (1 == imageFormat->depth) imgType = HGBASE_IMGTYPE_BINARY; else if (8 == imageFormat->depth) imgType = HGBASE_IMGTYPE_GRAY; } else if (imageFormat->format == SANE_FRAME_RGB) { imgType = HGBASE_IMGTYPE_RGB; } HGImageInfo imgInfo = { (HGUInt)imageFormat->pixels_per_line, (HGUInt)imageFormat->lines, imgType, (HGUInt)imageFormat->bytes_per_line, HGBASE_IMGORIGIN_TOP }; HGImage img = NULL; HGBase_CreateImageWithData((HGByte*)imageData, &imgInfo, &img); if (NULL != img) { HGBase_SetImageDpi(img, p->m_dpi, p->m_dpi); p->m_imageFunc((HGSaneDevice)p, img, p->m_imageParam); HGBase_DestroyImage(img); } } }