code_twain/sane/scanner.cpp

2800 lines
80 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "scanner.h"
#include <Windows.h>
#include <Shlwapi.h> // for PathFileExistsW
#include "../sdk/hginclude/huagaoxxx_warraper_ex.h"
#include <sane/sane_option_definitions.h>
#include "../../code_device/hgsane/sane_hg_mdw.h"
#include "sane_option_trans.h"
#include <chrono>
#include <mutex>
#include "DlgIndicator.h"
#include "DlgSetting.h"
#include "gb_json.h"
#pragma comment(lib, "Shlwapi.lib")
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; \
extension(id); \
}
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
void __stdcall log_info(const wchar_t* info, int level);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// callback
extern "C"
{
extern SANE_Status inner_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize);
extern void inner_sane_exit(void);
extern SANE_Status inner_sane_get_devices(const SANE_Device*** device_list, SANE_Bool local_only);
extern SANE_Status inner_sane_open(SANE_String_Const devicename, SANE_Handle* handle);
extern void inner_sane_close(SANE_Handle handle);
extern const SANE_Option_Descriptor* inner_sane_get_option_descriptor(SANE_Handle handle, SANE_Int option);
extern SANE_Status inner_sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info);
extern SANE_Status inner_sane_get_parameters(SANE_Handle handle, SANE_Parameters* params);
extern SANE_Status inner_sane_start(SANE_Handle handle);
extern SANE_Status inner_sane_read(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length);
extern void inner_sane_cancel(SANE_Handle handle);
extern SANE_Status inner_sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking);
extern SANE_Status inner_sane_get_select_fd(SANE_Handle handle, SANE_Int* fd);
extern SANE_String_Const inner_sane_strstatus(SANE_Status status);
extern SANE_Status inner_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param);
extern SANE_Status inner_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len);
}
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
{
wchar_t msg[218] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"Lost device(0x%08X) when event(%u) occurs!\r\n", hdev, code);
log_info(msg, 0);
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}
},
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* __stdcall 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* __stdcall 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 "";
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// class scanner
scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START)
, dpi_(200), tmp_path_(L""), img_ind_(0)
, scanner_name_(L""), cfg_(NULL), is_ui_wait_img_(false), is_scanning_(false)
{
cfg_ = new gb::sane_config();
tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str());
{
char* tmp = getenv("LOCALAPPDATA");
if (tmp)
{
tmp_path_ = local_trans::a2u(tmp) + L"\\";
tmp_path_ += local_trans::a2u(PRODUCT_VENDOR) + L"Scan\\";
CreateDirectoryW(tmp_path_.c_str(), NULL);
}
}
cfg_path_ = tmp_path_ + L"config";
CreateDirectoryW(cfg_path_.c_str(), NULL);
cfg_path_ += L"\\";
tmp_path_ += L"imgs";
CreateDirectoryW(tmp_path_.c_str(), NULL);
tmp_path_ += L"\\";
img_fmt_.img_format = SANE_IMAGE_TYPE_BMP;
img_fmt_.compress.compression = SANE_COMPRESSION_NONE;
err_ = open();
}
scanner::~scanner()
{
close();
if (cfg_)
delete cfg_;
}
bool scanner::is_belong_serial(int vid, int pid, SCANNERID serial)
{
if (vid == PRODUCT_VENDOR_HG)
{
if (GET_SCANNER_VID(serial) == PRODUCT_VENDOR_HG)
{
if (GET_SCANNER_PID(serial) == 0x100)
{
return pid == 0x100 || pid == 0x139 ;
}
else if (GET_SCANNER_PID(serial) == 0x200)
{
return pid == 0x200 || pid == 0x239;
}
else if (GET_SCANNER_PID(serial) == 0x300)
{
return pid == 0x300 || pid == 0x302 || pid == 0x339;
}
else if (GET_SCANNER_PID(serial) == 0x400)
{
return pid == 0x400 || pid == 0x402 || pid == 0x439;
}
}
}
else if (vid == PRODUCT_VENDOR_HG1)
{
return pid == 0x7823 && GET_SCANNER_VID(serial) == PRODUCT_VENDOR_HG && GET_SCANNER_PID(serial) == 0x200;
}
else if (vid == PRODUCT_VENDOR_HW)
{
return GET_SCANNER_VID(serial) == vid && GET_SCANNER_PID(serial) == pid;
}
else if (vid == PRODUCT_VENDOR_LSC)
{
if (GET_SCANNER_VID(serial) == PRODUCT_VENDOR_LSC)
{
if (GET_SCANNER_PID(serial) == 0x8420)
{
return pid == 0x8200 || pid == 0x8420 || pid == 0x8429;
}
else if (GET_SCANNER_PID(serial) == 0x8520)
{
return pid == 0x8520 || pid == 0x8529;
}
else if (GET_SCANNER_PID(serial) == 0x8620)
{
return pid == 0x8620 || pid == 0x8629;
}
else if (GET_SCANNER_PID(serial) == 0x8730)
{
return pid == 0x8730 || pid == 0x8739;
}
}
}
return false;
}
void scanner::get_scanner_name(SCANNERID id, std::vector<std::string>& names)
{
ScannerInfo* devs = NULL;
long count = 0;
names.clear();
if (hg_scanner_enum(devs, &count, true) == SCANNER_ERR_INSUFFICIENT_MEMORY)
{
count++;
devs = new ScannerInfo[count];
memset(devs, 0, count * sizeof(*devs));
if (hg_scanner_enum(devs, &count, true) == SCANNER_ERR_OK)
{
for (int i = 0; i < count; ++i)
{
if (scanner::is_belong_serial(devs[i].vid, devs[i].pid, id))
{
names.push_back(devs[i].name);
}
}
}
delete[] devs;
}
}
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::control_read_string(SANE_Handle hdev, int code, std::string& str)
{
char* buf = NULL;
unsigned len = 0;
int err = hg_sane_middleware::instance()->io_control(hdev, code, buf, &len);
str = "";
if (err == SANE_STATUS_NO_MEM)
{
len += 4;
buf = new char[len];
memset(buf, 0, len);
err = hg_sane_middleware::instance()->io_control(hdev, code, buf, &len);
if (err == SANE_STATUS_GOOD)
str = buf;
delete[] buf;
}
return err;
}
int __stdcall scanner::to_int(SANE_Int v)
{
return v;
}
float __stdcall scanner::to_float(SANE_Fixed v)
{
return (float)SANE_UNFIX(v);
}
void __stdcall scanner::ui_callback(int uev, void* sender, void* param)
{
((scanner*)param)->on_ui_event(uev, sender);
}
bool __stdcall scanner::is_option_float(int sn, void* param)
{
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->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();
}
void scanner::transport_config_file(void)
{
size_t pos = scanner_name_.find(L" - ");
std::wstring pid(L"G"), old(L"");
if (pos == std::wstring::npos)
return;
pid += scanner_name_.substr(pos + 3);
if (scanner_name_.find(L"HUAGOSCAN ") != std::wstring::npos)
{
old = local_trans::a2u("\345\215\216\351\253\230\346\211\253\346\217\217\344\273\252\342\200\224", CP_UTF8);
}
else if (scanner_name_.find(L"LANXUMSCAN ") != std::wstring::npos)
{
old = local_trans::a2u("\347\253\213\346\200\235\350\276\260\346\211\253\346\217\217\344\273\252\342\200\224", CP_UTF8);
pid += L"S";
}
old += pid;
if (PathFileExistsW((cfg_path_ + old).c_str()))
{
log_info((L"Rename config file '" + old + L"' to '" + scanner_name_.substr(0, pos) + L"'\r\n").c_str(), 0);
MoveFileW((cfg_path_ + old).c_str(), (cfg_path_ + scanner_name_.substr(0, pos)).c_str());
}
}
void scanner::update_config(void)
{
std::string notice("");
cfg_->update(&scanner::is_option_float, handle_, &callback::option_title_2_name, &notice);
if (notice.length())
{
std::wstring msg(L"\u4E0B\u5217\u914D\u7F6E\u6570\u636E\u9519\u8BEF\uFF0C\u5DF2\u7ECF\u6062\u590D\u5230\u9ED8\u8BA4\u503C\u3002\u5982\u679C\u9700\u8981\uFF0C\u8BF7\u91CD\u65B0\u8BBE\u7F6E\uFF1A\r\n\r\n");
size_t pos = notice.find("\r\n");
while (pos != std::string::npos)
{
msg += local_trans::a2u(callback::option_name_2_title(notice.substr(0, pos).c_str()), CP_UTF8) + L"\r\n";
notice.erase(0, pos + 2);
pos = notice.find("\r\n");
}
MessageBoxW(NULL, msg.c_str(), L"\u52A0\u8F7D\u914D\u7F6E", MB_OK | MB_ICONINFORMATION);
}
}
void scanner::load_config(const wchar_t* file)
{
cfg_->load_from_file(file);
update_config();
}
void scanner::save_config(const wchar_t* file)
{
cfg_->save_to(file);
}
void scanner::apply_config(void)
{
std::string n(""), v(""), ver(cfg_->get_version());
std::wstring notice(L"");
if (cfg_->first_config(n, v))
{
do
{
int id = cfg_->id_from_name(n.c_str());
if (id != -1)
{
void* data = &v[0];
SANE_Fixed fixed = 0;
const SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, id);
if (desc)
{
char* buf = NULL;
SANE_Int after = 0;
if (desc->type == SANE_TYPE_STRING)
{
buf = new char[desc->size + 4];
memset(buf, 0, desc->size + 4);
strcpy(buf, v.c_str());
data = buf;
}
hg_sane_middleware::instance()->set_option(handle_, id, SANE_ACTION_SET_VALUE, data, &after);
if (buf)
delete[] buf;
}
}
} while (cfg_->next_config(n, v));
}
}
void scanner::on_ui_event(int uev, void* sender)
{
bool indicator = sender == indicator_.get();
if (prev_start_result_ != SANE_STATUS_GOOD && indicator)
indicator_.reset();
else
{
if (/*events_.count() > 5 && !is_ui_wait_img_ &&*/
(uev == SANE_EVENT_UI_CLOSE_CANCEL || uev == SANE_EVENT_UI_CLOSE_NORMAL || uev == SANE_EVENT_UI_CLOSE_SETTING))
{
events_.clear();
ui_hide();
if(indicator)
events_.save(SANE_EVENT_SCAN_FINISHED);
else
events_.save(SANE_EVENT_UI_CLOSE_SETTING);
}
else
events_.save(uev);
}
}
std::string scanner::choose_scanner(const std::vector<std::string>& scanners)
{
if (scanners.empty())
return "";
std::map<std::string, std::string> devs;
std::string sel("");
for (size_t i = 0; i < scanners.size(); ++i)
{
SANE_Handle h = NULL;
int ret = hg_sane_middleware::instance()->open_device(scanners[i].c_str(), &h);
if (h)
{
std::string sn("");
scanner::control_read_string(h, IO_CTRL_CODE_GET_SERIAL, sn);
if (sn.length())
devs[scanners[i]] = sn;
hg_sane_middleware::instance()->close_device(h);
}
}
if (devs.size() == 0)
sel = scanners[0];
else if (devs.size() == 1)
sel = devs.begin()->first;
else
{
dlg_choose_dev dlg(NULL, 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_ = L"";
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 = hg_sane_middleware::instance()->open_device(name.c_str(), &handle_);
if (ret == SANE_STATUS_GOOD)
{
size_t pid = -1;
transport_config_file();
callback::reg_callback(handle_, this);
scanner_name_ = local_trans::a2u(name.c_str(), CP_UTF8);
pid = scanner_name_.find(L" - ");
if (pid == -1)
pid = scanner_name_.length();
ret = init_options_id();
load_config((cfg_path_ + scanner_name_.substr(0, pid) + L".cfg").c_str());
apply_config();
}
else
{
std::wstring msg(local_trans::a2u(hg_scanner_err_description(ret), CP_UTF8));
MessageBoxW(NULL, msg.c_str(), L"\u6253\u5F00\u5931\u8D25", MB_OK | MB_ICONERROR);
}
return ret;
}
int scanner::close(void)
{
ui_hide();
callback::unreg_callback(this);
if (handle_)
{
hg_sane_middleware::instance()->close_device(handle_);
}
handle_ = NULL;
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 = NULL;
int ret = SCANNER_ERR_OK;
#define SET_OPT_ID(var, predef, func) \
SET_SANE_OPT_ID(op_id, var, predef, desc->name, func)
while ((desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, op_id)))
{
void* val = hg_sane_middleware::instance()->get_def_value(handle_, op_id);
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;
}
if (len)
cfg_->set_default_value(op_id, desc->name, (char*)val, len);
local_utility::free_memory(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)
op_id++;
}
#define EX_APPENDIX_API(name) \
{ \
EXAPI ea; \
ea.ind = ex_##name##_id_ = ex_id_++; \
ea.ex_api = &scanner::handle_ex_##name; \
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.ex_api = &scanner::handle_ex_erase_hole;
ex_opts_.push_back(ea);
ea.ind = search_hole_range_id_ = ex_id_++;
ea.ex_api = &scanner::handle_ex_search_hole_range;
ex_opts_.push_back(ea);
}
return ret;
}
int scanner::control_read_string(int code, std::string& ret)
{
return scanner::control_read_string(handle_, code, 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;
wchar_t 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);
{
swprintf_s(msg, _countof(msg) - 1, L"handle_ex_duplex of id: %d\r\n", ea.ind);
log_info(msg, 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);
{
swprintf_s(msg, _countof(msg) - 1, L"handle_ex_discard_blank_page of id: %d\r\n", ea.ind);
log_info(msg, 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);
{
swprintf_s(msg, _countof(msg) - 1, L"handle_ex_discard_blank_receipt of id: %d\r\n", ea.ind);
log_info(msg, 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);
{
swprintf_s(msg, _countof(msg) - 1, L"handle_ex_page_fold of id: %d\r\n", ea.ind);
log_info(msg, 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_)
{
SANE_Option_Descriptor* parent = hg_sane_middleware::instance()->get_option_descriptor(handle_, scan_mode_id_);
char* buf = new char[parent->size + 4];
memset(buf, 0, parent->size);
hg_sane_middleware::instance()->get_cur_value(handle_, scan_mode_id_, buf);
handled = compare_sane_opt(OPTION_VALUE_SMZS_LXSM, buf);
delete[] buf;
if (handled)
{
int count = -1;
value_role role = VAL_ROLE_CURRENT;
buf = (char*)hg_sane_middleware::instance()->get_def_value(handle_, scan_mode_id_);
if (compare_sane_opt(OPTION_VALUE_SMZS_LXSM, buf))
role = value_role(role | VAL_ROLE_DEFAULT);
local_utility::free_memory(buf);
setv(&count, value_role(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT), param);
}
}
else
handled = false;
return handled;
}
bool scanner::set_option_value_with_parent(int sn, void* data, int* err) // return true if handled
{
bool handled = true;
if (sn == scan_count_id_)
{
SANE_Option_Descriptor* parent = hg_sane_middleware::instance()->get_option_descriptor(handle_, scan_mode_id_);
char* val = new char[parent->size + 4];
SANE_Int after = 0;
memset(val, 0, parent->size + 4);
hg_sane_middleware::instance()->get_cur_value(handle_, scan_mode_id_, val);
if (compare_sane_opt(OPTION_VALUE_SMZS_LXSM, val))
{
if (*(int*)data != -1)
{
strcpy(val, OPTION_VALUE_SMZS_SMZDZS);
*err = hg_sane_middleware::instance()->set_option(handle_, scan_mode_id_, SANE_ACTION_SET_VALUE, val, &after);
}
}
else if (*(int*)data == -1)
{
strcpy(val, OPTION_VALUE_SMZS_LXSM);
*err = hg_sane_middleware::instance()->set_option(handle_, scan_mode_id_, SANE_ACTION_SET_VALUE, val, &after);
}
handled = false;
}
else
{
handled = false;
}
return handled;
}
int scanner::set_option_value(int sn, SANE_Value_Type type, int size, void* data)
{
char* buf = NULL;
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 = hg_sane_middleware::instance()->set_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;
}
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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
if (setv)
{
char* cur = new char[desc->size],
* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id);
int now = 0, // sane_opt_trans::multiout_value_to_twain(cur)
init = sane_opt_trans::multiout_value_to_twain(def),
val = 0;
local_utility::free_memory(def);
memset(cur, 0, desc->size);
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, cur);
now = sane_opt_trans::multiout_value_to_twain(cur);
delete[] cur;
{
// parent item ...
SANE_Bool enable = SANE_TRUE;
if (hg_sane_middleware::instance()->get_cur_value(handle_, is_multiout_id_, &enable))
{
if (!enable)
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 (!setv(&val, role, 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, 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"))
{
// enable multi-out ...
*((SANE_Bool*)val) = SANE_TRUE;
ret = hg_sane_middleware::instance()->set_option(handle_, is_multiout_id_, SANE_ACTION_SET_VALUE, val, &after);
strcpy(val, in);
}
else
{
// disable multi-out, let multiout type side
base_id = is_multiout_id_;
*((SANE_Bool*)val) = SANE_FALSE;
}
if (ret == SANE_STATUS_GOOD)
ret = hg_sane_middleware::instance()->set_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(auto_color_type)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
int len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
if (setv)
{
len = sane_opt_trans::auto_color_type_to_twain(buf);
setv(&len, VAL_ROLE_CURRENT, data);
}
else
{
SANE_Int after = 0;
strcpy(buf, sane_opt_trans::auto_color_type_from_twain(*(int*)data));
ret = hg_sane_middleware::instance()->set_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_mode)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
if (setv)
{
char* cur = new char[desc->size],
* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id);
int now = 0, // sane_opt_trans::multiout_value_to_twain(cur)
init = sane_opt_trans::color_mode_to_twain(def),
val = 0;
local_utility::free_memory(def);
memset(cur, 0, desc->size);
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, cur);
now = sane_opt_trans::color_mode_to_twain(cur);
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, 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::color_mode_from_twain(*(int*)data);
SANE_Int after = 0;
strcpy(val, in);
ret = hg_sane_middleware::instance()->set_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(sharpen)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
if (setv)
{
char* cur = new char[desc->size],
* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id);
int now = 0, // sane_opt_trans::multiout_value_to_twain(cur)
init = sane_opt_trans::sharpen_to_twain(def),
val = 0;
local_utility::free_memory(def);
memset(cur, 0, desc->size);
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, cur);
now = sane_opt_trans::sharpen_to_twain(cur);
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, 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;
ret = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
int len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
char* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id);
int now = sane_opt_trans::paper_to_twain(buf),
init = sane_opt_trans::paper_to_twain(def),
val = 0;
local_utility::free_memory(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, 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 = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
int len = desc->size + 4;
char* buf = new char[len];
const char* lateral_swap = NULL;
bool lateral = false;
memset(buf, 0, len);
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
lateral_swap = sane_opt_trans::switch_paper_lateral(buf);
lateral = sane_opt_trans::is_paper_lateral(buf);
if (setv)
{
setv(&lateral, VAL_ROLE_CURRENT, data);
}
else if (lateral_swap)
{
SANE_Int after = 0;
if (lateral != *(bool*)data)
{
strcpy(buf, lateral_swap);
ret = hg_sane_middleware::instance()->set_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, OPTION_VALUE_ZZCC_A4HX);
ret = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
int len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
if (setv)
{
bool yes = strcmp(buf, OPTION_VALUE_ZZCC_PPYSCC) == 0;
setv(&yes, VAL_ROLE_CURRENT, data);
}
else
{
SANE_Int after = 0;
strcpy(buf, *(bool*)data ? OPTION_VALUE_ZZCC_PPYSCC : OPTION_VALUE_ZZCC_A4);
ret = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
int len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
if (setv)
{
bool yes = strcmp(buf, OPTION_VALUE_ZZCC_ZDSMCCZDCQ) == 0;
setv(&yes, VAL_ROLE_CURRENT, data);
}
else
{
SANE_Int after = 0;
strcpy(buf, *(bool*)data ? OPTION_VALUE_ZZCC_ZDSMCCZDCQ : OPTION_VALUE_ZZCC_ZDSMCC);
ret = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
int len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
char* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id);
float now = .0f, init = sane_opt_trans::text_direction_to_twain(def), val = .0f;
local_utility::free_memory(def);
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
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, 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 = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
unsigned len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
void* init = hg_sane_middleware::instance()->get_def_value(handle_, base_id);
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
val = strcmp(buf, OPTION_VALUE_SMYM_SM) == 0;
if (val && strcmp((char*)init, OPTION_VALUE_SMYM_SM) == 0 ||
!val && strcmp((char*)init, OPTION_VALUE_SMYM_DM) == 0)
setv(&val, value_role(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT), data);
else if (setv(&val, VAL_ROLE_CURRENT, data))
{
if (strcmp((char*)init, OPTION_VALUE_SMYM_SM) == 0)
{
val = true;
setv(&val, VAL_ROLE_DEFAULT, data);
}
if (strcmp((char*)init, OPTION_VALUE_SMYM_DM) == 0)
{
val = false;
setv(&val, VAL_ROLE_DEFAULT, data);
}
}
local_utility::free_memory(init);
}
else
{
strcpy(buf, val ? OPTION_VALUE_SMYM_SM : OPTION_VALUE_SMYM_DM);
SANE_Int after = 0;
ret = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
unsigned len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id);
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
val = strcmp(buf, OPTION_VALUE_SMYM_SM) == 0;
set_cur_and_def_value<bool>(strcmp(buf, OPTION_VALUE_BJTCFS_TDBX) == 0, strcmp(init, OPTION_VALUE_BJTCFS_TDBX) == 0, setv, data);
local_utility::free_memory(init);
}
else
{
strcpy(buf, val ? OPTION_VALUE_BJTCFS_TDBX : OPTION_VALUE_BJTCFS_ADBX);
SANE_Int after = 0;
ret = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
unsigned len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
val = strcmp(buf, OPTION_VALUE_SMYM_TGKBYTY) == 0;
setv(&val, VAL_ROLE_CURRENT, data);
}
else
{
if (val)
strcpy(buf, OPTION_VALUE_SMYM_TGKBYTY);
else
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id);
strcpy(buf, init);
local_utility::free_memory(init);
}
SANE_Int after = 0;
ret = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
unsigned len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
val = strcmp(buf, OPTION_VALUE_SMYM_TGKBYFPZ) == 0;
setv(&val, VAL_ROLE_CURRENT, data);
}
else
{
if (val)
strcpy(buf, OPTION_VALUE_SMYM_TGKBYFPZ);
else
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id);
strcpy(buf, init);
local_utility::free_memory(init);
}
SANE_Int after = 0;
ret = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
unsigned len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
val = strcmp(buf, OPTION_VALUE_SMYM_DZ) == 0;
setv(&val, VAL_ROLE_CURRENT, data);
}
else
{
if (val)
strcpy(buf, OPTION_VALUE_SMYM_DZ);
else
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id);
strcpy(buf, init);
local_utility::free_memory(init);
}
SANE_Int after = 0;
ret = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
char* buf = NULL;
unsigned int len = 0;
if (desc)
{
len = desc->size + 4;
buf = new char[len];
memset(buf, 0, len);
if (setv)
{
bool filter = false;
int val = FILTER_NONE, now = FILTER_NONE;
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
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, 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 = hg_sane_middleware::instance()->set_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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id);
char* buf = NULL;
unsigned int len = 0;
if (desc)
{
len = desc->size + 4;
buf = new char[len];
memset(buf, 0, len);
if (setv)
{
bool filter = false;
int val = ENHANCE_NONE, now = ENHANCE_NONE;
hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf);
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, 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 = hg_sane_middleware::instance()->set_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)
{
int val = 0;
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_COMPRESSION, &val, &len);
if (ret == SANE_STATUS_GOOD)
{
int i = SANE_COMPRESSION_FIRST;
for (; i < SANE_COMPRESSION_LAST; ++i)
{
value_role role = VAL_ROLE_NONE;
if (i == val)
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, 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);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(final_format)
{
int ret = SCANNER_ERR_OK;
SANE_FinalImgFormat ff;
unsigned int len = sizeof(ff);
if (setv)
{
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_IMAGE_FORMAT, &ff, &len);
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, data))
break;
}
}
}
else
{
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, data);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(to_be_scan)
{
int ret = SCANNER_ERR_OK;
SANE_Bool wait_paper = SANE_FALSE;
unsigned int len = sizeof(wait_paper);
if (setv)
{
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_SCAN_WHEN_PAPER_ON, &wait_paper, &len);
if (ret == SANE_STATUS_GOOD)
{
bool val = wait_paper == SANE_TRUE;
setv(&val, VAL_ROLE_CURRENT, data);
}
}
else
{
wait_paper = *((bool*)data) ? SANE_TRUE : SANE_FALSE;
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_SCAN_WHEN_PAPER_ON, &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;
unsigned int len = sizeof(with_hole);
if (setv)
{
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_SCAN_WITH_HOLE, &with_hole, &len);
if (ret == SANE_STATUS_GOOD)
{
bool val = with_hole == SANE_TRUE;
setv(&val, VAL_ROLE_CURRENT, data);
}
}
else
{
with_hole = *((bool*)data) ? SANE_TRUE : SANE_FALSE;
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_SCAN_WITH_HOLE, &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_DEVICE_CODE, val);
if (ret == SANE_STATUS_GOOD)
setv(&val, VAL_ROLE_CURRENT, data);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(power)
{
int ret = SCANNER_ERR_OK;
if (setv)
{
SANE_Power now = SANE_POWER_MINUTES_30, init = SANE_POWER_MINUTES_30;
unsigned int len = sizeof(now);
hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_POWER_LEVEL, &now, &len);
for (int i = SANE_POWER_FIRST; i < SANE_POWER_LAST; ++i)
{
value_role role = VAL_ROLE_NONE;
if (i == now)
role = VAL_ROLE_CURRENT;
if (i == init)
role = value_role(role | VAL_ROLE_DEFAULT);
SANE_Power power = (SANE_Power)i;
if (!setv(&power, role, data))
break;
}
}
else
{
SANE_Power power = *((SANE_Power*)data);
unsigned int len = sizeof(power);
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_POWER_LEVEL, &power, &len);
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, 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, 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;
SANE_Int after = 0;
if (setv)
{
if (is_erase_hole_l_id_ != -1)
hg_sane_middleware::instance()->set_option(handle_, is_erase_hole_l_id_, SANE_ACTION_GET_VALUE, &yes, &after);
if (!yes && is_erase_hole_r_id_ != -1)
hg_sane_middleware::instance()->set_option(handle_, is_erase_hole_r_id_, SANE_ACTION_GET_VALUE, &yes, &after);
bool v = yes == SANE_TRUE;
setv(&v, VAL_ROLE_CURRENT, data);
ret = SCANNER_ERR_OK;
}
else
{
yes = *(bool*)data ? SANE_TRUE : SANE_FALSE;
if (is_erase_hole_l_id_ != -1)
ret = hg_sane_middleware::instance()->set_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 = hg_sane_middleware::instance()->set_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;
if (setv)
{
if (search_hole_range_l_id_ != -1)
hg_sane_middleware::instance()->set_option(handle_, search_hole_range_l_id_, SANE_ACTION_GET_VALUE, &val, &after);
rv = SANE_UNFIX(val);
if (search_hole_range_r_id_ != -1)
{
hg_sane_middleware::instance()->set_option(handle_, search_hole_range_r_id_, SANE_ACTION_GET_VALUE, &val, &after);
if (rv < SANE_UNFIX(val))
rv = SANE_UNFIX(val);
}
setv(&rv, VAL_ROLE_CURRENT, data);
ret = SCANNER_ERR_OK;
}
else
{
val = SANE_FIX(*(double*)data);
if (search_hole_range_l_id_ != -1)
ret = hg_sane_middleware::instance()->set_option(handle_, search_hole_range_l_id_, SANE_ACTION_SET_VALUE, &val, &after);
val = SANE_FIX(*(double*)data);
if (search_hole_range_r_id_ != -1)
ret = hg_sane_middleware::instance()->set_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;
events_.clear();
images_.clear();
scan_msg_ = "OK";
scan_err_ = false;
ret = hg_sane_middleware::instance()->start(handle_, NULL);
// 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 = hg_sane_middleware::instance()->start(handle_, NULL);
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(hg_scanner_err_description(ret), true);
//}
else
{
std::wstring msg(local_trans::a2u(hg_scanner_err_description(ret), CP_UTF8));
HWND parent = setting_.get() ? setting_->hwnd() : NULL;
if (indicator_.get())
indicator_->show(false);
MessageBoxW(parent, msg.c_str(), L"\u542F\u52A8\u5931\u8D25", MB_OK | MB_ICONERROR);
}
prev_start_result_ = ret;
is_scanning_ = ret == SANE_STATUS_GOOD;
return local_utility::sane_statu_2_scanner_err(ret);
}
COM_API_IMPLEMENT(scanner, int, stop(void))
{
return hg_sane_middleware::instance()->stop(handle_);
}
COM_API_IMPLEMENT(scanner, int, get_event(void))
{
return events_.take();
}
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 = 10;
is_ui_wait_img_ = true;
while (is_scanning_ && count == 0 && milliseconds)
{
MSG msg = { 0 };
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
Sleep(elapse);
int ev = get_event();
count = images_.count();
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();
{
wchar_t msg[128] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"Wait image count = %d\r\n", count);
log_info(msg, 0);
}
return count;
}
COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(twain_xfer xfer))
{
scanned_img* img = images_.take();
return dynamic_cast<IScanImg*>(img);
}
COM_API_IMPLEMENT(scanner, bool, get_first_image_header(SANE_Parameters* header, size_t* bytes))
{
return images_.get_header(header, bytes);
}
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 (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_PAPER_ON, &on, &len) == SANE_STATUS_GOOD)
return on == SANE_TRUE;
else
return false;
}
COM_API_IMPLEMENT(scanner, bool, get_option_info(int sn, value_type* type, value_limit* limit, int* bytes))
{
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, sn);
bool ret = false;
if (desc)
{
if (type)
*type = scanner::from_sane_type(desc->type);
if (limit)
*limit = scanner::from_sane_constraint(desc->constraint_type);
if (bytes)
*bytes = desc->size;
ret = true;
}
return ret;
}
COM_API_IMPLEMENT(scanner, bool, get_value(int sn, set_opt_value setval, void* param))
{
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;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, sn);
void* init = hg_sane_middleware::instance()->get_def_value(handle_, sn);
ret = SANE_STATUS_GOOD;
if (desc->type == SANE_TYPE_BOOL)
{
SANE_Bool v = SANE_FALSE;
bool val = false;
hg_sane_middleware::instance()->get_cur_value(handle_, sn, &v);
val = v == SANE_TRUE;
set_cur_and_def_value<bool>(val, *(SANE_Bool*)init == SANE_TRUE, setval, param);
}
else if (desc->type == SANE_TYPE_INT)
{
SANE_Int cur = 0, def = *(SANE_Int*)init;
int val = 0;
hg_sane_middleware::instance()->get_cur_value(handle_, sn, &cur);
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, 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;
hg_sane_middleware::instance()->get_cur_value(handle_, sn, &cur);
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, 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);
hg_sane_middleware::instance()->get_cur_value(handle_, sn, buf);
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 (!setval(&val, role, param))
break;
}
}
else
set_cur_and_def_value<std::string>(val, def, setval, param);
} while (0);
delete[] buf;
}
else
{
ret = SANE_STATUS_INVAL;
}
local_utility::free_memory(init);
}
else
{
ret = (this->*ex->ex_api)(ex->base_ind, param, setval);
}
return ret == SANE_STATUS_GOOD;
}
COM_API_IMPLEMENT(scanner, int, set_value(int sn, void* val))
{
EXAPIPOS ex = find_ex_api(sn);
int ret = SANE_STATUS_INVAL;
SANE_Int after = 0;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, sn);
{
wchar_t msg[128] = { 0 };
if (ex == ex_opts_.end())
swprintf_s(msg, _countof(msg) - 1, L"set_value of ID: %d\r\n", sn);
else
swprintf_s(msg, _countof(msg) - 1, L"set_value of ID: %d (base id = %d)\r\n", sn, ex->base_ind);
log_info(msg, 0);
}
if (ex == ex_opts_.end())
{
if (!set_option_value_with_parent(sn, val, &ret))
ret = set_option_value(sn, desc->type, desc->size, val);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
else
{
ret = (this->*ex->ex_api)(ex->base_ind, val, NULL);
}
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 hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_CONVERT_IMAGE_FORMAT, conv, NULL);
}
COM_API_IMPLEMENT(scanner, void, free_buffer(void* buf, int len))
{
hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_FREE_MEMORY, buf, (unsigned int*)&len);
}
// SANE options ID ...
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-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))
{
std::string cont(cfg_->to_text_stream());
if (*len < cont.length())
{
*len = cont.length() + 4;
return SCANNER_ERR_INSUFFICIENT_MEMORY;
}
strcpy(buf, cont.c_str());
return SCANNER_ERR_OK;
}
COM_API_IMPLEMENT(scanner, int, twain_set_config(char* buf, size_t len))
{
if(cfg_->load_from_mem(buf))
{
update_config();
apply_config();
return SCANNER_ERR_OK;
}
return SCANNER_ERR_DATA_DAMAGED;
}
// 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))
{
SANEAPI api = { NULL };
if (with_scan)
{
events_.clear();
images_.clear();
scan_msg_ = "OK";
scan_err_ = false;
}
api.sane_cancel_api = inner_sane_cancel;
api.sane_close_api = inner_sane_close;
api.sane_control_option_api = inner_sane_control_option;
api.sane_get_devices_api = inner_sane_get_devices;
api.sane_get_option_descriptor_api = inner_sane_get_option_descriptor;
api.sane_get_parameters_api = inner_sane_get_parameters;
api.sane_get_select_fd_api = inner_sane_get_select_fd;
api.sane_io_control_api = inner_sane_io_control;
api.sane_open_api = inner_sane_open;
api.sane_read_api = inner_sane_read;
api.sane_set_io_mode_api = inner_sane_set_io_mode;
api.sane_start_api = inner_sane_start;
api.sane_strstatus_api = inner_sane_strstatus;
size_t pid = scanner_name_.find(L" - ");
if (pid == -1)
pid = scanner_name_.length();
setting_.reset(new dlg_setting(parent, &api, handle_, with_scan, scanner_name_.substr(0, pid).c_str()));
setting_->set_ui_event_notify(&scanner::ui_callback, this);
setting_->set_config(cfg_, (cfg_path_ + scanner_name_.substr(0, pid)).c_str());
cfg_->begin_setting();
indicator_.reset();
if (indicator)
{
indicator_.reset(new dlg_indicator(setting_->hwnd()));
indicator_->set_ui_event_notify(&scanner::ui_callback, this);
}
setting_->show(true);
return true;
}
COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent))
{
if(setting_.get() && IsWindowVisible(setting_->hwnd()))
parent = setting_->hwnd();
indicator_.reset(new dlg_indicator(parent));
indicator_->set_ui_event_notify(&scanner::ui_callback, this);
indicator_->show(true);
return true;
}
COM_API_IMPLEMENT(scanner, void, ui_hide(void))
{
if (indicator_.get())
indicator_.reset();
if (setting_.get())
setting_.reset();
}
COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void))
{
return true;
}
// called from device-layer ...
int scanner::handle_device_event(int ev_code, void* data, unsigned int* len)
{
if (ev_code == SANE_EVENT_WORKING)
{
if (indicator_.get())
indicator_->notify_working();
else
events_.save(ev_code);
log_info(L"Scanning ...\r\n", 0);
}
else if (ev_code == SANE_EVENT_IMAGE_OK)
{
SANE_Image* simg = (SANE_Image*)data;
scanned_img* img = NULL;
wchar_t name[40] = { 0 };
swprintf_s(name, _countof(name) - 1, L"img_%05u.bmp", ++img_ind_);
img = new scanned_img(handle_, simg->header, simg->data, simg->bytes, dpi_, (tmp_path_ + name).c_str(), xfer_, &img_fmt_);
if (img->bytes() /*>= simg->bytes*/)
{
img->set_image_status((SANE_Image_Statu)simg->flag.statu);
images_.save(img);
}
else
{
img->release();
}
if (indicator_.get())
indicator_->notify_data_arrived(true);
{
wchar_t msg[128] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"New image(%u) received with %u bytes\r\n", img_ind_, simg->bytes);
log_info(msg, 0);
}
}
else if (ev_code == SANE_EVENT_USB_DATA_RECEIVED)
{
if (indicator_.get())
indicator_->notify_data_arrived(false);
}
else if (ev_code == SANE_EVENT_SCAN_FINISHED)
{
if (indicator_.get())
indicator_->notify_scan_over((char*)data, *len != SCANNER_ERR_OK);
else
events_.save(ev_code);
is_scanning_ = false;
{
wchar_t msg[128] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"Scan finished with error: %u\r\n", *len);
log_info(msg, 0);
}
}
return 0;
}
int scanner::last_error(void)
{
return err_;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// log ...
#include <direct.h>
std::mutex g_lock_;
std::string g_path_file_("");
FILE* g_file_ = NULL;
void init_log(void)
{
char* tmp = getenv("LOCALAPPDATA");
if (tmp)
{
std::string path(tmp);
char name[MAX_PATH] = { 0 }, * last = NULL;
path += std::string("\\") + PRODUCT_VENDOR + "Scan\\Log\\";
mkdir(path.c_str());
GetModuleFileNameA(NULL, name, _countof(name) - 1);
last = strrchr(name, '\\');
if (last++ == NULL)
last = name;
path += last;
path += "_twain.log";
g_file_ = fopen(path.c_str(), "a+b");
g_path_file_ = path;
}
else
{
char name[MAX_PATH] = { 0 }, * last = NULL;
std::string path("");
GetModuleFileNameA(NULL, name, _countof(name) - 1);
path = std::string(name) + "_twain.log";
g_file_ = fopen(path.c_str(), "a+b");
g_path_file_ = path;
}
if (g_file_)
{
fseek(g_file_, 0, SEEK_END);
if (ftell(g_file_))
{
std::wstring sep(L"\r\n\r\n\r\n=================================================\r\n");
fwrite(sep.c_str(), 2, sep.length(), g_file_);
}
else
{
unsigned short bom = 0x0feff;
fwrite(&bom, sizeof(bom), 1, g_file_);
}
time_t now = time(NULL);
struct tm* t = localtime(&now);
wchar_t ts[128] = { 0 };
swprintf_s(ts, _countof(ts) - 1, L"==================%04d-%02d-%02d %02d:%02d:%02d==================\r\n"
, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
fwrite(ts, 2, lstrlenW(ts), g_file_);
}
}
void close_log(void)
{
if (g_file_)
fclose(g_file_);
g_file_ = NULL;
}
void log(const wchar_t* info)
{
if (g_file_)
{
std::lock_guard<std::mutex> lock(g_lock_);
fwrite(info, 2, lstrlenW(info), g_file_);
fflush(g_file_);
if (ftell(g_file_) > 10 * 1024 * 1024)
{
fclose(g_file_);
remove(g_path_file_.c_str());
g_file_ = fopen(g_path_file_.c_str(), "a+b");
if (g_file_)
{
unsigned short bom = 0x0feff;
time_t now = time(NULL);
struct tm* t = localtime(&now);
wchar_t ts[128] = { 0 };
swprintf_s(ts, _countof(ts) - 1, L"==================%04d-%02d-%02d %02d:%02d:%02d (Truncated when size > 10MB) ==================\r\n"
, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
fwrite(&bom, sizeof(bom), 1, g_file_);
fwrite(ts, 2, lstrlenW(ts), g_file_);
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// exports
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
int __stdcall initialize(void* reserve)
{
init_log();
hg_sane_middleware::set_callback(callback::sane_event_callback, NULL);
hg_sane_middleware::instance();
return SANE_STATUS_GOOD;
}
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
int __stdcall open_scanner(SCANNERID scanner_id, ISaneInvoker** invoker)
{
if (!invoker)
return SCANNER_ERR_INVALID_PARAMETER;
if (!is_scanner_online(scanner_id))
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 = NULL;
return ret;
}
}
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
bool __stdcall is_scanner_online(SCANNERID scanner_id)
{
std::vector<std::string> que;
scanner::get_scanner_name(scanner_id, que);
return !que.empty();
}
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
int __stdcall uninitialize(void* reserve)
{
hg_sane_middleware::set_callback(NULL, NULL);
hg_sane_middleware::clear();
close_log();
return 0;
}
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
void __stdcall log_info(const wchar_t* info, int level)
{
log(info);
}