code_twain/huagaotwain/twain/huagaods.cpp

2027 lines
67 KiB
C++
Raw Normal View History

2022-05-03 08:54:08 +00:00
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#include <memory>
#include "huagaods.hpp"
//#include "twpp/twglue.hpp"
#include <list>
#include <map>
#ifdef WIN32
#include <shlobj.h>
#include <Psapi.h>
#include <io.h>
#define mktemp _mktemp
#endif // WIN32
using namespace std;
#include "../huagaotwain.h"
#include "../ui.h"
#define enum2str(R) #R
using namespace Twpp;
using namespace std::placeholders;
//custom define caps enum
enum CapTypeEx : unsigned short {
CAP_TYPE_EX_FILL_BLACK_BKG = 0x8004,
CAP_TYPE_EX_ROTATE_BKG_180 = 0x8005,
CAP_TYPE_EX_SCREW_DETECT = 0x8006,
CAP_TYPE_EX_ENHANCE_COLOR = 0x8007,
CAP_TYPE_EX_FILL_HOLE = 0x8018,
CAP_TYPE_EX_SCREW_DETECT_LEVEL = 0x8021,
CAP_TYPE_EX_SHARPEN = 0x8022,
CAP_TYPE_EX_HARDWARE_VERSION = 0x8025,
CAP_TYPE_EX_RID_RED = 0x8026,
CAP_TYPE_EX_FOLD = 0x8037,
CAP_TYPE_EX_STAPLE_DETECT = 0x8090,
CAP_TYPE_EX_DISCARD_BLANK_RECEIPT = 0x8091,
CAP_TYPE_EX_FILL_HOLE_RATIO = 0x8092,
CAP_TYPE_EX_FLIP = 0x8094, // switch front back
CAP_TYPE_EX_RID_RED_HSV = 0x8095,
CAP_TYPE_EX_DOGEAR_DETECT = 0x8096,
CAP_TYPE_EX_BKG_FILLING_METHOD = 0x8097,
CAP_TYPE_EX_EDGE_IDENT = 0x8098,
CAP_TYPE_EX_THRESHOLD = 0x8099,
CAP_TYPE_EX_THRESHOLD_1 = 0x8100,
CAP_TYPE_EX_DETACH_NOISE = 0x8101,
CAP_TYPE_EX_DETACH_NOISE_THRESHOLD = 0x8102,
CAP_TYPE_EX_SIZE_DETECT = 0x8103,
CAP_TYPE_EX_POWER_LEVEL = 0x8104,
CAP_TYPE_EX_ENCODE = 0x8105,
CAP_TYPE_EX_DARK_SAMPLE = 0x8016,
CAP_TYPE_EX_DOGEAR_DIST = 0x8107,
CAP_TYPE_EX_IMAGE_SPLIT = 0x8108,
CAP_TYPE_EX_FADE_BKG = 0x8109,
CAP_TYPE_EX_FADE_BKG_VALUE = 0x8110,
CAP_TYPE_EX_TO_BE_SCAN = 0x8111,
CAP_TYPE_EX_MULTI_OUT = 0x8112,
CAP_TYPE_EX_MULTI_OUT_TYPE = 0x8113,
CAP_TYPE_EX_SCAN_WITH_HOLE = 0x8114,
CAP_TYPE_EX_IP = 0x8200,
CAP_TYPE_EX_0 = (int)CapType::CustomBase + 0x800,
CAP_TYPE_EX_1,
CAP_TYPE_EX_2,
CAP_TYPE_EX_3,
CAP_TYPE_EX_4,
CAP_TYPE_EX_5,
CAP_TYPE_EX_6,
CAP_TYPE_EX_7,
CAP_TYPE_EX_8,
CAP_TYPE_EX_9,
CAP_TYPE_EX_10,
CAP_TYPE_EX_11,
CAP_TYPE_EX_12,
CAP_TYPE_EX_13,
CAP_TYPE_EX_14,
CAP_TYPE_EX_15,
CAP_TYPE_EX_16,
CAP_TYPE_EX_17,
CAP_TYPE_EX_18,
CAP_TYPE_EX_19,
CAP_TYPE_EX_20,
CAP_TYPE_EX_21,
CAP_TYPE_EX_22,
CAP_TYPE_EX_23,
CAP_TYPE_EX_24,
CAP_TYPE_EX_25,
CAP_TYPE_EX_26,
CAP_TYPE_EX_27,
CAP_TYPE_EX_28,
CAP_TYPE_EX_29,
CAP_TYPE_EX_30,
CAP_TYPE_EX_31,
CAP_TYPE_EX_32,
CAP_TYPE_EX_33,
CAP_TYPE_EX_34,
CAP_TYPE_EX_35,
CAP_TYPE_EX_36,
CAP_TYPE_EX_37,
CAP_TYPE_EX_38,
CAP_TYPE_EX_39,
CAP_TYPE_EX_40,
CAP_TYPE_EX_41,
CAP_TYPE_EX_42,
CAP_TYPE_EX_43,
CAP_TYPE_EX_44,
CAP_TYPE_EX_45,
CAP_TYPE_EX_46,
CAP_TYPE_EX_47,
CAP_TYPE_EX_48,
CAP_TYPE_EX_49,
CAP_TYPE_EX_50,
CAP_TYPE_EX_51,
CAP_TYPE_EX_52,
CAP_TYPE_EX_53,
CAP_TYPE_EX_54,
CAP_TYPE_EX_55,
CAP_TYPE_EX_56,
CAP_TYPE_EX_57,
CAP_TYPE_EX_58,
CAP_TYPE_EX_59,
CAP_TYPE_EX_60,
CAP_TYPE_EX_61,
CAP_TYPE_EX_62,
CAP_TYPE_EX_63,
CAP_TYPE_EX_64,
CAP_TYPE_EX_65,
CAP_TYPE_EX_66,
CAP_TYPE_EX_67,
CAP_TYPE_EX_68,
CAP_TYPE_EX_69,
CAP_TYPE_EX_70,
CAP_TYPE_EX_71,
CAP_TYPE_EX_72,
CAP_TYPE_EX_73,
CAP_TYPE_EX_74,
CAP_TYPE_EX_75,
CAP_TYPE_EX_76,
CAP_TYPE_EX_77,
CAP_TYPE_EX_78,
CAP_TYPE_EX_79,
CAP_TYPE_EX_80,
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// entry ...
TWPP_ENTRY(huagao_ds)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// utilites ...
// some helper functions to handle capability stuff
template<typename T>
static Result oneValGet(Msg msg, Capability& data, const T& value) {
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
data = Capability::createOneValue(data.type(), value);
return {};
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
static Result oneValGetString(Msg msg, Capability& data, std::string value) {
Str255 str;
str.setData(value.c_str(), value.size());
return oneValGet(msg, data, str);
}
template<typename T>
static Result enmGet(Msg msg, Capability& data, const T& value) {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration(data.type(), { value });
return {};
case Msg::GetCurrent:
case Msg::GetDefault:
data = Capability::createOneValue(data.type(), value);
return {};
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T>
static Result oneValGetSet(Msg msg, Capability& data, T& value, const T& def) {
switch (msg) {
case Msg::Reset:
value = def;
// fallthrough
case Msg::Get:
case Msg::GetCurrent:
data = Capability::createOneValue(data.type(), value);
return {};
case Msg::GetDefault:
data = Capability::createOneValue(data.type(), def);
return {};
case Msg::Set:
value = data.currentItem<T>();
return {};
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T>
static Result oneValGetSetConst(Msg msg, Capability& data, const T& def) {
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
case Msg::Reset:
data = Capability::createOneValue(data.type(), def);
return {};
case Msg::Set:
return data.currentItem<T>() == def ?
Result() : Result(ReturnCode::Failure, ConditionCode::BadValue);
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T>
static Result enmGetSetConst(Msg msg, Capability& data, const T& def) {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration(data.type(), { def });
return {};
case Msg::GetCurrent:
case Msg::GetDefault:
case Msg::Reset:
data = Capability::createOneValue(data.type(), def);
return {};
case Msg::Set:
return data.currentItem<T>() == def ?
Result() : Result(ReturnCode::Failure, ConditionCode::BadValue);
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T1, typename T2, Twpp::CapType cap>
Result CapSupGetAllReset(Msg msg, Capability& data, std::initializer_list<T2> values, T1& currvalue, T2 defaultvalue, UInt32 currindex, UInt32 defaultindex) {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<cap>(values, currindex, defaultindex);
return { ReturnCode::Success, ConditionCode::Success };
case Msg::GetCurrent:
data = Capability::createOneValue<cap>((T2)currvalue);
return { ReturnCode::Success, ConditionCode::Success };
case Msg::Reset:
case Msg::GetDefault:
currvalue = (T1)defaultvalue;
data = Capability::createOneValue<cap>(defaultvalue);
return { ReturnCode::Success, ConditionCode::Success };
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T1, typename T2, Twpp::CapType cap>
Result CapSupGetAllResetEx(Msg msg, Capability& data, std::initializer_list<T2> values, T1& currvalue, T2 defaultvalue, UInt32 currindex, UInt32 defaultindex) {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<T2>(cap, values, currindex, defaultindex);
return { ReturnCode::Success, ConditionCode::Success };
case Msg::GetCurrent:
data = Capability::createOneValue<T2>(cap, (T2)currvalue);
return { ReturnCode::Success, ConditionCode::Success };
case Msg::Reset:
case Msg::GetDefault:
currvalue = (T1)defaultvalue;
data = Capability::createOneValue<T2>(cap, defaultvalue);
return { ReturnCode::Success, ConditionCode::Success };
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T1, typename T2, Twpp::CapType cap>
Result CapSupGetAllReset(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) {
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
data = Capability::createOneValue<cap>((T2)currvalue);
return { ReturnCode::Success, ConditionCode::Success };
case Msg::Reset:
case Msg::GetDefault:
currvalue = (T1)defaultvalue;
data = Capability::createOneValue<cap>(defaultvalue);
return { ReturnCode::Success, ConditionCode::Success };
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T1, typename T2, Twpp::CapType cap>
Result CapSupGetAllResetEx(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) {
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
data = Capability::createOneValue<T2>(cap, (T2)currvalue);
return { ReturnCode::Success, ConditionCode::Success };
case Msg::Reset:
case Msg::GetDefault:
currvalue = (T1)defaultvalue;
data = Capability::createOneValue<T2>(cap, defaultvalue);
return { ReturnCode::Success, ConditionCode::Success };
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T, Twpp::CapType cap>
Result cap_get_enum_values(Msg msg, Capability& data, std::list<T> values, T& cur, T& def, UInt32 cur_ind, UInt32 def_ind)
{
switch (msg)
{
case Msg::Get:
data = Capability::createEnumeration<T>(cap, values.size(), cur_ind, def_ind);
//data = Capability::createArray<T>(cap, values.size());
{
auto arr = data.enumeration<T>();
int i = 0;
for (const auto& v : values)
arr[i++] = v;
}
return { ReturnCode::Success, ConditionCode::Success };
case Msg::GetCurrent:
data = Capability::createOneValue<T>(cap, cur);
return { ReturnCode::Success, ConditionCode::Success };
case Msg::Reset:
case Msg::GetDefault:
data = Capability::createOneValue<T>(cap, def);
return { ReturnCode::Success, ConditionCode::Success };
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T, Twpp::CapType cap>
Result cap_get_one_value(Msg msg, Capability& data, T& cur, T& def, T* lower, T* upper, T* step)
{
switch (msg)
{
case Msg::Get:
if (lower && upper && step)
{
data = Capability::createRange<T>(cap, *lower, *upper, *step, cur, def);
return { ReturnCode::Success, ConditionCode::Success };
}
case Msg::GetCurrent:
data = Capability::createOneValue<T>(cap, cur);
return { ReturnCode::Success, ConditionCode::Success };
case Msg::Reset:
case Msg::GetDefault:
data = Capability::createOneValue<T>(cap, def);
return { ReturnCode::Success, ConditionCode::Success };
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T1, typename T2, Twpp::CapType cap>
Result CapSupGetAll(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) {
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
data = Capability::createOneValue<cap>((T2)defaultvalue);
return { ReturnCode::Success, ConditionCode::Success };
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
template<typename T1, typename T2, Twpp::CapType cap>
Result CapSupGetAllEx(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) {
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
data = Capability::createOneValue<cap, T2>(defaultvalue);
return { ReturnCode::Success, ConditionCode::Success };
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
}
static void copy_type(Bool& to, bool from)
{
to = from;
}
static void copy_type(bool& to, Bool from)
{
to = (bool)from;
}
static void copy_type(UInt32& to, int from)
{
to = from;
}
static void copy_type(Fix32& to, double from)
{
to = from;
}
static void copy_type(Fix32& to, float from)
{
to = from;
}
static void copy_type(Str255& to, std::string from)
{
to.setData(sane_invoker::utf82ansi(from.c_str()).c_str());
}
static void copy_type(std::string& to, Str255 from)
{
to = sane_invoker::ansi2utf8(from.data());
}
static void copy_type(Str64& to, std::string from)
{
to.setData(sane_invoker::utf82ansi(from.c_str()).c_str());
}
static void copy_type(std::string& to, Str64 from)
{
to = sane_invoker::ansi2utf8(from.data());
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// huagao_ds ...
static Identity* srcIdent = new Identity(
Version(3, 3, Language::English, Country::China, "v3.3.5.6"),
DataGroup::Image, "HUAGO", "HUAGAO Series", "Huagao scanner series");
static std::once_flag oc;
huagao_ds::huagao_ds()
{
//std::call_once(oc, [&]() { log4cplus::Initializer(); });
}
huagao_ds::~huagao_ds()
{
if (memoryinfo.get()) {
m_memoryfalg = false;
if (memoryinfo->joinable())
memoryinfo->join();
}
}
std::string huagao_ds::get_hidedlg_path(void)
{
char szIniFile[MAX_PATH] = { 0 };
SHGetSpecialFolderPathA(NULL, szIniFile, CSIDL_WINDOWS, TRUE);
#ifdef MAKEHUAGAO
strcat(szIniFile, "\\twain_32\\HuaGoScan\\hidedlg.exe");
#elif defined AUGE
strcat(szIniFile, "\\twain_32\\AuGeScan\\hidedlg.exe");
#elif defined HANVON
strcat(szIniFile, "\\twain_32\\HanvonScan\\hidedlg.exe");
#elif defined LANXUM
strcat(szIniFile, "\\twain_32\\LANXUMSCAN\\hidedlg.exe");
#else // MAKEHUAGAO
strcat(szIniFile, "\\twain_32\\ZhibenScan\\hidedlg.exe");
#endif
return szIniFile;
}
void huagao_ds::showmsg(const char* msg, int err)
{
ShellExecuteA(NULL, "open", huagao_ds::get_hidedlg_path().c_str(), msg, NULL, SW_HIDE);
}
void huagao_ds::scan_event(int sane_event, void* data, unsigned int* len, void* param)
{
((huagao_ds*)param)->on_scan_event(sane_event, data, len);
}
const Identity& huagao_ds::defaultIdentity() noexcept {
// remember, we return a reference, therefore the identity must not be placed on the stack of this method
if (sane_invoker::is_ok())
{
DWORD ver = 0;
std::string v(sane_invoker::version(&ver)),
n("HUAGO"), t("Huagao scanner series"), m("HUAGAO Series");
std::vector<SANEDEV> devs;
char v32[32] = { 0 }, n32[32] = { 0 }, t32[32] = { 0 }, m32[32] = { 0 };
sane_invoker::get_devices(devs);
if (devs.size())
{
n = devs[0].vendor;
t = devs[0].name;
m = devs[0].product;
}
if (ver == 0)
{
ver = MAKELPARAM(56, 0x303);
v = "v3.3.56";
}
else
v.insert(0, "v");
delete srcIdent;
#define COPY_32(a) strcpy_s(v##32, _countof(v##32), v##.c_str())
COPY_32(v);
COPY_32(n);
COPY_32(t);
COPY_32(m);
srcIdent = new Twpp::Identity(Twpp::Version((ver >> 24) & 0x0ff, (ver >> 16) & 0x0ff, Language::English, Country::China, v32),
DataGroup::Image, n32, m32, t32);
}
return *srcIdent;
}
Result huagao_ds::selectIdentity(Twpp::Identity& ident) noexcept {
// remember, we return a reference, therefore the identity must not be placed on the stack of this method
if (sane_invoker::is_ok())
{
DWORD ver = 0;
std::vector<SANEDEV> devs;
Version twver;
char v32[32] = { 0 }, n32[32] = { 0 }, t32[32] = { 0 }, m32[32] = { 0 };
sane_invoker::get_devices(devs);
if (devs.size())
{
strcpy(m32, devs[0].type.c_str());
strcpy(n32, devs[0].product.c_str());
strcpy(t32, devs[0].name.c_str());
ident = Identity(twver, DataGroup::Image, n32, m32, t32);
return success();
}
// show dialog to select the devices listed in devs here ...
//if (dlg.DoModal() == IDOK)
//{
// ident = Identity(twver, DataGroup::Image, n32, m32, t32);
// return success();
//}
//else
{
return { ReturnCode::Failure, ConditionCode::Bummer };
}
}
return { ReturnCode::Failure, ConditionCode::NoDs };
}
Twpp::ConditionCode huagao_ds::condition_code_from_hg_error(int hgerr)
{
if (hgerr == HG_ERR_OK)
return Twpp::ConditionCode::Success;
if (hgerr == HG_ERR_DEVICE_NOT_FOUND)
return Twpp::ConditionCode::CheckDeviceOnline;
if (hgerr == HG_ERR_IO)
return Twpp::ConditionCode::OperationError;
if(hgerr == HG_ERR_OUT_OF_RANGE)
return Twpp::ConditionCode::BadCap;
if(hgerr == HG_ERR_DEVICE_NOT_SUPPORT)
return Twpp::ConditionCode::BadProtocol;
if(hgerr == HG_ERR_INVALID_PARAMETER)
return Twpp::ConditionCode::BadValue;
if(hgerr == HG_ERR_ACCESS_DENIED)
return Twpp::ConditionCode::Denied;
if(hgerr == HG_ERR_OPEN_FILE_FAILED)
return Twpp::ConditionCode::FileNotFound;
if (hgerr == HG_ERR_DEVICE_PAPER_JAMMED)
return Twpp::ConditionCode::PaperJam;
if (hgerr == HG_ERR_DEVICE_DOUBLE_FEEDING)
return Twpp::ConditionCode::PaperDoubleFeed;
if (hgerr == HG_ERR_WRITE_FILE_FAILED)
return Twpp::ConditionCode::FileWriteError;
if (hgerr == HG_ERR_DEVICE_DOGEAR)
return Twpp::ConditionCode::DamagedCorner;
if (hgerr == HG_ERR_DEVICE_NO_PAPER)
return Twpp::ConditionCode::NoMedia;
return (Twpp::ConditionCode)((int)Twpp::ConditionCode::CustomBase + hgerr);
}
Result huagao_ds::capabilityGet(const Identity& origin, Capability& data)
{
return capCommon(origin, Msg::Get, data);
}
Result huagao_ds::capabilityGetCurrent(const Identity& origin, Capability& data)
{
return capCommon(origin, Msg::GetCurrent, data);
}
Result huagao_ds::capabilityGetDefault(const Identity& origin, Capability& data)
{
return capCommon(origin, Msg::GetDefault, data);
}
Result huagao_ds::capabilityQuerySupport(const Identity&, Capability& data)
{
auto it = m_query.find(data.type());
MsgSupport sup = it != m_query.end() ? it->second : msgSupportEmpty;
data = Capability::createOneValue(data.type(), sup);
return success();
}
Result huagao_ds::capabilityReset(const Identity& origin, Capability& data)
{
return capCommon(origin, Msg::Reset, data);
}
Result huagao_ds::capabilityResetAll(const Identity& origin)
{
for (auto& pair : m_query) {
if ((pair.second & MsgSupport::Reset) != msgSupportEmpty) {
Capability dummyCap(pair.first);
capCommon(origin, Msg::Reset, dummyCap);
}
}
return success();
}
Result huagao_ds::capabilitySet(const Identity& origin, Capability& data)
{
return capCommon(origin, Msg::Set, data);
}
Result huagao_ds::eventProcess(const Identity&, Event& event)
{
return { ReturnCode::NotDsEvent, ConditionCode::Success };
}
Twpp::Result huagao_ds::deviceEventGet(const Twpp::Identity& origin, Twpp::DeviceEvent& data)
{
// data = DeviceEvent::simple(sane_invoker::take_event(), "HUAGAO");
// return success();
return seqError();
}
Result huagao_ds::identityOpenDs(const Identity& id)
{
//singleton_ = CreateMutexA(NULL, FALSE, "LookitApp");
//if (GetLastError() == ERROR_ALREADY_EXISTS) { //<2F><><EFBFBD><EFBFBD><EFBFBD>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD>Mutex<65><78><EFBFBD>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
// CloseHandle(singleton_);
// singleton_ = NULL;
// showmsg("<22><>ʾ", 202);
//
// return { ReturnCode::Failure, ConditionCode::CapBadOperation };
//}
if (!sane_invoker::is_ok())
sane_invoker::initialize(me_);
if (!sane_invoker::is_ok())
{
CloseHandle(singleton_);
singleton_ = NULL;
return bummer();
}
Identity target(id);
Result result = huagao_ds::selectIdentity(target);
if (scanner_.get())
scanner_.reset();
if (result.returnCode() != ReturnCode::Success)
{
CloseHandle(singleton_);
singleton_ = NULL;
sane_invoker::uninitialize();
return result;
}
int err = 0;
scanner_.reset(sane_invoker::open_scanner(target.productName().begin(), &err));
if (!scanner_.get())
{
//CloseHandle(singleton_);
//singleton_ = NULL;
sane_invoker::uninitialize();
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(err) };
}
ui_.reset(new twain_ui(local_utility::reg_get_app_installing_path().c_str()));
scanner_->set_event_callback(&huagao_ds::scan_event, this);
init_support_caps();
return success();
}
Result huagao_ds::identityCloseDs(const Identity&)
{
ui_.reset();
if (scanner_.get())
{
scanner_.reset();
}
if (singleton_)
{
CloseHandle(singleton_);
singleton_ = NULL;
}
sane_invoker::uninitialize();
return success();
}
Result huagao_ds::pendingXfersGet(const Identity&, PendingXfers& data)
{
if (!scanner_.get())
return seqError();
data.setCount(scanner_->get_scanned_images(-1));
return success();
}
Result huagao_ds::pendingXfersEnd(const Identity& id, PendingXfers& data)
{
return pendingXfersGet(id, data);
}
Result huagao_ds::pendingXfersReset(const Identity&, PendingXfers& data)
{
data.setCount(0);
if (scanner_.get())
scanner_->stop();
//if (scanner.get())
//{
// scanner->Stop_scan();
// scanner->reset();
// scanner->ResetScanner();
//}
return success();
}
Result huagao_ds::setupMemXferGet(const Identity&, SetupMemXfer& data)
{
SANE_Parameters head;
if (!scanner_.get() || scanner_->get_scanned_images() == 0)
return seqError();
if (scanner_->get_first_image_header(&head))
{
data.setMinSize(head.bytes_per_line);
data.setPreferredSize(head.bytes_per_line * head.lines);
data.setMaxSize(head.bytes_per_line * head.lines);
return success();
}
else
return badValue();
}
Result huagao_ds::userInterfaceDisable(const Identity&, UserInterface& ui)
{
ui_->hide_ui();
return success();
}
Result huagao_ds::userInterfaceEnable(const Identity&, UserInterface& ui)
{
if (!ui.showUi())
{
if (m_bIndicator)
ui_->show_main_ui(sane_invoker::get_api());
return scanner_->start() == HG_ERR_OK ? success() : seqError();
}
return showTwainUI(ui);
}
Result huagao_ds::userInterfaceEnableUiOnly(const Identity&, UserInterface& ui)
{
// as a minimal source, we do not support GUI that just saves settings
return showTwainUI(ui, true);
}
Result huagao_ds::imageInfoGet(const Identity&, ImageInfo& data)
{
SANE_Parameters head;
if (!scanner_.get())
return seqError();
if (!scanner_->wait_image())
return bummer();
if (scanner_->get_first_image_header(&head))
{
data.setBitsPerPixel(head.depth);
data.setHeight(head.lines);
data.setPixelType(head.depth == 24 ? PixelType::Rgb : PixelType::Gray);
data.setPlanar(false);
data.setWidth(head.pixels_per_line);
data.setXResolution(scanner_->twain_get_resolution());
data.setYResolution(scanner_->twain_get_resolution());
data.compression(Compression::None);
}
return success();
}
Result huagao_ds::imageLayoutGet(const Identity&, ImageLayout& data)
{
SANE_Parameters head = { 0 };
if (!scanner_.get() || scanner_->get_scanned_images() == 0)
return seqError();
scanner_->get_first_image_header(&head);
data.setDocumentNumber(1);
data.setFrameNumber(1);
data.setPageNumber(1);
data.setFrame(Frame(0, 0, static_cast<float>(head.pixels_per_line) / scanner_->twain_get_resolution(), static_cast<float>(head.lines) / scanner_->twain_get_resolution()));
return success();
}
Result huagao_ds::imageLayoutGetDefault(const Identity& origin, ImageLayout& data)
{
return imageLayoutGet(origin, data);
}
Result huagao_ds::imageLayoutSet(const Identity& origin, ImageLayout& lay)
{
// we dont support setting image frame
ImageLayout def;
imageLayoutGetDefault(origin, def);
return lay.frame() == def.frame() ? success() : badValue();
}
Result huagao_ds::imageLayoutReset(const Identity& origin, ImageLayout& data)
{
return imageLayoutGet(origin, data);
}
Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data)
{
if (!scanner_.get() || scanner_->get_scanned_images() == 0)
return seqError();
scanned_img *img = scanner_->take_first_image();
unsigned char *src = img->bits() + img->bytes() - img->line_bytes(),
*dst = NULL;
data.setBytesPerRow(img->line_bytes());
data.setColumns(img->width());
data.setRows(img->height());
data.setBytesWritten(img->bytes());
data.setXOffset(0);
data.setYOffset(0);
data.setCompression(Compression::None);
dst = (unsigned char*)data.memory().data().data();
for (int i = 0; i < img->height(); ++i, src -= img->line_bytes(), dst += img->line_bytes())
std::copy(src, src + img->line_bytes(), dst);
delete img;
return success();
}
Result huagao_ds::imageNativeXferGet(const Identity& id, ImageNativeXfer& data)
{
if (!scanner_.get() || scanner_->get_scanned_images() == 0)
return seqError();
scanned_img* img = scanner_->take_first_image();
if (!img)
return seqError();
if (data)
data.release();
data = ImageNativeXfer(img->bytes());
std::copy(img->bits(), img->bits() + img->bytes(), data.data<unsigned char>().data());
delete img;
return { ReturnCode::XferDone, ConditionCode::Success };
}
Twpp::Result huagao_ds::pendingXfersStopFeeder(const Identity& origin, PendingXfers& data)
{
// sane_invoker::invoke_sane_cancel();
return success();
}
Twpp::Result huagao_ds::imageFileXferGet(const Twpp::Identity& origin)
{
// assume that the file format has set before start-scanning, so we write-down the image content to file directly here ...
if (!scanner_.get() || scanner_->get_scanned_images() == 0)
return seqError();
scanned_img *img = scanner_->take_first_image();
Twpp::Result ret = seqError();
FILE* dst = NULL;
if (img)
{
dst = fopen(m_fileXfer.filePath().string().c_str(), "wb");
ret = { ReturnCode::Failure, ConditionCode::FileWriteError };
if (dst)
{
if(fwrite(img->bits(), 1, img->bytes(), dst) == img->bytes())
ret = Result(ReturnCode::XferDone, ConditionCode::Success);
fclose(dst);
}
delete img;
}
return ret;
}
Twpp::Result huagao_ds::setupFileXferGet(const Twpp::Identity& origin, Twpp::SetupFileXfer& data)
{
data.setFilePath(m_fileXfer.filePath());
data.setFormat(m_fileXfer.format());
return success();
}
Twpp::Result huagao_ds::setupFileXferGetDefault(const Twpp::Identity& origin, Twpp::SetupFileXfer& data)
{
Str255 str("HGTwain.bmp");
data.setFilePath(str);
data.setFormat(ImageFileFormat::Bmp);
return success();
}
Twpp::Result huagao_ds::setupFileXferSet(const Twpp::Identity& origin, Twpp::SetupFileXfer& data)
{
m_fileXfer.setFilePath(data.filePath());
m_fileXfer.setFormat(data.format());
return success();
}
Twpp::Result huagao_ds::setupFileXferReset(const Twpp::Identity& origin, Twpp::SetupFileXfer& data)
{
m_fileXfer.setFormat(Twpp::ImageFileFormat::Bmp);
std::string templateName = "HG";
char* tempPath = mktemp((char*)templateName.c_str());
if (tempPath) {
Str255 str;
str.setData(tempPath, strlen(tempPath));
m_fileXfer.setFilePath(str);
return success();
}
return badProtocol();
}
Result huagao_ds::call(const Identity& origin, DataGroup dg, Dat dat, Msg msg, void* data) {
try {
// we can override almost anything from SourceFromThis, even the top-most source instance call
//FileTools::write_log("D:\\1.txt", "call:datagroup-"+to_string((int)dg)+"dat-"+to_string(int(dat))+"msg-"+to_string(int(msg)));
return Base::call(origin, dg, dat, msg, data);
}
catch (const CapabilityException& e) {
//FileTools::writelog(log_ERROR, e.what());
return badValue();
}
}
Result huagao_ds::customDataGet(const Twpp::Identity& origin, Twpp::CustomData& data)
{
// get user setting from local file ...
return success();
}
Result huagao_ds::customDataSet(const Twpp::Identity& origin, Twpp::CustomData& data)
{
// write user setting to local file ...
return success();
}
void huagao_ds::CapabilityPrintf(Twpp::Msg msg, std::string capability, std::string value)
{
}
Result huagao_ds::capCommon(const Identity&, Msg msg, Capability& data) {
auto it = m_caps.find(data.type());
if (it != m_caps.end()) {
return (it->second)(msg, data);
}
return capUnsupported();
}
Twpp::Result huagao_ds::showTwainUI(Twpp::UserInterface& data, bool bUiOnly)
{
// display user UI ... (setting UI, can we show my own main window here ?)
LPSANEAPI api = sane_invoker::get_api();
if (bUiOnly)
ui_->show_setting_ui(api, false);
else
ui_->show_main_ui(api);
return success();
}
void huagao_ds::init_support_caps(void)
{
m_query.clear();
m_caps.clear();
m_query[CapType::SupportedCaps] = msgSupportGetAll;
m_caps[CapType::SupportedCaps] = [this](Msg msg, Capability& data) {
if ((msg == Msg::Get) || (Msg::GetCurrent == msg) || (Msg::GetDefault == msg)) {
data = Capability::createArray<CapType::SupportedCaps>(m_caps.size());
auto arr = data.array<CapType::SupportedCaps>();
UInt32 i = 0;
for (const auto& kv : m_caps) {
arr[i] = kv.first;
i++;
}
return success();
}
else
return capBadOperation();
};
m_query[CapType::XferCount] = msgSupportGetAllSetReset;
m_caps[CapType::XferCount] = [this](Msg msg, Capability& data) -> Result {
if (msg == Msg::Set) {
auto item = data.currentItem<Int16>();
if (item > 65535 || item < -1 || item == 0) {
return badValue();
}
return scanner_->twain_set_scan_count(item) == HG_ERR_OK ? success() : badValue();
}
Int16 tmp_count = scanner_->twain_get_scan_count();
return oneValGetSet<Int16>(msg, data, tmp_count, -1);
};
if (ui_->is_ok())
{
m_query[CapType::UiControllable] = msgSupportGetAll;
m_caps[CapType::UiControllable] = std::bind(oneValGet<Bool>, _1, _2, Bool(true));
}
m_query[CapType::DeviceOnline] = msgSupportGetAll;
m_caps[CapType::DeviceOnline] = [this](Msg msg, Capability& data) -> Result {
CapabilityPrintf(msg, enum2str(CapType::DeviceOnline));
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
if(scanner_.get())
data = Capability::createOneValue<CapType::DeviceOnline>((Twpp::Bool)scanner_->is_online());
else
data = Capability::createOneValue<CapType::DeviceOnline>((Twpp::Bool)(sane_invoker::online_devices() > 0));
return success();
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
};
m_query[CapType::ICompression] = msgSupportGetAllSetReset;
m_caps[CapType::ICompression] = [this](Msg msg, Capability& data)->Result {
if (!scanner_.get())
return seqError();
if (msg == Msg::Set || msg == Msg::Reset)
{
int mech = (int)data.currentItem<CapType::ICompression>();
if (msg == Msg::Reset)
scanner_->twain_get_final_compression(&mech);
return scanner_->twain_set_final_compression(mech) == HG_ERR_OK ? success() : badValue();
}
std::vector<int> values;
std::list<Compression> vals;
Compression Now, Init;
UInt32 ni = 0, ii = 0;
int init = 0, now = scanner_->twain_get_final_compression(&init, &values);
Now = (Compression)now;
Init = (Compression)init;
for (const auto& v : values)
vals.push_back((Compression)v);
ni = std::distance(values.begin(), std::find(values.begin(), values.end(), now));
ii = std::distance(values.begin(), std::find(values.begin(), values.end(), init));
return cap_get_enum_values<Compression, CapType::ICompression>(msg, data, vals, Now, Init, ni, ii);
};
m_query[CapType::IUnits] = msgSupportGetAllSetReset;
m_caps[CapType::IUnits] = std::bind(enmGetSetConst<Unit>, _1, _2, Unit::Inches);
m_query[CapType::IBitDepth] = msgSupportGetAllSetReset;
m_caps[CapType::IBitDepth] = [this](Msg msg, Capability& data) -> Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IBitDepth>();
int ret = HG_ERR_INVALID_PARAMETER;
if (mech == 1)
ret = scanner_->twain_set_color_mode((int)PixelType::BlackWhite);
else if(mech == 8)
ret = scanner_->twain_set_color_mode((int)PixelType::Gray);
else if(mech == 24)
ret = scanner_->twain_set_color_mode((int)PixelType::Rgb);
return ret == HG_ERR_OK ? success() : badValue();
}
UINT16 twpt = scanner_->twain_get_color_mode();
if (twpt == (int)PixelType::BlackWhite)
twpt = 1;
else if (twpt == (int)PixelType::Gray)
twpt = 8;
else
twpt = 24;
return CapSupGetAllReset<UINT16, UINT16, CapType::IBitDepth>(msg, data, twpt, 24);
};
m_query[CapType::IBitOrder] = msgSupportGetAllSetReset;
m_caps[CapType::IBitOrder] = std::bind(oneValGetSetConst<BitOrder>, _1, _2, BitOrder::MsbFirst);
m_query[CapType::IPlanarChunky] = msgSupportGetAllSetReset;
m_caps[CapType::IPlanarChunky] = std::bind(enmGetSetConst<PlanarChunky>, _1, _2, PlanarChunky::Chunky);
m_query[CapType::IXResolution] = msgSupportGetAllSetReset;
m_caps[CapType::IXResolution] = [this](Msg msg, Capability& data) {
if (!scanner_.get())
return seqError();
std::vector<float> values;
value_limit limit = VAL_LIMIT_NONE;
float init = .0f, now = .0f;
switch (msg) {
case Msg::Get:
now = scanner_->twain_get_resolution(&init, &values, &limit);
if (limit == VAL_LIMIT_RANGE)
{
data = Capability::createRange<CapType::IXResolution>(Fix32(values[0]), Fix32(values[1]), Fix32(50.0f), Fix32(now), Fix32(init));
return success();
}
else if (limit == VAL_LIMIT_ENUM)
{
std::list<Fix32> vals;
Fix32 Now, Init;
UInt32 ni, ii;
for (const auto& v : values)
{
Fix32 f;
copy_type(f, v);
vals.push_back(f);
}
copy_type(Now, now);
copy_type(Init, init);
ni = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), Now));
ii = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), Init));
return cap_get_enum_values<Fix32, CapType::IXResolution>(msg, data, vals, Now, Init, ni, ii);
}
case Msg::GetCurrent:
now = scanner_->twain_get_resolution();
data = Capability::createOneValue<CapType::IXResolution>(Fix32(now));
return success();
case Msg::GetDefault:
now = scanner_->twain_get_resolution(&init);
data = Capability::createOneValue<CapType::IXResolution>(Fix32(init));
return success();
case Msg::Reset:
now = scanner_->twain_get_resolution(&init);
data = Capability::createOneValue<CapType::IXResolution>(Fix32(init));
case Msg::Set: {
auto mech = data.currentItem<CapType::IXResolution>();
return scanner_->twain_set_resolution((float)mech) == HG_ERR_OK ? success() : badValue();
}
default:
return capBadOperation();
}
};
m_query[CapType::IYResolution] = msgSupportGetAllSetReset;
m_caps[CapType::IYResolution] = m_caps[CapType::IXResolution];
m_query[CapType::IXNativeResolution] = msgSupportGetAll;
m_caps[CapType::IXNativeResolution] = std::bind(enmGet<Fix32>, _1, _2, Fix32(200.0));
m_query[CapType::IYNativeResolution] = msgSupportGetAll;
m_caps[CapType::IYNativeResolution] = m_caps[CapType::IXNativeResolution];
m_query[CapType::IPhysicalWidth] = msgSupportGetAll;
m_caps[CapType::IPhysicalWidth] = [this](Msg msg, Capability& data) -> Result {
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
{
float init = 10.0f;
SANE_Parameters param = { 0 };
if (scanner_.get() && scanner_->get_first_image_header(&param))
init = param.bytes_per_line / scanner_->twain_get_resolution();
data = Capability::createOneValue<Fix32>(data.type(), Fix32(init));
return success();
}
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
};
m_query[CapType::IPhysicalHeight] = msgSupportGetAll;
m_caps[CapType::IPhysicalHeight] = [this](Msg msg, Capability& data) -> Result {
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
{
float init = 10.0f;
SANE_Parameters param = { 0 };
if (scanner_.get() && scanner_->get_first_image_header(&param))
init = param.lines / scanner_->twain_get_resolution();
data = Capability::createOneValue<Fix32>(data.type(), Fix32(init));
return success();
}
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
};
m_query[CapType::IPixelFlavor] = msgSupportGetAllSetReset;
m_caps[CapType::IPixelFlavor] = std::bind(enmGetSetConst<PixelFlavor>, _1, _2, PixelFlavor::Chocolate);
m_query[CapType::IXferMech] = msgSupportGetAllSetReset;
m_caps[CapType::IXferMech] = [this](Msg msg, Capability& data) -> Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IXferMech>();
if (mech == XferMech::Native || mech == XferMech::Memory || mech == XferMech::File) {
m_capXferMech = mech;
return success();
}
else {
return badValue();
}
}
return CapSupGetAllReset<XferMech, XferMech, CapType::IXferMech>(msg, data, { XferMech::Native, XferMech::File, XferMech::Memory }, m_capXferMech, XferMech::Native, (int)m_capXferMech, 0);
};
m_query[CapType::IPixelType] = msgSupportGetAllSetReset;
m_caps[CapType::IPixelType] = [this](Msg msg, Capability& data) -> Result {
if (!scanner_.get())
return seqError();
if (Msg::Reset == msg)
{
int init = 0;
scanner_->twain_get_color_mode(&init);
data = Capability::createOneValue<CapType::IPixelType>((Twpp::PixelType)init);
msg = Msg::Set;
}
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IPixelType>();
return scanner_->twain_set_color_mode((int)mech) == HG_ERR_OK ? success() : badValue();
}
std::vector<int> values;
value_limit limit = VAL_LIMIT_NONE;
int init = 0, now = 0;
switch (msg) {
case Msg::Get:
now = scanner_->twain_get_color_mode(&init, &values, &limit);
//if (limit == VAL_LIMIT_RANGE)
//{
// data = Capability::createRange<CapType::IPixelType>((Twpp::PixelType)(values[0]), (Twpp::PixelType)(values[1]), (Twpp::PixelType)(1), (Twpp::PixelType)(now), (Twpp::PixelType)(init));
// return success();
//}
if (limit == VAL_LIMIT_ENUM)
{
std::list<Twpp::PixelType> vals;
UInt32 ni, ii;
Twpp::PixelType Init = (Twpp::PixelType)init, Now = (Twpp::PixelType)now;
for (const auto& v : values)
vals.push_back((Twpp::PixelType)v);
ni = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), (Twpp::PixelType)now));
ii = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), (Twpp::PixelType)init));
return cap_get_enum_values<Twpp::PixelType, CapType::IPixelType>(msg, data, vals, Now, Init, ni, ii);
}
case Msg::GetCurrent:
now = scanner_->twain_get_color_mode();
data = Capability::createOneValue<CapType::IPixelType>((Twpp::PixelType)now);
return success();
case Msg::GetDefault:
now = scanner_->twain_get_color_mode(&init);
data = Capability::createOneValue<CapType::IPixelType>((Twpp::PixelType)init);
return success();
}
return capBadOperation();
};
m_query[CapType::IAutomaticColorEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticColorEnabled] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IAutomaticColorEnabled>();
scanner_->twain_set_color_mode(mech ? TWPT_AUTOMATIC_COLOR : (int)PixelType::Rgb);
return success();
}
int twpt = scanner_->twain_get_color_mode() == TWPT_AUTOMATIC_COLOR ? 1 : 0;
return CapSupGetAllReset<int, Bool, CapType::IAutomaticColorEnabled>(msg, data, { FALSE,TRUE }, twpt, false, twpt ? 1 : 0, 0);
};
m_query[CapType::IAutomaticColorNonColorPixelType] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticColorNonColorPixelType] = [this](Msg msg, Capability& data)->Result {
if (msg == Msg::Set) {
auto mech = data.currentItem<CapType::IAutomaticColorNonColorPixelType>();
if (scanner_->twain_get_color_mode() == TWPT_AUTOMATIC_COLOR) {
if ((UInt16)mech == 0 || (UInt16)mech == 1) {
if (scanner_->twain_set_auto_color_type((int)mech) == HG_ERR_OK)
{
automaticcolortype_ = (UInt16)mech;
return success();
}
}
}
return seqError();
}
return CapSupGetAllReset<int, PixelType, CapType::IAutomaticColorNonColorPixelType>(msg, data, { PixelType::BlackWhite, PixelType::Gray }, automaticcolortype_, PixelType::Gray, automaticcolortype_, 1);
};
m_query[CapType::IJpegQuality] = msgSupportGetAllSetReset;
m_caps[CapType::IJpegQuality] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IJpegQuality>();
if ((int)mech <= 0 || (int)mech > 100)
return badValue();
return scanner_->twain_set_final_format(SANE_IMAGE_TYPE_JPG, (void*)mech) == HG_ERR_OK ? success() : badValue();
}
unsigned short q = scanner_->twain_get_jpeg_quality();
return CapSupGetAllResetEx<unsigned short, UInt16, CapType::IJpegQuality>(msg, data, q, 80);
};
m_query[CapType::IOrientation] = msgSupportGetAllSetReset;
m_caps[CapType::IOrientation] = [this](Msg msg, Capability& data) -> Result {
CapabilityPrintf(msg, enum2str(CapTypeEx::IOrientation), msg == Msg::Set ? to_string((int)data.currentItem<CapType::IOrientation>()) : "");
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IOrientation>();
return scanner_->twain_set_paper_lateral(mech == Orientation::Landscape) ? success() : badValue();
}
int lateral = scanner_->twain_is_paper_lateral() ? (int)Orientation::Landscape : (int)Orientation::Portrait;
return CapSupGetAllReset<int, Orientation, CapType::IOrientation>(msg, data, { Orientation::Portrait, Orientation::Landscape }, lateral, Orientation::Portrait, lateral == 0 ? 0 : 1, 0);
};
m_query[CapType::IRotation] = msgSupportGetAllSetReset;
m_caps[CapType::IRotation] = [this](Msg msg, Capability& data) -> Result {
if (Msg::Set == msg) {
auto res = data.currentItem<Fix32>();
return scanner_->twain_set_text_direction(res.toFloat()) == HG_ERR_OK ? success() : badValue();
}
double init = .0f, now = .0f;
std::list<double> values;
value_limit limit = VAL_LIMIT_NONE;
now = scanner_->twain_get_text_direction(&init, &values, &limit);
Fix32 Init = Fix32(init), Now = Fix32(now);
std::list<Fix32> vls;
UInt32 i = 0, n = 0;
for (const auto& v : values)
vls.push_back(Fix32(v));
i = std::distance(vls.begin(), std::find(vls.begin(), vls.end(), Init));
n = std::distance(vls.begin(), std::find(vls.begin(), vls.end(), Now));
return cap_get_enum_values<Fix32, CapType::IRotation>(msg, data, vls, Now, Init, n, i);
};
m_query[CapType::EnableDsUiOnly] = msgSupportGetAll;
m_caps[CapType::EnableDsUiOnly] = std::bind(enmGet<Bool>, _1, _2, Bool(true));
m_query[CapType::PaperDetectable] = msgSupportGetAll;
m_caps[CapType::PaperDetectable] = std::bind(oneValGet<Bool>, _1, _2, Bool(true));
m_query[CapType::FeederEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::FeederEnabled] = [this](Msg msg, Capability& data) -> Result {
CapabilityPrintf(msg, enum2str(CapType::FeederEnabled), msg == Msg::Set ? to_string((int)data.currentItem<CapType::FeederEnabled>()) : "");
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::FeederEnabled>();
m_bFeederEnabled = mech;
return success();
}
return CapSupGetAllReset<bool, Bool, CapType::PaperDetectable>(msg, data, m_bFeederEnabled, Bool(true));
};
m_query[CapType::Duplex] = msgSupportGetAll;
m_caps[CapType::Duplex] = std::bind(oneValGet<Duplex>, _1, _2, Duplex::OnePass);
m_query[CapType::DuplexEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::DuplexEnabled] = [this](Msg msg, Capability& data) -> Result {
if (Msg::Set == msg) {
bool mech = data.currentItem<CapType::DuplexEnabled>();
return scanner_->twain_set_page_duplex(mech) == HG_ERR_OK ? success() : badValue();
}
BYTE dup = scanner_->twain_is_page_duplex();
return CapSupGetAllReset<BYTE, Bool, CapType::DuplexEnabled>(msg, data, dup, Bool(true));
};
m_query[CapType::AutoFeed] = msgSupportGetAllSetReset;
m_caps[CapType::AutoFeed] = [this](Msg msg, Capability& data) -> Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::AutoFeed>();
m_bAutoFeed = mech;
return success();
}
return CapSupGetAllReset<bool, Bool, CapType::AutoFeed>(msg, data, { false,true }, m_bAutoFeed, true, m_bAutoFeed ? 1 : 0, 1);
};
m_query[CapType::IImageFileFormat] = msgSupportGetAllSetReset;
m_caps[CapType::IImageFileFormat] = [this](Msg msg, Capability& data) -> Result {
CapabilityPrintf(msg, enum2str(CapType::IImageFileFormat), msg == Msg::Set ? to_string((int)data.currentItem<CapType::IImageFileFormat>()) : "");
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IImageFileFormat>();
SANE_ImageType type = SANE_IMAGE_TYPE_BMP;
if (mech == ImageFileFormat::Bmp)
type = SANE_IMAGE_TYPE_BMP;
else if(mech == ImageFileFormat::Tiff)
type = SANE_IMAGE_TYPE_TIFF;
else if(mech == ImageFileFormat::Jfif)
type = SANE_IMAGE_TYPE_JFIF;
else
return badValue();
return scanner_->twain_set_final_format(type, NULL) == HG_ERR_OK ? success() : badValue();
}
ImageFileFormat fmt = ImageFileFormat::Bmp;
SANE_ImageType type = scanner_->get_final_format();
if (type == SANE_IMAGE_TYPE_TIFF)
fmt = ImageFileFormat::Tiff;
else if(type == SANE_IMAGE_TYPE_JFIF)
fmt = ImageFileFormat::Jfif;
return CapSupGetAllReset < ImageFileFormat, ImageFileFormat, CapType::IImageFileFormat>(msg, data, { ImageFileFormat::Bmp, ImageFileFormat::Tiff,ImageFileFormat::Jfif },
fmt, ImageFileFormat::Bmp, fmt == ImageFileFormat::Bmp ? 0 : (fmt == ImageFileFormat::Tiff ? 1 : 2), 0);
};
m_query[CapType::IAutomaticDeskew] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticDeskew] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto atuodsw = data.currentItem<CapType::IAutomaticDeskew>();
return scanner_->twain_set_auto_descrew((bool)atuodsw) == HG_ERR_OK ? success() : seqError();
}
BYTE ato = scanner_->twain_is_auto_descrew();
return CapSupGetAllReset<BYTE, bool, CapType::IAutomaticDeskew>(msg, data, ato, true);
};
m_query[CapType::IAutomaticRotate] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticRotate] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IAutomaticRotate>();
return scanner_->twain_set_text_auto_matic(mech) == HG_ERR_OK ? success() : badValue();
}
BYTE am = scanner_->twain_is_text_auto_matic();
return CapSupGetAllReset<BYTE, bool, CapType::IAutomaticRotate>(msg, data, am, false);
};
m_query[CapType::SerialNumber] = msgSupportGetAll;
m_caps[CapType::SerialNumber] = [this](Msg msg, Capability& data)->Result {
Str255 str;
scanner_->twain_get_serial_num(str.data());
return CapSupGetAll<Str255, Str255, CapType::SerialNumber>(msg, data, str, str);
};
m_query[CapType::AutoScan] = msgSupportGetAllSetReset;
m_caps[CapType::AutoScan] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto autoscan = data.currentItem<CapType::AutoScan>();
m_autoscan = autoscan;
return success();
}
return CapSupGetAllReset<Bool, Bool, CapType::AutoScan>(msg, data, m_autoscan, FALSE);
};
m_query[CapType::IAutoSize] = msgSupportGetAllSetReset;
m_caps[CapType::IAutoSize] = [this](Msg msg, Capability& data)->Result {
CapabilityPrintf(msg, enum2str(CapType::IAutoSize), msg == Msg::Set ? to_string((int)data.currentItem<CapType::IAutoSize>()) : "");
if (Msg::Set == msg) {
auto autosize = data.currentItem<CapType::IAutoSize>();
return scanner_->twain_set_paper_auto_match_size(autosize == AutoSize::Auto) == HG_ERR_OK ? success() : badValue();
}
UInt16 size = scanner_->twain_is_paper_auto_match_size() ? (UInt16)AutoSize::Auto : (UInt16)AutoSize::None;
return CapSupGetAllReset<UInt16, AutoSize, CapType::IAutoSize>(msg, data, { AutoSize::None, AutoSize::Auto }, size, AutoSize::None, (size == (UInt16)AutoSize::Auto) ? 1 : 0, 0);
};
m_query[CapType::IAutomaticBorderDetection] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticBorderDetection] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto autodetectborder = data.currentItem<CapType::IAutomaticBorderDetection>();
return scanner_->twain_set_erase_black_frame((bool)autodetectborder) == HG_ERR_OK ? success() : badValue();
}
bool val = false;
Bool init = false,
erase = scanner_->twain_is_erase_black_frame(&val);
init = val;
return CapSupGetAllReset<Bool, Bool, CapType::IAutomaticBorderDetection>(msg, data, { false,true }, erase, init, erase ? 1 : 0, 0);
};
m_query[CapType::IAutoDiscardBlankPages] = msgSupportGetAllSetReset;
m_caps[CapType::IAutoDiscardBlankPages] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IAutoDiscardBlankPages>();
return scanner_->twain_set_page_discarding_blank_page(mech == DiscardBlankPages::Auto, false) == HG_ERR_OK ? success() : badValue();
}
DiscardBlankPages autodiscradblank = scanner_->twain_is_page_discarding_blank_page(false) ?
DiscardBlankPages::Auto : DiscardBlankPages::Disabled;
return CapSupGetAllReset<DiscardBlankPages, DiscardBlankPages, CapType::IAutoDiscardBlankPages>(msg, data, autodiscradblank, DiscardBlankPages::Disabled);
};
m_query[(CapType)CAP_TYPE_EX_DISCARD_BLANK_RECEIPT] = msgSupportGetAllSetReset;
m_caps[(CapType)CAP_TYPE_EX_DISCARD_BLANK_RECEIPT] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<DiscardBlankPages>();
return scanner_->twain_set_page_discarding_blank_page(mech == DiscardBlankPages::Auto, true) == HG_ERR_OK ? success() : badValue();
}
DiscardBlankPages autodiscradblank = scanner_->twain_is_page_discarding_blank_page(true) ?
DiscardBlankPages::Auto : DiscardBlankPages::Disabled;
return CapSupGetAllResetEx<DiscardBlankPages, DiscardBlankPages, (CapType)CapTypeEx::CAP_TYPE_EX_DISCARD_BLANK_RECEIPT>(msg, data, autodiscradblank, DiscardBlankPages::Disabled);
};
m_query[CapType::IFilter] = msgSupportGetAllSetReset;
m_caps[CapType::IFilter] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IFilter>();
return scanner_->twain_set_filter((int)mech, false) == HG_ERR_OK ? success() : badValue();
}
BYTE f = (BYTE)scanner_->twain_get_filter(false);
UInt32 ind = 3;
if (f == (BYTE)Filter::Red)
ind = 0;
else if (f == (BYTE)Filter::Green)
ind = 1;
else if (f == (BYTE)Filter::Blue)
ind = 2;
return CapSupGetAllReset<BYTE, Filter, CapType::IFilter>(msg, data, { Filter::Red, Filter::Green,Filter::Blue,Filter::None }, f, Filter::None, ind, 3);
};
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<Filter>();
return scanner_->twain_set_filter((int)mech, true) == HG_ERR_OK ? success() : badValue();
}
BYTE f = (BYTE)scanner_->twain_get_filter(true);
UInt32 ind = 3;
if (f == ENHANCE_COLOR_RED)
ind = 0;
else if (f == ENHANCE_COLOR_GREEN)
ind = 1;
else if (f == ENHANCE_COLOR_BLUE)
ind = 2;
return CapSupGetAllResetEx<BYTE, Filter, (CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR>(msg, data, { Filter::Red, Filter::Green,Filter::Blue,Filter::None }, f, Filter::None, ind, 3);
};
m_query[CapType::IBrightness] = msgSupportGetAllSetReset;
m_caps[CapType::IBrightness] = [this](Msg msg, Capability& data)->Result {
double init = .0f, l = .0f, u = .0f, step = .0f,
now = scanner_->twain_get_bright(&init, &l, &u, &step);
switch (msg) {
case Msg::Get:
data = Capability::createRange<CapType::IBrightness>(Fix32(l), Fix32(u), Fix32(step), Fix32(now), Fix32(init));
return success();
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IBrightness>(Fix32(now));
return success();
case Msg::GetDefault:
case Msg::Reset:
data = Capability::createOneValue<CapType::IBrightness>(Fix32(init));
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IBrightness>();
if (mech > u || mech < -l)
return badValue();
return scanner_->twain_set_bright(mech.toFloat()) == HG_ERR_OK ? success() : badValue();
}
default:
return capBadOperation();
}
};
m_query[CapType::IContrast] = msgSupportGetAllSetReset;
m_caps[CapType::IContrast] = [this](Msg msg, Capability& data)->Result {
double init = .0f, l = .0f, u = .0f, step = .0f,
now = scanner_->twain_get_contrast(&init, &l, &u, &step);
switch (msg) {
case Msg::Get:
data = Capability::createRange<CapType::IContrast>(Fix32(l), Fix32(u), Fix32(step), Fix32(now), Fix32(init));
return success();
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IContrast>(Fix32(now));
return success();
case Msg::GetDefault:
case Msg::Reset:
data = Capability::createOneValue<CapType::IContrast>(Fix32(init));
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IContrast>();
if (mech > u || mech < -l)
return badValue();
return scanner_->twain_set_contrast(mech.toFloat()) == HG_ERR_OK ? success() : badValue();
}
default:
return capBadOperation();
}
};
m_query[CapType::IGamma] = msgSupportGetAllSetReset;
m_caps[CapType::IGamma] = [this](Msg msg, Capability& data)->Result {
double init = .0f, l = .0f, u = .0f, step = .0f,
now = scanner_->twain_get_gamma(&init, &l, &u, &step);
switch (msg) {
case Msg::Get:
data = Capability::createRange<CapType::IGamma>(Fix32(l), Fix32(u), Fix32(step), Fix32(now), Fix32(init));
return success();
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IGamma>(Fix32(now));
return success();
case Msg::GetDefault:
case Msg::Reset:
data = Capability::createOneValue<CapType::IGamma>(Fix32(init));
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IGamma>();
if (mech > u || mech < l)
return badValue();
return scanner_->twain_set_gamma(mech.toFloat()) == HG_ERR_OK ? success() : badValue();
}
default:
return capBadOperation();
}
};
m_query[CapType::CustomDsData] = msgSupportGetAll;
m_caps[CapType::CustomDsData] = [this](Msg msg, Capability& data) -> Result {
return CapSupGetAll<Bool, Bool, CapType::CustomDsData>(msg, data, Bool(true), Bool(true));
};
m_query[CapType::DoubleFeedDetection] = msgSupportGetAllSetReset;
m_caps[CapType::DoubleFeedDetection] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto atuodsw = data.currentItem<CapType::DoubleFeedDetection>();
return scanner_->twain_set_ultrasonic_check((bool)atuodsw) == HG_ERR_OK ? success() : seqError();
}
DoubleFeedDetection init = DoubleFeedDetection::Ultrasonic;
BYTE ato = scanner_->twain_is_ultrasonic_check();
return CapSupGetAllReset<BYTE, DoubleFeedDetection, CapType::DoubleFeedDetection>(msg, data, ato, init);
};
m_query[CapType::IAutomaticCropUsesFrame] = msgSupportGetAll;
m_caps[CapType::IAutomaticCropUsesFrame] = [this](Msg msg, Capability& data)->Result {
BYTE crop = scanner_->twain_is_auto_crop();
return CapSupGetAll<BYTE, bool, CapType::IAutomaticCropUsesFrame>(msg, data, crop, false);
};
m_query[CapType::FeederLoaded] = msgSupportGetAll;
m_caps[CapType::FeederLoaded] = [this](Msg msg, Capability& data) -> Result {
Bool paperon = scanner_->twain_is_paper_on();
return CapSupGetAll<Bool, Bool, CapType::FeederLoaded>(msg, data, paperon, paperon);
};
m_query[CapType::Indicators] = msgSupportGetAllSetReset;
m_caps[CapType::Indicators] = [this](Msg msg, Capability& data) -> Result {
if (Msg::Set == msg) {
auto show = data.currentItem<CapType::Indicators>();
m_bIndicator = show;
return success();
}
return CapSupGetAllReset<bool, Bool, CapType::Indicators>(msg, data, { FALSE,TRUE }, m_bIndicator, TRUE, m_bIndicator ? 1 : 0, 1);
};
m_query[CapType(CapTypeEx::CAP_TYPE_EX_FOLD)] = msgSupportGetAllSetReset;
m_caps[CapType(CapTypeEx::CAP_TYPE_EX_FOLD)] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg || Msg::Reset == msg) {
auto fold = data.currentItem<Int32>();
if (msg == Msg::Reset)
fold = false;
return scanner_->twain_set_page_fold(fold) == HG_ERR_OK ? success() : badValue();
}
BYTE fold = scanner_->twain_is_page_fold();
return CapSupGetAllResetEx<BYTE, Int32, (CapType)CapTypeEx::CAP_TYPE_EX_FOLD>(msg, data, fold, 0);
};
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<BYTE>();
return scanner_->twain_set_sharpen((int)mech) == HG_ERR_OK ? success() : badValue();
}
BYTE f = (BYTE)scanner_->twain_get_sharpen();
return CapSupGetAllResetEx<BYTE, BYTE, (CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN>(msg, data, { 0, 1, 2, 3, 4}, f, 0, f, 0);
};
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST)] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg) {
auto mech = data.currentItem<UInt32>();
if (mech < 10 || mech > 300)
return badValue();
return scanner_->twain_set_dogear_distance(mech) == HG_ERR_OK ? success() : badValue();
}
UInt32 init = 50,
now = scanner_->twain_get_dogear_distance();
return CapSupGetAllResetEx<UInt32, UInt32, (CapType)CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST>(msg, data, now, init);
};
m_query[CapType(CapTypeEx::CAP_TYPE_EX_MULTI_OUT)] = msgSupportGetAllSetReset;
m_caps[CapType(CapTypeEx::CAP_TYPE_EX_MULTI_OUT)] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg || Msg::Reset == msg) {
auto multi = data.currentItem<Int32>();
if (msg == Msg::Reset)
multi = false;
multi_out_ = multi;
return success();
}
BYTE multi = multi_out_;
return CapSupGetAllResetEx<BYTE, Int32, (CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT>(msg, data, multi, 0);
};
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg || Msg::Reset == msg) {
auto mech = data.currentItem<UInt32>();
if (msg == Msg::Reset)
mech = -1;
return scanner_->twain_set_multioutput_type((int)mech) == HG_ERR_OK ? success() : badValue();
}
UInt32 f = (UInt32)scanner_->twain_get_multioutput_type();
return CapSupGetAllResetEx<UInt32, UInt32, (CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE>(msg, data, { (UInt32)-1, 0, 1, 2, 3 }, f, -1, 0, 0);
};
m_query[CapType(CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN)] = msgSupportGetAllSetReset;
m_caps[CapType(CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN)] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg || Msg::Reset == msg) {
auto tobe = data.currentItem<Int32>();
if (msg == Msg::Reset)
tobe = false;
return scanner_->twain_set_to_be_scan(tobe) == HG_ERR_OK ? success() : seqError();
}
BYTE tobe = scanner_->twain_get_to_be_scan();
return CapSupGetAllResetEx<BYTE, Int32, (CapType)CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN>(msg, data, tobe, 0);
};
m_query[CapType(CapTypeEx::CAP_TYPE_EX_SCAN_WITH_HOLE)] = msgSupportGetAllSetReset;
m_caps[CapType(CapTypeEx::CAP_TYPE_EX_SCAN_WITH_HOLE)] = [this](Msg msg, Capability& data)->Result {
if (Msg::Set == msg || Msg::Reset == msg) {
auto tobe = data.currentItem<Int32>();
if (msg == Msg::Reset)
tobe = false;
return scanner_->twain_set_scan_with_hole(tobe) == HG_ERR_OK ? success() : seqError();
}
BYTE tobe = scanner_->twain_get_scan_with_hole();
return CapSupGetAllResetEx<BYTE, Int32, (CapType)CapTypeEx::CAP_TYPE_EX_SCAN_WITH_HOLE>(msg, data, tobe, 0);
};
char code[256] = { 0 };
unsigned int len = _countof(code);
if (scanner_->twain_get_device_code(code, len) == HG_ERR_OK)
{
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = msgSupportGetAll;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = [this](Msg msg, Capability& data)->Result {
char code[256] = { 0 };
unsigned int len = _countof(code);
Str255 str;
scanner_->twain_get_device_code(code, len);
str.setData(code, 32);
data = Capability::createOneValue<Str255>((CapType)CapTypeEx::CAP_TYPE_EX_ENCODE, str);
return success();
};
}
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_POWER_LEVEL)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_POWER_LEVEL)] = [this](Msg msg, Capability& data)->Result {
UInt32 init = 4;
if (Msg::Set == msg || Msg::Reset == msg) {
if(msg == Msg::Set)
init = data.currentItem<UInt32>();
scanner_->twain_set_power_level(init);
return success();
}
UInt32 level = scanner_->twain_get_power_level();
return CapSupGetAllResetEx<UInt32, UInt32, (CapType)CapTypeEx::CAP_TYPE_EX_POWER_LEVEL>(msg, data, level, init);
};
init_support_caps_ex();
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION] = msgSupportGetAll;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION] = [this](Msg msg, Capability& data)->Result {
Str255 str;
scanner_->twain_get_hareware_version(str.data());
data = Capability::createOneValue<Str255>((CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION, str);
return success(); // CapSupGetAllEx<Str255, Str255, (CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION>(msg, data, str, str);
};
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_IP] = msgSupportGetAll;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_IP] = [this](Msg msg, Capability& data)->Result {
Str255 str;
scanner_->twain_get_ip(str.data());
data = Capability::createOneValue<Str255>((CapType)CapTypeEx::CAP_TYPE_EX_IP, str);
return success(); // CapSupGetAll<Str255, Str255, (CapType)CapTypeEx::CAP_TYPE_EX_IP>(msg, data, str, str);
};
#define SET_EXISTING_EXTENSION(scan_ind, cap) \
op_ind = scanner_->##scan_ind(); \
if(op_ind != -1) \
{ \
m_query[(CapType)cap] = msgSupportGetAllSetReset; \
m_caps[(CapType)cap] = m_caps[CapType((int)CAP_TYPE_EX_0 + op_ind)]; \
}
int op_ind = -1;
SET_EXISTING_EXTENSION(twain_get_paper_ind, CapType::ISupportedSizes);
SET_EXISTING_EXTENSION(twain_get_flip_ind, CapTypeEx::CAP_TYPE_EX_FLIP);
SET_EXISTING_EXTENSION(twain_get_rotate_bkg_ind, CapTypeEx::CAP_TYPE_EX_ROTATE_BKG_180);
SET_EXISTING_EXTENSION(twain_get_fill_black_bkg_ind, CapTypeEx::CAP_TYPE_EX_FILL_BLACK_BKG);
SET_EXISTING_EXTENSION(twain_get_edge_ident_ind, CapTypeEx::CAP_TYPE_EX_EDGE_IDENT);
SET_EXISTING_EXTENSION(twain_get_threshold_ind, CapTypeEx::CAP_TYPE_EX_THRESHOLD);
SET_EXISTING_EXTENSION(twain_get_threshold_ind, CapTypeEx::CAP_TYPE_EX_THRESHOLD_1);
SET_EXISTING_EXTENSION(twain_bkg_filling_method_ind, CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD);
SET_EXISTING_EXTENSION(twain_fill_hole_ind, CapTypeEx::CAP_TYPE_EX_FILL_HOLE);
SET_EXISTING_EXTENSION(twain_fill_hole_ratio_ind, CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO);
SET_EXISTING_EXTENSION(twain_detach_noise_ind, CapTypeEx::CAP_TYPE_EX_DETACH_NOISE);
SET_EXISTING_EXTENSION(twain_detach_noise_threshold_ind, CapTypeEx::CAP_TYPE_EX_DETACH_NOISE_THRESHOLD);
SET_EXISTING_EXTENSION(twain_rid_red_ind, CapTypeEx::CAP_TYPE_EX_RID_RED);
SET_EXISTING_EXTENSION(twain_rid_red_hsv_ind, CapTypeEx::CAP_TYPE_EX_RID_RED_HSV);
SET_EXISTING_EXTENSION(twain_screw_detect_ind, CapTypeEx::CAP_TYPE_EX_SCREW_DETECT);
SET_EXISTING_EXTENSION(twain_screw_detect_level_ind, CapTypeEx::CAP_TYPE_EX_SCREW_DETECT_LEVEL);
SET_EXISTING_EXTENSION(twain_staple_detect_ind, CapTypeEx::CAP_TYPE_EX_STAPLE_DETECT);
SET_EXISTING_EXTENSION(twain_dogear_detect_ind, CapTypeEx::CAP_TYPE_EX_DOGEAR_DETECT);
SET_EXISTING_EXTENSION(twain_dark_sample_ind, CapTypeEx::CAP_TYPE_EX_DARK_SAMPLE);
SET_EXISTING_EXTENSION(twain_image_split_ind, CapTypeEx::CAP_TYPE_EX_IMAGE_SPLIT);
SET_EXISTING_EXTENSION(twain_fade_bkground_ind, CapTypeEx::CAP_TYPE_EX_FADE_BKG);
SET_EXISTING_EXTENSION(twain_fade_bkground_val_ind, CapTypeEx::CAP_TYPE_EX_FADE_BKG_VALUE);
SET_EXISTING_EXTENSION(twain_size_detect_ind, CapTypeEx::CAP_TYPE_EX_SIZE_DETECT);
}
void huagao_ds::init_support_caps_ex(void)
{
#define SET_CAP_ENUM(sn, ctype, ttype, cap) \
m_query[(CapType)cap] = msgSupportGetAllSetReset; \
m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \
if (!scanner_.get()) \
return seqError(); \
if(msg == Msg::Set) { \
ctype item; \
copy_type(item, data.currentItem<ttype>()); \
return scanner_->set_value(sn, item) == HG_ERR_OK ? success() : badValue(); \
} \
std::list<ctype> org; \
ctype now, init; \
std::list<ttype> vals; \
ttype Now, Init; \
UInt32 ni, ii; \
scanner_->get_value(sn, org, now, init); \
ni = std::distance(org.begin(), std::find(org.begin(), org.end(), now)); \
ii = std::distance(org.begin(), std::find(org.begin(), org.end(), init)); \
copy_type(Now, now); \
for(const auto& v: org) \
{ \
copy_type(Init, v); \
vals.push_back(Init); \
} \
copy_type(Init, init); \
return cap_get_enum_values<ttype, (CapType)cap>(msg, data, vals, Now, Init, ni, ii); \
};
#define SET_CAP_RANGE(sn, ctype, ttype, cap) \
m_query[(CapType)cap] = msgSupportGetAllSetReset; \
m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \
if (!scanner_.get()) \
return seqError(); \
if(msg == Msg::Set) { \
ctype item = (ctype)data.currentItem<ttype>(); \
return scanner_->set_value(sn, item) == HG_ERR_OK ? success() : badValue(); \
} \
ctype now, init, lower, upper, step; \
ttype Now, Init, Lower, Upper, Step; \
scanner_->get_value(sn, now, init, &lower, &upper, &step); \
copy_type(Now, now); \
copy_type(Init, init); \
copy_type(Lower, lower); \
copy_type(Upper, upper); \
copy_type(Step, step); \
return cap_get_one_value<ttype, (CapType)cap>(msg, data, Now, Init, &Lower, &Upper, &Step); \
};
#define SET_BOOL(sn, cap) \
m_query[(CapType)cap] = msgSupportGetAllSetReset; \
m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \
if (!scanner_.get()) \
return seqError(); \
if(msg == Msg::Set) { \
auto item = data.currentItem<Bool>(); \
return scanner_->set_value(sn, (bool)item) == HG_ERR_OK ? success() : badValue(); \
} \
bool init = false, now = false; \
std::list<bool> vals; \
scanner_->get_value(sn, vals, now, init); \
BYTE v = now; \
return CapSupGetAllResetEx<BYTE, Bool, (CapType)cap>(msg, data, v, init); \
};
#define SET_CAP(sn, ctype, ttype, cap) \
m_query[(CapType)cap] = msgSupportGetAllSetReset; \
m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \
if (!scanner_.get()) \
return seqError(); \
if(msg == Msg::Set) { \
ctype item = (ctype)data.currentItem<ttype>(); \
return scanner_->set_value(sn, item) == HG_ERR_OK ? success() : badValue(); \
} \
ctype now, init; \
ttype Now, Init; \
scanner_->get_value(sn, now, init); \
copy_type(Now, now); \
copy_type(Init, init); \
return cap_get_one_value<ttype, (CapType)cap>(msg, data, Now, Init, NULL, NULL, NULL); \
};
#define ADD_CAP(sn) \
{ \
std::string data_type(""); \
value_limit vl = VAL_LIMIT_NONE; \
if(!scanner_->get_value_info(sn, data_type, vl)) \
return; \
if(data_type == "bool") \
{ \
SET_BOOL(sn, CAP_TYPE_EX_##sn); \
} \
else if(data_type == "int") \
{ \
if(vl == VAL_LIMIT_RANGE) \
{ SET_CAP_RANGE(sn, int, UInt32, CAP_TYPE_EX_##sn); } \
else \
{ SET_CAP(sn, int, UInt32, CAP_TYPE_EX_##sn); } \
} \
else if(data_type == "float") \
{ \
if(vl == VAL_LIMIT_RANGE) \
{ SET_CAP_RANGE(sn, float, Fix32, CAP_TYPE_EX_##sn); } \
else \
{ SET_CAP(sn, float, Fix32, CAP_TYPE_EX_##sn); } \
} \
else if(data_type == "string") \
{ \
if(vl == VAL_LIMIT_ENUM) \
{ SET_CAP_ENUM(sn, std::string, Twpp::Str64, CAP_TYPE_EX_##sn); } \
} \
else if(data_type == "button") \
{ \
m_query[(CapType)CAP_TYPE_EX_##sn] = MsgSupport::Set | MsgSupport::Reset; \
m_caps[(CapType)CAP_TYPE_EX_##sn] = [this](Msg msg, Capability& data) -> Result { \
if (!scanner_.get()) \
return seqError(); \
if(msg == Msg::Set) { \
scanner_->set_value(sn, false); \
return success(); \
} \
return enmGet<Bool>(msg, data, true); \
}; \
} \
}
// setting items ...
ADD_CAP(1);
ADD_CAP(2);
ADD_CAP(3);
ADD_CAP(4);
ADD_CAP(5);
ADD_CAP(6);
ADD_CAP(7);
ADD_CAP(8);
ADD_CAP(9);
ADD_CAP(10);
ADD_CAP(11);
ADD_CAP(12);
ADD_CAP(13);
ADD_CAP(14);
ADD_CAP(15);
ADD_CAP(16);
ADD_CAP(17);
ADD_CAP(18);
ADD_CAP(19);
ADD_CAP(20);
ADD_CAP(21);
ADD_CAP(22);
ADD_CAP(23);
ADD_CAP(24);
ADD_CAP(25);
ADD_CAP(26);
ADD_CAP(27);
ADD_CAP(28);
ADD_CAP(29);
ADD_CAP(30);
ADD_CAP(31);
ADD_CAP(32);
ADD_CAP(33);
ADD_CAP(34);
ADD_CAP(35);
ADD_CAP(36);
ADD_CAP(37);
ADD_CAP(38);
ADD_CAP(39);
ADD_CAP(40);
ADD_CAP(41);
ADD_CAP(42);
ADD_CAP(43);
ADD_CAP(44);
ADD_CAP(45);
ADD_CAP(46);
ADD_CAP(47);
ADD_CAP(48);
ADD_CAP(49);
ADD_CAP(50);
ADD_CAP(51);
ADD_CAP(52);
ADD_CAP(53);
ADD_CAP(54);
ADD_CAP(55);
ADD_CAP(56);
ADD_CAP(57);
ADD_CAP(58);
ADD_CAP(59);
ADD_CAP(60);
ADD_CAP(61);
ADD_CAP(62);
ADD_CAP(63);
ADD_CAP(64);
ADD_CAP(65);
ADD_CAP(66);
ADD_CAP(67);
ADD_CAP(68);
ADD_CAP(69);
ADD_CAP(70);
ADD_CAP(71);
ADD_CAP(72);
ADD_CAP(73);
ADD_CAP(74);
ADD_CAP(75);
ADD_CAP(76);
ADD_CAP(77);
ADD_CAP(78);
ADD_CAP(79);
ADD_CAP(80);
}
void huagao_ds::on_scan_event(int sane_event, void* data, unsigned int* len)
{
if (ui_.get())
{
ui_->handle_sane_event(sane_event, data, len);
if (sane_event == SANE_EVENT_SCAN_FINISHED)
{
if (ui_->is_progress_ui_showing())
ui_->hide_ui();
else if (!scanner_->twain_get_to_be_scan())
ui_->hide_ui();
}
}
}