3222 lines
94 KiB
C++
3222 lines
94 KiB
C++
|
||
|
||
#include "scanner.h"
|
||
|
||
|
||
#include <sane/sane_option_definitions.h>
|
||
#include "sane_option_trans.h"
|
||
#include <chrono>
|
||
#include <mutex>
|
||
#include <string.h>
|
||
#include <functional>
|
||
|
||
#include <twain_user/twainui.h>
|
||
#include <huagao/brand.h>
|
||
#include "sane_helper.h"
|
||
#include "../../sdk/hginclude/utils.h"
|
||
|
||
#define START_SCAN_IN_THREAD
|
||
|
||
static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt);
|
||
|
||
#define SET_SANE_OPT_ID(id, id_name, name, val, extension) \
|
||
if(strcmp(SANE_STD_OPT_NAME_##name, val) == 0) \
|
||
{ \
|
||
id_name##_id_ = id; \
|
||
sane_ids_[(sane_option_id)SANE_OPT_ID_##name] = id; \
|
||
extension(id); \
|
||
}
|
||
|
||
|
||
|
||
#if !defined(WIN32) && !defined(_WIN64)
|
||
template<typename ... Args>
|
||
int sprintf_s(char* buf, size_t len, const char* fmt, Args ... args)
|
||
{
|
||
return sprintf(buf, fmt, args ...);
|
||
}
|
||
|
||
std::string g_scanner_path = ""; // hg_log::get_module_full_path((std::string(GET_BACKEND_NAME) + ".so").c_str());
|
||
#endif
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// callback
|
||
sane_helper* sane_helper_ = nullptr;
|
||
|
||
namespace callback
|
||
{
|
||
static std::mutex cb_lock_;
|
||
typedef struct _scanner_inst
|
||
{
|
||
SANE_Handle dev;
|
||
scanner* invoker;
|
||
|
||
bool operator==(const SANE_Handle& h)
|
||
{
|
||
return dev == h;
|
||
}
|
||
bool operator==(const scanner* obj)
|
||
{
|
||
return invoker == obj;
|
||
}
|
||
}SCNINST;
|
||
std::vector<SCNINST> g_scanner_instances;
|
||
|
||
int sane_event_callback( // 注册回调的对象,需要保证该回调是多线程安全的
|
||
SANE_Handle hdev // 产生事件的设备句柄
|
||
, int code // 回调事件代码
|
||
, void* data // 回调事件数据,根据事件代码有所不同,参照具体事件定义
|
||
, unsigned int* len // 数据长度(字节),或者event_data的缓冲区长度,详细请看相应的事件代码
|
||
, void* param // 用户自定义数据,与调用sane_init_ex传入时的保持一致
|
||
) // 返回值依不同的事件代码而定,通常为“0”
|
||
{
|
||
std::lock_guard<std::mutex> lock(cb_lock_);
|
||
std::vector<SCNINST>::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), hdev);
|
||
|
||
if (it != g_scanner_instances.end())
|
||
return it->invoker->handle_device_event(code, data, len);
|
||
else if(code != SANE_EVENT_SCANNER_CLOSED)
|
||
{
|
||
char msg[218] = { 0 };
|
||
sprintf_s(msg, _countof(msg) - 1, "Lost device(0x%08X) when event(%u) occurs!\r\n", hdev, code);
|
||
utils::log_info(msg, (log_level)1);
|
||
|
||
return 0;
|
||
}
|
||
}
|
||
void reg_callback(SANE_Handle dev, scanner* invoker)
|
||
{
|
||
std::lock_guard<std::mutex> lock(cb_lock_);
|
||
std::vector<SCNINST>::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), dev);
|
||
if (it == g_scanner_instances.end())
|
||
{
|
||
SCNINST inst;
|
||
|
||
inst.dev = dev;
|
||
inst.invoker = invoker;
|
||
g_scanner_instances.push_back(inst);
|
||
}
|
||
else
|
||
it->invoker = invoker;
|
||
}
|
||
void unreg_callback(scanner* invoker)
|
||
{
|
||
std::lock_guard<std::mutex> lock(cb_lock_);
|
||
std::vector<SCNINST>::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), invoker);
|
||
if (it != g_scanner_instances.end())
|
||
g_scanner_instances.erase(it);
|
||
}
|
||
|
||
struct
|
||
{
|
||
const char* name;
|
||
const char* title;
|
||
}g_opts[] = { {SANE_STD_OPT_NAME_RESTORE , OPTION_TITLE_HFMRSZ}
|
||
, {SANE_STD_OPT_NAME_HELP , OPTION_TITLE_BZ}
|
||
, {SANE_STD_OPT_NAME_IS_MULTI_OUT , OPTION_TITLE_DLSC}
|
||
, {SANE_STD_OPT_NAME_MULTI_OUT_TYPE , OPTION_TITLE_DLSCLX}
|
||
, {SANE_STD_OPT_NAME_COLOR_MODE , OPTION_TITLE_YSMS}
|
||
, {SANE_STD_OPT_NAME_BINARY_THRESHOLD , OPTION_TITLE_HBTXYZ}
|
||
, {SANE_STD_OPT_NAME_REVERSE_01 , OPTION_TITLE_HBTXFSSC}
|
||
, {SANE_STD_OPT_NAME_FILTER , OPTION_TITLE_HDHHBTX_CSYZQ}
|
||
, {SANE_STD_OPT_NAME_RID_MULTIOUT_RED , OPTION_TITLE_24WCSTX_DLSCCH}
|
||
, {SANE_STD_OPT_NAME_RID_ANSWER_SHEET_RED , OPTION_TITLE_24WCSTX_DTKCH}
|
||
, {SANE_STD_OPT_NAME_ERASE_BACKGROUND , OPTION_TITLE_BJYC}
|
||
, {SANE_STD_OPT_NAME_BKG_COLOR_RANGE , OPTION_TITLE_BJSCFDFW}
|
||
, {SANE_STD_OPT_NAME_SHARPEN , OPTION_TITLE_RHYMH}
|
||
, {SANE_STD_OPT_NAME_RID_MORR , OPTION_TITLE_QCMW}
|
||
, {SANE_STD_OPT_NAME_RID_GRID , OPTION_TITLE_CWW}
|
||
, {SANE_STD_OPT_NAME_ERROR_EXTENSION , OPTION_TITLE_CWKS}
|
||
, {SANE_STD_OPT_NAME_NOISE_OPTIMIZE , OPTION_TITLE_HBTXZDYH}
|
||
, {SANE_STD_OPT_NAME_NOISE_SIZE , OPTION_TITLE_ZDYHCC}
|
||
, {SANE_STD_OPT_NAME_PAPER , OPTION_TITLE_ZZCC}
|
||
, {SANE_STD_OPT_NAME_CUSTOM_AREA , OPTION_TITLE_ZDYSMQY}
|
||
, {SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT , OPTION_TITLE_SMQYZCmm}
|
||
, {SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT , OPTION_TITLE_SMQYYCmm}
|
||
, {SANE_STD_OPT_NAME_CUSTOM_AREA_TOP , OPTION_TITLE_SMQYSCmm}
|
||
, {SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM , OPTION_TITLE_SMQYXCmm}
|
||
, {SANE_STD_OPT_NAME_SIZE_CHECK , OPTION_TITLE_CCJC}
|
||
, {SANE_STD_OPT_NAME_PAGE , OPTION_TITLE_SMYM}
|
||
, {SANE_STD_OPT_NAME_DISCARD_BLANK_SENS , OPTION_TITLE_TGKBYLMD}
|
||
, {SANE_STD_OPT_NAME_RESOLUTION , OPTION_TITLE_FBL}
|
||
, {SANE_STD_OPT_NAME_TIME_TO_SLEEP , OPTION_TITLE_XMSJ}
|
||
, {SANE_STD_OPT_NAME_IMAGE_QUALITY , OPTION_TITLE_HZ}
|
||
, {SANE_STD_OPT_NAME_EXCHANGE ,OPTION_TITLE_JHZFM}
|
||
, {SANE_STD_OPT_NAME_SPLIT ,OPTION_TITLE_TXCF }
|
||
, {SANE_STD_OPT_NAME_ANTI_SKEW , OPTION_TITLE_ZDJP}
|
||
, {SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA , OPTION_TITLE_QYSDQX}
|
||
, {SANE_STD_OPT_NAME_GAMMA , OPTION_TITLE_JMZ}
|
||
, {SANE_STD_OPT_NAME_BRIGHTNESS , OPTION_TITLE_LDZ}
|
||
, {SANE_STD_OPT_NAME_CONTRAST , OPTION_TITLE_DBD}
|
||
, {SANE_STD_OPT_NAME_IS_PHOTO_MODE , OPTION_TITLE_ZPMS}
|
||
, {SANE_STD_OPT_NAME_ERASE_BLACK_FRAME , OPTION_TITLE_XCHK}
|
||
, {SANE_STD_OPT_NAME_DARK_SAMPLE , OPTION_TITLE_SSYZ}
|
||
, {SANE_STD_OPT_NAME_THRESHOLD , OPTION_TITLE_YZ}
|
||
, {SANE_STD_OPT_NAME_ANTI_NOISE_LEVEL , OPTION_TITLE_BJKZDJ}
|
||
, {SANE_STD_OPT_NAME_MARGIN , OPTION_TITLE_BYSJ}
|
||
, {SANE_STD_OPT_NAME_FILL_BKG_MODE , OPTION_TITLE_BJTCFS}
|
||
, {SANE_STD_OPT_NAME_IS_ANTI_PERMEATE , OPTION_TITLE_FZST}
|
||
, {SANE_STD_OPT_NAME_ANTI_PERMEATE_LEVEL , OPTION_TITLE_FZSTDJ}
|
||
, {SANE_STD_OPT_NAME_RID_HOLE_L , OPTION_TITLE_CKYCZC}
|
||
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_L , OPTION_TITLE_ZCCKSSFWZFMBL}
|
||
, {SANE_STD_OPT_NAME_RID_HOLE_R , OPTION_TITLE_CKYCYC}
|
||
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_R , OPTION_TITLE_YCCKSSFWZFMBL}
|
||
, {SANE_STD_OPT_NAME_RID_HOLE_T , OPTION_TITLE_CKYCSC}
|
||
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_T , OPTION_TITLE_SCCKSSFWZFMBL}
|
||
, {SANE_STD_OPT_NAME_RID_HOLE_B , OPTION_TITLE_CKYCXC}
|
||
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_B , OPTION_TITLE_XCCKSSFWZFMBL}
|
||
, {SANE_STD_OPT_NAME_IS_FILL_COLOR , OPTION_TITLE_SCTC}
|
||
, {SANE_STD_OPT_NAME_IS_ULTROSONIC_CHECK , OPTION_TITLE_CSBJC}
|
||
, {SANE_STD_OPT_NAME_DOUBLE_FEED_HANDLE , OPTION_TITLE_SZTPCL}
|
||
, {SANE_STD_OPT_NAME_IS_CHECK_STAPLE , OPTION_TITLE_ZDJC}
|
||
, {SANE_STD_OPT_NAME_SCAN_MODE , OPTION_TITLE_SMZS}
|
||
, {SANE_STD_OPT_NAME_SCAN_COUNT , OPTION_TITLE_SMSL}
|
||
, {SANE_STD_OPT_NAME_TEXT_DIRECTION , OPTION_TITLE_WGFX}
|
||
, {SANE_STD_OPT_NAME_IS_ROTATE_BKG_180 , OPTION_TITLE_BMXZ180}
|
||
, {SANE_STD_OPT_NAME_IS_CHECK_DOG_EAR , OPTION_TITLE_ZJJC}
|
||
, {SANE_STD_OPT_NAME_DOG_EAR_SIZE , OPTION_TITLE_ZJDX}
|
||
, {SANE_STD_OPT_NAME_IS_CHECK_ASKEW , OPTION_TITLE_WXJC}
|
||
, {SANE_STD_OPT_NAME_ASKEW_RANGE , OPTION_TITLE_WXRRD}
|
||
, {SANE_STD_OPT_NAME_FEED_STRENGTH , OPTION_TITLE_FZQD}
|
||
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , OPTION_TITLE_ZDFZQD}
|
||
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , OPTION_TITLE_JZSBL}
|
||
, {SANE_STD_OPT_NAME_WAIT_TO_SCAN , OPTION_TITLE_DZSM}
|
||
, {SANE_STD_OPT_NAME_FOLD_TYPE , OPTION_TITLE_DZMS}
|
||
, {SANE_STD_OPT_NAME_COLOR_CORRECTION , OPTION_TITLE_SPJZ}
|
||
},
|
||
g_discard[] = { {SANE_STD_OPT_NAME_REVERSE_01 , "\351\273\221\347\231\275\345\233\276\345\203\217\345\217\215\350\211\262\350\276\223\345\207\272\357\274\210\346\255\243\345\270\270\351\242\234\350\211\262\344\270\272\357\274\2320-\351\273\221\350\211\262\357\274\2331-\347\231\275\350\211\262\357\274\211"} // 黑白图像反色输出(正常颜色为:0-黑色;1-白色)
|
||
, {SANE_STD_OPT_NAME_FILTER , "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262"} // 灰度或黑白图像 - 除色
|
||
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , "\350\207\252\345\212\250\346\220\223\347\272\270\345\274\272\345\272\246"} // 自动搓纸强度
|
||
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , "\346\220\223\347\272\270\351\230\210\345\200\274"} // " 搓纸阈值"
|
||
};
|
||
const char* option_title_2_name(const char* title)
|
||
{
|
||
while (*title == ' ')
|
||
title++;
|
||
|
||
for (size_t i = 0; i < _countof(g_discard); ++i)
|
||
{
|
||
if (strcmp(title, g_discard[i].title) == 0)
|
||
return g_discard[i].name;
|
||
}
|
||
for (size_t i = 0; i < _countof(g_opts); ++i)
|
||
{
|
||
if (strcmp(title, g_opts[i].title) == 0)
|
||
return g_opts[i].name;
|
||
}
|
||
|
||
return "";
|
||
}
|
||
const char* option_name_2_title(const char* name)
|
||
{
|
||
for (size_t i = 0; i < _countof(g_opts); ++i)
|
||
{
|
||
if (strcmp(name, g_opts[i].name) == 0)
|
||
return g_opts[i].title;
|
||
}
|
||
|
||
return "";
|
||
}
|
||
|
||
static HWND find_main_wnd(void)
|
||
{
|
||
return nullptr;
|
||
}
|
||
|
||
static std::string option_value_2_string(SANE_Value_Type type, void* value)
|
||
{
|
||
if(type == SANE_TYPE_BOOL)
|
||
return *(SANE_Bool*)value == SANE_TRUE ? "true" : "false";
|
||
if(type == SANE_TYPE_INT)
|
||
return std::to_string(*(SANE_Int*)value);
|
||
if(type == SANE_TYPE_FIXED)
|
||
return std::to_string(SANE_UNFIX(*(SANE_Int*)value));
|
||
if(type == SANE_TYPE_STRING)
|
||
return (char*)value;
|
||
|
||
return "Unknown";
|
||
}
|
||
|
||
// UI ...
|
||
//
|
||
// events code, see SANE_Event
|
||
//
|
||
// callback events: SANE_EVENT_UI_CLOSE_CANCEL/SANE_EVENT_UI_CLOSE_NORMAL/SANE_EVENT_UI_SCAN_COMMAND/SANE_EVENT_UI_CLOSE_SETTING
|
||
//
|
||
// notify events: SANE_EVENT_WORKING - void*: unused, be nullptr, flag - unused, be 0
|
||
// SANE_EVENT_SCAN_FINISHED - void*: (utf8*)message, flag - error code (0 is success)
|
||
// SANE_EVENT_USB_DATA_RECEIVED- void* unused, be nullptr, flag - unused, be 0
|
||
// SANE_EVENT_IMAGE_OK - void* unused, be nullptr, flag - unused, be 0
|
||
static HMODULE hui = nullptr;
|
||
int (*choose_scanner)(const std::vector<DEVQUEUI>& devs) = nullptr; // blocked. return selected DEVQUE::id or -1 if user cancelled
|
||
char* (*apply_current_config)(const char* dev_name, SANE_Handle device, LPSANEAPI api) = nullptr; // 应用设备的当前配<E5898D>?
|
||
int (*show_setting_ui)(SANE_Handle device, HWND parent, LPSANEAPI api, const char* devname, bool with_scan, std::function<void(ui_result)> callback) = nullptr;
|
||
int (*show_progress_ui)(HWND parent, std::function<void(ui_result)> callback, std::function<void(int/*event*/, void* /*msg*/, int/*flag*/)>* notify) = nullptr;
|
||
int (*show_messagebox_ui)(HWND parent, int event, void* msg, int flag) = nullptr;
|
||
int (*close_ui)(int) = nullptr;
|
||
void (*twain_ui_free)(void* buf) = nullptr;
|
||
|
||
|
||
static void init_ui(void)
|
||
{
|
||
std::string root(utils::get_module_full_path(SCANNER_DRIVER_PART_NAME));
|
||
size_t pos = root.rfind(PATH_SEPARATOR[0]);
|
||
|
||
if(pos != std::string::npos)
|
||
root.erase(pos);
|
||
root = utils::find_file(root.c_str(), "*twainui*", false);
|
||
utils::to_log(LOG_LEVEL_DEBUG, "TwainUI component: %s\n", root.c_str());
|
||
// #if defined(WIN32) || defined(_WIN64)
|
||
// root += OEM_SHORT_NAME_E;
|
||
// #else
|
||
// std::string vnd(OEM_SHORT_NAME_E);
|
||
//
|
||
// std::transform(vnd.begin(), vnd.end(), vnd.begin(), toupper);
|
||
// root += "lib" + vnd;
|
||
// #endif
|
||
// root += "TwainUI.";
|
||
// root += DLL_EXTESION;
|
||
if (hui)
|
||
FreeLibrary(hui);
|
||
|
||
// hui = LoadLibraryExA(root.c_str(), nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||
hui = LOAD_LIB(root.c_str(), LOAD_WITH_ALTERED_SEARCH_PATH);
|
||
if (!hui)
|
||
{
|
||
std::string info("Load '" + root);
|
||
|
||
info += "' failed: " + std::string(strerror(GetLastError())) + "\r\n";
|
||
|
||
|
||
utils::log_info(info.c_str(), LOG_LEVEL_DEBUG);
|
||
}
|
||
else
|
||
{
|
||
#define GET_API(api) \
|
||
proc = (FARPROC*)&api; \
|
||
*proc = GetProcAddress(hui, #api); \
|
||
if(*proc == nullptr) \
|
||
utils::to_log(LOG_LEVEL_FATAL, "TWAINUI - function '%s' not found!\n", #api);
|
||
|
||
FARPROC* proc = nullptr;
|
||
|
||
GET_API(choose_scanner);
|
||
GET_API(apply_current_config);
|
||
GET_API(show_setting_ui);
|
||
GET_API(show_progress_ui);
|
||
GET_API(show_messagebox_ui);
|
||
GET_API(close_ui);
|
||
GET_API(twain_ui_free);
|
||
}
|
||
}
|
||
static void unint_ui(void)
|
||
{
|
||
if (close_ui)
|
||
close_ui(UI_UNLOAD_MODULE);
|
||
choose_scanner = nullptr;
|
||
apply_current_config = nullptr;
|
||
show_setting_ui = nullptr;
|
||
show_progress_ui = nullptr;
|
||
show_messagebox_ui = nullptr;
|
||
close_ui = nullptr;
|
||
twain_ui_free = nullptr;
|
||
if (hui)
|
||
{
|
||
FreeLibrary(hui);
|
||
hui = nullptr;
|
||
}
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// class scanner
|
||
scanner::scanner(SCANNERID id) : handle_(nullptr), id_(id), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START)
|
||
, dpi_(200), tmp_path_(""), img_ind_(0)
|
||
, scanner_name_(""), is_ui_wait_img_(false), is_scanning_(false)
|
||
, scanner_ev_handler_(nullptr), evh_param_(nullptr), app_wnd_(nullptr), user_cancel_(false)
|
||
, max_img_mem_(1 * 1024), twain_set_(false), ev_cnt_(0), is_bIndicator(false), is_show_setting_(false)
|
||
{
|
||
ui_notify = std::function<void(int, void*, int)>();
|
||
|
||
sane_api_.sane_cancel_api = sane_helper_->invoke_sane_cancel;
|
||
sane_api_.sane_close_api = sane_helper_->invoke_sane_close;
|
||
sane_api_.sane_control_option_api = sane_helper_->invoke_sane_control_option;
|
||
sane_api_.sane_get_devices_api = sane_helper_->invoke_sane_get_devices;
|
||
sane_api_.sane_get_option_descriptor_api = sane_helper_->invoke_sane_get_option_descriptor;
|
||
sane_api_.sane_get_parameters_api = sane_helper_->invoke_sane_get_parameters;
|
||
sane_api_.sane_get_select_fd_api = sane_helper_->invoke_sane_get_select_fd;
|
||
sane_api_.sane_io_control_api = nullptr;
|
||
sane_api_.sane_open_api = sane_helper_->invoke_sane_open;
|
||
sane_api_.sane_read_api = sane_helper_->invoke_sane_read;
|
||
sane_api_.sane_set_io_mode_api = sane_helper_->invoke_sane_set_io_mode;
|
||
sane_api_.sane_start_api = sane_helper_->invoke_sane_start;
|
||
sane_api_.sane_strstatus_api = sane_helper_->invoke_sane_strstatus;
|
||
|
||
tmp_path_ = utils::get_local_data_path() + PATH_SEPARATOR;
|
||
cfg_path_ = tmp_path_ + "config";
|
||
utils::create_folder(cfg_path_.c_str());
|
||
cfg_path_ += PATH_SEPARATOR;
|
||
tmp_path_ += "imgs";
|
||
utils::create_folder(tmp_path_.c_str());
|
||
tmp_path_ += PATH_SEPARATOR;
|
||
img_fmt_.img_format = SANE_IMAGE_TYPE_BMP;
|
||
img_fmt_.compress.compression = SANE_COMPRESSION_NONE;
|
||
|
||
int mem_limit = GetPrivateProfileIntA("mem", "max_img", 0, (cfg_path_ + "debug.cfg").c_str());
|
||
if (mem_limit > 0)
|
||
{
|
||
// this value is same as driver memory limit ...
|
||
max_img_mem_ = mem_limit;
|
||
}
|
||
err_ = open();
|
||
}
|
||
scanner::~scanner()
|
||
{
|
||
close();
|
||
if (thread_starting_.get() && thread_starting_->joinable())
|
||
thread_starting_->join();
|
||
thread_starting_.reset();
|
||
}
|
||
|
||
void scanner::get_scanner_name(SCANNERID id, std::vector<std::string>& names)
|
||
{
|
||
const SANE_Device **devs = nullptr;
|
||
int count = 0;
|
||
|
||
names.clear();
|
||
if (sane_helper_->invoke_sane_get_devices(&devs, SANE_TRUE) == SANE_STATUS_GOOD)
|
||
{
|
||
for(; devs[count]; ++count)
|
||
{
|
||
if (strcmp(devs[count]->type, PRODUCT_FAMILY) == 0)
|
||
names.push_back(devs[count]->name);
|
||
}
|
||
}
|
||
}
|
||
value_type scanner::from_sane_type(SANE_Value_Type type)
|
||
{
|
||
if (type == SANE_TYPE_BOOL)
|
||
return VAL_TYPE_BOOL;
|
||
else if (type == SANE_TYPE_INT)
|
||
return VAL_TYPE_INT;
|
||
else if (type == SANE_TYPE_FIXED)
|
||
return VAL_TYPE_FLOAT;
|
||
else if (type == SANE_TYPE_STRING)
|
||
return VAL_TYPE_STR;
|
||
else
|
||
return VAL_TYPE_NONE;
|
||
}
|
||
value_limit scanner::from_sane_constraint(SANE_Constraint_Type type)
|
||
{
|
||
if (type == SANE_CONSTRAINT_RANGE)
|
||
return VAL_LIMIT_RANGE;
|
||
else if (type == SANE_CONSTRAINT_STRING_LIST || type == SANE_CONSTRAINT_WORD_LIST)
|
||
return VAL_LIMIT_ENUM;
|
||
else
|
||
return VAL_LIMIT_NONE;
|
||
}
|
||
|
||
int scanner::to_int(SANE_Int v)
|
||
{
|
||
return v;
|
||
}
|
||
float scanner::to_float(SANE_Fixed v)
|
||
{
|
||
return (float)SANE_UNFIX(v);
|
||
}
|
||
void scanner::ui_callback(int uev, void* sender, void* param)
|
||
{
|
||
((scanner*)param)->on_ui_event(uev, sender);
|
||
}
|
||
bool scanner::is_option_float(int sn, void* param)
|
||
{
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor((SANE_Handle)param, sn);
|
||
|
||
if (desc)
|
||
return desc->type == SANE_TYPE_FIXED;
|
||
else
|
||
return false;
|
||
}
|
||
|
||
// IRef
|
||
COM_API_IMPLEMENT(scanner, long, add_ref(void))
|
||
{
|
||
return refer::add_ref();
|
||
}
|
||
COM_API_IMPLEMENT(scanner, long, release(void))
|
||
{
|
||
return refer::release();
|
||
}
|
||
|
||
int scanner::transfer_id(int id)
|
||
{
|
||
if (id > SANE_OPT_ID_BASE)
|
||
{
|
||
if (sane_ids_.count((sane_option_id)id) == 0)
|
||
id = -1;
|
||
else
|
||
id = sane_ids_[(sane_option_id)id];
|
||
}
|
||
|
||
return id;
|
||
}
|
||
void scanner::apply_config(void)
|
||
{
|
||
if (callback::apply_current_config)
|
||
{
|
||
char* cfg = callback::apply_current_config(scanner_name_.c_str(), handle_, &sane_api_);
|
||
if (cfg && callback::twain_ui_free)
|
||
callback::twain_ui_free(cfg);
|
||
}
|
||
}
|
||
void scanner::on_ui_event(int uev, void* sender)
|
||
{
|
||
if (uev == SANE_EVENT_UI_CLOSE_SETTING)
|
||
{
|
||
// setting UI closed ...
|
||
is_scanning_ = is_show_setting_ = false;
|
||
}
|
||
else if (uev == SANE_EVENT_UI_CLOSE_NORMAL)
|
||
{
|
||
// scan complete
|
||
|
||
// FIX on 2023-05-30: restore scan finished status, whether close UI is up to APP
|
||
//is_scanning_ = is_show_setting_;
|
||
is_scanning_ = false;
|
||
ui_notify = std::function<void(int, void*, int)>();
|
||
}
|
||
else if (uev == SANE_EVENT_UI_CLOSE_CANCEL)
|
||
{
|
||
// scan cancelled
|
||
|
||
stop(); // nothing to do, the finishing work do in SANE_EVENT_SCAN_FINISHED
|
||
}
|
||
else if (uev == SANE_EVENT_SCAN_FINISHED)
|
||
{
|
||
// FIX on 2023-05-30: restore scan finished status, whether close UI is up to APP
|
||
//is_scanning_ = is_show_setting_;
|
||
is_scanning_ = false;
|
||
ui_notify = std::function<void(int, void*, int)>();
|
||
}
|
||
|
||
int( * h)(int, void*) = scanner_ev_handler_;
|
||
if (h)
|
||
{
|
||
h(uev, evh_param_);
|
||
}
|
||
return;
|
||
|
||
events_.save(uev, sizeof(uev));
|
||
|
||
}
|
||
std::string scanner::choose_scanner(const std::vector<std::string>& scanners)
|
||
{
|
||
if (scanners.empty())
|
||
return "";
|
||
|
||
std::vector<DEVQUEUI> devs;
|
||
std::string sel("");
|
||
int id = 1;
|
||
|
||
for (size_t i = 0; i < scanners.size(); ++i)
|
||
{
|
||
SANE_Handle h = nullptr;
|
||
int ret = sane_helper_->invoke_sane_open(scanners[i].c_str(), &h);
|
||
|
||
if (h)
|
||
{
|
||
char sn[256] = {0};
|
||
SANE_Int len = sizeof(sn) - 1;
|
||
sane_helper_->invoke_sane_control_option(h, SANE_OPT_ID_DEVICE_SERIAL_NO, SANE_ACTION_GET_VALUE, sn, &len);
|
||
if (sn[0])
|
||
{
|
||
DEVQUEUI dev;
|
||
dev.id = id++;
|
||
dev.name = scanners[i];
|
||
dev.sn = sn;
|
||
devs.push_back(dev);
|
||
}
|
||
sane_helper_->invoke_sane_close(h);
|
||
}
|
||
}
|
||
|
||
if (devs.size() == 0)
|
||
sel = scanners[0];
|
||
else if (devs.size() == 1)
|
||
sel = devs[0].name;
|
||
else if (callback::choose_scanner)
|
||
{
|
||
id = callback::choose_scanner(devs);
|
||
if (id != -1)
|
||
{
|
||
for (auto& v : devs)
|
||
{
|
||
if (v.id == id)
|
||
{
|
||
sel = v.name;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//dlg_choose_dev dlg(nullptr, devs);
|
||
//dlg.show(true, true);
|
||
//sel = dlg.get_selected_device();
|
||
}
|
||
|
||
return sel;
|
||
}
|
||
int scanner::open(void)
|
||
{
|
||
int ret = close();
|
||
std::vector<std::string> que;
|
||
std::string name("");
|
||
|
||
scanner::get_scanner_name(id_, que);
|
||
|
||
scanner_name_ = "";
|
||
if (que.empty())
|
||
return SCANNER_ERR_DEVICE_NOT_FOUND;
|
||
|
||
if (que.size() == 1)
|
||
name = que[0];
|
||
else
|
||
{
|
||
name = choose_scanner(que);
|
||
if (name.empty())
|
||
return SCANNER_ERR_USER_CANCELED;
|
||
}
|
||
|
||
ret = sane_helper_->invoke_sane_open(name.c_str(), &handle_);
|
||
if (ret == SANE_STATUS_GOOD)
|
||
{
|
||
size_t pid = -1;
|
||
|
||
// transport_config_file();
|
||
callback::reg_callback(handle_, this);
|
||
scanner_name_ = name;
|
||
pid = scanner_name_.find(" - ");
|
||
if (pid == -1)
|
||
pid = scanner_name_.length();
|
||
ret = init_options_id();
|
||
apply_config();
|
||
img_fmt_.compress.compression = SANE_CompressionType::SANE_COMPRESSION_NONE;
|
||
img_fmt_.compress.detail = 0;
|
||
img_fmt_.img_format = SANE_IMAGE_TYPE_BMP;
|
||
img_fmt_.detail = 0;
|
||
|
||
// check roller life ...
|
||
SANE_Int cnt = 0, life = 0, after = 0;
|
||
if (sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_ROLLER_COUNT, SANE_ACTION_GET_VALUE, &cnt, &after) == SANE_STATUS_GOOD &&
|
||
sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_ROLLER_LIFE, SANE_ACTION_GET_VALUE, &life, &after) == SANE_STATUS_GOOD)
|
||
{
|
||
if (cnt >= life)
|
||
{
|
||
if (callback::show_messagebox_ui)
|
||
{
|
||
// 纸轮搓纸次数已超过设计使用范围,扫描过程中搓纸失败、歪斜、搓多张等异常频次可能会明显增多,请注意及时清洁、并联系设备供应商购买替换纸轮!
|
||
std::string roller_msg(local_trans::lang_trans_between_hz936("\347\272\270\350\275\256\346\220\223\347\272\270\346\254\241\346\225\260\345\267\262\350\266\205\350\277\207\350\256\276\350\256\241\344\275\277\347\224\250\350\214\203\345\233\264\357\274\214\346\211\253\346\217\217\350\277\207\347\250\213\344\270\255\346\220\223\347\272\270\345\244\261\350\264\245\343\200\201\346\255\252\346\226\234\343\200\201\346\220\223\345\244\232\345\274\240\347\255\211\345\274\202\345\270\270\351\242\221\346\254\241\345\217\257\350\203\275\344\274\232\346\230\216\346\230\276\345\242\236\345\244\232\357\274\214\350\257\267\346\263\250\346\204\217\345\217\212\346\227\266\346\270\205\346\264\201\343\200\201\345\271\266\350\201\224\347\263\273\350\256\276\345\244\207\344\276\233\345\272\224\345\225\206\350\264\255\344\271\260\346\233\277\346\215\242\347\272\270\350\275\256\357\274\201"));
|
||
app_wnd_ = callback::find_main_wnd();
|
||
callback::show_messagebox_ui(app_wnd_, ret, (void*)&roller_msg[0], 0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (callback::show_messagebox_ui)
|
||
{
|
||
app_wnd_ = callback::find_main_wnd();
|
||
callback::show_messagebox_ui(app_wnd_, ret, (void*)sane_helper_->invoke_sane_strstatus((SANE_Status)ret), 0);
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
int scanner::close(void)
|
||
{
|
||
scanner_ev_handler_ = nullptr;
|
||
ui_hide();
|
||
callback::unreg_callback(this);
|
||
if (handle_)
|
||
{
|
||
sane_helper_->invoke_sane_close(handle_);
|
||
}
|
||
handle_ = nullptr;
|
||
ex_id_ = EXTENSION_ID_BASE;
|
||
|
||
return SCANNER_ERR_OK;
|
||
}
|
||
int scanner::init_options_id(void)
|
||
{
|
||
SANE_Int op_id = 1;
|
||
const SANE_Option_Descriptor* desc = nullptr;
|
||
int ret = SCANNER_ERR_OK;
|
||
|
||
#define SET_OPT_ID(var, predef, func) \
|
||
SET_SANE_OPT_ID(op_id, var, predef, desc->name, func)
|
||
|
||
#define INIT_FIXED_IDS(id) \
|
||
sane_ids_[SANE_OPT_ID_##id] = SANE_OPT_ID_##id;
|
||
|
||
INIT_FIXED_IDS(HISTORY_COUNT);
|
||
INIT_FIXED_IDS(DRIVER_VERSION);
|
||
INIT_FIXED_IDS(MANUFACTURER);
|
||
INIT_FIXED_IDS(COPYRIGHT);
|
||
INIT_FIXED_IDS(CO_URL);
|
||
INIT_FIXED_IDS(CO_TEL);
|
||
INIT_FIXED_IDS(CO_ADDR);
|
||
INIT_FIXED_IDS(CO_GPS);
|
||
INIT_FIXED_IDS(HELP);
|
||
INIT_FIXED_IDS(VID);
|
||
INIT_FIXED_IDS(PID);
|
||
INIT_FIXED_IDS(DEV_NAME);
|
||
INIT_FIXED_IDS(DEV_FAMILY);
|
||
INIT_FIXED_IDS(LOGIN);
|
||
INIT_FIXED_IDS(LOGOUT);
|
||
INIT_FIXED_IDS(ROLLER_COUNT);
|
||
INIT_FIXED_IDS(DRIVER_LOG);
|
||
INIT_FIXED_IDS(DEVICE_LOG);
|
||
INIT_FIXED_IDS(ROLLER_LIFE);
|
||
INIT_FIXED_IDS(DEVICE_MAC_ADDR);
|
||
INIT_FIXED_IDS(CUSTOM_GAMMA);
|
||
INIT_FIXED_IDS(MOTOR_VER);
|
||
|
||
while ((desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, op_id)))
|
||
{
|
||
char* val = new char[desc->size + 4];
|
||
sane_helper_->invoke_sane_control_option(handle_, op_id, (SANE_Action)SANE_ACTION_GET_DEFAULT_VALUE, val, nullptr);
|
||
if (val)
|
||
{
|
||
size_t len = 0;
|
||
switch (desc->type)
|
||
{
|
||
case SANE_TYPE_BOOL:
|
||
len = sizeof(SANE_Bool);
|
||
break;
|
||
case SANE_TYPE_INT:
|
||
len = sizeof(SANE_Int);
|
||
break;
|
||
case SANE_TYPE_FIXED:
|
||
len = sizeof(SANE_Fixed);
|
||
break;
|
||
case SANE_TYPE_STRING:
|
||
len = lstrlenA((char*)val);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
delete[] val;
|
||
}
|
||
|
||
SET_OPT_ID(is_multiout, IS_MULTI_OUT, extension_none)
|
||
else SET_OPT_ID(multiout_type, MULTI_OUT_TYPE, extension_multiout_type)
|
||
else SET_OPT_ID(color_mode, COLOR_MODE, extension_color_mode)
|
||
else SET_OPT_ID(erase_color, FILTER, extension_erase_color)
|
||
else SET_OPT_ID(erase_multiout_red, RID_MULTIOUT_RED, extension_none)
|
||
else SET_OPT_ID(erase_paper_red, RID_ANSWER_SHEET_RED, extension_none)
|
||
else SET_OPT_ID(is_erase_background, ERASE_BACKGROUND, extension_none)
|
||
else SET_OPT_ID(background_color_range, BKG_COLOR_RANGE, extension_none)
|
||
else SET_OPT_ID(sharpen, SHARPEN, extension_sharpen)
|
||
else SET_OPT_ID(erase_morr, RID_MORR, extension_none)
|
||
else SET_OPT_ID(erase_grids, RID_GRID, extension_none)
|
||
else SET_OPT_ID(error_extend, ERROR_EXTENSION, extension_none)
|
||
else SET_OPT_ID(is_noise_modify, NOISE_OPTIMIZE, extension_none)
|
||
else SET_OPT_ID(noise_threshold, NOISE_SIZE, extension_none)
|
||
else SET_OPT_ID(paper, PAPER, extension_paper)
|
||
else SET_OPT_ID(is_custom_area, CUSTOM_AREA, extension_none)
|
||
else SET_OPT_ID(curstom_area_l, CUSTOM_AREA_LEFT, extension_none)
|
||
else SET_OPT_ID(curstom_area_r, CUSTOM_AREA_RIGHT, extension_none)
|
||
else SET_OPT_ID(curstom_area_t, CUSTOM_AREA_TOP, extension_none)
|
||
else SET_OPT_ID(curstom_area_b, CUSTOM_AREA_BOTTOM, extension_none)
|
||
else SET_OPT_ID(is_size_check, SIZE_CHECK, extension_none)
|
||
else SET_OPT_ID(page, PAGE, extension_page)
|
||
else SET_OPT_ID(blank_page_threshold, DISCARD_BLANK_SENS, extension_none)
|
||
else SET_OPT_ID(resolution, RESOLUTION, extension_none)
|
||
else SET_OPT_ID(image_quality, IMAGE_QUALITY, extension_none)
|
||
else SET_OPT_ID(is_swap, EXCHANGE, extension_none)
|
||
else SET_OPT_ID(is_split, SPLIT, extension_none)
|
||
else SET_OPT_ID(is_auto_deskew, ANTI_SKEW, extension_none)
|
||
else SET_OPT_ID(is_custom_gamma, IS_CUSTOM_GAMMA, extension_none)
|
||
else SET_OPT_ID(bright, BRIGHTNESS, extension_none)
|
||
else SET_OPT_ID(contrast, CONTRAST, extension_none)
|
||
else SET_OPT_ID(gamma, GAMMA, extension_none)
|
||
else SET_OPT_ID(is_erase_black_frame, ERASE_BLACK_FRAME, extension_none)
|
||
else SET_OPT_ID(deep_sample, DARK_SAMPLE, extension_none)
|
||
else SET_OPT_ID(threshold, THRESHOLD, extension_none)
|
||
else SET_OPT_ID(anti_noise, ANTI_NOISE_LEVEL, extension_none)
|
||
else SET_OPT_ID(margin, MARGIN, extension_none)
|
||
else SET_OPT_ID(fill_background, FILL_BKG_MODE, extension_fill_bkg_method)
|
||
else SET_OPT_ID(is_anti_permeate, IS_ANTI_PERMEATE, extension_none)
|
||
else SET_OPT_ID(anti_permeate_level, ANTI_PERMEATE_LEVEL, extension_none)
|
||
else SET_OPT_ID(is_erase_hole, RID_HOLE, extension_none)
|
||
else SET_OPT_ID(search_hole_range, SEARCH_HOLE_RANGE, extension_none)
|
||
else SET_OPT_ID(is_filling_color, IS_FILL_COLOR, extension_none)
|
||
else SET_OPT_ID(is_ultrasonic_check, IS_ULTROSONIC_CHECK, extension_none)
|
||
else SET_OPT_ID(is_check_staple, IS_CHECK_STAPLE, extension_none)
|
||
else SET_OPT_ID(scan_mode, SCAN_MODE, extension_none)
|
||
else SET_OPT_ID(scan_count, SCAN_COUNT, extension_none)
|
||
else SET_OPT_ID(text_direction, TEXT_DIRECTION, extension_text_direction)
|
||
else SET_OPT_ID(is_rotate_bkg180, IS_ROTATE_BKG_180, extension_none)
|
||
else SET_OPT_ID(is_check_dogear, IS_CHECK_DOG_EAR, extension_none)
|
||
else SET_OPT_ID(dogear_size, DOG_EAR_SIZE, extension_none)
|
||
else SET_OPT_ID(is_check_skew, IS_CHECK_ASKEW, extension_none)
|
||
else SET_OPT_ID(skew_range, ASKEW_RANGE, extension_none)
|
||
else SET_OPT_ID(black_white_threshold, BINARY_THRESHOLD, extension_none)
|
||
else SET_OPT_ID(is_photo_mode, IS_PHOTO_MODE, extension_none)
|
||
else SET_OPT_ID(double_feed_handle, DOUBLE_FEED_HANDLE, extension_none)
|
||
else SET_OPT_ID(scan_when_paper_on, WAIT_TO_SCAN, extension_none)
|
||
else SET_OPT_ID(feed_strength, FEED_STRENGTH, extension_none)
|
||
else SET_OPT_ID(power_scheme, TIME_TO_SLEEP, extension_none)
|
||
else SET_OPT_ID(is_auto_strength, IS_AUTO_FEED_STRENGTH, extension_none)
|
||
else SET_OPT_ID(feed_strength_value , FEED_STRENGTH_VALUE, extension_none)
|
||
else SET_OPT_ID(is_reverse_bw, REVERSE_01, extension_none)
|
||
else SET_OPT_ID(is_erase_hole_l, RID_HOLE_L, extension_none)
|
||
else SET_OPT_ID(search_hole_range_l, SEARCH_HOLE_RANGE_L, extension_none)
|
||
else SET_OPT_ID(is_erase_hole_r, RID_HOLE_R, extension_none)
|
||
else SET_OPT_ID(search_hole_range_r, SEARCH_HOLE_RANGE_R, extension_none)
|
||
else SET_OPT_ID(is_erase_hole_t, RID_HOLE_T, extension_none)
|
||
else SET_OPT_ID(search_hole_range_t, SEARCH_HOLE_RANGE_T, extension_none)
|
||
else SET_OPT_ID(is_erase_hole_b, RID_HOLE_B, extension_none)
|
||
else SET_OPT_ID(search_hole_range_b, SEARCH_HOLE_RANGE_B, extension_none)
|
||
else SET_OPT_ID(fold_direction, FOLD_TYPE, extension_none)
|
||
else SET_OPT_ID(color_correction, COLOR_CORRECTION, extension_none)
|
||
else SET_OPT_ID(language, LANGUAGE, extension_none)
|
||
op_id++;
|
||
}
|
||
|
||
#define EX_APPENDIX_API(name) \
|
||
{ \
|
||
EXAPI ea; \
|
||
ea.ind = ex_##name##_id_ = ex_id_++; \
|
||
ea.ex_api = &scanner::handle_ex_##name; \
|
||
ea.base_ind = -1; \
|
||
ex_opts_.push_back(ea); \
|
||
}
|
||
EX_APPENDIX_API(final_compression);
|
||
EX_APPENDIX_API(final_format);
|
||
EX_APPENDIX_API(serial);
|
||
EX_APPENDIX_API(to_be_scan);
|
||
EX_APPENDIX_API(scan_with_hole);
|
||
EX_APPENDIX_API(device_code);
|
||
EX_APPENDIX_API(power);
|
||
EX_APPENDIX_API(hardware_version);
|
||
EX_APPENDIX_API(ip);
|
||
|
||
if (black_white_threshold_id_ == -1)
|
||
black_white_threshold_id_ = 0x8836;
|
||
|
||
if (is_erase_hole_id_ == -1)
|
||
{
|
||
// 兼容老的除孔算法
|
||
EXAPI ea;
|
||
|
||
ea.ind = is_erase_hole_id_ = ex_id_++;
|
||
ea.base_ind = is_erase_hole_l_id_;
|
||
ea.ex_api = &scanner::handle_ex_erase_hole;
|
||
ex_opts_.push_back(ea);
|
||
|
||
ea.ind = search_hole_range_id_ = ex_id_++;
|
||
ea.base_ind = search_hole_range_l_id_;
|
||
ea.ex_api = &scanner::handle_ex_search_hole_range;
|
||
ex_opts_.push_back(ea);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
char* scanner::get_opt_value(int id, int size, bool def_val)
|
||
{
|
||
char *buf = new char[size + 4];
|
||
SANE_Action act = def_val ? (SANE_Action)SANE_ACTION_GET_DEFAULT_VALUE : SANE_ACTION_GET_VALUE;
|
||
|
||
memset(buf, 0, size + 4);
|
||
if(sane_helper_->invoke_sane_control_option(handle_, id, act, buf, nullptr))
|
||
{
|
||
delete[] buf;
|
||
buf = nullptr;
|
||
}
|
||
|
||
return buf;
|
||
}
|
||
bool scanner::get_opt_value(int id, void* buf, bool def_val)
|
||
{
|
||
SANE_Action act = def_val ? (SANE_Action)SANE_ACTION_GET_DEFAULT_VALUE : SANE_ACTION_GET_VALUE;
|
||
|
||
return sane_helper_->invoke_sane_control_option(handle_, id, act, buf, nullptr) == SANE_STATUS_GOOD;
|
||
}
|
||
int scanner::control_read_string(int io_code, std::string& val)
|
||
{
|
||
char buf[256] = {0};
|
||
int ret = SCANNER_ERR_OK, len = sizeof(buf) - 1;
|
||
|
||
if(io_code == IO_CTRL_CODE_GET_SERIAL)
|
||
io_code = SANE_OPT_ID_DEVICE_SERIAL_NO;
|
||
else
|
||
io_code = -1;
|
||
|
||
if(io_code == -1)
|
||
{
|
||
ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
||
}
|
||
else
|
||
{
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, io_code, SANE_ACTION_GET_VALUE, buf, &len);
|
||
val = buf;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
void scanner::extension_none(int id)
|
||
{
|
||
}
|
||
void scanner::extension_multiout_type(int id)
|
||
{
|
||
EXAPI ea;
|
||
|
||
ex_multiout_type_id_ = ex_id_++;
|
||
ea.ind = ex_multiout_type_id_;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_multiout;
|
||
|
||
ex_opts_.push_back(ea);
|
||
}
|
||
void scanner::extension_color_mode(int id)
|
||
{
|
||
EXAPI ea;
|
||
|
||
ea.ind = ex_color_mode_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_color_mode;
|
||
ex_opts_.push_back(ea);
|
||
|
||
ex_auto_color_type_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ind = ex_auto_color_type_id_;
|
||
ea.ex_api = &scanner::handle_ex_auto_color_type;
|
||
ex_opts_.push_back(ea);
|
||
}
|
||
void scanner::extension_sharpen(int id)
|
||
{
|
||
EXAPI ea;
|
||
|
||
ex_sharpen_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ind = ex_sharpen_id_;
|
||
ea.ex_api = &scanner::handle_ex_sharpen;
|
||
|
||
ex_opts_.push_back(ea);
|
||
}
|
||
void scanner::extension_paper(int id)
|
||
{
|
||
EXAPI ea;
|
||
|
||
ea.ind = ex_paper_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_paper;
|
||
ex_opts_.push_back(ea);
|
||
|
||
ea.ind = ex_paper_lateral_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_paper_lateral;
|
||
ex_opts_.push_back(ea);
|
||
|
||
ea.ind = ex_auto_paper_size_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_auto_paper_size;
|
||
ex_opts_.push_back(ea);
|
||
|
||
ea.ind = ex_is_paper_auto_crop_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_auto_paper_crop;
|
||
ex_opts_.push_back(ea);
|
||
}
|
||
void scanner::extension_fill_bkg_method(int id)
|
||
{
|
||
EXAPI ea;
|
||
|
||
ea.ind = ex_fill_background_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_fill_background;
|
||
ex_opts_.push_back(ea);
|
||
}
|
||
void scanner::extension_text_direction(int id)
|
||
{
|
||
EXAPI ea;
|
||
|
||
ea.ind = ex_text_direction_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_text_direction;
|
||
ex_opts_.push_back(ea);
|
||
}
|
||
void scanner::extension_page(int id)
|
||
{
|
||
EXAPI ea;
|
||
char msg[128] = { 0 };
|
||
|
||
ea.ind = ex_duplex_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_duplex;
|
||
ex_opts_.push_back(ea);
|
||
{
|
||
sprintf_s(msg, _countof(msg) - 1, "handle_ex_duplex of id: %d\r\n", ea.ind);
|
||
utils::log_info(msg, (log_level)0);
|
||
}
|
||
|
||
ea.ind = ex_discard_blank_page_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_discard_blank_page;
|
||
ex_opts_.push_back(ea);
|
||
{
|
||
sprintf_s(msg, _countof(msg) - 1, "handle_ex_discard_blank_page of id: %d\r\n", ea.ind);
|
||
utils::log_info(msg, (log_level)0);
|
||
}
|
||
|
||
ea.ind = ex_discard_blank_receipt_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_discard_blank_receipt;
|
||
ex_opts_.push_back(ea);
|
||
{
|
||
sprintf_s(msg, _countof(msg) - 1, "handle_ex_discard_blank_receipt of id: %d\r\n", ea.ind);
|
||
utils::log_info(msg, (log_level)0);
|
||
}
|
||
|
||
ea.ind = ex_is_page_fold_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_page_fold;
|
||
ex_opts_.push_back(ea);
|
||
{
|
||
sprintf_s(msg, _countof(msg) - 1, "handle_ex_page_fold of id: %d\r\n", ea.ind);
|
||
utils::log_info(msg, (log_level)0);
|
||
}
|
||
}
|
||
void scanner::extension_erase_color(int id)
|
||
{
|
||
EXAPI ea;
|
||
|
||
ea.ind = ex_color_filter_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_color_filter;
|
||
ex_opts_.push_back(ea);
|
||
|
||
ea.ind = ex_color_enhance_id_ = ex_id_++;
|
||
ea.base_ind = id;
|
||
ea.ex_api = &scanner::handle_ex_color_enhance;
|
||
ex_opts_.push_back(ea);
|
||
}
|
||
bool scanner::get_option_value_with_parent(int sn, set_opt_value setv, void* param) // return true if handled
|
||
{
|
||
bool handled = true;
|
||
|
||
if (sn == scan_count_id_)
|
||
{
|
||
const SANE_Option_Descriptor* parent = sane_helper_->invoke_sane_get_option_descriptor(handle_, scan_mode_id_);
|
||
char* buf = new char[parent->size + 4];
|
||
|
||
memset(buf, 0, parent->size);
|
||
sane_helper_->invoke_sane_control_option(handle_, scan_mode_id_, SANE_ACTION_GET_VALUE, buf, nullptr);
|
||
handled = compare_sane_opt(local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr), buf);
|
||
if (handled)
|
||
{
|
||
int count = -1;
|
||
value_role role = VAL_ROLE_CURRENT;
|
||
sane_helper_->invoke_sane_control_option(handle_, scan_mode_id_, (SANE_Action)SANE_ACTION_GET_DEFAULT_VALUE, buf, nullptr);
|
||
if (compare_sane_opt(local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr), buf))
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
|
||
setv(&count, role, VAL_LIMIT_NONE, param);
|
||
}
|
||
delete[] buf;
|
||
}
|
||
else
|
||
handled = false;
|
||
|
||
return handled;
|
||
}
|
||
bool scanner::set_option_value_with_parent(int sn, void* data, int* err) // return true if handled sn
|
||
{
|
||
bool handled = false;
|
||
|
||
if (sn == scan_count_id_)
|
||
{
|
||
const SANE_Option_Descriptor* parent = sane_helper_->invoke_sane_get_option_descriptor(handle_, scan_mode_id_);
|
||
char* val = get_opt_value(scan_mode_id_, parent->size, false);
|
||
SANE_Int after = 0;
|
||
|
||
if(val)
|
||
{
|
||
if (compare_sane_opt(local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr), val))
|
||
{
|
||
if (*(int*)data != -1)
|
||
{
|
||
strcpy(val, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_SMZDZS, true, nullptr));
|
||
*err = sane_helper_->invoke_sane_control_option(handle_, scan_mode_id_, SANE_ACTION_SET_VALUE, val, &after);
|
||
}
|
||
}
|
||
else if (*(int*)data == -1)
|
||
{
|
||
strcpy(val, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr));
|
||
*err = sane_helper_->invoke_sane_control_option(handle_, scan_mode_id_, SANE_ACTION_SET_VALUE, val, &after);
|
||
}
|
||
delete[] val;
|
||
}
|
||
}
|
||
|
||
return handled;
|
||
}
|
||
int scanner::set_option_value(int sn, SANE_Value_Type type, int size, void* data)
|
||
{
|
||
char* buf = nullptr;
|
||
SANE_Bool sb = SANE_FALSE;
|
||
SANE_Int si = 0, after = 0;
|
||
SANE_Fixed sf = 0;
|
||
int ret = SCANNER_ERR_OK;
|
||
void* val = data;
|
||
|
||
if (type == SANE_TYPE_BOOL)
|
||
{
|
||
sb = *(bool*)data ? SANE_TRUE : SANE_FALSE;
|
||
val = &sb;
|
||
}
|
||
else if (type == SANE_TYPE_INT)
|
||
{
|
||
si = *(int*)data;
|
||
val = &si;
|
||
}
|
||
else if (type == SANE_TYPE_FIXED)
|
||
{
|
||
sf = SANE_FIX(*(float*)data);
|
||
val = &sf;
|
||
}
|
||
else
|
||
{
|
||
buf = new char[size + 4];
|
||
memset(buf, 0, size + 4);
|
||
strcpy(buf, ((std::string*)data)->c_str());
|
||
val = buf;
|
||
}
|
||
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, sn, SANE_ACTION_SET_VALUE, val, &after);
|
||
|
||
if (type == SANE_TYPE_BOOL)
|
||
{
|
||
*(bool*)data = sb == SANE_TRUE;
|
||
}
|
||
else if (type == SANE_TYPE_INT)
|
||
{
|
||
*(int*)data = si;
|
||
}
|
||
else if (type == SANE_TYPE_FIXED)
|
||
{
|
||
*(float*)data = (float)SANE_UNFIX(sf);
|
||
}
|
||
else if(buf)
|
||
{
|
||
strcpy((char*)val, buf);
|
||
delete[] buf;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
int scanner::set_is_multiout(bool enable)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
|
||
if (is_multiout_id_ > 0)
|
||
{
|
||
SANE_Bool multi = SANE_FALSE;
|
||
SANE_Int after = 0;
|
||
char *val = get_opt_value(is_multiout_id_, 4, false);
|
||
|
||
if(val)
|
||
{
|
||
multi = *(SANE_Bool*)val;
|
||
delete[] val;
|
||
}
|
||
if (enable ^ (multi == SANE_TRUE))
|
||
{
|
||
multi = enable ? SANE_TRUE : SANE_FALSE;
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, is_multiout_id_, SANE_ACTION_SET_VALUE, &multi, &after);
|
||
after = 0;
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
int scanner::thread_start(void)
|
||
{
|
||
int ret = sane_helper_->invoke_sane_start(handle_);
|
||
|
||
// the third-APPs in linux will call 'stop' after every start, but it not happens in windows-apps, so we handle this as following ...
|
||
if (ret == SANE_STATUS_NO_DOCS && prev_start_result_ == SANE_STATUS_GOOD)
|
||
ret = sane_helper_->invoke_sane_start(handle_);
|
||
|
||
if (ret == SANE_STATUS_GOOD)
|
||
{
|
||
/*if (indicator_.get() && !IsWindowVisible(indicator_->hwnd()))
|
||
indicator_->show(true);*/
|
||
|
||
// unsigned int l = sizeof(img_fmt_);
|
||
// SANE_CompressionType cmprsn = img_fmt_.compress.compression;
|
||
// if (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_IMAGE_FORMAT, &img_fmt_, &l))
|
||
// img_fmt_.img_format = SANE_IMAGE_TYPE_BMP;
|
||
// img_fmt_.compress.compression = cmprsn;
|
||
}
|
||
//else if (indicator_.get())
|
||
//{
|
||
// indicator_->notify_scan_over(sane_helper_->invoke_sane_strstatus((SANE_Status)ret), true);
|
||
//}
|
||
else
|
||
{
|
||
// display error message on progress UI, may be closed immediately by APP, so we hide progress UI and call message_box ...
|
||
//
|
||
#ifdef START_SCAN_IN_THREAD
|
||
if (callback::show_progress_ui && is_bIndicator && ui_notify)
|
||
{
|
||
int ev = SANE_EVENT_WORKING;
|
||
|
||
ui_notify(SANE_EVENT_SCAN_FINISHED, (void *)sane_helper_->invoke_sane_strstatus((SANE_Status)ret), ret);
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
if (callback::close_ui)
|
||
callback::close_ui(UI_INDICATOR);
|
||
|
||
if (callback::show_messagebox_ui)
|
||
{
|
||
callback::show_messagebox_ui(app_wnd_, ret, (void*)sane_helper_->invoke_sane_strstatus((SANE_Status)ret), 0);
|
||
}
|
||
// else
|
||
// {
|
||
// std::string msg(local_trans::a2u(sane_helper_->invoke_sane_strstatus((SANE_Status)ret), CP_UTF8));
|
||
|
||
// //if (indicator_.get())
|
||
// // indicator_->show(false);
|
||
// if (!IsWindow(app_wnd_))
|
||
// callback::bring_message_box_topmost(local_trans::lang_trans_between_hz936(CONST_STRING_START_FAILED).c_str());
|
||
// MessageBoxW(app_wnd_, msg.c_str(), local_trans::lang_trans_between_hz936(CONST_STRING_START_FAILED).c_str(), MB_OK | MB_ICONERROR);
|
||
// }
|
||
is_scanning_ = false;
|
||
}
|
||
}
|
||
prev_start_result_ = ret;
|
||
|
||
return ret;
|
||
}
|
||
|
||
scanner::EXAPIPOS scanner::find_ex_api(int op_id)
|
||
{
|
||
return std::find(ex_opts_.begin(), ex_opts_.end(), op_id);
|
||
}
|
||
|
||
EX_OPTION_HANDLER_IMPL(multiout)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
SANE_Bool parent = SANE_FALSE;
|
||
void *val = get_opt_value(is_multiout_id_, sizeof(SANE_Bool), false);
|
||
|
||
if(val)
|
||
{
|
||
parent = *(SANE_Bool*)val;
|
||
delete[] val;
|
||
}
|
||
|
||
if (setv)
|
||
{
|
||
char* cur = get_opt_value(base_id, desc->size, false),
|
||
* def = get_opt_value(base_id, desc->size, true);
|
||
int now = sane_opt_trans::multiout_value_to_twain(cur),
|
||
init = sane_opt_trans::multiout_value_to_twain(def),
|
||
val = 0;
|
||
|
||
delete[] def;
|
||
delete[] cur;
|
||
|
||
{
|
||
// parent item ...
|
||
if (!parent)
|
||
now = MULTI_OUT_NONE;
|
||
}
|
||
|
||
do
|
||
{
|
||
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
|
||
{
|
||
// we have no 'MULTI_OUT_NONE' item in this option, this is used as is_multiout_id_
|
||
val = MULTI_OUT_NONE;
|
||
value_role role = val == now ? VAL_ROLE_CURRENT : VAL_ROLE_NONE;
|
||
if (val == init)
|
||
role = (value_role)(role | VAL_ROLE_DEFAULT);
|
||
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
|
||
break;
|
||
for (int i = 0; desc->constraint.string_list[i]; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
val = sane_opt_trans::multiout_value_to_twain(desc->constraint.string_list[i]);
|
||
if (val == now)
|
||
role = VAL_ROLE_CURRENT;
|
||
if (val == init)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
set_cur_and_def_value<int>(now, init, setv, data);
|
||
} while (0);
|
||
}
|
||
else
|
||
{
|
||
char* val = new char[desc->size];
|
||
const char* in = sane_opt_trans::multiout_value_from_twain(*(int*)data);
|
||
SANE_Int after = 0;
|
||
|
||
//if (in && strcmp(in, "\346\227\240"))
|
||
//{
|
||
// ret = set_is_multiout(true);
|
||
// if (ret == SANE_STATUS_GOOD)
|
||
// {
|
||
strcpy(val, in);
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, val, &after);
|
||
// }
|
||
//}
|
||
//else
|
||
//{
|
||
// // disable multi-out, let multiout type aside
|
||
// ret = set_is_multiout(false);
|
||
//}
|
||
delete[] val;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(auto_color_type)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
int len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
char* def = get_opt_value(base_id, desc->size, true);
|
||
int init = sane_opt_trans::auto_color_type_to_twain(def);
|
||
|
||
delete[] def;
|
||
len = sane_opt_trans::auto_color_type_to_twain(buf);
|
||
set_cur_and_def_value<int>(len, init, setv, data);
|
||
}
|
||
else
|
||
{
|
||
SANE_Int after = 0;
|
||
|
||
// ret = set_is_multiout(false);
|
||
if (ret == SCANNER_ERR_OK)
|
||
{
|
||
strcpy(buf, sane_opt_trans::auto_color_type_from_twain(*(int*)data));
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
}
|
||
ret = ret;
|
||
}
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(color_mode)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
|
||
if (setv)
|
||
{
|
||
char* cur = get_opt_value(base_id, desc->size, false),
|
||
* def = get_opt_value(base_id, desc->size, true);
|
||
int now = sane_opt_trans::color_mode_to_twain(cur), // sane_opt_trans::multiout_value_to_twain(cur)
|
||
init = sane_opt_trans::color_mode_to_twain(def),
|
||
val = 0;
|
||
|
||
delete[] def;
|
||
delete[] cur;
|
||
|
||
do
|
||
{
|
||
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
|
||
{
|
||
for (int i = 0; desc->constraint.string_list[i]; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
val = sane_opt_trans::color_mode_to_twain(desc->constraint.string_list[i]);
|
||
if (val == now)
|
||
role = VAL_ROLE_CURRENT;
|
||
if (val == init)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
set_cur_and_def_value<int>(now, init, setv, data);
|
||
} while (0);
|
||
}
|
||
else
|
||
{
|
||
SANE_Int after = 0;
|
||
|
||
// ret = set_is_multiout(false);
|
||
if (ret == SCANNER_ERR_OK)
|
||
{
|
||
char* val = new char[desc->size];
|
||
const char* in = sane_opt_trans::color_mode_from_twain(*(int*)data);
|
||
|
||
strcpy(val, in);
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, val, &after);
|
||
delete[] val;
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(sharpen)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
|
||
if (setv)
|
||
{
|
||
char* cur = get_opt_value(base_id, desc->size, false),
|
||
* def = get_opt_value(base_id, desc->size, true);
|
||
int now = sane_opt_trans::multiout_value_to_twain(cur),
|
||
init = sane_opt_trans::sharpen_to_twain(def),
|
||
val = 0;
|
||
|
||
delete[] def;
|
||
delete[] cur;
|
||
|
||
do
|
||
{
|
||
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
|
||
{
|
||
for (int i = 0; desc->constraint.string_list[i]; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
val = sane_opt_trans::sharpen_to_twain(desc->constraint.string_list[i]);
|
||
if (val == now)
|
||
role = VAL_ROLE_CURRENT;
|
||
if (val == init)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
set_cur_and_def_value<int>(now, init, setv, data);
|
||
} while (0);
|
||
}
|
||
else
|
||
{
|
||
char* val = new char[desc->size];
|
||
const char* in = sane_opt_trans::sharpen_from_twain(*(int*)data);
|
||
SANE_Int after = 0;
|
||
|
||
strcpy(val, in);
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, val, &after);
|
||
delete[] val;
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(paper)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
int len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
char* def = get_opt_value(base_id, desc->size, true);
|
||
int now = sane_opt_trans::paper_to_twain(buf),
|
||
init = sane_opt_trans::paper_to_twain(def),
|
||
val = 0;
|
||
|
||
delete[] def;
|
||
do
|
||
{
|
||
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
|
||
{
|
||
for (int i = 0; desc->constraint.string_list[i]; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
val = sane_opt_trans::paper_to_twain(desc->constraint.string_list[i]);
|
||
if (val == -1)
|
||
continue;
|
||
if (val == now)
|
||
role = VAL_ROLE_CURRENT;
|
||
if (val == init)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
set_cur_and_def_value<int>(now, init, setv, data);
|
||
} while (0);
|
||
}
|
||
else if (sane_opt_trans::paper_from_twain(*(int*)data))
|
||
{
|
||
SANE_Int after = 0;
|
||
strcpy(buf, sane_opt_trans::paper_from_twain(*(int*)data));
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
}
|
||
else
|
||
ret = SCANNER_ERR_INVALID_PARAMETER;
|
||
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(paper_lateral)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
int len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
const char* lateral_swap = nullptr;
|
||
bool lateral = false;
|
||
|
||
lateral_swap = sane_opt_trans::switch_paper_lateral(buf);
|
||
lateral = sane_opt_trans::is_paper_lateral(buf);
|
||
if (setv)
|
||
{
|
||
set_cur_and_def_value<bool>(lateral, false, setv, data);
|
||
}
|
||
else if (lateral_swap)
|
||
{
|
||
SANE_Int after = 0;
|
||
if (lateral != *(bool*)data)
|
||
{
|
||
strcpy(buf, lateral_swap);
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SANE_Int after = 0;
|
||
if (*(bool*)data)
|
||
{
|
||
// set to A4Lateral ...
|
||
strcpy(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_A4HX, true, nullptr));
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
//ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
||
}
|
||
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(auto_paper_size)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
int len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
char* init = get_opt_value(base_id, desc->size, true);
|
||
bool yes = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_PPYSCC, true, nullptr)) == 0,
|
||
def = strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_PPYSCC, true, nullptr)) == 0;
|
||
|
||
delete[] init;
|
||
set_cur_and_def_value<bool>(yes, def, setv, data);
|
||
}
|
||
else
|
||
{
|
||
SANE_Int after = 0;
|
||
strcpy(buf, *(bool*)data ? local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_PPYSCC, true, nullptr) : local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_A4, true, nullptr));
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(auto_paper_crop)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
int len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
char* init = get_opt_value(base_id, desc->size, true);
|
||
bool yes = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_ZDSMCCZDCQ, true, nullptr)) == 0,
|
||
def = strcmp(init, OPTION_VALUE_ZZCC_ZDSMCCZDCQ) == 0;
|
||
|
||
delete[] init;
|
||
set_cur_and_def_value<bool>(yes, def, setv, data);
|
||
}
|
||
else
|
||
{
|
||
SANE_Int after = 0;
|
||
strcpy(buf, *(bool*)data ? local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_ZDSMCCZDCQ, true, nullptr) : local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_ZDSMCC, true, nullptr));
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(text_direction)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
int len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
char* def = get_opt_value(base_id, desc->size, true);
|
||
float now = .0f, init = sane_opt_trans::text_direction_to_twain(def), val = .0f;
|
||
|
||
delete[] def;
|
||
now = sane_opt_trans::text_direction_to_twain(buf);
|
||
do
|
||
{
|
||
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
|
||
{
|
||
for (int i = 0; desc->constraint.string_list[i]; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
val = sane_opt_trans::text_direction_to_twain(desc->constraint.string_list[i]);
|
||
if (IS_DOUBLE_EQUAL(val, now))
|
||
role = VAL_ROLE_CURRENT;
|
||
if (IS_DOUBLE_EQUAL(val, init))
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
set_cur_and_def_value<float>(now, init, setv, data);
|
||
} while (0);
|
||
}
|
||
else
|
||
{
|
||
SANE_Int after = 0;
|
||
|
||
strcpy(buf, sane_opt_trans::text_direction_from_twain(*(float*)data));
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(duplex)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
bool val = *(bool*)data;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
unsigned len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
char* init = get_opt_value(base_id, desc->size, true);
|
||
|
||
set_cur_and_def_value<bool>(strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_SM, true, nullptr)) == 0, strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_SM, true, nullptr)) == 0, setv, data);
|
||
delete[] init;
|
||
}
|
||
else
|
||
{
|
||
strcpy(buf, val ? local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_SM, true, nullptr) : local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_DM, true, nullptr));
|
||
SANE_Int after = 0;
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(fill_background)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
bool val = *(bool*)data;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
unsigned len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
char* init = get_opt_value(base_id, desc->size, true);
|
||
val = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_SM, true, nullptr)) == 0;
|
||
set_cur_and_def_value<bool>(strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_BJTCFS_TDBX, true, nullptr)) == 0, strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_BJTCFS_TDBX, true, nullptr)) == 0, setv, data);
|
||
delete[] init;
|
||
}
|
||
else
|
||
{
|
||
strcpy(buf, val ? local_trans::lang_trans_between_hz936(OPTION_VALUE_BJTCFS_TDBX, true, nullptr) : local_trans::lang_trans_between_hz936(OPTION_VALUE_BJTCFS_ADBX, true, nullptr));
|
||
SANE_Int after = 0;
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(discard_blank_page)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
bool val = *(bool*)data;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
unsigned len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
char* init = get_opt_value(base_id, desc->size, true);
|
||
bool def = strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYTY, true, nullptr)) == 0;
|
||
|
||
delete[] init;
|
||
val = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYTY, true, nullptr)) == 0;
|
||
set_cur_and_def_value<bool>(val, def, setv, data);
|
||
}
|
||
else
|
||
{
|
||
if (val)
|
||
strcpy(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYTY, true, nullptr));
|
||
else
|
||
{
|
||
char* init = get_opt_value(base_id, desc->size, true);
|
||
strcpy(buf, init);
|
||
delete[] init;
|
||
}
|
||
SANE_Int after = 0;
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(discard_blank_receipt)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
bool val = *(bool*)data;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
unsigned len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
char* init = get_opt_value(base_id, desc->size, true);
|
||
bool def = strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYFPZ, true, nullptr)) == 0;
|
||
|
||
delete[] init;
|
||
val = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYFPZ, true, nullptr)) == 0;
|
||
set_cur_and_def_value<bool>(val, def, setv, data);
|
||
}
|
||
else
|
||
{
|
||
if (val)
|
||
strcpy(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYFPZ, true, nullptr));
|
||
else
|
||
{
|
||
char* init = get_opt_value(base_id, desc->size, true);
|
||
strcpy(buf, init);
|
||
delete[] init;
|
||
}
|
||
SANE_Int after = 0;
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(page_fold)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
bool val = *(bool*)data;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
unsigned len = desc->size + 4;
|
||
char* buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
char* init = get_opt_value(base_id, desc->size, true);
|
||
bool def = strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_DZ, true, nullptr)) == 0;
|
||
|
||
delete[] init;
|
||
val = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_DZ, true, nullptr)) == 0;
|
||
set_cur_and_def_value<bool>(val, def, setv, data);
|
||
}
|
||
else
|
||
{
|
||
if (val)
|
||
strcpy(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_DZ, true, nullptr));
|
||
else
|
||
{
|
||
char* init = get_opt_value(base_id, desc->size, true);
|
||
strcpy(buf, init);
|
||
delete[] init;
|
||
}
|
||
SANE_Int after = 0;
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
delete[] buf;
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(color_filter) // int (filter_value)
|
||
{
|
||
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
char* buf = nullptr;
|
||
unsigned int len = 0;
|
||
|
||
if (desc)
|
||
{
|
||
len = desc->size + 4;
|
||
buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
bool filter = false;
|
||
int val = FILTER_NONE, now = FILTER_NONE;
|
||
now = sane_opt_trans::filter_enhance_value_to_twain(buf, &filter);
|
||
if (!filter)
|
||
now = val;
|
||
do
|
||
{
|
||
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
|
||
{
|
||
for (int i = 0; desc->constraint.string_list[i]; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
int v = sane_opt_trans::filter_enhance_value_to_twain(desc->constraint.string_list[i], &filter);
|
||
if (!filter && v != FILTER_NONE)
|
||
continue;
|
||
if (v == now)
|
||
role = VAL_ROLE_CURRENT;
|
||
if (v == val)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
if (!setv(&v, role, VAL_LIMIT_ENUM, data))
|
||
break;
|
||
}
|
||
}
|
||
}while (0);
|
||
}
|
||
else
|
||
{
|
||
const char* val = sane_opt_trans::filter_enhance_value_from_twain(*((int*)data), true);
|
||
SANE_Int after = 0;
|
||
|
||
strcpy(buf, val);
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
delete[] buf;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(color_enhance) // int (enhance_value)
|
||
{
|
||
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
char* buf = nullptr;
|
||
unsigned int len = 0;
|
||
|
||
if (desc)
|
||
{
|
||
len = desc->size + 4;
|
||
buf = get_opt_value(base_id, desc->size, false);
|
||
|
||
if (setv)
|
||
{
|
||
bool filter = false;
|
||
int val = ENHANCE_NONE, now = ENHANCE_NONE;
|
||
now = sane_opt_trans::filter_enhance_value_to_twain(buf, &filter);
|
||
if (filter)
|
||
now = val;
|
||
do
|
||
{
|
||
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
|
||
{
|
||
for (int i = 0; desc->constraint.string_list[i]; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
int v = sane_opt_trans::filter_enhance_value_to_twain(desc->constraint.string_list[i], &filter);
|
||
if (filter && v != ENHANCE_NONE)
|
||
continue;
|
||
if (v == now)
|
||
role = VAL_ROLE_CURRENT;
|
||
if (v == val)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
if (!setv(&v, role, VAL_LIMIT_ENUM, data))
|
||
break;
|
||
}
|
||
}
|
||
} while (0);
|
||
}
|
||
else
|
||
{
|
||
const char* val = sane_opt_trans::filter_enhance_value_from_twain(*((int*)data), false);
|
||
SANE_Int after = 0;
|
||
|
||
strcpy(buf, val);
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
delete[] buf;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
EX_OPTION_HANDLER_IMPL(final_compression)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
int* compression = (int*)data;
|
||
unsigned int len = sizeof(*compression);
|
||
|
||
if (setv)
|
||
{
|
||
if (ret == SANE_STATUS_GOOD)
|
||
{
|
||
int i = SANE_COMPRESSION_FIRST;
|
||
for (; i < SANE_COMPRESSION_LAST; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
if (i == img_fmt_.img_format)
|
||
role = VAL_ROLE_CURRENT;
|
||
if (i == SANE_COMPRESSION_NONE)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
int v = sane_opt_trans::compression_to_twain(i);
|
||
if (!setv(&v, role, VAL_LIMIT_ENUM, data))
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int val = sane_opt_trans::compression_from_twain(*(int*)data);
|
||
len = sizeof(val);
|
||
// ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_FINAL_COMPRESSION, &val, &len);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
img_fmt_.compress.compression = (SANE_CompressionType)val;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(final_format)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
SANE_FinalImgFormat ff = img_fmt_;
|
||
unsigned int len = sizeof(ff);
|
||
|
||
if (setv)
|
||
{
|
||
if (ret == SANE_STATUS_GOOD)
|
||
{
|
||
int now = ff.img_format, init = SANE_IMAGE_TYPE_BMP;
|
||
std::vector<int> all(sane_opt_trans::support_image_types());
|
||
for (int i = 0; i < (int)all.size(); ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
ff.img_format = (SANE_ImageType)all[i];
|
||
if (ff.img_format == now)
|
||
role = VAL_ROLE_CURRENT;
|
||
if (ff.img_format == init)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
if (!setv(&ff, role, VAL_LIMIT_ENUM, data))
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
img_fmt_ = *(SANE_FinalImgFormat*)data;
|
||
// ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_FINAL_IMAGE_FORMAT, data, &len);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(serial)
|
||
{
|
||
int ret = SCANNER_ERR_INVALID_PARAMETER;
|
||
if (setv)
|
||
{
|
||
std::string val("");
|
||
|
||
ret = control_read_string(IO_CTRL_CODE_GET_SERIAL, val);
|
||
if (ret == SANE_STATUS_GOOD)
|
||
setv(&val, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, data);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(to_be_scan)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
SANE_Bool wait_paper = SANE_FALSE;
|
||
SANE_Int len = sizeof(wait_paper);
|
||
|
||
if (setv)
|
||
{
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_WAIT_TO_SCAN, SANE_ACTION_GET_VALUE, &wait_paper, &len);
|
||
if (ret == SANE_STATUS_GOOD)
|
||
{
|
||
bool val = wait_paper == SANE_TRUE;
|
||
|
||
set_cur_and_def_value<bool>(val, false, setv, data);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
wait_paper = *((bool*)data) ? SANE_TRUE : SANE_FALSE;
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_WAIT_TO_SCAN, SANE_ACTION_SET_VALUE, &wait_paper, &len);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(scan_with_hole)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
SANE_Bool with_hole = SANE_FALSE;
|
||
SANE_Int len = sizeof(with_hole);
|
||
|
||
if (setv)
|
||
{
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_RID_HOLE, SANE_ACTION_GET_VALUE, &with_hole, &len);
|
||
if (ret == SANE_STATUS_GOOD)
|
||
{
|
||
bool val = with_hole == SANE_TRUE;
|
||
|
||
set_cur_and_def_value<bool>(val, false, setv, data);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
with_hole = *((bool*)data) ? SANE_TRUE : SANE_FALSE;
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_RID_HOLE, SANE_ACTION_SET_VALUE, &with_hole, &len);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(device_code)
|
||
{
|
||
int ret = SCANNER_ERR_INVALID_PARAMETER;
|
||
if (setv)
|
||
{
|
||
std::string val("");
|
||
|
||
ret = control_read_string(IO_CTRL_CODE_GET_SERIAL, val);
|
||
if (ret == SANE_STATUS_GOOD)
|
||
setv(&val, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, data);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(power)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
|
||
if (setv)
|
||
{
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, SANE_OPT_ID_TIME_TO_SLEEP);
|
||
if(desc)
|
||
{
|
||
char init[256] = {0}, now[256] = {0};
|
||
int len = sizeof(now) - 1;
|
||
value_role role = VAL_ROLE_NONE;
|
||
int8_t power = SANE_POWER_NONE, cur = SANE_POWER_NONE, def = SANE_POWER_NONE;
|
||
|
||
sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_TIME_TO_SLEEP, SANE_ACTION_GET_VALUE, now, &len);
|
||
len = sizeof(init) - 1;
|
||
sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_TIME_TO_SLEEP, (SANE_Action)SANE_ACTION_GET_DEFAULT_VALUE, init, &len);
|
||
cur = sane_opt_trans::sleep_time(now);
|
||
def = sane_opt_trans::sleep_time(init);
|
||
if(desc->constraint_type == SANE_CONSTRAINT_STRING_LIST && desc->constraint.string_list)
|
||
{
|
||
for(int i = 0; desc->constraint.string_list[i]; ++i)
|
||
{
|
||
power = sane_opt_trans::sleep_time(desc->constraint.string_list[i]);
|
||
role = VAL_ROLE_NONE;
|
||
if(power == cur)
|
||
role = VAL_ROLE_CURRENT;
|
||
if(power == def)
|
||
role = (value_role)(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT);
|
||
if(!setv(&power, role, VAL_LIMIT_NONE, data))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
role = VAL_ROLE_CURRENT;
|
||
if(cur == def)
|
||
{
|
||
role = (value_role)(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT);
|
||
setv(&cur, role, VAL_LIMIT_NONE, data);
|
||
}
|
||
else
|
||
{
|
||
setv(&cur, role, VAL_LIMIT_NONE, data);
|
||
setv(&def, VAL_ROLE_DEFAULT, VAL_LIMIT_NONE, data);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SANE_Power power = *((SANE_Power*)data);
|
||
char buf[128] = {0};
|
||
unsigned int len = sizeof(buf);
|
||
|
||
strcpy(buf, sane_opt_trans::sleep_time(power));
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_TIME_TO_SLEEP, SANE_ACTION_SET_VALUE, buf, (SANE_Int*)&len);
|
||
*(int*)data = sane_opt_trans::sleep_time(buf);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(hardware_version)
|
||
{
|
||
int ret = SCANNER_ERR_INVALID_PARAMETER;
|
||
if (setv)
|
||
{
|
||
std::string val("");
|
||
|
||
ret = control_read_string(IO_CTRL_CODE_GET_HARDWARE_VERSION, val);
|
||
if (ret == SANE_STATUS_GOOD)
|
||
setv(&val, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, data);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(ip)
|
||
{
|
||
int ret = SCANNER_ERR_INVALID_PARAMETER;
|
||
if (setv)
|
||
{
|
||
std::string val("");
|
||
|
||
ret = control_read_string(IO_CTRL_CODE_GET_IP, val);
|
||
if (ret == SANE_STATUS_GOOD)
|
||
setv(&val, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, data);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(erase_hole)
|
||
{
|
||
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
||
if (is_erase_hole_l_id_ != -1 || is_erase_hole_r_id_ != -1)
|
||
{
|
||
SANE_Bool yes = SANE_FALSE, def = SANE_FALSE;
|
||
SANE_Int after = 0;
|
||
if (setv)
|
||
{
|
||
if (is_erase_hole_l_id_ != -1)
|
||
{
|
||
get_opt_value(is_erase_hole_l_id_, &yes, false);
|
||
get_opt_value(is_erase_hole_l_id_, &def, true);
|
||
}
|
||
if (!yes && is_erase_hole_r_id_ != -1)
|
||
{
|
||
get_opt_value(is_erase_hole_r_id_, &yes, false);
|
||
get_opt_value(is_erase_hole_r_id_, &def, true);
|
||
}
|
||
|
||
set_cur_and_def_value<bool>(yes == SANE_TRUE, def == SANE_TRUE, setv, data);
|
||
ret = SCANNER_ERR_OK;
|
||
}
|
||
else
|
||
{
|
||
yes = *(bool*)data ? SANE_TRUE : SANE_FALSE;
|
||
if (is_erase_hole_l_id_ != -1)
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, is_erase_hole_l_id_, SANE_ACTION_SET_VALUE, &yes, &after);
|
||
yes = *(bool*)data ? SANE_TRUE : SANE_FALSE;
|
||
if (is_erase_hole_r_id_ != -1)
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, is_erase_hole_r_id_, SANE_ACTION_SET_VALUE, &yes, &after);
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
EX_OPTION_HANDLER_IMPL(search_hole_range)
|
||
{
|
||
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
||
if (search_hole_range_l_id_ != -1 || search_hole_range_r_id_ != -1)
|
||
{
|
||
SANE_Fixed val = 0;
|
||
SANE_Int after = 0;
|
||
double rv = .0f, def = .0f;
|
||
if (setv)
|
||
{
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, base_id);
|
||
void* init = get_opt_value(base_id, desc->size, true),
|
||
* cur = get_opt_value(base_id, desc->size, false);
|
||
float n = SANE_UNFIX(*(SANE_Fixed*)cur),
|
||
d = SANE_UNFIX(*(SANE_Fixed*)init);
|
||
|
||
if (desc->constraint_type == SANE_CONSTRAINT_RANGE)
|
||
{
|
||
float l = SANE_UNFIX(desc->constraint.range->min),
|
||
u = SANE_UNFIX(desc->constraint.range->max),
|
||
s = SANE_UNFIX(desc->constraint.range->quant);
|
||
set_value_range<SANE_Fixed, float>(*(SANE_Fixed*)cur, *(SANE_Fixed*)init, desc->constraint.range->min, desc->constraint.range->max, desc->constraint.range->quant, setv, data, &scanner::to_float);
|
||
}
|
||
else
|
||
set_cur_and_def_value<float>(n, d, setv, data);
|
||
delete[] init;
|
||
delete[] cur;
|
||
|
||
ret = SCANNER_ERR_OK;
|
||
}
|
||
else
|
||
{
|
||
rv = (double)*(float*)data;
|
||
val = SANE_FIX(rv);
|
||
if (search_hole_range_l_id_ != -1)
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, search_hole_range_l_id_, SANE_ACTION_SET_VALUE, &val, &after);
|
||
val = SANE_FIX(rv);
|
||
if (search_hole_range_r_id_ != -1)
|
||
ret = sane_helper_->invoke_sane_control_option(handle_, search_hole_range_r_id_, SANE_ACTION_SET_VALUE, &val, &after);
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
// ISaneInvoker
|
||
COM_API_IMPLEMENT(scanner, int, start(void))
|
||
{
|
||
int ret = SANE_STATUS_GOOD;
|
||
|
||
ev_cnt_ = 0;
|
||
events_.clear();
|
||
images_.clear();
|
||
scan_msg_ = "OK";
|
||
scan_err_ = false;
|
||
user_cancel_ = false;
|
||
fetch_imgs_ = 0;
|
||
is_scanning_ = true;
|
||
app_wnd_ = callback::find_main_wnd();
|
||
|
||
if (thread_starting_.get() && thread_starting_->joinable())
|
||
thread_starting_->join();
|
||
#ifdef START_SCAN_IN_THREAD
|
||
thread_starting_.reset(new std::thread(&scanner::thread_start, this));
|
||
#else
|
||
ret = thread_start();
|
||
#endif
|
||
|
||
return ret;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, int, stop(void))
|
||
{
|
||
user_cancel_ = true;
|
||
|
||
sane_helper_->invoke_sane_cancel(handle_);
|
||
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, int, get_event(void))
|
||
{
|
||
return events_.take();
|
||
}
|
||
COM_API_IMPLEMENT(scanner, void, set_event_callback(int(* handle_ev)(int, void*), void* para))
|
||
{
|
||
scanner_ev_handler_ = handle_ev;
|
||
evh_param_ = para;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, bool, wait_image(DWORD milliseconds))
|
||
{
|
||
int count = get_scanned_images(milliseconds);
|
||
|
||
return count > 0;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, int, get_scanned_images(DWORD milliseconds))
|
||
{
|
||
size_t count = images_.count();
|
||
DWORD elapse = 2;
|
||
|
||
is_ui_wait_img_ = true;
|
||
while (is_scanning_ && count == 0 && milliseconds)
|
||
{
|
||
// MSG msg = { 0 };
|
||
// if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
|
||
// {
|
||
// TranslateMessage(&msg);
|
||
// DispatchMessageW(&msg);
|
||
// }
|
||
// else
|
||
Sleep(elapse);
|
||
|
||
count = images_.count();
|
||
|
||
//int ev = get_event();
|
||
//
|
||
|
||
//if (ev == SANE_EVENT_SCAN_FINISHED)
|
||
//{
|
||
// ui_hide();
|
||
// break;
|
||
//}
|
||
//else if (ev == SANE_EVENT_UI_CLOSE_CANCEL)
|
||
//{
|
||
// stop();
|
||
// ui_hide();
|
||
// break;
|
||
//}
|
||
//else if (ev == SANE_EVENT_UI_CLOSE_NORMAL)
|
||
//{
|
||
// ui_hide();
|
||
// break;
|
||
//}
|
||
if (milliseconds != -1)
|
||
{
|
||
if (milliseconds <= elapse)
|
||
break;
|
||
|
||
milliseconds -= elapse;
|
||
}
|
||
}
|
||
is_ui_wait_img_ = false;
|
||
count = images_.count();
|
||
|
||
{
|
||
char msg[128] = { 0 };
|
||
sprintf_s(msg, _countof(msg) - 1, "Wait image count = %d\r\n", count);
|
||
utils::log_info(msg, (log_level)1);
|
||
}
|
||
|
||
return count;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(twain_xfer xfer))
|
||
{
|
||
scanned_img* img = images_.take(false);
|
||
|
||
if (img)
|
||
{
|
||
img->prepare_data_for_transfer(xfer);
|
||
img->add_ref();
|
||
|
||
utils::to_log(LOG_LEVEL_DEBUG, "Begin transferring image %d of %p\r\n", fetch_imgs_ + 1, img);
|
||
}
|
||
|
||
return dynamic_cast<IScanImg*>(img);
|
||
}
|
||
COM_API_IMPLEMENT(scanner, bool, get_first_image_header(SANE_Parameters* header, size_t* bytes, int* dpi))
|
||
{
|
||
return images_.get_header(header, bytes, dpi);
|
||
}
|
||
COM_API_IMPLEMENT(scanner, bool, discard_first_image(void))
|
||
{
|
||
scanned_img* img = images_.take();
|
||
if (img)
|
||
{
|
||
img->release();
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
COM_API_IMPLEMENT(scanner, bool, is_online(void))
|
||
{
|
||
std::string sn("");
|
||
|
||
return handle_ && control_read_string(IO_CTRL_CODE_GET_SERIAL, sn) != SCANNER_ERR_DEVICE_NOT_FOUND;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, bool, is_paper_on(void))
|
||
{
|
||
SANE_Bool on = SANE_FALSE;
|
||
unsigned int len = sizeof(on);
|
||
|
||
if (get_opt_value(SANE_OPT_ID_PAPER_ON, &on, false) == SANE_STATUS_GOOD)
|
||
return on == SANE_TRUE;
|
||
else
|
||
return false;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, int, last_error(void))
|
||
{
|
||
return err_;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, int, image_fetched(IScanImg* tx))
|
||
{
|
||
fetch_imgs_++;
|
||
if (ui_notify)
|
||
ui_notify(SANE_EVENT_IMG_UPLOADED, nullptr, fetch_imgs_);
|
||
|
||
utils::to_log(LOG_LEVEL_DEBUG, "Transferring image %d of %p finished.\r\n", fetch_imgs_, tx);
|
||
|
||
return 0;
|
||
}
|
||
|
||
COM_API_IMPLEMENT(scanner, bool, get_option_info(int sn, value_type* type, value_limit* limit, int* bytes))
|
||
{
|
||
#define SIMPLE_STR_INFO(id, rdo) \
|
||
if (sn == id) \
|
||
{ \
|
||
if (type) \
|
||
*type = VAL_TYPE_STR; \
|
||
if (limit) \
|
||
*limit = rdo ? VAL_LIMIT_READONLY : VAL_LIMIT_NONE; \
|
||
if (bytes) \
|
||
*bytes = 255; \
|
||
\
|
||
return true; \
|
||
}
|
||
#define SIMPLE_INT_INFO(id, rdo) \
|
||
if (sn == id) \
|
||
{ \
|
||
if (type) \
|
||
*type = VAL_TYPE_INT; \
|
||
if (limit) \
|
||
*limit = rdo ? VAL_LIMIT_READONLY : VAL_LIMIT_NONE; \
|
||
if (bytes) \
|
||
*bytes = sizeof(int); \
|
||
\
|
||
return true; \
|
||
}
|
||
|
||
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_DRIVER_VERSION, true);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_MANUFACTURER, true);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_COPYRIGHT, true);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_CO_URL, true);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_CO_TEL, true);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_CO_ADDR, true);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_CO_GPS, true);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_DEV_NAME, true);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_DEV_FAMILY, true);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_LOGIN, false);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_LOGOUT, false);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_DRIVER_LOG, false);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_DEVICE_LOG, false);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_DEVICE_MAC_ADDR, true);
|
||
SIMPLE_STR_INFO(SANE_OPT_ID_MOTOR_VER, true);
|
||
|
||
SIMPLE_INT_INFO(SANE_OPT_ID_HELP, false);
|
||
SIMPLE_INT_INFO(SANE_OPT_ID_HISTORY_COUNT, true);
|
||
SIMPLE_INT_INFO(SANE_OPT_ID_ROLLER_COUNT, false);
|
||
SIMPLE_INT_INFO(SANE_OPT_ID_VID, true);
|
||
SIMPLE_INT_INFO(SANE_OPT_ID_PID, true);
|
||
SIMPLE_INT_INFO(SANE_OPT_ID_ROLLER_LIFE, true);
|
||
|
||
sn = transfer_id(sn);
|
||
if (sn == -1)
|
||
return false;
|
||
|
||
EXAPIPOS ex = find_ex_api(sn);
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, ex == ex_opts_.end() ? sn : ex->base_ind);
|
||
bool ret = false;
|
||
|
||
if (desc)
|
||
{
|
||
if (type)
|
||
*type = scanner::from_sane_type(desc->type);
|
||
if (limit)
|
||
{
|
||
int lmt = scanner::from_sane_constraint(desc->constraint_type);
|
||
if (IS_CAP_READONLY(desc->cap))
|
||
lmt |= VAL_LIMIT_READONLY;
|
||
*limit = (value_limit)lmt;
|
||
}
|
||
if (bytes)
|
||
*bytes = desc->size;
|
||
|
||
ret = true;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, bool, get_value(int sn, set_opt_value setval, void* param))
|
||
{
|
||
if (sane_ids_.count((sane_option_id)sn) &&
|
||
sane_ids_[(sane_option_id)sn] == sn)
|
||
{
|
||
char buf[256] = { 0 };
|
||
value_type type = VAL_TYPE_NONE;
|
||
int ret = sane_helper_->invoke_sane_control_option(handle_, sn, SANE_ACTION_GET_VALUE, buf, nullptr);
|
||
|
||
if (ret == SANE_STATUS_GOOD)
|
||
{
|
||
get_option_info(sn, &type, nullptr, nullptr);
|
||
if (type == VAL_TYPE_STR)
|
||
{
|
||
std::string str(buf);
|
||
setval(&str, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, param);
|
||
}
|
||
else
|
||
setval(buf, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, param);
|
||
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
int org_id = sn;
|
||
if(sn == 0x102c) // CapType::Language
|
||
sn = transfer_id(SANE_OPT_ID_LANGUAGE);
|
||
else
|
||
sn = transfer_id(sn);
|
||
if (sn == -1)
|
||
return false;
|
||
|
||
EXAPIPOS ex = find_ex_api(sn);
|
||
int ret = SANE_STATUS_INVAL;
|
||
SANE_Int after = 0;
|
||
|
||
if (ex == ex_opts_.end())
|
||
{
|
||
if (get_option_value_with_parent(sn, setval, param))
|
||
return true;
|
||
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, sn);
|
||
void* init = get_opt_value(sn, desc->size, true);
|
||
ret = SANE_STATUS_GOOD;
|
||
if (desc->type == SANE_TYPE_BOOL)
|
||
{
|
||
SANE_Bool v = SANE_FALSE;
|
||
bool val = false;
|
||
|
||
get_opt_value(sn, &v, false);
|
||
val = v == SANE_TRUE;
|
||
//set_cur_and_def_value<bool>(val, *(SANE_Bool*)init == SANE_TRUE, setval, param);
|
||
{
|
||
int role = VAL_ROLE_NONE;
|
||
val = false;
|
||
if (*(SANE_Bool*)init == SANE_FALSE)
|
||
role |= VAL_ROLE_DEFAULT;
|
||
if (v == SANE_FALSE)
|
||
role |= VAL_ROLE_CURRENT;
|
||
setval(&val, (value_role)role, VAL_LIMIT_ENUM, param);
|
||
val = true;
|
||
role = VAL_ROLE_NONE;
|
||
if (*(SANE_Bool*)init == SANE_TRUE)
|
||
role |= VAL_ROLE_DEFAULT;
|
||
if (v == SANE_TRUE)
|
||
role |= VAL_ROLE_CURRENT;
|
||
setval(&val, (value_role)role, VAL_LIMIT_ENUM, param);
|
||
}
|
||
}
|
||
else if (desc->type == SANE_TYPE_INT)
|
||
{
|
||
SANE_Int cur = 0, def = *(SANE_Int*)init;
|
||
int val = 0;
|
||
|
||
get_opt_value(sn, &cur, false);
|
||
val = cur;
|
||
if (sn == resolution_id_)
|
||
dpi_ = cur;
|
||
do
|
||
{
|
||
if (desc->constraint_type == SANE_CONSTRAINT_RANGE)
|
||
{
|
||
set_value_range<SANE_Int, int>(cur, def, desc->constraint.range->min, desc->constraint.range->max, desc->constraint.range->quant, setval, param, scanner::to_int);
|
||
}
|
||
else if (desc->constraint_type == SANE_CONSTRAINT_WORD_LIST)
|
||
{
|
||
const SANE_Word* v = desc->constraint.word_list;
|
||
for (int i = 0; i < v[0]; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
if (v[i + 1] == cur)
|
||
role = value_role(role | VAL_ROLE_CURRENT);
|
||
if (v[i + 1] == *(SANE_Int*)init)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
val = v[i + 1];
|
||
if (!setval(&val, role, VAL_LIMIT_ENUM, param))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
set_cur_and_def_value<int>(val, *(SANE_Int*)init, setval, param);
|
||
|
||
}while (0);
|
||
}
|
||
else if (desc->type == SANE_TYPE_FIXED)
|
||
{
|
||
SANE_Fixed cur = 0, def = *(SANE_Fixed*)init;
|
||
float val = .0f;
|
||
|
||
get_opt_value(sn, &cur, false);
|
||
if (sn == resolution_id_)
|
||
dpi_ = (int)(SANE_UNFIX(cur) + .5f);
|
||
do
|
||
{
|
||
if (desc->constraint_type == SANE_CONSTRAINT_RANGE)
|
||
{
|
||
set_value_range<SANE_Fixed, float>(cur, def, desc->constraint.range->min, desc->constraint.range->max, desc->constraint.range->quant, setval, param, scanner::to_float);
|
||
}
|
||
else if (desc->constraint_type == SANE_CONSTRAINT_WORD_LIST)
|
||
{
|
||
const SANE_Word* v = desc->constraint.word_list;
|
||
for (int i = 0; i < v[0]; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
if (v[i + 1] == cur)
|
||
role = value_role(role | VAL_ROLE_CURRENT);
|
||
if (v[i + 1] == def)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
val = (float)SANE_UNFIX(v[i + 1]);
|
||
if (!setval(&val, role, VAL_LIMIT_ENUM, param))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
set_cur_and_def_value<float>(val, (float)SANE_UNFIX(*(SANE_Fixed*)init), setval, param);
|
||
} while (0);
|
||
}
|
||
else if (desc->type == SANE_TYPE_STRING)
|
||
{
|
||
char* buf = new char[desc->size + 4];
|
||
std::string val(""), def((char*)init);
|
||
|
||
memset(buf, 0, desc->size + 4);
|
||
get_opt_value(sn, buf, false);
|
||
val = buf;
|
||
do
|
||
{
|
||
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
|
||
{
|
||
for (int i = 0; desc->constraint.string_list[i]; ++i)
|
||
{
|
||
value_role role = VAL_ROLE_NONE;
|
||
if (strcmp(desc->constraint.string_list[i], buf) == 0)
|
||
role = value_role(role | VAL_ROLE_CURRENT);
|
||
if (strcmp(desc->constraint.string_list[i], (char*)init) == 0)
|
||
role = value_role(role | VAL_ROLE_DEFAULT);
|
||
|
||
val = desc->constraint.string_list[i];
|
||
if (org_id == 0x102c)
|
||
{
|
||
// const char* hz = local_trans::lang_trans_between_hz936(val.c_str(), false, nullptr);
|
||
int lid = sane_opt_trans::language_to_twain(val.c_str());
|
||
if (!setval(&lid, role, VAL_LIMIT_ENUM, param))
|
||
break;
|
||
}
|
||
else if (!setval(&val, role, VAL_LIMIT_ENUM, param))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
set_cur_and_def_value<std::string>(val, def, setval, param);
|
||
} while (0);
|
||
delete[] buf;
|
||
}
|
||
else
|
||
{
|
||
ret = SANE_STATUS_INVAL;
|
||
}
|
||
delete[] init;
|
||
}
|
||
else
|
||
{
|
||
ret = (this->*ex->ex_api)(ex->base_ind, param, setval);
|
||
}
|
||
|
||
return ret == SANE_STATUS_GOOD;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, bool, get_value(int sn, void* data, int* len))
|
||
{
|
||
if (sn != SANE_OPT_ID_DRIVER_LOG && sn != SANE_OPT_ID_DEVICE_LOG)
|
||
return false;
|
||
|
||
return sane_helper_->invoke_sane_control_option(handle_, sn, SANE_ACTION_GET_VALUE, data, nullptr) == SANE_STATUS_GOOD;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, int, set_value(int sn, void* val))
|
||
{
|
||
if (sane_ids_.count((sane_option_id)sn) &&
|
||
sane_ids_[(sane_option_id)sn] == sn)
|
||
{
|
||
int ret = sane_helper_->invoke_sane_control_option(handle_, sn, SANE_ACTION_SET_VALUE, val, nullptr);
|
||
|
||
return ret;
|
||
}
|
||
|
||
int org_id = sn;
|
||
if (sn == 0x102c) // CapType::Language
|
||
sn = transfer_id(SANE_OPT_ID_LANGUAGE);
|
||
else
|
||
sn = transfer_id(sn);
|
||
if (sn == -1)
|
||
return SANE_STATUS_UNSUPPORTED;
|
||
|
||
EXAPIPOS ex = find_ex_api(sn);
|
||
int ret = SANE_STATUS_INVAL;
|
||
SANE_Int after = 0;
|
||
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, sn);
|
||
|
||
{
|
||
char msg[256] = { 0 };
|
||
if (ex == ex_opts_.end())
|
||
sprintf_s(msg, _countof(msg) - 1, "set_value of %s(%s) of ID %d\r\n", desc->name, callback::option_value_2_string(desc->type, val).c_str(), sn);
|
||
else if(ex->base_ind != -1)
|
||
{
|
||
desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, ex->base_ind);
|
||
sprintf_s(msg, _countof(msg) - 1, "set_value of %s(0x%x) of ID %d, base id = %d)\r\n", desc->name, *(unsigned*)val, sn, ex->base_ind);
|
||
}
|
||
utils::log_info(msg, (log_level)0);
|
||
}
|
||
|
||
twain_set_ = true;
|
||
if (ex == ex_opts_.end())
|
||
{
|
||
std::string strv("");
|
||
void* w = val;
|
||
if (org_id == 0x102c)
|
||
{
|
||
// const char* str = sane_opt_trans::language_from_twain(*(int*)val);
|
||
strv = sane_opt_trans::language_from_twain(*(int*)val);
|
||
w = &strv;
|
||
}
|
||
|
||
if (!set_option_value_with_parent(sn, w, &ret))
|
||
ret = set_option_value(sn, desc->type, desc->size, w);
|
||
// ret = local_utility::sane_statu_2_scanner_err(ret);
|
||
}
|
||
else
|
||
{
|
||
ret = (this->*ex->ex_api)(ex->base_ind, val, nullptr);
|
||
}
|
||
|
||
if (sn == resolution_id_)
|
||
{
|
||
if (desc->type == SANE_TYPE_FIXED)
|
||
dpi_ = (int)(*(float*)val + .5f);
|
||
else
|
||
dpi_ = *(int*)val;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, int, convert_image(SANE_ImageFormatConvert* conv))
|
||
{
|
||
return sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_TRANSFORM_IMAGE_FORMAT, SANE_ACTION_SET_VALUE, conv, nullptr);
|
||
}
|
||
COM_API_IMPLEMENT(scanner, void, free_buffer(void* buf, int len))
|
||
{
|
||
sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_FREE_BUFFER, SANE_ACTION_SET_VALUE, &buf, nullptr);
|
||
}
|
||
COM_API_IMPLEMENT(scanner, int, get_fixed_ids(bool(* cb)(uint32_t id, void* param), void* param))
|
||
{
|
||
for (auto& v : sane_ids_)
|
||
{
|
||
if (!cb(v.first, param))
|
||
break;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
// SANE options ID ...
|
||
SANE_OPTION_ID_IMPLEMENT(color_correction)
|
||
SANE_OPTION_ID_IMPLEMENT(fold_type)
|
||
SANE_OPTION_ID_IMPLEMENT(is_multiout)
|
||
SANE_OPTION_ID_IMPLEMENT(multiout_type)
|
||
SANE_OPTION_ID_IMPLEMENT(color_mode)
|
||
SANE_OPTION_ID_IMPLEMENT(erase_color)
|
||
SANE_OPTION_ID_IMPLEMENT(erase_multiout_red)
|
||
SANE_OPTION_ID_IMPLEMENT(erase_paper_red)
|
||
SANE_OPTION_ID_IMPLEMENT(is_erase_background)
|
||
SANE_OPTION_ID_IMPLEMENT(background_color_range)
|
||
SANE_OPTION_ID_IMPLEMENT(sharpen)
|
||
SANE_OPTION_ID_IMPLEMENT(erase_morr)
|
||
SANE_OPTION_ID_IMPLEMENT(erase_grids)
|
||
SANE_OPTION_ID_IMPLEMENT(error_extend)
|
||
SANE_OPTION_ID_IMPLEMENT(is_noise_modify)
|
||
SANE_OPTION_ID_IMPLEMENT(noise_threshold)
|
||
SANE_OPTION_ID_IMPLEMENT(paper)
|
||
SANE_OPTION_ID_IMPLEMENT(is_custom_area)
|
||
SANE_OPTION_ID_IMPLEMENT(curstom_area_l)
|
||
SANE_OPTION_ID_IMPLEMENT(curstom_area_r)
|
||
SANE_OPTION_ID_IMPLEMENT(curstom_area_t)
|
||
SANE_OPTION_ID_IMPLEMENT(curstom_area_b)
|
||
SANE_OPTION_ID_IMPLEMENT(is_size_check)
|
||
SANE_OPTION_ID_IMPLEMENT(page)
|
||
SANE_OPTION_ID_IMPLEMENT(blank_page_threshold)
|
||
SANE_OPTION_ID_IMPLEMENT(resolution)
|
||
SANE_OPTION_ID_IMPLEMENT(image_quality)
|
||
SANE_OPTION_ID_IMPLEMENT(is_swap)
|
||
SANE_OPTION_ID_IMPLEMENT(is_split)
|
||
SANE_OPTION_ID_IMPLEMENT(is_auto_deskew)
|
||
SANE_OPTION_ID_IMPLEMENT(is_custom_gamma)
|
||
SANE_OPTION_ID_IMPLEMENT(bright)
|
||
SANE_OPTION_ID_IMPLEMENT(contrast)
|
||
SANE_OPTION_ID_IMPLEMENT(gamma)
|
||
SANE_OPTION_ID_IMPLEMENT(is_erase_black_frame)
|
||
SANE_OPTION_ID_IMPLEMENT(deep_sample)
|
||
SANE_OPTION_ID_IMPLEMENT(threshold)
|
||
SANE_OPTION_ID_IMPLEMENT(anti_noise)
|
||
SANE_OPTION_ID_IMPLEMENT(margin)
|
||
SANE_OPTION_ID_IMPLEMENT(fill_background)
|
||
SANE_OPTION_ID_IMPLEMENT(is_anti_permeate)
|
||
SANE_OPTION_ID_IMPLEMENT(anti_permeate_level)
|
||
SANE_OPTION_ID_IMPLEMENT(is_erase_hole)
|
||
SANE_OPTION_ID_IMPLEMENT(search_hole_range)
|
||
SANE_OPTION_ID_IMPLEMENT(is_filling_color)
|
||
SANE_OPTION_ID_IMPLEMENT(is_ultrasonic_check)
|
||
SANE_OPTION_ID_IMPLEMENT(is_check_staple)
|
||
SANE_OPTION_ID_IMPLEMENT(scan_mode)
|
||
SANE_OPTION_ID_IMPLEMENT(scan_count)
|
||
SANE_OPTION_ID_IMPLEMENT(text_direction)
|
||
SANE_OPTION_ID_IMPLEMENT(is_rotate_bkg180)
|
||
SANE_OPTION_ID_IMPLEMENT(is_check_dogear)
|
||
SANE_OPTION_ID_IMPLEMENT(dogear_size)
|
||
SANE_OPTION_ID_IMPLEMENT(is_check_skew)
|
||
SANE_OPTION_ID_IMPLEMENT(skew_range)
|
||
SANE_OPTION_ID_IMPLEMENT(black_white_threshold)
|
||
SANE_OPTION_ID_IMPLEMENT(is_photo_mode)
|
||
SANE_OPTION_ID_IMPLEMENT(double_feed_handle)
|
||
SANE_OPTION_ID_IMPLEMENT(scan_when_paper_on)
|
||
SANE_OPTION_ID_IMPLEMENT(feed_strength)
|
||
SANE_OPTION_ID_IMPLEMENT(power_scheme)
|
||
SANE_OPTION_ID_IMPLEMENT(is_auto_strength)
|
||
SANE_OPTION_ID_IMPLEMENT(feed_strength_value)
|
||
SANE_OPTION_ID_IMPLEMENT(is_reverse_bw)
|
||
SANE_OPTION_ID_IMPLEMENT(is_erase_hole_l)
|
||
SANE_OPTION_ID_IMPLEMENT(search_hole_range_l)
|
||
SANE_OPTION_ID_IMPLEMENT(is_erase_hole_r)
|
||
SANE_OPTION_ID_IMPLEMENT(search_hole_range_r)
|
||
SANE_OPTION_ID_IMPLEMENT(is_erase_hole_t)
|
||
SANE_OPTION_ID_IMPLEMENT(search_hole_range_t)
|
||
SANE_OPTION_ID_IMPLEMENT(is_erase_hole_b)
|
||
SANE_OPTION_ID_IMPLEMENT(search_hole_range_b)
|
||
SANE_OPTION_ID_IMPLEMENT(fold_direction)
|
||
|
||
// SANE-ex option ID:
|
||
SANE_OPTION_ID_IMPLEMENT(ex_multiout_type)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_auto_color_type)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_color_mode)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_sharpen)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_paper)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_paper_lateral)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_auto_paper_size)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_is_paper_auto_crop)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_text_direction)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_duplex)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_fill_background)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_discard_blank_page)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_discard_blank_receipt)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_is_page_fold)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_color_filter)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_color_enhance)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_final_compression)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_final_format)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_serial)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_to_be_scan)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_scan_with_hole)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_device_code)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_power)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_hardware_version)
|
||
SANE_OPTION_ID_IMPLEMENT(ex_ip)
|
||
|
||
COM_API_IMPLEMENT(scanner, void, twain_set_transfer(twain_xfer xfer))
|
||
{
|
||
xfer_ = xfer;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, void, twain_set_compression(SANE_CompressionType compression, void* detail))
|
||
{
|
||
img_fmt_.compress.compression = compression;
|
||
img_fmt_.compress.detail = detail;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, int, twain_get_config(char* buf, size_t* len))
|
||
{
|
||
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, int, twain_set_config(char* buf, size_t len))
|
||
{
|
||
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
||
}
|
||
|
||
|
||
// ui ...
|
||
COM_API_IMPLEMENT(scanner, bool, ui_show_main(HWND parent))
|
||
{
|
||
return false;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, bool, ui_show_setting(HWND parent, bool with_scan, bool indicator))
|
||
{
|
||
printf("ui_show_setting(%p, %s, %s), api = %p\n", parent, with_scan ? "with scan" : "only ui", indicator ? "has indicator" : "no indicator", callback::show_setting_ui);
|
||
is_show_ui_ = with_scan;
|
||
is_show_setting_ = true;
|
||
events_.clear();
|
||
if (callback::show_setting_ui)
|
||
{
|
||
if (with_scan)
|
||
{
|
||
images_.clear();
|
||
scan_msg_ = "OK";
|
||
scan_err_ = false;
|
||
}
|
||
auto ui = [this](ui_result res)
|
||
{
|
||
int uev = SANE_EVENT_SCAN_FINISHED;
|
||
switch (res)
|
||
{
|
||
case UI_RESULT_FAILED:
|
||
|
||
break;
|
||
case UI_RESULT_OK:
|
||
|
||
break;
|
||
case UI_RESULT_CLOSE_NORMAL:
|
||
is_show_ui_ = false;
|
||
uev = SANE_EVENT_UI_CLOSE_NORMAL;
|
||
on_ui_event(uev, (void*)uev);
|
||
break;
|
||
case UI_RESULT_CLOSE_CANCEL:
|
||
is_show_ui_ = false;
|
||
uev = SANE_EVENT_UI_CLOSE_CANCEL;
|
||
on_ui_event(uev, (void*)uev);
|
||
break;
|
||
case UI_RESULT_CLOSE_SETTING:
|
||
is_show_setting_ = false;
|
||
uev = SANE_EVENT_UI_CLOSE_SETTING;
|
||
on_ui_event(uev, (void*)uev);
|
||
break;
|
||
case UI_RESULT_START_SCAN:
|
||
on_ui_event(SANE_EVENT_UI_SCAN_COMMAND, nullptr);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
};
|
||
int res = callback::show_setting_ui(handle_, parent, &sane_api_, scanner_name_.c_str(), with_scan, ui);
|
||
//if (res == ui_result::UI_RESULT_CLOSE_NORMAL)
|
||
//{
|
||
// int ev = SANE_EVENT_UI_CLOSE_NORMAL;
|
||
// on_ui_event(ev, (void*)ev);
|
||
//}
|
||
//else if (res == ui_result::UI_RESULT_START_SCAN)
|
||
//{
|
||
// //callback::show_progress_ui(parent, ui_process, &ui_notify);
|
||
// //start();
|
||
// on_ui_event(SANE_EVENT_UI_SCAN_COMMAND, nullptr);
|
||
//}
|
||
//else if (res == UI_RESULT_CLOSE_CANCEL)
|
||
//{
|
||
// int ev = SANE_EVENT_UI_CLOSE_CANCEL;
|
||
// on_ui_event(ev, (void*)ev);
|
||
//}
|
||
//on_ui_event(ev, nullptr);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent, bool bIndicator))
|
||
{
|
||
bIndicator = false;
|
||
is_bIndicator = bIndicator;
|
||
ui_notify = std::function<void(int, void*, int)>();
|
||
auto ui_process = [this](ui_result res)
|
||
{
|
||
int uev = SANE_EVENT_SCAN_FINISHED;
|
||
switch (res)
|
||
{
|
||
case UI_RESULT_CLOSE_NORMAL:
|
||
uev = SANE_EVENT_UI_CLOSE_NORMAL;
|
||
//if (!is_show_ui_)
|
||
{
|
||
on_ui_event(uev, (void*)uev);
|
||
}
|
||
break;
|
||
case UI_RESULT_CLOSE_CANCEL:
|
||
uev = SANE_EVENT_UI_CLOSE_CANCEL;
|
||
//if (!is_show_ui_)
|
||
{
|
||
on_ui_event(uev, (void*)uev);
|
||
}
|
||
//else
|
||
// stop();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
};
|
||
if (callback::show_progress_ui && bIndicator)
|
||
{
|
||
callback::show_progress_ui(parent, ui_process,&ui_notify);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
COM_API_IMPLEMENT(scanner, void, ui_hide(void))
|
||
{
|
||
if (callback::close_ui)
|
||
callback::close_ui(UI_INDICATOR | UI_SETTING | UI_MSG_BOX);
|
||
is_show_setting_ = false;
|
||
ui_notify = std::function<void(int, void*, int)>();
|
||
}
|
||
COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void))
|
||
{
|
||
return callback::show_setting_ui != nullptr;
|
||
}
|
||
|
||
|
||
|
||
// called from device-layer ...
|
||
int scanner::handle_device_event(int ev_code, void* data, unsigned int* len)
|
||
{
|
||
if (ev_code == SANE_EVENT_WORKING)
|
||
{
|
||
img_ind_ = 0;
|
||
if (callback::show_progress_ui && is_bIndicator)
|
||
ui_notify(ev_code, data, *len);
|
||
on_ui_event(ev_code, (void*)ev_code);
|
||
utils::log_info("Scanning ...\r\n", LOG_LEVEL_DEBUG);
|
||
}
|
||
else if (ev_code == SANE_EVENT_IMAGE_OK)
|
||
{
|
||
SANE_Image* simg = (SANE_Image*)data;
|
||
scanned_img* img = nullptr;
|
||
char name[40] = { 0 };
|
||
|
||
sprintf_s(name, _countof(name) - 1, "img_%05u.bmp", ++img_ind_);
|
||
img = new scanned_img(handle_, simg->header, simg->data, simg->bytes, simg->flag.dpi, (tmp_path_ + name).c_str(), xfer_, &img_fmt_);
|
||
if (img->bytes() /*>= simg->bytes*/)
|
||
{
|
||
size_t bytes = 0;
|
||
int times = 0;
|
||
|
||
images_.count(&bytes);
|
||
img->set_image_status((SANE_Image_Statu)simg->flag.statu);
|
||
bytes /= 1024 * 1024;
|
||
while (bytes > max_img_mem_ && !user_cancel_ && times++ < 20) // memory control
|
||
{
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||
images_.count(&bytes);
|
||
bytes /= 1024 * 1024;
|
||
if (times == 1)
|
||
utils::log_info("Memory usage upto limit! wait up to 100 ms ...\r\n", LOG_LEVEL_DEBUG);
|
||
}
|
||
images_.save(img, img->bytes());
|
||
}
|
||
else
|
||
{
|
||
img->release();
|
||
}
|
||
|
||
if (ui_notify)
|
||
ui_notify(ev_code, data, img_ind_);
|
||
|
||
{
|
||
char msg[128] = { 0 };
|
||
sprintf_s(msg, _countof(msg) - 1, "New image(%u) received with %u bytes\r\n", img_ind_, simg->bytes);
|
||
utils::log_info(msg, (log_level)1);
|
||
}
|
||
}
|
||
else if (ev_code == SANE_EVENT_USB_DATA_RECEIVED)
|
||
{
|
||
//if (indicator_.get())
|
||
// indicator_->notify_data_arrived(false);
|
||
//else if (ui_notify)
|
||
// ui_notify(ev_code, data, 0);
|
||
}
|
||
else if (ev_code == SANE_EVENT_SCAN_FINISHED)
|
||
{
|
||
err_ = *len;
|
||
if (ui_notify)
|
||
ui_notify(ev_code, data, *len);
|
||
else
|
||
{
|
||
if (*len)
|
||
{
|
||
if (callback::show_messagebox_ui)
|
||
{
|
||
callback::show_messagebox_ui(app_wnd_, ev_code, (void*)data, 0);
|
||
}
|
||
}
|
||
on_ui_event(ev_code, (void*)ev_code);
|
||
}
|
||
// is_scanning_ = false;
|
||
|
||
{
|
||
char msg[128] = { 0 };
|
||
sprintf_s(msg, _countof(msg) - 1, "Scan finished with error: %u\r\n", *len);
|
||
utils::log_info(msg, (log_level)1);
|
||
}
|
||
}
|
||
//else if (ev_code == SANE_EVENT_ERROR) // 屏蔽,在停止扫描时展示信息 - 2023-05-30
|
||
//{
|
||
// if (callback::show_messagebox_ui && *len)
|
||
// {
|
||
// callback::show_messagebox_ui(app_wnd_, ev_code, (void*)data, 0);
|
||
// }
|
||
// else if (*len) //错误弹出
|
||
// {
|
||
// std::string msg(local_trans::a2u((char*)data, CP_UTF8));
|
||
// if (!IsWindow(app_wnd_))
|
||
// callback::bring_message_box_topmost(local_trans::lang_trans_between_hz936(CONST_STRING_ERROR).c_str());
|
||
// MessageBoxW(app_wnd_, msg.c_str(), local_trans::lang_trans_between_hz936(CONST_STRING_ERROR).c_str(), MB_OK);
|
||
// }
|
||
//// on_ui_event(ev_code, (void*)ev_code);
|
||
//}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// exports
|
||
extern "C"
|
||
{
|
||
int initialize_sane(void* reserve)
|
||
{
|
||
SANE_Int ver = 0;
|
||
|
||
utils::init_log(LOG_TYPE_FILE, LOG_LEVEL_ALL, "_twain");
|
||
sane_helper_ = new sane_helper();
|
||
if(!sane_helper_->load_sane((std::string(OEM_SHORT_NAME_E) + "sane").c_str()))
|
||
{
|
||
printf("Load sane dll failed.\n");
|
||
delete sane_helper_;
|
||
sane_helper_ = nullptr;
|
||
|
||
return SCANNER_ERR_NOT_OPEN;
|
||
}
|
||
callback::init_ui();
|
||
|
||
if (sane_helper_->invoke_sane_init_ex(&ver, callback::sane_event_callback, nullptr) == SANE_STATUS_GOOD)
|
||
{
|
||
std::string lang(utils::get_module_full_path(SCANNER_DRIVER_PART_NAME));
|
||
size_t pos = lang.rfind(PATH_SEPARATOR[0]);
|
||
if(pos++ == std::string::npos)
|
||
pos = 0;
|
||
lang.erase(pos);
|
||
lang += LANG_DLL_NAME;
|
||
pos = local_trans::load_lang_pak(lang.c_str());
|
||
utils::to_log(LOG_LEVEL_WARNING, "load language component (%s) = %s\n", lang.c_str(), strerror(pos));
|
||
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
else
|
||
return SCANNER_ERR_LANG_PAK_LOST;
|
||
}
|
||
int open_scanner(SCANNERID scanner_id, ISaneInvoker** invoker, bool last_try)
|
||
{
|
||
if (!invoker)
|
||
return SCANNER_ERR_INVALID_PARAMETER;
|
||
|
||
if (!is_scanner_online(scanner_id))
|
||
{
|
||
if (last_try)
|
||
{
|
||
HWND parent = callback::find_main_wnd();
|
||
std::string msg(local_trans::lang_trans_between_hz936("\xE6\xB2\xA1\xE6\x9C\x89\xE6\x89\xBE\xE5\x88\xB0\xE6\x89\xAB\xE6\x8F\x8F\xE4\xBB\xAA\xEF\xBC\x81", true, nullptr)),
|
||
title(local_trans::lang_trans_between_hz936("\xE9\x94\x99\xE8\xAF\xAF", true, nullptr));
|
||
|
||
if (callback::show_messagebox_ui)
|
||
callback::show_messagebox_ui(parent, 0, &msg[0], SCANNER_ERR_DEVICE_NOT_FOUND);
|
||
}
|
||
|
||
return SCANNER_ERR_DEVICE_NOT_FOUND;
|
||
}
|
||
|
||
scanner* scn = new scanner(scanner_id);
|
||
if (scn->last_error() == SCANNER_ERR_OK)
|
||
{
|
||
*invoker = dynamic_cast<ISaneInvoker*>(scn);
|
||
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
int ret = scn->last_error();
|
||
|
||
scn->release();
|
||
*invoker = nullptr;
|
||
if (last_try)
|
||
{
|
||
HWND parent = callback::find_main_wnd();
|
||
std::string msg(local_trans::lang_trans_between_hz936("\xE6\x89\x93\xE5\xBC\x80\xE6\x89\xAB\xE6\x8F\x8F\xE4\xBB\xAA\xE5\xA4\xB1\xE8\xB4\xA5\xE3\x80\x82", true, nullptr)),
|
||
title(local_trans::lang_trans_between_hz936("\xE9\x94\x99\xE8\xAF\xAF", true, nullptr));
|
||
if (callback::show_messagebox_ui)
|
||
callback::show_messagebox_ui(parent, 0, &msg[0], ret);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
}
|
||
bool is_scanner_online(SCANNERID scanner_id)
|
||
{
|
||
std::vector<std::string> que;
|
||
|
||
scanner::get_scanner_name(scanner_id, que);
|
||
|
||
return !que.empty();
|
||
}
|
||
int uninitialize_sane(void* reserve)
|
||
{
|
||
if(sane_helper_ && sane_helper_->invoke_sane_exit)
|
||
sane_helper_->invoke_sane_exit();
|
||
callback::unint_ui();
|
||
if(sane_helper_)
|
||
delete sane_helper_;
|
||
sane_helper_ = nullptr;
|
||
|
||
return 0;
|
||
}
|
||
|
||
ISaneInvoker* sane_wapper_open_scanner(SCANNERID scanner_id, int* err, bool last_try)
|
||
{
|
||
if (!sane_helper_)
|
||
{
|
||
int rv = initialize_sane(nullptr);
|
||
if (rv)
|
||
{
|
||
if (err)
|
||
*err = rv;
|
||
|
||
return nullptr;
|
||
}
|
||
}
|
||
|
||
ISaneInvoker* sane = nullptr;
|
||
int ret = open_scanner(scanner_id, &sane, last_try);
|
||
|
||
if (err)
|
||
*err = ret;
|
||
|
||
return sane;
|
||
}
|
||
}
|