code_twain/huagaotwain/twain/huagaods.cpp

2027 lines
67 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

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

#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();
}
}
}