code_twain/huagaotwain/huagaotwain.cpp

2199 lines
54 KiB
C++

#include "pch.h"
#include "huagaotwain.h"
#include "huagao/hgscanner_error.h"
#include "./twain/twain_2.4.h"
#include "../../code_device/sdk/hginclude/hg_log.h"
#define STR(s) #s
#define PASTE_STR(a, b) STR(a##b)
#define SANE_API(api) PASTE_STR(sane_hgsane_, api)
#define API_ELEM(api) {SANE_API(api), (FARPROC*)&real_sane_##api##_}
#ifdef VLOG_OK
#define vlog_debug_info sane_invoker::log_debug_info
#else
#define vlog_debug_info
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// utilities ...
namespace local_utility
{
std::wstring reg_read(HKEY root, const wchar_t* path, const wchar_t* name)
{
HKEY key = NULL;
RegOpenKeyW(root, path, &key);
if (!key)
return L"";
wchar_t* buf = NULL;
DWORD len = 0;
DWORD type = REG_SZ;
std::wstring ret(L"");
RegQueryValueExW(key, name, NULL, &type, (LPBYTE)buf, &len);
if(len)
{
buf = new wchar_t[len + 4];
memset(buf, 0, (len + 4) * sizeof(*buf));
RegQueryValueExW(key, name, NULL, &type, (LPBYTE)buf, &len);
ret = buf;
delete[] buf;
}
RegCloseKey(key);
return ret;
}
std::wstring reg_get_app_installing_path(void)
{
return reg_read(HKEY_LOCAL_MACHINE, L"SOFTWARE\\HuaGoScan", L"AppDirectory");
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// scanned image ...
scanned_img::scanned_img(SANE_Image* img, SANE_FinalImgFormat* header) : param_(img->header)
{
// PBITMAPINFOHEADER
size_t bytes = line_bytes() * height();
std::string h(file_header(header, bytes));
unsigned char *src = img->data + img->bytes - param_.bytes_per_line,
*dst = NULL;
data_.resize(bytes + h.length());
memcpy(&data_[0], h.c_str(), h.length());
dst = (unsigned char*)&data_[0] + h.length();
if (param_.format == SANE_FRAME_RGB)
{
for (int i = 0; i < height(); ++i)
{
for (int j = 0; j < param_.pixels_per_line; ++j)
{
dst[j * 3 + 0] = src[j * 3 + 2];
dst[j * 3 + 1] = src[j * 3 + 1];
dst[j * 3 + 2] = src[j * 3 + 0];
}
src -= param_.bytes_per_line;
dst += line_bytes();
}
}
else
{
for (int i = 0; i < height(); ++i, dst += line_bytes(), src -= param_.bytes_per_line)
memcpy(dst, src, param_.bytes_per_line);
}
}
scanned_img::~scanned_img()
{}
std::string scanned_img::file_header(SANE_FinalImgFormat* header, float resolution)
{
std::string h("");
if (header->img_format == SANE_IMAGE_TYPE_BMP)
{
BITMAPINFOHEADER bih = { 0 };
bih.biSize = sizeof(bih);
bih.biWidth = width();
bih.biBitCount = depth();
bih.biSizeImage = line_bytes() * height();
bih.biPlanes = 1;
bih.biHeight = height();
bih.biCompression = BI_RGB;
bih.biXPelsPerMeter = bih.biYPelsPerMeter = resolution * 39.37f + .5f;
h = std::string((char*)&bih, sizeof(bih));
}
return h;
}
int scanned_img::width(void)
{
return param_.pixels_per_line;
}
int scanned_img::line_bytes(void)
{
return (param_.bytes_per_line + 3) / 4 * 4;
}
int scanned_img::height(void)
{
return param_.lines;
}
int scanned_img::depth(void)
{
if (param_.format == SANE_FRAME_RGB)
return param_.depth * 3;
else
return param_.depth;
}
int scanned_img::channel(void)
{
return param_.format == SANE_FRAME_RGB ? 3 : 1;
}
SANE_Frame scanned_img::type(void)
{
return param_.format;
}
unsigned int scanned_img::bytes(void)
{
return data_.size();
}
unsigned char* scanned_img::bits(void)
{
return &data_[0];
}
void scanned_img::copy_header(SANE_Parameters* head)
{
*head = param_;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// sane_invoker ...
sane_invoker* sane_invoker::inst_ = NULL;
sane_invoker::sane_invoker(const wchar_t* path) : ok_(false), ver_(0), sane_(NULL), first_cb_(NULL)
{
memset(&sane_api_, 0, sizeof(sane_api_));
cfg_file_ = std::wstring(path) + L"config.txt";
if (load_sane())
{
first_cb_ = CreateEventA(NULL, FALSE, FALSE, NULL);
real_sane_init_ex_(&ver_, &sane_invoker::sane_callback_handler, this);
char msg[128] = { 0 };
sprintf_s(msg, _countof(msg) - 1, "Wait sane first callback = %d\r\n", WaitForSingleObject(first_cb_, 1000));
sane_invoker::log_debug_info(msg);
}
}
sane_invoker::~sane_invoker()
{
if (sane_)
{
if(real_sane_exit_)
real_sane_exit_();
FreeLibrary(sane_);
sane_ = NULL;
}
if (first_cb_)
CloseHandle(first_cb_);
}
bool sane_invoker::load_sane()
{
//sane_hgsane_init
//sane_hgsane_exit
//sane_hgsane_get_devices
//sane_hgsane_open
//sane_hgsane_close
//sane_hgsane_get_option_descriptor
//sane_hgsane_control_option
//sane_hgsane_get_parameters
//sane_hgsane_start
//sane_hgsane_read
//sane_hgsane_cancel
//sane_hgsane_set_io_mode
//sane_hgsane_get_select_fd
//sane_hgsane_strstatus
//sane_hgsane_init_ex
//sane_hgsane_io_control
struct {
std::string name;
FARPROC* api;
}apis[] = { API_ELEM(init),
API_ELEM(exit),
API_ELEM(get_devices),
API_ELEM(open),
API_ELEM(close),
API_ELEM(get_option_descriptor),
API_ELEM(control_option),
API_ELEM(get_parameters),
API_ELEM(start),
API_ELEM(read),
API_ELEM(cancel),
API_ELEM(set_io_mode),
API_ELEM(get_select_fd),
API_ELEM(strstatus),
API_ELEM(io_control),
API_ELEM(init_ex)
};
wchar_t sane_path[MAX_PATH] = { 0 };
DWORD size = _countof(sane_path);
log_ = &sane_invoker::no_log;
for (int i = 0; i < _countof(apis); ++i)
*apis[i].api = NULL;
ok_ = false;
#ifdef USE_LOCAL_CONFIG
if (GetPrivateProfileStringW(L"sane", L"pe", L"", sane_path, size - 1, cfg_file_.c_str()))
#else
std::wstring reg(local_utility::reg_get_app_installing_path());
wcscpy_s(sane_path, size - 1, reg.c_str());
if(reg.length())
#endif
{
wcscat(sane_path, L"\\hgsane.dll");
size = sane_invoker::load_dll(sane_path, &sane_);
if (sane_)
{
ok_ = true;
*((FARPROC*)&log_) = GetProcAddress(sane_, "hg_debug_log");
if (!log_)
log_ = &sane_invoker::no_log;
for (int i = 0; i < _countof(apis); ++i)
{
*apis[i].api = GetProcAddress(sane_, apis[i].name.c_str());
if (!(*apis[i].api))
{
vlog_debug_info(1024, "GetProcAddress(\"sane.dll\", \"%s\") failed with error: %d\r\n", apis[i].name.c_str(), GetLastError());
ok_ = false;
}
}
if (ok_)
{
vlog_debug_info(1024, "sane component load success, path = \"%s\"\r\n", sane_invoker::u2ansi(sane_path).c_str());
for (int i = 0; i < sizeof(sane_api_) / sizeof(sane_api_.sane_cancel_api); ++i)
((FARPROC*)&sane_api_)[i] = *apis[i + 2].api;
}
}
else
{
vlog_debug_info(1024, "LoadLibraryW(\"%s\") failed with error: %d\r\n", sane_invoker::u2ansi(sane_path).c_str(), GetLastError());
}
}
else
{
vlog_debug_info(1024, "GetPrivateProfileStringW(\"sane\", \"pe\", \"%s\") failed\r\n", sane_invoker::u2ansi(cfg_file_.c_str()).c_str());
}
return ok_;
}
int sane_invoker::handle_sane_event(SANE_Handle hdev, int code, void* data, unsigned int* len)
{
SetEvent(first_cb_);
if (code == SANE_EVENT_DEVICE_ARRIVED)
{
SANE_Device* sdev = (SANE_Device*)data;
SANEDEV dev;
std::lock_guard<std::mutex> lock(lock_dev_);
std::vector<SANEDEV>::iterator it = std::find(devices_.begin(), devices_.end(), sdev->name);
if (it == devices_.end())
{
dev.name = sdev->name;
dev.type = sdev->model;
dev.product = sdev->type;
dev.vendor = sdev->vendor;
devices_.push_back(dev);
}
else if (it->scanner)
it->scanner->set_online(true);
}
else if (code == SANE_EVENT_DEVICE_LEFT)
{
SANE_Device* sdev = (SANE_Device*)data;
std::lock_guard<std::mutex> lock(lock_dev_);
std::vector<SANEDEV>::iterator it = std::find(devices_.begin(), devices_.end(), sdev->name);
if (it != devices_.end())
{
if (it->scanner)
it->scanner->set_online(false);
else
devices_.erase(it);
}
}
else if (code == SANE_EVENT_IMAGE_OK)
{
scanner* dev = find_scanner(hdev);
if (dev)
{
dev->put_image((SANE_Image*)data, len);
dev->release();
}
}
else if (code == SANE_EVENT_SCAN_FINISHED)
{
scanner* dev = find_scanner(hdev);
if (dev)
{
dev->scan_finished((char*)data, *len);
}
}
else if (code == SANE_EVENT_ERROR)
{
std::wstring msg(sane_invoker::utf82u((char*)data));
MessageBoxW(NULL, msg.c_str(), L"Error", MB_OK);
}
return SCANNER_ERR_OK;
}
void sane_invoker::get_online_devices(std::vector<SANEDEV>& devs)
{
std::lock_guard<std::mutex> lock(lock_dev_);
devs = devices_;
}
int sane_invoker::get_online_device_count(void)
{
std::lock_guard<std::mutex> lock(lock_dev_);
return devices_.size();
}
scanner* sane_invoker::find_scanner(SANE_Handle hdev)
{
std::lock_guard<std::mutex> lock(lock_dev_);
std::vector<SANEDEV>::iterator it = std::find(devices_.begin(), devices_.end(), hdev);
if (it == devices_.end())
return NULL;
else
{
it->scanner->add_ref();
return it->scanner;
}
}
scanner* sane_invoker::open(const char* name, int* err)
{
std::lock_guard<std::mutex> lock(lock_dev_);
std::vector<SANEDEV>::iterator it = std::find(devices_.begin(), devices_.end(), name);
if (it == devices_.end())
{
if (err)
*err = SCANNER_ERR_DEVICE_NOT_FOUND;
return NULL;
}
scanner *s = new scanner(this, *it);
if (s->last_error() != SANE_STATUS_GOOD)
{
if (err)
*err = s->last_error();
s->release();
s = NULL;
}
return s;
}
void sane_invoker::no_log(int, const char* info)
{
OutputDebugStringA(info);
}
int sane_invoker::sane_callback_handler(SANE_Handle hdev, int code, void* data, unsigned int* len, void* param)
{
return ((sane_invoker*)param)->handle_sane_event(hdev, code, data, len);
}
int sane_invoker::load_dll(const wchar_t* path_dll, HMODULE* dll)
{
HMODULE h = LoadLibraryW(path_dll);
int ret = 0;
if (!h && GetLastError() == ERROR_MOD_NOT_FOUND)
{
std::wstring dir(path_dll);
size_t pos = dir.rfind(L'\\');
wchar_t path[MAX_PATH] = { 0 };
GetCurrentDirectoryW(_countof(path) - 1, path);
if (pos != std::wstring::npos)
dir.erase(pos);
SetCurrentDirectoryW(dir.c_str());
h = LoadLibraryW(path_dll);
ret = GetLastError();
SetCurrentDirectoryW(path);
}
else
ret = GetLastError();
if (dll)
*dll = h;
return ret;
}
bool sane_invoker::initialize(HMODULE me)
{
if (sane_invoker::inst_)
return false;
else
{
wchar_t path[MAX_PATH] = { 0 }, * last = NULL;
GetModuleFileNameW(me, path, _countof(path) - 1);
last = wcsrchr(path, L'\\');
if (last++)
*last = 0;
sane_invoker::inst_ = new sane_invoker(path);
return true;
}
}
void sane_invoker::uninitialize(void)
{
if (sane_invoker::inst_)
delete sane_invoker::inst_;
sane_invoker::inst_ = NULL;
}
std::string sane_invoker::u2m(const wchar_t* u, int page)
{
char *ansi = NULL;
int len = 0;
std::string mb("");
len = WideCharToMultiByte(page, 0, u, lstrlenW(u), NULL, 0, NULL, NULL);
ansi = new char[len + 2];
len = WideCharToMultiByte(page, 0, u, lstrlenW(u), ansi, len, NULL, NULL);
ansi[len--] = 0;
mb = ansi;
delete[] ansi;
return mb;
}
std::wstring sane_invoker::m2u(const char* m, int page)
{
wchar_t *unic = NULL;
int len = 0;
std::wstring u(L"");
len = MultiByteToWideChar(page, 0, m, lstrlenA(m), NULL, 0);
unic = new wchar_t[len + 2];
len = MultiByteToWideChar(page, 0, m, lstrlenA(m), unic, len);
unic[len--] = 0;
u = unic;
delete[] unic;
return u;
}
std::string sane_invoker::u2ansi(const wchar_t* u)
{
return sane_invoker::u2m(u, CP_ACP);
}
std::string sane_invoker::u2utf8(const wchar_t* u)
{
return sane_invoker::u2m(u, CP_UTF8);
}
std::string sane_invoker::utf82ansi(const char* utf8)
{
return sane_invoker::u2m(sane_invoker::m2u(utf8, CP_UTF8).c_str(), CP_ACP);
}
std::string sane_invoker::ansi2utf8(const char* ansi)
{
return sane_invoker::u2m(sane_invoker::m2u(ansi, CP_ACP).c_str(), CP_UTF8);
}
std::wstring sane_invoker::utf82u(const char* utf8)
{
return sane_invoker::m2u(utf8, CP_UTF8);
}
std::wstring sane_invoker::ansi2u(const char* ansi)
{
return sane_invoker::m2u(ansi, CP_ACP);
}
void sane_invoker::log_debug_info(const char* info)
{
if (sane_invoker::inst_)
sane_invoker::inst_->log_(LOG_LEVEL_DEBUG_INFO, info);
else
OutputDebugStringA(info);
}
#ifdef VLOG_OK
void __cdecl sane_invoker::log_debug_info(int bytes, const char* fmt, ...)
{
std::string str(bytes + 20, 0);
va_list args;
va_start(args, fmt);
sprintf_s(&str[0], bytes, fmt, args);
va_end(args);
vlog_debug_info(str.c_str());
}
#endif
SANE_Status sane_invoker::invoke_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_init_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_init_(version_code, authorize);
}
void sane_invoker::invoke_sane_exit(void)
{
if (sane_invoker::inst_ && sane_invoker::inst_->real_sane_exit_)
sane_invoker::inst_->real_sane_exit_();
}
SANE_Status sane_invoker::invoke_sane_get_devices(const SANE_Device*** device_list, SANE_Bool local_only)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_get_devices_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_get_devices_(device_list, local_only);
}
SANE_Status sane_invoker::invoke_sane_open(SANE_String_Const devicename, SANE_Handle* handle)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_open_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_open_(devicename, handle);
}
void sane_invoker::invoke_sane_close(SANE_Handle handle)
{
if (sane_invoker::inst_ && sane_invoker::inst_->real_sane_close_)
sane_invoker::inst_->real_sane_close_(handle);
}
const SANE_Option_Descriptor* sane_invoker::invoke_sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)
{
if (!sane_invoker::inst_)
return NULL;
if (!sane_invoker::inst_->real_sane_get_option_descriptor_)
return NULL;
return sane_invoker::inst_->real_sane_get_option_descriptor_(handle, option);
}
SANE_Status sane_invoker::invoke_sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_control_option_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_control_option_(handle, option, action, value, info);
}
SANE_Status sane_invoker::invoke_sane_get_parameters(SANE_Handle handle, SANE_Parameters* params)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_get_parameters_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_get_parameters_(handle, params);
}
SANE_Status sane_invoker::invoke_sane_start(SANE_Handle handle)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_start_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_start_(handle);
}
SANE_Status sane_invoker::invoke_sane_read(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_read_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_read_(handle, data, max_length, length);
}
void sane_invoker::invoke_sane_cancel(SANE_Handle handle)
{
if (sane_invoker::inst_ && sane_invoker::inst_->real_sane_cancel_)
sane_invoker::inst_->invoke_sane_cancel(handle);
}
SANE_Status sane_invoker::invoke_sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_set_io_mode_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_set_io_mode_(handle, non_blocking);
}
SANE_Status sane_invoker::invoke_sane_get_select_fd(SANE_Handle handle, SANE_Int* fd)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_get_select_fd_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_get_select_fd_(handle, fd);
}
SANE_String_Const sane_invoker::invoke_sane_strstatus(SANE_Status status)
{
if (sane_invoker::inst_ && sane_invoker::inst_->real_sane_strstatus_)
return sane_invoker::inst_->real_sane_strstatus_(status);
else
return "";
}
SANE_Status sane_invoker::invoke_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_init_ex_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_init_ex_(version_code, cb, param);
}
SANE_Status sane_invoker::invoke_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len)
{
if (!sane_invoker::inst_)
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
if (!sane_invoker::inst_->real_sane_io_control_)
return SANE_STATUS_UNSUPPORTED;
return sane_invoker::inst_->real_sane_io_control_(h, code, data, len);
}
LPSANEAPI sane_invoker::get_api(void)
{
if (sane_invoker::inst_)
return &sane_invoker::inst_->sane_api_;
else
return NULL;
}
bool sane_invoker::is_ok(void)
{
if (sane_invoker::inst_)
return sane_invoker::inst_->ok_;
else
return false;
}
std::string sane_invoker::version(LPDWORD v)
{
char vs[40] = { 0 };
DWORD ver = 0;
if (sane_invoker::inst_)
ver = sane_invoker::inst_->ver_;
sprintf_s(vs, _countof(vs) - 1, "%u.%u.%u", (ver >> 24) & 0x0ff, (ver >> 16) & 0x0ff, ver & 0x0ffff);
if (v)
*v = ver;
return vs;
}
void sane_invoker::get_devices(std::vector<SANEDEV>& devs)
{
if (sane_invoker::inst_)
sane_invoker::inst_->get_online_devices(devs);
}
scanner* sane_invoker::open_scanner(const char* name, int* err)
{
if (!sane_invoker::inst_)
{
if (err)
*err = SCANNER_ERR_NOT_OPEN;
return NULL;
}
return sane_invoker::inst_->open(name, err);
}
int sane_invoker::online_devices(void)
{
if (sane_invoker::inst_)
sane_invoker::inst_->get_online_device_count();
else
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// scanner ...
#define FIND_OPTION(opt) \
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), opt);
scanner::scanner(sane_invoker* host, struct _dev& dev) : host_(host), hdev_(NULL), dpi_(200.0f), option_count_(0), event_cb_(NULL)
, name_(dev.name), type_(dev.type), vendor_(dev.vendor), product_(dev.product), cb_param_(NULL)
, scanning_(false), wait_img_(CreateEventA(NULL, TRUE, FALSE, NULL)), fmt_(NULL)
, opt_ind_dpi_(-1), opt_ind_color_mode_(-1), opt_ind_paper_(-1), opt_ind_scann_count_(-1)
, jpeg_quality_(80), opt_ind_text_direction_(-1), opt_ind_page_(-1), img_fmt_(SANE_IMAGE_TYPE_BMP)
, opt_ind_auto_descrew_(-1), opt_ind_erase_black_frame_(-1), opt_ind_filter_(-1), opt_ind_bright_(-1)
, opt_ind_contrast_(-1), opt_ind_gamma_(-1), opt_ind_ultrasonic_(-1), err_(SCANNER_ERR_OK), desc_("")
, compression_(SANE_COMPRESSION_NONE), opt_ind_flip_(-1), auto_crop_(false), opt_ind_rotate_bkg_(-1)
, opt_ind_fill_blank_bkg_(-1), opt_ind_edge_ident_(-1), opt_ind_threshold_(-1), opt_ind_bkg_filling_method_(-1)
, opt_ind_fill_hole_(-1), opt_ind_fill_hole_ratio_(-1), opt_ind_noise_(-1), opt_ind_noise_threshold_(-1)
, opt_ind_rid_red_hsv_(-1), opt_ind_rid_red_(-1), opt_ind_sharpen_(-1), opt_ind_screw_detect_(-1), opt_ind_screw_detect_level_(-1)
, opt_ind_staple_(-1), opt_ind_dogear_(-1), opt_ind_dark_sample_(-1), opt_ind_split_(-1), opt_ind_fade_bkg_(-1)
, opt_ind_fade_bkg_val_(-1), opt_ind_size_detect_(-1), opt_ind_multi_out_(-1)
{
dev.scanner = this;
SANE_Status statu = sane_invoker::invoke_sane_open(name_.c_str(), &hdev_);
online_ = statu == SANE_STATUS_GOOD;
{
vlog_debug_info(128, "scanner(0x%x) generated, open '%s' = %d\r\n", this, name_.c_str(), statu);
}
if (online_)
load_options();
init_image_format();
err_ = statu;
}
scanner::~scanner()
{
if (fmt_)
delete[](char*)fmt_;
for (auto& v : options_)
{
if (v.desc->type == SANE_Value_Type::SANE_TYPE_STRING)
delete v.val.sv;
}
vlog_debug_info(128, "scanner(0x%x) destroyed\r\n", this);
}
std::string scanner::type(SANE_Value_Type st)
{
switch (st)
{
case SANE_Value_Type::SANE_TYPE_BOOL:
return "bool";
case SANE_Value_Type::SANE_TYPE_BUTTON:
return "button";
case SANE_Value_Type::SANE_TYPE_FIXED:
return "float";
case SANE_Value_Type::SANE_TYPE_INT:
return "int";
case SANE_Value_Type::SANE_TYPE_STRING:
return "string";
default:
return "";
}
}
value_limit scanner::limit(SANE_Constraint_Type st)
{
switch (st)
{
case SANE_Constraint_Type::SANE_CONSTRAINT_RANGE:
return VAL_LIMIT_RANGE;
case SANE_Constraint_Type::SANE_CONSTRAINT_STRING_LIST:
case SANE_Constraint_Type::SANE_CONSTRAINT_WORD_LIST:
return VAL_LIMIT_ENUM;
default:
return VAL_LIMIT_NONE;
}
}
void scanner::load_options(void)
{
SANE_Int count = 0, afterdo = 0;
SANE_Status statu = sane_invoker::invoke_sane_control_option(hdev_, 0, SANE_ACTION_GET_VALUE, &count, &afterdo);
option_count_ = 0;
if (statu != SANE_STATUS_GOOD)
{
vlog_debug_info(128, "get option count failed with error: %d\r\n", statu);
return;
}
else
vlog_debug_info(128, "\"%s\" has %d options.\r\n", count);
option_count_ = count;
for (int i = 1; i < option_count_; ++i)
{
const SANE_Option_Descriptor* desc = sane_invoker::invoke_sane_get_option_descriptor(hdev_, i);
SANEOPTION op;
op.ind = i;
op.desc = desc;
if (desc->name == KNOWN_OPT_NAME_CUSTOM_GAMMA)
{
SANE_Int afterdo = 0;
SANE_Int *v = new SANE_Int[3 * 256];
sane_invoker::invoke_sane_control_option(hdev_, i, SANE_ACTION_GET_VALUE, v, &afterdo);
op.val.iv = 0;
delete[] v;
}
else if (desc->type == SANE_Value_Type::SANE_TYPE_BOOL)
op.val.bv = get_boolean(i);
else if (desc->type == SANE_Value_Type::SANE_TYPE_FIXED)
op.val.dv = get_double(i);
else if (desc->type == SANE_Value_Type::SANE_TYPE_INT)
op.val.iv = get_integer(i);
else if (desc->type == SANE_Value_Type::SANE_TYPE_STRING)
op.val.sv = new std::string(get_string(i, desc->size));
options_.push_back(op);
if (color_mode::is_me(desc->title))
opt_ind_color_mode_ = i;
else if (dpi::is_me(desc->title))
opt_ind_dpi_ = i;
else if (paper::is_me(desc->title))
opt_ind_paper_ = i;
else if (scan_count::is_me(desc->title))
opt_ind_scann_count_ = MAKELPARAM(i, HIWORD(opt_ind_scann_count_));
else if (scan_count::is_parent(desc->title))
opt_ind_scann_count_ = MAKELPARAM(LOWORD(opt_ind_scann_count_), i);
else if (text_direction::is_me(desc->title))
opt_ind_text_direction_ = i;
else if (page::is_me(desc->title))
opt_ind_page_ = i;
else if (auto_descrew::is_me(desc->title))
opt_ind_auto_descrew_ = i;
else if (erase_black_frame::is_me(desc->title))
opt_ind_erase_black_frame_ = i;
else if (filter::is_me(desc->title))
opt_ind_filter_ = i;
else if (bright::is_me(desc->title))
opt_ind_bright_ = i;
else if (contrast::is_me(desc->title))
opt_ind_contrast_ = i;
else if (gamma::is_me(desc->title))
opt_ind_gamma_ = i;
else if (ultrasonic::is_me(desc->title))
opt_ind_ultrasonic_ = i;
else if (flip::is_me(desc->title))
opt_ind_flip_ = i;
else if (rotate_bg::is_me(desc->title))
opt_ind_rotate_bkg_ = i;
else if (fill_black_border::is_me(desc->title))
opt_ind_fill_blank_bkg_ = i;
else if (edge_ident::is_me(desc->title))
opt_ind_edge_ident_ = i;
else if (threshold::is_me(desc->title))
opt_ind_threshold_ = i;
else if (bkg_filling_method::is_me(desc->title))
opt_ind_bkg_filling_method_ = i;
else if (fill_hole::is_me(desc->title))
opt_ind_fill_hole_ = i;
else if (fill_hole::is_ratio(desc->title))
opt_ind_fill_hole_ratio_ = i;
else if (noise::is_me(desc->title))
opt_ind_noise_ = i;
else if (noise::is_threshold(desc->title))
opt_ind_noise_threshold_ = i;
else if (rid_red::is_me(desc->title, false))
opt_ind_rid_red_ = i;
else if (rid_red::is_me(desc->title, true))
opt_ind_rid_red_hsv_ = i;
else if (sharpen::is_me(desc->title))
opt_ind_sharpen_ = i;
else if (screw::is_me(desc->title))
opt_ind_screw_detect_ = i;
else if (screw::is_level(desc->title))
opt_ind_screw_detect_level_ = i;
else if (staple::is_me(desc->title))
opt_ind_staple_ = i;
else if (dogear::is_me(desc->title))
opt_ind_dogear_ = i;
else if (sample::is_me(desc->title))
opt_ind_dark_sample_ = i;
else if (split::is_me(desc->title))
opt_ind_split_ = i;
else if (fade_bkg::is_me(desc->title))
opt_ind_fade_bkg_ = i;
else if (fade_bkg::is_value(desc->title))
opt_ind_fade_bkg_val_ = i;
else if (size_detect::is_me(desc->title))
opt_ind_size_detect_ = i;
else if (multi_out::is_me(desc->title))
opt_ind_multi_out_ = i;
}
}
void scanner::init_image_format(void)
{
if (fmt_)
delete[](char*)fmt_;
int len = sizeof(SANE_FinalImgFormat) + sizeof(BITMAPINFOHEADER);
PBITMAPINFOHEADER pbi = NULL;
fmt_ = (SANE_FinalImgFormat*)new char[len];
memset(fmt_, 0, len);
fmt_->img_format = SANE_IMAGE_TYPE_BMP;
pbi = (PBITMAPINFOHEADER)fmt_->detail;
}
std::string scanner::get_string(int opt, int bytes)
{
std::string ret("");
char* v = new char[bytes + 4];
SANE_Int afterdo = 0;
memset(v, 0, bytes + 4);
sane_invoker::invoke_sane_control_option(hdev_, opt, SANE_ACTION_GET_VALUE, v, &afterdo);
ret = v;
delete[] v;
return ret;
}
bool scanner::get_boolean(int opt)
{
SANE_Int afterdo = 0;
SANE_Bool v = 0;
sane_invoker::invoke_sane_control_option(hdev_, opt, SANE_ACTION_GET_VALUE, &v, &afterdo);
return v;
}
int scanner::get_integer(int opt)
{
SANE_Int afterdo = 0;
SANE_Int v = 0;
sane_invoker::invoke_sane_control_option(hdev_, opt, SANE_ACTION_GET_VALUE, &v, &afterdo);
return v;
}
double scanner::get_double(int opt)
{
SANE_Int afterdo = 0;
SANE_Fixed f = 0;
sane_invoker::invoke_sane_control_option(hdev_, opt, SANE_ACTION_GET_VALUE, &f, &afterdo);
return SANE_UNFIX(f);
}
int scanner::set_string(int opt, std::string& val, int size, SANE_Int* afterdo)
{
SANE_Int after = 0;
char* buf = new char[size + 20];
int ret = 0;
memset(buf, 0, size + 20);
strcpy(buf, val.c_str());
ret = sane_invoker::invoke_sane_control_option(hdev_, opt, SANE_ACTION_SET_VALUE, buf, &after);
val = buf;
delete[] buf;
if (afterdo)
*afterdo = after;
return ret;
}
int scanner::close(void)
{
if (hdev_)
{
sane_invoker::invoke_sane_close(hdev_);
hdev_ = NULL;
}
return SCANNER_ERR_OK;
}
int scanner::start(void)
{
int ret = SCANNER_ERR_NOT_OPEN;
ResetEvent(wait_img_);
if (hdev_)
ret = sane_invoker::invoke_sane_start(hdev_);
scanning_ = ret == SANE_STATUS_GOOD;
return ret;
}
int scanner::stop(void)
{
scanning_ = false;
if (hdev_)
sane_invoker::invoke_sane_cancel(hdev_);
return SCANNER_ERR_OK;
}
void scanner::set_event_callback(void(*cb)(int, void*, unsigned int*, void*), void* param)
{
cb_param_ = param;
event_cb_ = cb;
}
bool scanner::wait_image(DWORD milliseconds)
{
{
std::lock_guard<std::mutex> lock(lock_img_);
if (img_.size())
return true;
}
if (!scanning_)
{
if (err_)
{
std::wstring tips(sane_invoker::utf82u(desc_.c_str()));
MessageBoxW(NULL, tips.c_str(), L"\u9519\u8bef", MB_OK);
}
return false;
}
WaitForSingleObject(wait_img_, milliseconds);
return img_.size() > 0;
}
int scanner::get_scanned_images(DWORD milliseconds)
{
if (milliseconds && !wait_image(milliseconds))
return 0;
else
{
std::lock_guard<std::mutex> lock(lock_img_);
return img_.size();
}
}
scanned_img* scanner::take_first_image(void) // delete returned value, plz
{
std::lock_guard<std::mutex> lock(lock_img_);
scanned_img* img = NULL;
if (img_.size())
{
img = img_[0];
img_.erase(img_.begin());
ResetEvent(wait_img_);
}
return img;
}
bool scanner::get_first_image_header(SANE_Parameters* header)
{
std::lock_guard<std::mutex> lock(lock_img_);
if (img_.size())
{
img_[0]->copy_header(header);
header->bytes_per_line = img_[0]->line_bytes();
if (header->format == SANE_FRAME_RGB)
header->depth *= 3;
return true;
}
return false;
}
int scanner::last_error(void)
{
return err_;
}
SANE_Handle scanner::handle(void)
{
return hdev_;
}
bool scanner::is_online(void)
{
return online_;
}
void scanner::set_online(bool online)
{
online_ = online;
}
void scanner::put_image(SANE_Image* img, unsigned int* len)
{
std::lock_guard<std::mutex> lock(lock_img_);
img_.push_back(new scanned_img(img, fmt_));
SetEvent(wait_img_);
if (event_cb_)
event_cb_(SANE_EVENT_IMAGE_OK, (void*)img, len, cb_param_);
}
void scanner::scan_finished(const char* desc, int err)
{
desc_ = desc ? desc : "OK";
err_ = err;
scanning_ = false;
SetEvent(wait_img_);
if (event_cb_)
event_cb_(SANE_EVENT_SCAN_FINISHED, (void*)desc, (unsigned int*)&err, cb_param_);
}
// up to sane, we set the CAP_xxx according to settings display in UI ...
bool scanner::get_value_info(int sn, std::string& type, value_limit& limit)
{
if (sn <= 0 || sn >= option_count_)
return false;
FIND_OPTION(sn);
if (it == options_.end())
return false;
type = scanner::type(it->desc->type);
limit = scanner::limit(it->desc->constraint_type);
return true;
}
bool scanner::get_value(int sn, std::list<std::string>& values, std::string& now, std::string& init)
{
if (sn <= 0 || sn >= option_count_)
return false;
FIND_OPTION(sn);
if (it == options_.end())
return false;
if (scanner::type(it->desc->type) != "string" ||
scanner::limit(it->desc->constraint_type) != VAL_LIMIT_ENUM)
return false;
sane_trans::get_value_list(it->desc, &values);
init = *it->val.sv;
now = get_string(sn, it->desc->size);
return true;
}
bool scanner::get_value(int sn, std::list<float>& values, float& now, float& init)
{
if (sn <= 0 || sn >= option_count_)
return false;
FIND_OPTION(sn);
if (it == options_.end())
return false;
if (scanner::type(it->desc->type) != "float" ||
scanner::limit(it->desc->constraint_type) != VAL_LIMIT_ENUM)
return false;
std::list<double> vals;
sane_trans::get_value_list(it->desc, &vals);
for(const auto& v : vals)
values.push_back(v);
init = it->val.dv;
now = get_double(sn);
return true;
}
bool scanner::get_value(int sn, std::list<bool>& values, bool& now, bool& init)
{
if (sn <= 0 || sn >= option_count_)
return false;
FIND_OPTION(sn);
if (it == options_.end())
return false;
values.push_back(false);
values.push_back(true);
now = get_boolean(sn);
init = it->val.bv;
return true;
}
bool scanner::get_value(int sn, int& now, int& init, int* lower, int* upper, int* step)
{
if (sn <= 0 || sn >= option_count_)
return false;
FIND_OPTION(sn);
if (it == options_.end())
return false;
if (scanner::type(it->desc->type) != "int")
return false;
bool ret = true;
now = get_integer(sn);
init = it->val.iv;
if (lower && upper && step)
{
*lower = *upper = *step = 0;
if (scanner::limit(it->desc->constraint_type) == VAL_LIMIT_RANGE)
{
*lower = it->desc->constraint.range->min;
*upper = it->desc->constraint.range->max;
*step = it->desc->constraint.range->quant;
}
else
ret = false;
}
return ret;
}
bool scanner::get_value(int sn, float& now, float& init, float* lower, float* upper, float* step)
{
if (sn <= 0 || sn >= option_count_)
return false;
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), sn);
if (it == options_.end())
return false;
if (scanner::type(it->desc->type) != "float")
return false;
bool ret = true;
double ratio = sn == opt_ind_fill_hole_ratio_ ? 100.0f : 1.0f;
now = get_double(sn) * ratio;
init = it->val.dv * ratio;
if (lower && upper && step)
{
*lower = *upper = *step = 0;
if (scanner::limit(it->desc->constraint_type) == VAL_LIMIT_RANGE)
{
*lower = SANE_UNFIX(it->desc->constraint.range->min) * ratio;
*upper = SANE_UNFIX(it->desc->constraint.range->max) * ratio;
*step = SANE_UNFIX(it->desc->constraint.range->quant) * ratio;
}
else
ret = false;
}
return ret;
}
int scanner::set_value(int sn, std::string val)
{
if (sn <= 0 || sn >= option_count_)
return SCANNER_ERR_OUT_OF_RANGE;
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), sn);
if (it == options_.end())
return SCANNER_ERR_NO_DATA;
if (scanner::type(it->desc->type) != "string" ||
val.length() > it->desc->size)
return SCANNER_ERR_INVALID_PARAMETER;
char* buf = new char[it->desc->size + 20];
int ret = SCANNER_ERR_OK;
SANE_Int afterdo = 0;
memset(buf, 0, it->desc->size + 20);
strcpy(buf, val.c_str());
ret = sane_invoker::invoke_sane_control_option(hdev_, sn, SANE_ACTION_SET_VALUE, buf, &afterdo);
if (sn == opt_ind_paper_ && (ret == SCANNER_ERR_OK || ret == SCANNER_ERR_NOT_EXACT))
{
auto_crop_ = paper::is_auto_crop(buf);
}
delete[] buf;
return ret;
}
int scanner::set_value(int sn, bool val)
{
if (sn <= 0 || sn >= option_count_)
return SCANNER_ERR_OUT_OF_RANGE;
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), sn);
if (it == options_.end())
return SCANNER_ERR_NO_DATA;
if (scanner::type(it->desc->type) != "bool" &&
scanner::type(it->desc->type) != "button")
return SCANNER_ERR_INVALID_PARAMETER;
int ret = SCANNER_ERR_OK;
SANE_Int afterdo = 0;
SANE_Bool v = val;
ret = sane_invoker::invoke_sane_control_option(hdev_, sn, SANE_ACTION_SET_VALUE, &v, &afterdo);
return ret;
}
int scanner::set_value(int sn, int val)
{
if (sn <= 0 || sn >= option_count_)
return SCANNER_ERR_OUT_OF_RANGE;
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), sn);
if (it == options_.end())
return SCANNER_ERR_NO_DATA;
if (scanner::type(it->desc->type) != "int")
return SCANNER_ERR_INVALID_PARAMETER;
int ret = SCANNER_ERR_OK;
SANE_Int afterdo = 0;
SANE_Int v = val;
ret = sane_invoker::invoke_sane_control_option(hdev_, sn, SANE_ACTION_SET_VALUE, &v, &afterdo);
return ret;
}
int scanner::set_value(int sn, double val)
{
if (sn <= 0 || sn >= option_count_)
return SCANNER_ERR_OUT_OF_RANGE;
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), sn);
if (it == options_.end())
return SCANNER_ERR_NO_DATA;
if (scanner::type(it->desc->type) != "float")
return SCANNER_ERR_INVALID_PARAMETER;
if (sn == opt_ind_fill_hole_ratio_)
val /= 100.0f;
int ret = SCANNER_ERR_OK;
SANE_Int afterdo = 0;
SANE_Fixed v = SANE_FIX(val);
ret = sane_invoker::invoke_sane_control_option(hdev_, sn, SANE_ACTION_SET_VALUE, &v, &afterdo);
return ret;
}
int scanner::twain_set_resolution(float dpi)
{
float l = .0f, u = .0f, n = .0f, i = .0f;
if(opt_ind_dpi_ == -1 ||
!get_value(opt_ind_dpi_, n, i, &l, &u))
return dpi >= 200.0f && dpi <= 600.0f ? SCANNER_ERR_OK : SCANNER_ERR_INVALID_PARAMETER;
if (dpi <= l || dpi >= u)
return SCANNER_ERR_INVALID_PARAMETER;
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), opt_ind_dpi_);
SANE_Fixed v = it->desc->type == SANE_TYPE_FIXED ? SANE_FIX(dpi) : dpi;
SANE_Int afterdo = 0;
int ret = sane_invoker::invoke_sane_control_option(hdev_, opt_ind_dpi_, SANE_ACTION_SET_VALUE, &v, &afterdo);
dpi_ = it->desc->type == SANE_TYPE_FIXED ? SANE_UNFIX(v) : v;
return ret;
}
float scanner::twain_get_resolution(float* init, std::vector<float>* values, value_limit* limit)
{
if (opt_ind_dpi_ != -1)
{
std::vector< SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), opt_ind_dpi_);
if (it != options_.end())
{
if(init)
*init = it->val.dv;
if (limit)
*limit = scanner::limit(it->desc->constraint_type);
if (values && (it->desc->type == SANE_TYPE_FIXED || it->desc->type == SANE_TYPE_INT))
{
if (it->desc->constraint_type == SANE_CONSTRAINT_WORD_LIST)
{
const SANE_Word* val = it->desc->constraint.word_list;
for (SANE_Word i = 1; i < val[0]; ++i)
values->push_back(it->desc->type == SANE_TYPE_FIXED ? SANE_UNFIX(val[i]) : val[i]);
}
else if (it->desc->constraint_type == SANE_CONSTRAINT_RANGE)
{
const SANE_Range* r = it->desc->constraint.range;
values->push_back(it->desc->type == SANE_TYPE_FIXED ? SANE_UNFIX(r->min) : r->min);
values->push_back(it->desc->type == SANE_TYPE_FIXED ? SANE_UNFIX(r->max) : r->max);
}
}
}
}
if (values && values->empty())
{
values->push_back(100.0f);
values->push_back(600.0f);
if (limit)
*limit = VAL_LIMIT_RANGE;
}
return dpi_;
}
int scanner::twain_set_color_mode(int twain_pixel_type)
{
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
for (const auto& v : options_)
{
if (v.ind != opt_ind_color_mode_)
continue;
std::string val(color_mode::from_twain_pixel_type(twain_pixel_type));
char* buf = new char[v.desc->size + 8];
SANE_Int afterdo = 0;
memset(buf, 0, v.desc->size + 8);
strcpy(buf, val.c_str());
ret = sane_invoker::invoke_sane_control_option(hdev_, v.ind, SANE_ACTION_SET_VALUE, buf, &afterdo);
delete buf;
break;
}
return SCANNER_ERR_OK;
}
int scanner::twain_get_color_mode(int* init, std::vector<int>* values, value_limit* limit)
{
int tw_pixel_type = TWPT_RGB;
for(const auto& v : options_)
{
if (v.ind != opt_ind_color_mode_)
continue;
if (v.desc->type == SANE_Value_Type::SANE_TYPE_STRING)
{
SANE_Int afterdo = 0;
char* now = new char[v.desc->size + 8];
memset(now, 0, v.desc->size + 8);
sane_invoker::invoke_sane_control_option(hdev_, v.ind, SANE_ACTION_GET_VALUE, now, &afterdo);
tw_pixel_type = color_mode::to_twain_pixel_type(now);
if (init)
*init = color_mode::to_twain_pixel_type(v.val.sv->c_str());
if (values && limit)
{
std::list<std::string> vals;
if (sane_trans::get_value_list(v.desc, &vals))
{
*limit = VAL_LIMIT_ENUM;
for (const auto& var : vals)
values->push_back(color_mode::to_twain_pixel_type(var.c_str()));
}
}
delete[] now;
}
break;
}
if (values && values->empty())
{
values->push_back(TWPT_BW);
values->push_back(TWPT_GRAY);
values->push_back(TWPT_RGB);
if (limit)
*limit = VAL_LIMIT_ENUM;
}
return tw_pixel_type;
}
int scanner::twain_set_auto_color_type(int type)
{
unsigned int len = sizeof(type);
return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_AUTO_COLOR_TYPE, &type, &len);
}
int scanner::twain_get_paper_ind(void)
{
return opt_ind_paper_;
}
int scanner::twain_set_paper_lateral(bool lateral)
{
FIND_OPTION(opt_ind_paper_);
if (it == options_.end())
return SCANNER_ERR_INVALID_PARAMETER;
std::list<std::string> vals;
std::string now(get_string(opt_ind_paper_, it->desc->size));
size_t pos = now.find(paper::lateral_title());
int ret = SCANNER_ERR_OK;
if (lateral)
{
if (!paper::is_lateral(now.c_str()))
{
now += paper::lateral_title();
sane_trans::get_value_list(it->desc, &vals);
if (std::find(vals.begin(), vals.end(), now) == vals.end())
ret = SCANNER_ERR_INVALID_PARAMETER;
else
{
ret = set_string(opt_ind_paper_, now, it->desc->size);
}
}
}
else
{
if (paper::is_lateral(now.c_str()))
{
size_t pos = now.find(paper::lateral_title());
if (pos != std::string::npos)
{
now.erase(pos);
ret = set_string(opt_ind_paper_, now, it->desc->size);
}
}
}
return ret;
}
bool scanner::twain_is_paper_lateral(void)
{
FIND_OPTION(opt_ind_paper_);
if (it == options_.end())
return false;
std::string now(get_string(opt_ind_paper_, it->desc->size));
return paper::is_lateral(now.c_str());
}
int scanner::twain_set_paper_auto_match_size(bool match)
{
FIND_OPTION(opt_ind_paper_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
std::string val(match ? paper::auto_size_title() : *it->val.sv);
return set_string(opt_ind_paper_, val, it->desc->size);
}
bool scanner::twain_is_paper_auto_match_size(void)
{
FIND_OPTION(opt_ind_paper_);
if (it == options_.end())
return false;
std::string now(get_string(opt_ind_paper_, it->desc->size));
return paper::is_auto_size(now.c_str());
}
int scanner::twain_set_scan_count(int count)
{
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
if (opt_ind_scann_count_ != -1)
{
SANE_Int afterdo = 0;
char buf[80] = { 0 };
strcpy(buf, scan_count::scan_continous_val().c_str());
if (count == -1)
{
ret = sane_invoker::invoke_sane_control_option(hdev_, HIWORD(opt_ind_scann_count_), SANE_ACTION_SET_VALUE, buf, &afterdo);
}
else
{
std::list<std::string> vals;
std::string now(""), init("");
get_value(HIWORD(opt_ind_scann_count_), vals, now, init);
for (const auto& v : vals)
{
if (v != buf)
{
init = v;
break;
}
}
strcpy(buf, init.c_str());
ret = sane_invoker::invoke_sane_control_option(hdev_, HIWORD(opt_ind_scann_count_), SANE_ACTION_SET_VALUE, buf, &afterdo);
if (ret == SANE_STATUS_GOOD)
{
SANE_Int v = count;
ret = sane_invoker::invoke_sane_control_option(hdev_, LOWORD(opt_ind_scann_count_), SANE_ACTION_SET_VALUE, &v, &afterdo);
}
}
}
return ret;
}
int scanner::twain_get_scan_count(void)
{
int ret = -1;
if (opt_ind_scann_count_ != -1)
{
char buf[80] = { 0 };
SANE_Int afterdo = 0, count = -1;
ret = sane_invoker::invoke_sane_control_option(hdev_, HIWORD(opt_ind_scann_count_), SANE_ACTION_GET_VALUE, buf, &afterdo);
if (scan_count::scan_continous_val() == buf)
ret = -1;
else
{
sane_invoker::invoke_sane_control_option(hdev_, LOWORD(opt_ind_scann_count_), SANE_ACTION_GET_VALUE, &count, &afterdo);
ret = count;
}
}
return ret;
}
int scanner::twain_set_final_format(SANE_ImageType type, void* param)
{
SANE_FinalImgFormat fmt;
unsigned int len = sizeof(fmt);
int ret = SCANNER_ERR_OK;
fmt.img_format = type;
fmt.detail = param;
ret = sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_FINAL_IMAGE_FORMAT, &fmt, &len);
if (ret == SCANNER_ERR_OK)
{
if (type == SANE_IMAGE_TYPE_JPG)
jpeg_quality_ = (int)param;
img_fmt_ = type;
}
return ret;
}
int scanner::twain_get_jpeg_quality(void)
{
return jpeg_quality_;
}
SANE_ImageType scanner::get_final_format(void)
{
return img_fmt_;
}
int scanner::twain_set_final_compression(int compression)
{
SANE_Compression compr;
unsigned int len = sizeof(compr);
int ret = SCANNER_ERR_OK;
compr.compression = (SANE_CompressionType)compression;
compr.detail = NULL;
ret = sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_FINAL_COMPRESSION, &compr, &len);
if (ret == SCANNER_ERR_OK || ret == SCANNER_ERR_NOT_EXACT)
compression_ = compr.compression;
return ret;
}
int scanner::twain_get_final_compression(int* init, std::vector<int>* values)
{
if (init || values)
{
SANE_Int vals[80] = { 0 };
unsigned int len = _countof(vals) - 4;
int ret = sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_FINAL_COMPRESSION, vals, &len);
if (ret == SCANNER_ERR_OK)
{
if (init)
*init = vals[1];
if (values)
{
for (int i = 0; i < vals[0]; ++i)
values->push_back(vals[3 + i]);
}
}
compression_ = (SANE_CompressionType)vals[2];
}
return compression_;
}
int scanner::twain_set_text_direction(double degree)
{
int ret = SCANNER_ERR_INVALID_PARAMETER;
std::string val(text_direction::from_twain_angle(degree));
if (val.length())
{
FIND_OPTION(opt_ind_text_direction_);
if (it != options_.end())
{
ret = set_string(opt_ind_text_direction_, val, it->desc->size);
}
}
return ret;
}
double scanner::twain_get_text_direction(double* init, std::list<double>* vals, value_limit* limit)
{
double dir = .0f;
FIND_OPTION(opt_ind_text_direction_);
if (it != options_.end())
{
if (init)
*init = text_direction::to_twain_angle(it->val.sv->c_str());
if (vals)
{
std::list<std::string> values;
sane_trans::get_value_list(it->desc, &values);
for (const auto& v : values)
vals->push_back(text_direction::to_twain_angle(v.c_str()));
if (limit)
*limit = scanner::limit(it->desc->constraint_type);
}
dir = text_direction::to_twain_angle(get_string(opt_ind_text_direction_, it->desc->size).c_str());
}
return dir;
}
int scanner::twain_set_text_auto_matic(bool am)
{
FIND_OPTION(opt_ind_text_direction_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
std::string val(am ? text_direction::auto_val() : text_direction::from_twain_angle(0));
return set_string(opt_ind_text_direction_, val, it->desc->size);
}
bool scanner::twain_is_text_auto_matic(void)
{
FIND_OPTION(opt_ind_text_direction_);
if (it == options_.end())
return false;
return text_direction::is_auto(get_string(opt_ind_text_direction_, it->desc->size).c_str());
}
int scanner::twain_set_page_duplex(bool dup)
{
std::string val(page::from_duplex(dup));
FIND_OPTION(opt_ind_page_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
return set_string(opt_ind_page_, val, it->desc->size);
}
bool scanner::twain_is_page_duplex(void)
{
FIND_OPTION(opt_ind_page_);
if (it == options_.end())
return true;
std::string now(get_string(opt_ind_page_, it->desc->size));
return page::is_duplex(now.c_str());
}
int scanner::twain_set_page_discarding_blank_page(bool discard, bool receipt)
{
std::string val(discard ? page::discard_blank_page_title(receipt) : page::from_duplex(true));
FIND_OPTION(opt_ind_page_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
return set_string(opt_ind_page_, val, it->desc->size);
}
bool scanner::twain_is_page_discarding_blank_page(bool receipt)
{
FIND_OPTION(opt_ind_page_);
if (it == options_.end())
return true;
std::string now(get_string(opt_ind_page_, it->desc->size));
return page::is_discard_blank_page(now.c_str(), receipt);
}
int scanner::twain_set_page_fold(bool fold)
{
std::string val(page::fold_page_title());
FIND_OPTION(opt_ind_page_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
return set_string(opt_ind_page_, val, it->desc->size);
}
bool scanner::twain_is_page_fold(void)
{
FIND_OPTION(opt_ind_page_);
if (it == options_.end())
return true;
std::string now(get_string(opt_ind_page_, it->desc->size));
return page::is_fold(now.c_str());
}
int scanner::twain_set_auto_descrew(bool enable)
{
FIND_OPTION(opt_ind_auto_descrew_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
SANE_Bool v = enable;
SANE_Int after = 0;
return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_auto_descrew_, SANE_ACTION_SET_VALUE, &v, &after);
}
bool scanner::twain_is_auto_descrew(void)
{
return get_boolean(opt_ind_auto_descrew_);
}
int scanner::twain_set_erase_black_frame(bool erase)
{
FIND_OPTION(opt_ind_erase_black_frame_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
SANE_Bool v = erase;
SANE_Int after = 0;
return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_erase_black_frame_, SANE_ACTION_SET_VALUE, &v, &after);
}
bool scanner::twain_is_erase_black_frame(bool* init)
{
FIND_OPTION(opt_ind_erase_black_frame_);
if (it == options_.end())
return false;
if (init)
*init = it->val.bv;
return get_boolean(opt_ind_erase_black_frame_);
}
int scanner::twain_set_filter(int tw_filter, bool enhance)
{
FIND_OPTION(opt_ind_filter_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
std::string val(filter::from_filter_type(tw_filter, enhance));
return set_string(opt_ind_filter_, val, it->desc->size);
}
int scanner::twain_get_filter(bool enhance)
{
FIND_OPTION(opt_ind_filter_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
std::string val(get_string(opt_ind_filter_, it->desc->size));
return filter::to_filter_type(val.c_str(), enhance);
}
int scanner::twain_set_bright(double bright)
{
FIND_OPTION(opt_ind_bright_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
SANE_Fixed v = SANE_FIX(bright);
SANE_Int after = 0;
return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_bright_, SANE_ACTION_SET_VALUE, &v, &after);
}
double scanner::twain_get_bright(double* init, double* lower, double* upper, double* step)
{
FIND_OPTION(opt_ind_bright_);
if (it == options_.end())
return .0f;
if(lower && upper)
sane_trans::get_value_range(it->desc, lower, upper);
if (init)
*init = it->val.dv;
if (step)
*step = 1.0f;
return get_double(opt_ind_bright_);
}
int scanner::twain_set_contrast(double bright)
{
FIND_OPTION(opt_ind_contrast_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
SANE_Fixed v = SANE_FIX(bright);
SANE_Int after = 0;
return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_contrast_, SANE_ACTION_SET_VALUE, &v, &after);
}
double scanner::twain_get_contrast(double* init, double* lower, double* upper, double* step)
{
FIND_OPTION(opt_ind_contrast_);
if (it == options_.end())
return .0f;
if (lower && upper)
sane_trans::get_value_range(it->desc, lower, upper);
if (init)
*init = it->val.dv;
if (step)
*step = 1.0f;
return get_double(opt_ind_contrast_);
}
int scanner::twain_set_gamma(double bright)
{
FIND_OPTION(opt_ind_gamma_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
SANE_Fixed v = SANE_FIX(bright);
SANE_Int after = 0;
return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_gamma_, SANE_ACTION_SET_VALUE, &v, &after);
}
double scanner::twain_get_gamma(double* init, double* lower, double* upper, double* step)
{
FIND_OPTION(opt_ind_gamma_);
if (it == options_.end())
return .0f;
if (lower && upper)
sane_trans::get_value_range(it->desc, lower, upper);
if (init)
*init = it->val.dv;
if (step)
*step = 1.0f;
return get_double(opt_ind_gamma_);
}
int scanner::twain_set_ultrasonic_check(bool check)
{
FIND_OPTION(opt_ind_ultrasonic_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
SANE_Bool v = check;
SANE_Int after = 0;
return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_ultrasonic_, SANE_ACTION_SET_VALUE, &v, &after);
}
bool scanner::twain_is_ultrasonic_check(bool* init)
{
FIND_OPTION(opt_ind_ultrasonic_);
if (it == options_.end())
return false;
if (init)
*init = it->val.bv;
return get_boolean(opt_ind_ultrasonic_);
}
bool scanner::twain_is_auto_crop(void)
{
return auto_crop_;
}
bool scanner::twain_is_paper_on(void)
{
SANE_Bool on = false;
unsigned int len = sizeof(on);
sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_PAPER_ON, &on, &len);
return on;
}
int scanner::twain_get_device_code(char* buf, unsigned int len)
{
return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_DEVICE_CODE, buf, &len);
}
int scanner::twain_set_sharpen(int sharpen)
{
std::string val(sharpen::from_type(sharpen));
FIND_OPTION(opt_ind_sharpen_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
return set_string(opt_ind_sharpen_, val, it->desc->size);
}
int scanner::twain_get_sharpen(void)
{
FIND_OPTION(opt_ind_sharpen_);
if (it == options_.end())
return SHARPEN_NONE;
std::string now(get_string(opt_ind_sharpen_, it->desc->size));
return sharpen::to_type(now.c_str());
}
int scanner::twain_get_serial_num(char buf[])
{
unsigned int len = 240;
return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_SERIAL, buf, &len);
}
int scanner::twain_get_hareware_version(char buf[])
{
unsigned int len = 240;
return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_HARDWARE_VERSION, buf, &len);
}
int scanner::twain_get_ip(char buf[])
{
unsigned int len = 240;
return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_IP, buf, &len);
}
int scanner::twain_get_dogear_distance(void)
{
SANE_Int v = 0;
unsigned int len = sizeof(v);
sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_DOGEAR_DISTANCE, &v, &len);
return v;
}
int scanner::twain_set_dogear_distance(int dist)
{
SANE_Int v = dist;
unsigned int len = sizeof(v);
return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_DOGEAR_DISTANCE, &v, &len);
}
int scanner::twain_set_power_level(int level)
{
SANE_Power v = (SANE_Power)level;
unsigned int len = sizeof(v);
return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_POWER_LEVEL, &v, &len);
}
int scanner::twain_get_power_level(void)
{
SANE_Power v = SANE_POWER_NONE;
unsigned int len = sizeof(v);
sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_POWER_LEVEL, &v, &len);
return v;
}
int scanner::twain_set_to_be_scan(bool yes)
{
SANE_Bool v = yes;
unsigned int len = sizeof(v);
return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_SCAN_WHEN_PAPER_ON, &v, &len);
}
bool scanner::twain_get_to_be_scan(void)
{
SANE_Bool v = 0;
unsigned int len = sizeof(v);
sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_SCAN_WHEN_PAPER_ON, &v, &len);
return v;
}
int scanner::twain_set_scan_with_hole(bool yes)
{
SANE_Bool v = yes;
unsigned int len = sizeof(v);
return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_SCAN_WITH_HOLE, &v, &len);
}
bool scanner::twain_get_scan_with_hole(void)
{
SANE_Bool v = 0;
unsigned int len = sizeof(v);
sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_SCAN_WITH_HOLE, &v, &len);
return v;
}
int scanner::twain_set_multioutput_type(int type)
{
FIND_OPTION(opt_ind_multi_out_);
if (it == options_.end())
return SCANNER_ERR_NOT_OPEN;
std::string val(multi_out::from_twain_type(type));
return set_string(opt_ind_multi_out_, val, it->desc->size);
}
int scanner::twain_get_multioutput_type(void)
{
FIND_OPTION(opt_ind_multi_out_);
if (it == options_.end())
return MULTI_OUT_NONE;
std::string now(get_string(opt_ind_multi_out_, it->desc->size));
return multi_out::to_twain_type(now.c_str());
}
int scanner::twain_get_flip_ind(void)
{
return opt_ind_flip_;
}
int scanner::twain_get_rotate_bkg_ind(void)
{
return opt_ind_rotate_bkg_;
}
int scanner::twain_get_fill_black_bkg_ind(void)
{
return opt_ind_fill_blank_bkg_;
}
int scanner::twain_get_edge_ident_ind(void)
{
return opt_ind_edge_ident_;
}
int scanner::twain_get_threshold_ind(void)
{
return opt_ind_threshold_;
}
int scanner::twain_bkg_filling_method_ind(void)
{
return opt_ind_bkg_filling_method_;
}
int scanner::twain_fill_hole_ind(void)
{
return opt_ind_fill_hole_;
}
int scanner::twain_fill_hole_ratio_ind(void)
{
return opt_ind_fill_hole_ratio_;
}
int scanner::twain_detach_noise_ind(void)
{
return opt_ind_noise_;
}
int scanner::twain_detach_noise_threshold_ind(void)
{
return opt_ind_noise_threshold_;
}
int scanner::twain_rid_red_ind(void)
{
return opt_ind_rid_red_;
}
int scanner::twain_rid_red_hsv_ind(void)
{
return opt_ind_rid_red_hsv_;
}
int scanner::twain_screw_detect_ind(void)
{
return opt_ind_screw_detect_;
}
int scanner::twain_screw_detect_level_ind(void)
{
return opt_ind_screw_detect_level_;
}
int scanner::twain_staple_detect_ind(void)
{
return opt_ind_staple_;
}
int scanner::twain_dogear_detect_ind(void)
{
return opt_ind_dogear_;
}
int scanner::twain_dark_sample_ind(void)
{
return opt_ind_dark_sample_;
}
int scanner::twain_image_split_ind(void)
{
return opt_ind_split_;
}
int scanner::twain_fade_bkground_ind(void)
{
return opt_ind_fade_bkg_;
}
int scanner::twain_fade_bkground_val_ind(void)
{
return opt_ind_fade_bkg_val_;
}
int scanner::twain_size_detect_ind(void)
{
return opt_ind_size_detect_;
}