2022-05-03 08:54:08 +00:00
|
|
|
|
#include "pch.h"
|
|
|
|
|
#include "huagaotwain.h"
|
|
|
|
|
#include "huagao/hgscanner_error.h"
|
|
|
|
|
#include "./twain/twain_2.4.h"
|
2022-05-04 03:55:11 +00:00
|
|
|
|
#include "../../code_device/sdk/hginclude/hg_log.h"
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
#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);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
*err = SCANNER_ERR_DEVICE_NOT_FOUND;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
sane_invoker::inst_->log_(LOG_LEVEL_DEBUG_INFO, info);
|
2022-05-03 08:54:08 +00:00
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return (SANE_Status)SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
*err = SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
, opt_ind_contrast_(-1), opt_ind_gamma_(-1), opt_ind_ultrasonic_(-1), err_(SCANNER_ERR_OK), desc_("")
|
2022-05-03 08:54:08 +00:00
|
|
|
|
, 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;
|
2022-05-17 07:57:43 +00:00
|
|
|
|
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)
|
2022-05-03 08:54:08 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
}
|
|
|
|
|
int scanner::start(void)
|
|
|
|
|
{
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_);
|
|
|
|
|
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
}
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_OUT_OF_RANGE;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), sn);
|
|
|
|
|
if (it == options_.end())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NO_DATA;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
if (scanner::type(it->desc->type) != "string" ||
|
|
|
|
|
val.length() > it->desc->size)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_INVALID_PARAMETER;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
char* buf = new char[it->desc->size + 20];
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
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);
|
2022-05-17 07:57:43 +00:00
|
|
|
|
if (sn == opt_ind_paper_ && (ret == SCANNER_ERR_OK || ret == SCANNER_ERR_NOT_EXACT))
|
2022-05-03 08:54:08 +00:00
|
|
|
|
{
|
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_OUT_OF_RANGE;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), sn);
|
|
|
|
|
if (it == options_.end())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NO_DATA;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
if (scanner::type(it->desc->type) != "bool" &&
|
|
|
|
|
scanner::type(it->desc->type) != "button")
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_INVALID_PARAMETER;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_OUT_OF_RANGE;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), sn);
|
|
|
|
|
if (it == options_.end())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NO_DATA;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
if (scanner::type(it->desc->type) != "int")
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_INVALID_PARAMETER;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
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_)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_OUT_OF_RANGE;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
std::vector<SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), sn);
|
|
|
|
|
if (it == options_.end())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NO_DATA;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
if (scanner::type(it->desc->type) != "float")
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_INVALID_PARAMETER;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
if (sn == opt_ind_fill_hole_ratio_)
|
|
|
|
|
val /= 100.0f;
|
|
|
|
|
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
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))
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return dpi >= 200.0f && dpi <= 600.0f ? SCANNER_ERR_OK : SCANNER_ERR_INVALID_PARAMETER;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
if (dpi <= l || dpi >= u)
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_INVALID_PARAMETER;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
}
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_INVALID_PARAMETER;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
std::list<std::string> vals;
|
|
|
|
|
std::string now(get_string(opt_ind_paper_, it->desc->size));
|
|
|
|
|
size_t pos = now.find(paper::lateral_title());
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
ret = SCANNER_ERR_INVALID_PARAMETER;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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);
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
fmt.img_format = type;
|
|
|
|
|
fmt.detail = param;
|
|
|
|
|
ret = sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_FINAL_IMAGE_FORMAT, &fmt, &len);
|
2022-05-17 07:57:43 +00:00
|
|
|
|
if (ret == SCANNER_ERR_OK)
|
2022-05-03 08:54:08 +00:00
|
|
|
|
{
|
|
|
|
|
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);
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_OK;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
compr.compression = (SANE_CompressionType)compression;
|
|
|
|
|
compr.detail = NULL;
|
|
|
|
|
|
|
|
|
|
ret = sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_FINAL_COMPRESSION, &compr, &len);
|
2022-05-17 07:57:43 +00:00
|
|
|
|
if (ret == SCANNER_ERR_OK || ret == SCANNER_ERR_NOT_EXACT)
|
2022-05-03 08:54:08 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2022-05-17 07:57:43 +00:00
|
|
|
|
if (ret == SCANNER_ERR_OK)
|
2022-05-03 08:54:08 +00:00
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
2022-05-17 07:57:43 +00:00
|
|
|
|
int ret = SCANNER_ERR_INVALID_PARAMETER;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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())
|
2022-05-17 07:57:43 +00:00
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
2022-05-03 08:54:08 +00:00
|
|
|
|
|
|
|
|
|
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_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|