2027 lines
67 KiB
C++
2027 lines
67 KiB
C++
#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(¶m))
|
||
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(¶m))
|
||
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();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|