code_device/twain/ds/huagaods.cpp

3943 lines
132 KiB
C++
Raw Normal View History

2023-07-10 07:28:45 +00:00
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#include <memory>
#include "huagaods.hpp"
//#include "twpp/twglue.hpp"
#include <list>
#include <map>
#if defined(WIN32) || defined(_WIN64) // WIN32
#include <shlobj.h>
#include <Psapi.h>
#include <io.h>
#define mktemp _mktemp
#endif // WIN32
#include <algorithm>
using namespace std;
#define enum2str(R) #R
#pragma warning(disable: 4700)
using namespace Twpp;
using namespace std::placeholders;
extern HMODULE me_;
// WIA COM: IStiUSD & IWiaMiniDrv
//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_DARK_SAMPLE = 0x8016,
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_ANTI_NOISE = 0x8099,
CAP_TYPE_EX_THRESHOLD = 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_CROP_MODEL = 0x8106,
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,
};
enum // .twain/first.cfg: [twain-app] flow=0
{
TWAIN_APP_TRANSFER_NORMAL = 0, // first get head and then bits
TWAIN_APP_TRANSFER_REVERSE, // first get bits and then head
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// entry ...
TWPP_ENTRY(huagao_ds)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// utilites ...
// some helper functions to handle capability stuff
#define RETURN_ENUM_DESC(en, v, space) \
if(v == space::en) \
return #en;
const char* desc_state(DsState s, char unk[20])
{
RETURN_ENUM_DESC(Closed, s, DsState);
RETURN_ENUM_DESC(Open, s, DsState);
RETURN_ENUM_DESC(Enabled, s, DsState);
RETURN_ENUM_DESC(XferReady, s, DsState);
RETURN_ENUM_DESC(Xferring, s, DsState);
sprintf(unk, "%d", s);
return unk;
}
const char* desc_data_group(DataGroup d, char unk[20])
{
RETURN_ENUM_DESC(Control, d, DataGroup);
RETURN_ENUM_DESC(Image, d, DataGroup);
RETURN_ENUM_DESC(Audio, d, DataGroup);
{
sprintf(unk, "%d", d);
return unk;
}
}
const char* desc_data(Dat d, char unk[20])
{
RETURN_ENUM_DESC(Null, d, Dat);
RETURN_ENUM_DESC(Capability, d, Dat);
RETURN_ENUM_DESC(Event, d, Dat);
RETURN_ENUM_DESC(Identity, d, Dat);
RETURN_ENUM_DESC(Parent, d, Dat);
RETURN_ENUM_DESC(PendingXfers, d, Dat);
RETURN_ENUM_DESC(SetupMemXfer, d, Dat);
RETURN_ENUM_DESC(SetupFileXfer, d, Dat);
RETURN_ENUM_DESC(Status, d, Dat);
RETURN_ENUM_DESC(UserInterface, d, Dat);
RETURN_ENUM_DESC(XferGroup, d, Dat);
RETURN_ENUM_DESC(CustomData, d, Dat);
RETURN_ENUM_DESC(DeviceEvent, d, Dat);
RETURN_ENUM_DESC(FileSystem, d, Dat);
RETURN_ENUM_DESC(PassThrough, d, Dat);
RETURN_ENUM_DESC(Callback, d, Dat);
RETURN_ENUM_DESC(StatusUtf8, d, Dat);
RETURN_ENUM_DESC(Callback2, d, Dat);
RETURN_ENUM_DESC(ImageInfo, d, Dat);
RETURN_ENUM_DESC(ImageLayout, d, Dat);
RETURN_ENUM_DESC(ImageMemXfer, d, Dat);
RETURN_ENUM_DESC(ImageNativeXfer, d, Dat);
RETURN_ENUM_DESC(ImageFileXfer, d, Dat);
RETURN_ENUM_DESC(CieColor, d, Dat);
RETURN_ENUM_DESC(GrayResponse, d, Dat);
RETURN_ENUM_DESC(RgbResponse, d, Dat);
RETURN_ENUM_DESC(JpegCompression, d, Dat);
RETURN_ENUM_DESC(Palette8, d, Dat);
RETURN_ENUM_DESC(ExtImageInfo, d, Dat);
RETURN_ENUM_DESC(Filter, d, Dat);
RETURN_ENUM_DESC(AudioFileXfer, d, Dat);
RETURN_ENUM_DESC(AudioInfo, d, Dat);
RETURN_ENUM_DESC(AudioNativeXfer, d, Dat);
RETURN_ENUM_DESC(IccProfile, d, Dat);
RETURN_ENUM_DESC(ImageMemFileXfer, d, Dat);
RETURN_ENUM_DESC(EntryPoint, d, Dat);
{
sprintf(unk, "%d", d);
return unk;
}
}
const char* desc_msg(Msg m, char unk[20])
{
RETURN_ENUM_DESC(Null, m, Msg);
RETURN_ENUM_DESC(Get, m, Msg);
RETURN_ENUM_DESC(GetCurrent, m, Msg);
RETURN_ENUM_DESC(GetDefault, m, Msg);
RETURN_ENUM_DESC(GetFirst, m, Msg);
RETURN_ENUM_DESC(GetNext, m, Msg);
RETURN_ENUM_DESC(Set, m, Msg);
RETURN_ENUM_DESC(Reset, m, Msg);
RETURN_ENUM_DESC(QuerySupport, m, Msg);
RETURN_ENUM_DESC(GetHelp, m, Msg);
RETURN_ENUM_DESC(GetLabel, m, Msg);
RETURN_ENUM_DESC(GetLabelEnum, m, Msg);
RETURN_ENUM_DESC(SetConstraint, m, Msg);
RETURN_ENUM_DESC(XferReady, m, Msg);
RETURN_ENUM_DESC(CloseDsReq, m, Msg);
RETURN_ENUM_DESC(CloseDsOk, m, Msg);
RETURN_ENUM_DESC(DeviceEvent, m, Msg);
RETURN_ENUM_DESC(OpenDsm, m, Msg);
RETURN_ENUM_DESC(CloseDsm, m, Msg);
RETURN_ENUM_DESC(OpenDs, m, Msg);
RETURN_ENUM_DESC(CloseDs, m, Msg);
RETURN_ENUM_DESC(UserSelect, m, Msg);
RETURN_ENUM_DESC(DisableDs, m, Msg);
RETURN_ENUM_DESC(EnableDs, m, Msg);
RETURN_ENUM_DESC(EnableDsUiOnly, m, Msg);
RETURN_ENUM_DESC(ProcessEvent, m, Msg);
RETURN_ENUM_DESC(EndXfer, m, Msg);
RETURN_ENUM_DESC(StopFeeder, m, Msg);
RETURN_ENUM_DESC(ChangeDir, m, Msg);
RETURN_ENUM_DESC(CreateDir, m, Msg);
RETURN_ENUM_DESC(Delete, m, Msg);
RETURN_ENUM_DESC(FormatMedia, m, Msg);
RETURN_ENUM_DESC(GetClose, m, Msg);
RETURN_ENUM_DESC(GetFirstFile, m, Msg);
RETURN_ENUM_DESC(GetInfo, m, Msg);
RETURN_ENUM_DESC(GetNextFile, m, Msg);
RETURN_ENUM_DESC(Rename, m, Msg);
RETURN_ENUM_DESC(Copy, m, Msg);
RETURN_ENUM_DESC(AutomaticCaptureDir, m, Msg);
RETURN_ENUM_DESC(PassThrough, m, Msg);
RETURN_ENUM_DESC(RegisterCallback, m, Msg);
RETURN_ENUM_DESC(ResetAll, m, Msg);
RETURN_ENUM_DESC(CustomBase, m, Msg);
{
sprintf(unk, "%d", m);
return unk;
}
}
const char* desc_return_code(ReturnCode rc, char unk[20])
{
RETURN_ENUM_DESC(Success, rc, ReturnCode);
RETURN_ENUM_DESC(Failure, rc, ReturnCode);
RETURN_ENUM_DESC(CheckStatus, rc, ReturnCode);
RETURN_ENUM_DESC(Cancel, rc, ReturnCode);
RETURN_ENUM_DESC(DsEvent, rc, ReturnCode);
RETURN_ENUM_DESC(NotDsEvent, rc, ReturnCode);
RETURN_ENUM_DESC(XferDone, rc, ReturnCode);
RETURN_ENUM_DESC(EndOfList, rc, ReturnCode);
RETURN_ENUM_DESC(InfoNotSupported, rc, ReturnCode);
RETURN_ENUM_DESC(DataNotAvailable, rc, ReturnCode);
RETURN_ENUM_DESC(Busy, rc, ReturnCode);
RETURN_ENUM_DESC(ScannerLocked, rc, ReturnCode);
{
sprintf(unk, "%d", rc);
return unk;
}
}
const char* desc_condition_code(ConditionCode c, char unk[20])
{
RETURN_ENUM_DESC(Success, c, ConditionCode);
RETURN_ENUM_DESC(Bummer, c, ConditionCode);
RETURN_ENUM_DESC(LowMemory, c, ConditionCode);
RETURN_ENUM_DESC(NoDs, c, ConditionCode);
RETURN_ENUM_DESC(MaxConnections, c, ConditionCode);
RETURN_ENUM_DESC(OperationError, c, ConditionCode);
RETURN_ENUM_DESC(BadCap, c, ConditionCode);
RETURN_ENUM_DESC(BadProtocol, c, ConditionCode);
RETURN_ENUM_DESC(BadValue, c, ConditionCode);
RETURN_ENUM_DESC(SeqError, c, ConditionCode);
RETURN_ENUM_DESC(BadDest, c, ConditionCode);
RETURN_ENUM_DESC(CapUnsupported, c, ConditionCode);
RETURN_ENUM_DESC(CapBadOperation, c, ConditionCode);
RETURN_ENUM_DESC(CapSeqError, c, ConditionCode);
RETURN_ENUM_DESC(Denied, c, ConditionCode);
RETURN_ENUM_DESC(FileExists, c, ConditionCode);
RETURN_ENUM_DESC(FileNotFound, c, ConditionCode);
RETURN_ENUM_DESC(NotEmpty, c, ConditionCode);
RETURN_ENUM_DESC(PaperJam, c, ConditionCode);
RETURN_ENUM_DESC(PaperDoubleFeed, c, ConditionCode);
RETURN_ENUM_DESC(FileWriteError, c, ConditionCode);
RETURN_ENUM_DESC(CheckDeviceOnline, c, ConditionCode);
RETURN_ENUM_DESC(InterLock, c, ConditionCode);
RETURN_ENUM_DESC(DamagedCorner, c, ConditionCode);
RETURN_ENUM_DESC(FocusError, c, ConditionCode);
RETURN_ENUM_DESC(DocTooLight, c, ConditionCode);
RETURN_ENUM_DESC(DocTooDark, c, ConditionCode);
RETURN_ENUM_DESC(NoMedia, c, ConditionCode);
{
sprintf(unk, "%d", c);
return unk;
}
}
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 CapSupGetAllReset(Msg msg, Capability& data, std::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 CapSupGetAllResetEx(Msg msg, Capability& data, std::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(BYTE& to, bool from)
{
to = from;
}
static void copy_type(bool& to, BYTE from)
{
to = (bool)from;
}
static void copy_type(UInt32& to, int from)
{
to = from;
}
static void copy_type(int& to, UInt32 from)
{
to = from;
}
static void copy_type(Fix32& to, double from)
{
to = (float)from;
}
static void copy_type(Fix32& to, float from)
{
to = from;
}
static void copy_type(float& to, Fix32 from)
{
to = from.toFloat();
}
static void copy_type(Str255& to, std::string from)
{
to.setData(utils::utf82ansi(from.c_str()).c_str());
}
static void copy_type(std::string& to, Str255 from)
{
to = std::move(utils::ansi2utf8(from.data()));
2023-07-10 07:28:45 +00:00
}
static void copy_type(Str64& to, std::string from)
{
to.setData(utils::utf82ansi(from.c_str()).c_str());
}
static void copy_type(std::string& to, Str64 from)
{
to = std::move(utils::ansi2utf8(from.data()));
}
template<typename T>
bool list_value_at(std::list<T>& lst, int ind, T& t)
{
bool found = false;
if (ind >= 0)
{
typename std::list<T>::iterator it = lst.begin();
for (; it != lst.end(); ++it, --ind)
{
if (ind == 0)
{
t = *it;
found = true;
break;
}
}
}
return found;
}
template<typename T>
int distance(std::vector<T>& vec, const T& v, int offset = sane_opts::RANGE_POS_ENUM_BEGIN)
{
return std::distance(vec.begin() + offset,
std::find(vec.begin() + offset, vec.end(), v));
}
UINT16 bit_depth_from_sane(int sane)
{
if (sane == COLOR_BW)
return 1;
else if (sane == COLOR_GRAY)
return 8;
else if (sane == COLOR_RGB)
return 24;
else
return /*sane*/24;
}
static ImageFileFormat from_sane_image_type(int sane_img_type)
{
ImageFileFormat fmt = ImageFileFormat::Bmp;
switch (sane_img_type)
{
case SANE_IMAGE_TYPE_PNG:
fmt = ImageFileFormat::Png;
break;
case SANE_IMAGE_TYPE_JPG:
fmt = ImageFileFormat::Jpx;
break;
case SANE_IMAGE_TYPE_TIFF:
fmt = ImageFileFormat::Tiff;
break;
case SANE_IMAGE_TYPE_JFIF:
fmt = ImageFileFormat::Jfif;
break;
case SANE_IMAGE_TYPE_WEBP:
break;
case SANE_IMAGE_TYPE_PDF:
fmt = ImageFileFormat::Pdf;
break;
case SANE_IMAGE_TYPE_GIF:
break;
case SANE_IMAGE_TYPE_SVG:
break;
default:
break;
}
return fmt;
}
struct
{
Filter twain;
int sane;
}g_filter[] = { {Filter::Red, FILTER_RED}, {Filter::Green, FILTER_GREEN}, {Filter::Blue, FILTER_BLUE}, {Filter::None, FILTER_NONE} };
Filter from_sane_filter(int sane)
{
for (int i = 0; i < _countof(g_filter); ++i)
{
if (g_filter[i].sane == sane)
return g_filter[i].twain;
}
return Filter::None;
}
int to_sane_filter(Filter twain)
{
for (int i = 0; i < _countof(g_filter); ++i)
{
if (g_filter[i].twain == twain)
return g_filter[i].sane;
}
return FILTER_NONE;
}
struct
{
Filter twain;
int sane;
}g_enhance[] = { {Filter::Red, ENHANCE_RED}, {Filter::Green, ENHANCE_GREEN}, {Filter::Blue, ENHANCE_BLUE}, {Filter::None, ENHANCE_NONE} };
Filter from_sane_enhance(int sane)
{
for (int i = 0; i < _countof(g_filter); ++i)
{
if (g_filter[i].sane == sane)
return g_filter[i].twain;
}
return Filter::None;
}
int to_sane_enhance(Filter twain)
{
for (int i = 0; i < _countof(g_filter); ++i)
{
if (g_filter[i].twain == twain)
return g_filter[i].sane;
}
return FILTER_NONE;
}
float trans_range(float val, float min_from, float max_from, float min_to, float max_to, bool for_step = false)
{
// transfer val in range [min_from, max_from] to value in range [min_to, max_to]
if (for_step)
{
val /= max_from - min_from;
val *= max_to - min_to;
}
else
{
val -= min_from;
val /= max_from - min_from;
val *= max_to - min_to;
val += min_to;
}
return val;
}
static void log_attr_access(int attr, int method)
{
const char* op = "Unknown Oper";
#define METHOD_DESC(oper) \
if (method == (int)Msg::oper) \
op = #oper;
METHOD_DESC(Set)
else METHOD_DESC(Reset)
else METHOD_DESC(Get)
else METHOD_DESC(GetCurrent)
else METHOD_DESC(GetDefault)
utils::to_log(1, "%s 0x%04x\r\n", op, attr);
}
// get fixed-ids from SANE option ...
static bool got_fixed_id(uint32_t id, void* param)
{
((std::vector<uint32_t>*)param)->push_back(id);
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// huagao_ds ...
#include "../../../sdk/include/huagao/brand.h"
2023-07-20 09:52:33 +00:00
static Identity* srcIdent = nullptr;
// static Identity* srcIdent = new Identity(
// Version(VERSION_MAIN, VERSION_SUB, Language::English, Country::China, VERSION_STR(VERSION_MAIN, VERSION_SUB, VERSION_BUILD1, VERSION_PATCH)),
// DataGroup::Image, PRODUCT_VENDOR, PRODUCT_FAMILY, Str32(product_twain_name.c_str()));
2023-07-10 07:28:45 +00:00
static const SCANNERID scanner_guid = MAKE_SCANNER_ID(PRODUCT_PID, PRODUCT_VID);
2023-07-20 09:52:33 +00:00
static void init_identity(void)
{
if(!srcIdent)
{
Str32 n;
n.setData((std::string(PRODUCT_NAME) + " TWAIN").c_str());
srcIdent = new Identity(Version(VERSION_MAIN, VERSION_SUB, Language::English, Country::China, VERSION_STR(VERSION_MAIN, VERSION_SUB, VERSION_BUILD1, VERSION_PATCH)),
DataGroup::Image, PRODUCT_VENDOR, PRODUCT_FAMILY, n);
}
}
2023-07-10 07:28:45 +00:00
static std::once_flag oc;
huagao_ds::huagao_ds() : cur_head_(NULL), dpi_(200), xfer_ready_failed_(false), log_all_triple_(false), scanner_status_(SCANNER_STATUS_NOT_INIT)
,count_(-1), bUiOnly_(false), show_setting_(false)
{
//std::call_once(oc, [&]() { log4cplus::Initializer(); });
}
huagao_ds::~huagao_ds()
{
if (memoryinfo.get()) {
m_memoryfalg = false;
if (memoryinfo->joinable())
memoryinfo->join();
}
if (cur_head_)
delete cur_head_;
}
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);
}
int huagao_ds::on_scanner_event(int ev, void* param)
{
return ((huagao_ds*)param)->handle_scanner_event(ev, false);
}
const Identity& huagao_ds::defaultIdentity() noexcept {
// remember, we return a reference, therefore the identity must not be placed on the stack of this method
2023-07-20 09:52:33 +00:00
init_identity();
2023-07-11 03:20:11 +00:00
2023-07-10 07:28:45 +00:00
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
2023-07-20 09:52:33 +00:00
init_identity();
2023-07-10 07:28:45 +00:00
ident = *srcIdent;
return success();
return { ReturnCode::Failure, ConditionCode::NoDs };
}
Twpp::ConditionCode huagao_ds::condition_code_from_hg_error(int hgerr)
{
if (hgerr == SCANNER_ERR_OK)
return Twpp::ConditionCode::Success;
if (hgerr == SCANNER_ERR_DEVICE_NOT_FOUND)
return Twpp::ConditionCode::CheckDeviceOnline;
if (hgerr == SCANNER_ERR_IO || hgerr == SANE_STATUS_IO_ERROR)
return Twpp::ConditionCode::OperationError;
if(hgerr == SCANNER_ERR_OUT_OF_RANGE)
return Twpp::ConditionCode::BadCap;
if(hgerr == SCANNER_ERR_DEVICE_NOT_SUPPORT || hgerr == SANE_STATUS_UNSUPPORTED)
return Twpp::ConditionCode::BadProtocol;
if(hgerr == SCANNER_ERR_INVALID_PARAMETER || hgerr == SANE_STATUS_INVAL)
return Twpp::ConditionCode::BadValue;
if(hgerr == SCANNER_ERR_ACCESS_DENIED || hgerr == SANE_STATUS_ACCESS_DENIED)
return Twpp::ConditionCode::Denied;
if(hgerr == SCANNER_ERR_OPEN_FILE_FAILED)
return Twpp::ConditionCode::FileNotFound;
if (hgerr == SCANNER_ERR_DEVICE_PAPER_JAMMED || hgerr == SANE_STATUS_JAMMED)
return Twpp::ConditionCode::PaperJam;
if (hgerr == SCANNER_ERR_DEVICE_DOUBLE_FEEDING)
return Twpp::ConditionCode::PaperDoubleFeed;
if (hgerr == SCANNER_ERR_WRITE_FILE_FAILED)
return Twpp::ConditionCode::FileWriteError;
if (hgerr == SCANNER_ERR_DEVICE_DOGEAR)
return Twpp::ConditionCode::DamagedCorner;
if (hgerr == SCANNER_ERR_DEVICE_NO_PAPER || hgerr == SANE_STATUS_NO_DOCS)
return Twpp::ConditionCode::NoMedia;
if (hgerr == SCANNER_ERR_OPENED_BY_OTHER_PROCESS)
return Twpp::ConditionCode::MaxConnections;
if(hgerr == SCANNER_ERR_INSUFFICIENT_MEMORY || hgerr == SANE_STATUS_NO_MEM)
return Twpp::ConditionCode::LowMemory;
if(hgerr == SCANNER_ERR_DEVICE_NOT_FOUND)
return Twpp::ConditionCode::NoDs;
return ConditionCode::Bummer;
// 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)
{
// const MSG* msg = (const MSG*)event.event();
//if (scanner_.get() && show_setting_)
//{
// int ev = scanner_->get_event();
//
// if(ev)
// handle_scanner_event(ev);
//}
/*if (xfer_ready_)
{
notifyXferReady();
xfer_ready_ = false;
}
else*/ if (take_and_reset_notify_close_flag())
{
notifyCloseCancel();
}
event.setMessage(Msg::Null);
return { ReturnCode::NotDsEvent, ConditionCode::Success };
}
Twpp::Result huagao_ds::deviceEventGet(const Twpp::Identity& origin, Twpp::DeviceEvent& data)
{
// data = DeviceEvent::simple(load_sane_util::take_event(), "HUAGAO");
// return success();
return seqError();
}
Result huagao_ds::identityOpenDs(const Identity& id)
{
//if (!load_sane_util::is_ok())
// load_sane_util::initialize(me_);
//if (!load_sane_util::is_ok())
//{
// return bummer();
//}
Identity target(id);
Result result = huagao_ds::selectIdentity(target);
if (scanner_.get())
scanner_.reset();
if (result.returnCode() != ReturnCode::Success)
{
// load_sane_util::uninitialize();
return result;
}
int err = 0, attempt = 0, max_try = 100;
// Sleep(500);
scanner_.reset(sane_wapper_open_scanner(scanner_guid, &err, false));
while (err == SCANNER_ERR_DEVICE_NOT_FOUND && attempt++ < max_try)
{
if (attempt == 1)
{
utils::log_info("Driver is not ready, we wait ... \r\n", 1);
}
std::this_thread::sleep_for(std::chrono::milliseconds(5));
err = 0;
scanner_.reset(sane_wapper_open_scanner(scanner_guid, &err, attempt >= max_try));
}
if(attempt > 1)
utils::to_log(2, "OpenDS: wait and try %d times.\r\n", attempt);
if (!scanner_.get())
{
2023-07-21 08:56:28 +00:00
utils::to_log(3, "OpenDS(%s) error: %d\r\n", PRODUCT_FAMILY, err);
2023-07-10 07:28:45 +00:00
// load_sane_util::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::on_scanner_event, this);
if (get_config_number("twain-app", "flow") == TWAIN_APP_TRANSFER_REVERSE)
{
cur_head_ = new SANE_Parameters;
memset(cur_head_, 0, sizeof(SANE_Parameters));
}
log_all_triple_ = get_config_number("twain-app", "log-all-triple") == 1;
notify_close_ = get_config_number("twain-app", "notify-close");
double_check_mode_ = get_config_number("twain-app", "double-check");
if (double_check_mode_ == 0)
{
char pe[MAX_PATH] = { 0 }, * name = NULL;
GetModuleFileNameA(NULL, pe, _countof(pe) - 1);
name = strrchr(pe, '\\');
if (name++ == NULL)
name = pe;
if (STRICMP(name, "\u597D\u5206\u6570\u9605\u5377\u626B\u63CF\u7AEF.exe") == 0)
double_check_mode_ = DOUBLE_CHECK_ULTRASONIC;
else
double_check_mode_ = DOUBLE_CHECK_TWAIN;
}
utils::to_log(1, "Double check mode = %d\r\n", double_check_mode_);
int nobd = get_config_number("twain-app", "no-bitdepth", 0, -1);
if (nobd == -1)
{
char pe[MAX_PATH] = { 0 }, * name = NULL;
GetModuleFileNameA(NULL, pe, _countof(pe) - 1);
name = strrchr(pe, '\\');
if (name++ == NULL)
name = pe;
if (STRICMP(name, "\u519B\u961F\u626B\u63CF2.0.exe") == 0) // 军队扫描2.0.exe
nobd = 1;
else
nobd = 0;
}
no_bitdepth_ = nobd == 1;
2023-07-26 02:39:07 +00:00
utils::to_log(LOG_LEVEL_DEBUG, "BitDepth protocol disabled = %d\r\n", nobd);
2023-07-10 07:28:45 +00:00
m_compression = Compression::None;
init_support_caps();
m_fileXfer.setFormat(ImageFileFormat::Bmp);
scanner_status_ = SCANNER_STATUS_READY;
utils::log_mem_info("srcIdent:", srcIdent, sizeof(*srcIdent));
2023-07-11 03:20:11 +00:00
2023-07-10 07:28:45 +00:00
return success();
}
Result huagao_ds::identityCloseDs(const Identity&)
{
if (notify_close_thread_.get() && notify_close_thread_->joinable())
notify_close_thread_->join();
// ui_.reset();
if (scanner_.get())
{
scanner_->set_event_callback();
scanner_->ui_hide();
scanner_.reset();
}
// load_sane_util::uninitialize();
scanner_status_ = SCANNER_STATUS_NOT_INIT;
return success();
}
Result huagao_ds::pendingXfersGet(const Identity&, PendingXfers& data)
{
if (!scanner_.get())
return seqError();
// <20><>ʾ<EFBFBD><CABE><EFBFBD>ý<EFBFBD><C3BD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>EndXfer<65><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>ͼƬ<CDBC><C6AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
int cnt = get_scanned_image_count(-1);
// FIX-2023-05-29: <20>Ƿ񱣳<C7B7><F1B1A3B3><EFBFBD><EFBFBD>ý<EFBFBD><C3BD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>APP<50><50><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>ʾUI<55><49><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>ɨ<EFBFBD><C9A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//int cnt = show_setting_ ? 1 : get_scanned_image_count(-1);
data.setCount(cnt);
return success();
}
Result huagao_ds::pendingXfersEnd(const Identity& id, PendingXfers& data)
{
return pendingXfersGet(id, data);
}
Result huagao_ds::pendingXfersReset(const Identity& id, PendingXfers& data)
{
pending_xfer_.clear();
return pendingXfersGet(id, data);
}
Result huagao_ds::setupMemXferGet(const Identity& id, SetupMemXfer& data)
{
SANE_Parameters head;
size_t total = 0;
DWORD to = cur_head_ ? -1 : 0;
if (!scanner_.get() || get_scanned_image_count(to) == 0)
{
if (cur_head_)
{
UserInterface ui(FALSE, FALSE, (Twpp::Handle)0);
data.setPreferredSize(1);
call(id, DataGroup::Control, Dat::UserInterface, Msg::DisableDs, &ui);
}
else
{
int def_w = 2000,
def_h = 6000;
data.setMinSize(def_w * 3/* * def_h*/);
data.setPreferredSize(def_w * 3 * def_h);
data.setMaxSize(def_w * 3 * def_h);
}
return success();
}
if (scanner_->get_first_image_header(&head, &total))
{
if (m_compression == Compression::None)
{
int line_bytes = (head.bytes_per_line + 3) / 4 * 4;
data.setMinSize(head.bytes_per_line);
data.setPreferredSize(line_bytes * head.lines);
data.setMaxSize(line_bytes * head.lines);
}
else
{
data.setMinSize(total);
data.setPreferredSize(total);
data.setMaxSize(total);
}
return success();
}
else
return badValue();
}
Result huagao_ds::userInterfaceDisable(const Identity&, UserInterface& ui)
{
if (scanner_.get())
{
scanner_->stop();
scanner_->ui_hide();
}
return success();
}
Result huagao_ds::userInterfaceEnable(const Identity&, UserInterface& ui)
{
notfify_close_ = false;
bUiOnly_ = false;
show_setting_ = false;
scanner_->twain_set_transfer((twain_xfer)m_capXferMech);
2023-07-18 06:13:43 +00:00
if (!ui.showUi() || !scanner_->ui_is_ok())
2023-07-10 07:28:45 +00:00
{
if(scanner_->ui_is_ok())
scanner_->ui_show_progress((HWND)ui.parent().raw(), m_bIndicator);
else
2023-07-18 06:13:43 +00:00
utils::to_log(LOG_LEVEL_WARNING, "APP want to show setting UI, but UI is not in service!\n");
2023-07-10 07:28:45 +00:00
xfer_ready_failed_ = false;
scanner_status_ = SCANNER_STATUS_SCAN_1;
app_trigger_event_ = false;
int err = scanner_->start();
if (err == SCANNER_ERR_OK)
{
return success();
}
else
{
scanner_status_ = SCANNER_STATUS_READY;
// if (err == SCANNER_ERR_DEVICE_NO_PAPER)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(err) };
return bummer();
}
}
return showTwainUI(ui);
}
Result huagao_ds::userInterfaceEnableUiOnly(const Identity&, UserInterface& ui)
{
// as a minimal source, we do not support GUI that just saves settings
if (!scanner_->ui_is_ok())
return bummer();
2023-07-10 07:28:45 +00:00
return showTwainUI(ui, true);
}
Twpp::Result huagao_ds::extImageInfoGet(const Identity& origin, ExtImageInfo& data)
{
for (int i = 0; i < data.size(); ++i)
{
InfoId id = data.at(i).id();
Twpp::Info& info = data.at(i);
if (id == InfoId::BarCodeCount)
{
info.allocSimple(Type::UInt32);
*info.items<Twpp::InfoId::BarCodeCount>()[0].data() = 0;
}
else if (id == InfoId::BarCodeType)
{
info.allocSimple(Type::UInt32);
*info.items<Twpp::InfoId::BarCodeType>()[0].data() = BarCodeType::ThreeOfNine;
}
else if(id == InfoId::BarCodeTextLength)
{
info.allocSimple(Type::UInt32);
*info.items<Twpp::InfoId::BarCodeTextLength>()[0].data() = 0;
}
else if (id == InfoId::BarCodeText)
{
//info.allocSimple(Type::Str255, 1);
//info.items<Twpp::InfoId::PrinterText>()[0].data()->setData(std::to_string(6922868285266 + i).c_str());
}
else
info.setReturnCode(ReturnCode::InfoNotSupported);
}
return success();
return { ReturnCode::Failure, ConditionCode::NoMedia };
}
Result huagao_ds::imageInfoGet(const Identity&, ImageInfo& data)
{
SANE_Parameters head;
bool ok = false;
int res = 200;
if (!scanner_.get())
return seqError();
if (cur_head_ && cur_head_->lines)
{
memcpy(&head, cur_head_, sizeof(head));
ok = true;
cur_head_->lines = 0;
res = dpi_;
}
else
{
//if (!scanner_->wait_image())
//{
//// notifyCloseOk();
// return success(); // 好分数需要返回成<E59B9E>?
//}
if (get_scanned_image_count(-1) > 0) // 显示设置界面时不能阻塞在EndXfer否则最后一张图片传输后显示不出来故在此做阻塞调用
{
ok = scanner_->get_first_image_header(&head, NULL, &res);
if (ok)
dpi_ = res;
}
}
if (ok)
{
if (head.format == SANE_FRAME_RGB)
{
data.setBitsPerPixel(head.depth * 3);
data.setSamplesPerPixel(3);
data.bitsPerSample()[0] = data.bitsPerSample()[1] = data.bitsPerSample()[2] = head.depth;
}
else
{
data.setSamplesPerPixel(1);
data.setBitsPerPixel(head.depth);
data.bitsPerSample()[0] = head.depth;
}
data.setHeight(head.lines);
if (m_compression == Compression::Group4)
data.setPixelType(PixelType::BlackWhite);
else
{
if (head.format == SANE_FRAME_RGB)
data.setPixelType(PixelType::Rgb);
else if(head.format == SANE_FRAME_GRAY)
data.setPixelType(head.depth == 1 ? PixelType::BlackWhite : PixelType::Gray);
}
data.setPlanar(false);
data.setWidth(head.pixels_per_line);
data.setXResolution((float)res);
data.setYResolution((float)res);
data.compression(m_compression);
}
else
{
utils::log_info(" imageInfoGet is false\r\n", 1);
data.setHeight(0);
return { ReturnCode::XferDone, ConditionCode::Bummer };
}
char buf[128];
std::string f("imageInfoGet:");
int h = data.height();
int w = data.width();
int bitsPerPixel = data.bitsPerPixel();
Compression compression = data.compression();
PixelType pixelType = data.pixelType();
bool planar = data.planar();
Fix32 xr = data.xResolution();
sprintf(buf, "imageInfoGet: h-->%d w-->%d bitsPerPixel-->%d compression-->%d pixelType-->%d planar-->%d\r\n", h, w, bitsPerPixel, compression, pixelType, planar);
utils::log_info(buf, 1);
return success();
}
Result huagao_ds::imageLayoutGet(const Identity&, ImageLayout& data)
{
SANE_Parameters head;
memset(&head, 0, sizeof(head));
if (!scanner_.get())
return seqError();
else if(get_scanned_image_count(-1) == 0)
return { ReturnCode::Failure, condition_code_from_hg_error(scanner_->last_error()) };
int res = 200;
scanner_->get_first_image_header(&head, NULL, &res);
data.setDocumentNumber(1);
data.setFrameNumber(1);
data.setPageNumber(1);
data.setFrame(Frame(0, 0, static_cast<float>(head.pixels_per_line) / res, static_cast<float>(head.lines) / res));
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())
return seqError();
if (get_scanned_image_count(-1) == 0 && !pending_xfer_.img)
{
//if (!cur_head_ || !scanner_->wait_image())
//{
// notifyCloseOk();
// return seqError();
//}
return { ReturnCode::Failure, condition_code_from_hg_error(scanner_->last_error()) };
}
IScanImg *img = pending_xfer_.img ? pending_xfer_.img : scanner_->take_first_image(TWAIN_XFER_Memory);
unsigned long long off = pending_xfer_.img ? pending_xfer_.off : img->get_bits_offset();
unsigned char *dst = (unsigned char*)data.memory().data().data();
UInt32 buf_l = data.memory().size();
unsigned int line_l = img->line_bytes(),
rows = data.memory().size() / line_l;
size_t want_read = rows * line_l;
Result ret = { ReturnCode::XferDone, ConditionCode::Success };
if (rows == 0)
return badValue();
if (pending_xfer_.img)
{
img->add_ref();
pending_xfer_.clear();
}
else if(cur_head_)
{
img->copy_header(cur_head_);
}
data.setBytesPerRow(line_l);
data.setColumns(img->width());
data.setRows(rows);
data.setXOffset(0);
data.setYOffset(UInt32(off / line_l));
data.setCompression(m_compression);
if (m_compression != Compression::None)
{
want_read = img->bytes() - off;
if (buf_l < want_read)
{
want_read = buf_l;
}
img->read(dst, &want_read, off);
data.setBytesWritten(want_read);
off += want_read;
if (off < img->bytes())
{
pending_xfer_.img = img;
pending_xfer_.off = (unsigned int)off;
img->add_ref();
ret = success();
}
else
scanner_->image_fetched(img);
}
else if (img->read(dst, &want_read, off) == SCANNER_ERR_OK)
{
want_read /= line_l;
data.setRows(want_read);
want_read *= line_l;
data.setBytesWritten(want_read);
off += want_read;
if (off < img->bytes())
{
pending_xfer_.img = img;
pending_xfer_.off = (unsigned int)off;
img->add_ref();
ret = success();
}
else
scanner_->image_fetched(img);
}
else
{
ret = { ReturnCode::XferDone, ConditionCode::Bummer };
}
img->release();
return ret;
}
Result huagao_ds::imageNativeXferGet(const Identity& id, ImageNativeXfer& data)
{
if (!scanner_.get())
return seqError();
else if (get_scanned_image_count(-1) == 0)
{
return { ReturnCode::Failure, condition_code_from_hg_error(scanner_->last_error()) };
}
IScanImg* img = scanner_->take_first_image(TWAIN_XFER_Native);
if (!img)
return seqError();
if (data)
data.release();
data = ImageNativeXfer(img->bytes());
unsigned long long off = sizeof(BITMAPFILEHEADER);
unsigned int total = img->bytes() - off;
unsigned char* src = img->data(off, &total),
* dst = data.data<unsigned char>().data();
while (off < img->bytes() && src)
{
std::copy(src, src + total, dst);
dst += total;
off += total;
if (off >= img->bytes())
break;
total = img->bytes() - (unsigned int)off;
src = img->data(off, &total);
}
scanner_->image_fetched(img);
img->release();
return { ReturnCode::XferDone, ConditionCode::Success };
}
Twpp::Result huagao_ds::pendingXfersStopFeeder(const Identity& origin, PendingXfers& data)
{
if (scanner_.get())
scanner_->stop();
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())
return seqError();
else if(get_scanned_image_count(-1) == 0)
return { ReturnCode::Failure, condition_code_from_hg_error(scanner_->last_error()) };
IScanImg* img = scanner_->take_first_image(TWAIN_XFER_File);
Twpp::Result ret = seqError();
FILE* dst = NULL;
if (img)
{
std::string file(img->file());
int cv_e = 0,
status = img->image_status();
if (file.empty())
{
dst = fopen(m_fileXfer.filePath().string().c_str(), "wb");
ret = { ReturnCode::Failure, ConditionCode::FileWriteError };
if (dst)
{
unsigned long long off = 0;
unsigned int total = img->bytes();
unsigned char* src = img->data(off, &total);
while (src)
{
if (fwrite(src, 1, total, dst) != total)
break;
off += total;
if (off >= img->bytes())
{
ret = Result(ReturnCode::XferDone, ConditionCode::Success);
break;
}
total = img->bytes() - (unsigned int)off;
src = img->data(off, &total);
}
fclose(dst);
scanner_->image_fetched(img);
}
else
{
std::string f("CreateFile(" + m_fileXfer.filePath().string());
char msg[128] = { 0 };
sprintf(msg, ") = %d\r\n", GetLastError());
f += msg;
utils::log_info(f.c_str(), 3);
}
img->release();
}
else
{
utils::log_info(("Map file to " + m_fileXfer.filePath().string() + "\r\n").c_str(), 1);
img->keep_file(true);
scanner_->image_fetched(img);
img->release();
cv_e = utils::move_file(file.c_str(), m_fileXfer.filePath().string().c_str());
if (cv_e == 0)
ret = Result(ReturnCode::XferDone, ConditionCode::Success);
else
remove(file.c_str());
}
if (ret.status() == ConditionCode::Success && m_fileXfer.format() != ImageFileFormat::Bmp)
{
SANE_ImageFormatConvert conv;
std::string target(m_fileXfer.filePath().string().c_str());
memset(&conv, 0, sizeof(conv));
file = target + ".src";
conv.src.fmt.img_format = SANE_IMAGE_TYPE_BMP;
conv.src.is_file = SANE_TRUE;
conv.src.data = file.c_str();
conv.src.data_len = file.length();
conv.dst.fmt.img_format = (SANE_ImageType)m_fileXfer.format();
conv.dst.fmt.compress.compression = (SANE_CompressionType)m_compression;
conv.dst.fmt.compress.detail = (void*)0;
conv.dst.fmt.detail = (void*)m_jpegQuality;
conv.dst.is_file = SANE_TRUE;
conv.dst.data = target.c_str();
conv.dst.data_len = target.length();
while (rename(target.c_str(), file.c_str()))
{
if (cv_e == 0)
{
std::string info("[convert image format] Move '");
char buf[80] = { 0 };
sprintf(buf, "%d\r\n", GetLastError());
info += target + "' to '" + file + "' failed: ";
utils::log_info((info + buf).c_str(), 3);
}
if (++cv_e >= 9)
break;
Sleep(30);
}
if (cv_e < 9)
{
cv_e = scanner_->convert_image(&conv);
if (cv_e != SCANNER_ERR_OK)
ret = { ReturnCode::Failure, ConditionCode::OperationError };
remove(file.c_str());
}
}
//if (ret.status() == ConditionCode::Success)
//{
// switch (status)
// {
// case SANE_Image_Statu_Blank:
// break;
// case SANE_Image_Statu_Double:
// ret.setStatus(ConditionCode::PaperDoubleFeed);
// break;
// case SANE_Image_Statu_Jammed:
// ret.setStatus(ConditionCode::PaperJam);
// break;
// }
//}
{
std::string info(m_fileXfer.filePath().string());
char r[80] = { 0 };
sprintf(r, ": status = %d(Fail: 0x%x)\r\n", (int)ret.status(), cv_e);
utils::log_info((info + r).c_str(), 1);
}
}
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)));
Result rt;
char dgs[20] = { 0 }, dts[20] = { 0 }, ms[20] = { 0 }, ss[20] = { 0 }, rcs[20] = { 0 }, cs[20] = { 0 };
//trigger_ProcessEvent(dg, dat, msg); // some APPs may be not trigger (Control, Event, ProcessEvent), we help them :( ... // 云阅卷扫描端不等状态改变直接取图此处设置一次状<E6ACA1>?2022-11-07
rt = Base::call(origin, dg, dat, msg, data);
if (log_all_triple_ || ((int)rt.returnCode() && rt.returnCode() != ReturnCode::NotDsEvent))
{
if (dat == Dat::Capability)
{
Twpp::Capability& cap = *(Twpp::Capability*)data;
utils::to_log(7, "[%x - %s]DSEntry(%s, %s.%x, %s) = {%s, %s}\r\n", GetCurrentThreadId(), desc_state(state(), ss),
desc_data_group(dg, dgs), desc_data(dat, dts), (int)cap.type(), desc_msg(msg, ms), desc_return_code(rt, rcs), desc_condition_code((ConditionCode)(Status)rt, cs));
}
else
utils::to_log(7, "[%x - %s]DSEntry(%s, %s, %s) = {%s, %s}\r\n", GetCurrentThreadId(), desc_state(state(), ss),
desc_data_group(dg, dgs), desc_data(dat, dts), desc_msg(msg, ms), desc_return_code(rt, rcs), desc_condition_code((ConditionCode)(Status)rt, cs));
if ((int)rt.returnCode() && rt.returnCode() != ReturnCode::NotDsEvent)
{
bool changed = false;
if (dat == Dat::PendingXfers && Msg::Reset == msg && scanner_status_ == SCANNER_STATUS_STOPPED) // PurvarScannerForHomework.exe - move modifying from EndXfer to xfer::Reset
{
changed = true;
rt = success();
}
else if (rt.status() == ConditionCode::SeqError)
{
if (dat == Dat::ImageInfo && Msg::Get == msg && scanner_status_ == SCANNER_STATUS_STOPPED) // for demo.exe
{
changed = true;
rt = { ReturnCode::Success, ConditionCode::Bummer };
}
else if (dat == Dat::PendingXfers && Msg::EndXfer == msg && scanner_status_ == SCANNER_STATUS_STOPPED) // for photoshop.exe
{
// PendingXfers& data
(static_cast<PendingXfers*>(data))->setCount(0);
changed = true;
rt = { ReturnCode::Success, ConditionCode::Success };
}
}
else if (rt.status() == ConditionCode::Bummer && rt.returnCode() == ReturnCode::XferDone && scanner_status_ == SCANNER_STATUS_STOPPED) // for demo.exe
{
changed = true;
rt = { ReturnCode::Success, ConditionCode::Bummer };
}
if(changed)
utils::to_log(7, " modify result to {%s, %s}.\r\n", desc_return_code(rt, rcs), desc_condition_code((ConditionCode)(Status)rt, cs));
}
}
return rt;
}
catch (const CapabilityException& e) {
//FileTools::writelog(log_ERROR, e.what());
//UNREFERENCED_PARAMETER(e);
return badValue();
}
}
Result huagao_ds::customDataGet(const Twpp::Identity& origin, Twpp::CustomData& data)
{
// get user setting from local file ...
if (!scanner_.get())
return seqError();
char * buf = NULL;
size_t len = 0;
if (scanner_->twain_get_config(buf, &len) == SCANNER_ERR_INSUFFICIENT_MEMORY)
{
data = CustomData(len);
buf = data.lock<char>();
scanner_->twain_get_config(buf, &len);
}
return success();
}
Result huagao_ds::customDataSet(const Twpp::Identity& origin, Twpp::CustomData& data)
{
// write user setting to local file ...
if (!scanner_.get())
return seqError();
char* buf = data.lock<char>();
scanner_->twain_set_config(buf, data.size());
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()) {
int type = (int)data.type();
while (org_func_.count(type))
type = org_func_[type];
return (it->second)((Twpp::CapType)type, msg, data);
}
return capUnsupported();
}
Twpp::Result huagao_ds::showTwainUI(Twpp::UserInterface& data, bool bUiOnly)
{
if (!scanner_->is_online())
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(SCANNER_ERR_DEVICE_NOT_FOUND) };
show_setting_ = true;
bUiOnly_ = bUiOnly;
// display user UI ... (setting UI, can we show my own main window here ?)
return scanner_->ui_show_setting((HWND)data.parent().raw(), !bUiOnly, m_bIndicator) ? success() : seqError();
}
void huagao_ds::init_support_caps(void)
{
#define SANE_ID(name) scanner_->sane_opt_id_##name()
m_query.clear();
m_caps.clear();
org_func_.clear();
//m_query[CapType::IExtImageInfo] = msgSupportGetAll;
//m_caps[CapType::IExtImageInfo] = std::bind(enmGet<Bool>, _2, _3, Bool(true));
m_query[CapType::ISupportedExtImageInfo] = msgSupportGetAll;
m_caps[CapType::ISupportedExtImageInfo] = [this](Twpp::CapType type, Msg msg, Capability& data) {
data = Capability::createArray< CapType::ISupportedExtImageInfo>({ InfoId::BarCodeCount, InfoId::BarCodeText, InfoId::BarCodeType, InfoId::BarCodeTextLength });
return success();
};
m_query[CapType::SupportedCaps] = msgSupportGetAll;
m_caps[CapType::SupportedCaps] = [this](Twpp::CapType type, Msg msg, Capability& data) {
log_attr_access((int)CapType::SupportedCaps, (int)msg);
if ((msg == Msg::Get) || (Msg::GetCurrent == msg) || (Msg::GetDefault == msg)) {
data = Capability::createArray<CapType::SupportedCaps>(m_caps.size());
auto arr = data.array<CapType::SupportedCaps>();
std::vector<unsigned int> all;
for (const auto& v : m_caps)
all.push_back((int)v.first);
std::sort(all.begin(), all.end());
UInt32 i = 0;
for (const auto& kv : all) {
arr[i] = (CapType)kv;
i++;
}
return success();
}
else
return capBadOperation();
};
m_query[CapType::XferCount] = msgSupportGetAllSetReset;
m_caps[CapType::XferCount] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::XferCount, (int)msg);
if (msg == Msg::Set) {
auto item = data.currentItem<Int16>();
if (item > 65535 || item < -1 || item == 0) {
return badValue();
}
int ret = SCANNER_ERR_OK;
int count = count_ = item;
BYTE dup = 1;
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_duplex, NULL, &all);
dup = all[sane_opts::RANGE_POS_CURRENT];
if (dup && count >= 2)
{
count++;
count /= 2;
}
SET_SANE_OPT_EX(ret, scanner_, scan_count, &count);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
std::vector<int> count;
Int16 tmp_count = 0;
GET_SANE_OPT_EX(int, scanner_, scan_count, NULL, &count);
tmp_count = count[sane_opts::RANGE_POS_CURRENT];
BYTE dup = 1;
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_duplex, NULL, &all);
dup = all[sane_opts::RANGE_POS_CURRENT];
if (dup && tmp_count > 0 && tmp_count < 65535)
{
tmp_count *= 2;
}
return oneValGetSet<Int16>(msg, data, tmp_count, -1);
};
m_bIndicator = scanner_->ui_is_ok();
if (m_bIndicator)
{
m_query[CapType::UiControllable] = msgSupportGetAll;
m_caps[CapType::UiControllable] = std::bind(oneValGet<Bool>, _2, _3, Bool(true));
m_query[CapType::Indicators] = msgSupportGetAllSetReset;
m_caps[CapType::Indicators] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::Indicators, (int)msg);
if (Msg::Set == msg) {
auto show = data.currentItem<CapType::Indicators>();
m_bIndicator = show;
utils::log_info(m_bIndicator ? "Set show indicator: true\r\n" : "Set show indicator: false\r\n", 0);
return success();
}
// data.type
if (!data.operator bool()) //具有风险<E9A38E>?(和气) Twain sample app ,data.m_cont is null,but DotNet和气 data.m_cont not is null .
{
data = Capability::createEnumeration<CapType::Indicators>({ FALSE,TRUE }, m_bIndicator ? 1 : 0, 1);
}
else
data = Capability::createOneValue<CapType::Indicators>(m_bIndicator);
return success();
//return CapSupGetAllReset<bool, Bool, CapType::Indicators>(msg, data, { TRUE,FALSE }, m_bIndicator, TRUE, (BOOL)(m_bIndicator ? 1 : 0), 1);
};
}
m_query[CapType::DeviceOnline] = msgSupportGetAll;
m_caps[CapType::DeviceOnline] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::DeviceOnline, (int)msg);
// 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)(load_sane_util::is_online(scanner_guid)));
return success();
default:
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
}
};
m_query[CapType::ICompression] = msgSupportGetAllSetReset;
m_caps[CapType::ICompression] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::ICompression, (int)msg);
if (!scanner_.get())
return seqError();
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::ICompression>();
if (Compression::None == mech || mech == Compression::Group4) {
m_compression = mech;
scanner_->twain_set_compression((SANE_CompressionType)m_compression);
{
char info[128] = { 0 };
sprintf(info, "set CapType::ICompression = %s\r\n", Compression::None == mech ? "None" : "Group4");
utils::log_info(info, 0);
}
return success();
}
else
return badValue();
}
return CapSupGetAllReset<Compression, Compression, CapType::ICompression>(msg, data, { Compression::None, Compression::Group4 }, m_compression, Compression::None, m_compression == Compression::None ? 0 : 1, 0);
};
if (scanner_->get_option_info(SANE_OPT_ID_LANGUAGE, NULL, NULL, NULL))
{
m_query[CapType::Language] = msgSupportGetAllSetReset;
m_caps[CapType::Language] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::ICompression, (int)msg);
std::vector<int> all;
if (!scanner_.get())
return seqError();
sane_opts::get_opts<int> op(NULL, &all);
int sn = (int)CapType::Language; // SANE_OPT_ID_LANGUAGE;
scanner_->get_value(sn, sane_opts::set_opt_value<int>, &op);
op.re_order();
if (Msg::Set == msg || Msg::Reset == msg) {
int mech = (int)data.currentItem<CapType::Language>();
if (Msg::Reset == msg)
mech = all[sane_opts::RANGE_POS_DEFAULT];
int ret = scanner_->set_value(sn, &mech);
if (ret)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(ret) };
else
return success();
}
UInt16 cur = all[sane_opts::RANGE_POS_CURRENT], init = all[sane_opts::RANGE_POS_DEFAULT];
int ni = 0, ii = 0;
std::list<UInt16> alll;
for (int i = 0; i < all.size() - sane_opts::RANGE_POS_ENUM_BEGIN; ++i)
{
if (all[i + sane_opts::RANGE_POS_ENUM_BEGIN] == cur)
ni = i;
else if (all[i + sane_opts::RANGE_POS_ENUM_BEGIN] == init)
ii = i;
alll.push_back(all[i + sane_opts::RANGE_POS_ENUM_BEGIN]);
}
return cap_get_enum_values<UInt16, CapType::Language>(msg, data, alll, cur, init, ni, ii);
};
}
m_query[CapType::IUnits] = msgSupportGetAllSetReset;
m_caps[CapType::IUnits] = std::bind(enmGetSetConst<Unit>, _2, _3, Unit::Inches);
m_query[CapType::IBitDepth] = msgSupportGetAllSetReset;
m_caps[CapType::IBitDepth] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IBitDepth, (int)msg);
std::vector<int> all;
int val = 0;
GET_SANE_OPT_EX(int, scanner_, ex_color_mode, NULL, &all);
if (Msg::Set == msg || Msg::Reset == msg) {
if (no_bitdepth_)
return success();
2023-07-10 07:28:45 +00:00
int ret = SCANNER_ERR_INVALID_PARAMETER;
val = all[sane_opts::RANGE_POS_DEFAULT];
if (Msg::Set == msg)
{
auto mech = data.currentItem<CapType::IBitDepth>();
if (mech == 1)
val = COLOR_BW;
else if (mech == 8)
val = COLOR_GRAY;
else if (mech == 24)
val = COLOR_RGB;
else
{
val = COLOR_RGB; // mech;
utils::to_log(LOG_LEVEL_WARNING, "Set bit-depth to %d is out of range, we set to RGB\r\n", (int)mech);
}
2023-07-10 07:28:45 +00:00
}
{
char info[128] = { 0 };
sprintf(info, "set CapType::IBitDepth = %d\r\n", val);
utils::log_info(info, 0);
}
SET_SANE_OPT_EX(ret, scanner_, ex_color_mode, &val);
if (Msg::Reset == msg)
{
UINT16 v = val;
data = Capability::createOneValue<UINT16>(CapType::IBitDepth, v);
}
return ret == SCANNER_ERR_OK ? success() : badValue();
}
UINT16 Now = bit_depth_from_sane(all[sane_opts::RANGE_POS_CURRENT]), Init = bit_depth_from_sane(all[sane_opts::RANGE_POS_DEFAULT]);
std::list<UINT16> vals;
UInt32 ni = distance<int>(all, all[sane_opts::RANGE_POS_CURRENT]),
ii = distance<int>(all, all[sane_opts::RANGE_POS_DEFAULT]);
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < all.size(); ++i)
vals.push_back(bit_depth_from_sane(all[i]));
return cap_get_enum_values<UINT16, CapType::IBitDepth>(msg, data, vals, Now, Init, ni, ii);
};
m_query[CapType::IBitOrder] = msgSupportGetAllSetReset;
m_caps[CapType::IBitOrder] = std::bind(oneValGetSetConst<BitOrder>, _2, _3, BitOrder::MsbFirst);
m_query[CapType::IPlanarChunky] = msgSupportGetAllSetReset;
m_caps[CapType::IPlanarChunky] = std::bind(enmGetSetConst<PlanarChunky>, _2, _3, PlanarChunky::Chunky);
m_query[CapType::IXResolution] = msgSupportGetAllSetReset;
m_caps[CapType::IXResolution] = /*m_caps[CapTypeEx::CAP_EX_SANE_resolution];*/ [this](Twpp::CapType type, Twpp::Msg msg, Capability& data) {
log_attr_access((int)CapType::IXResolution, (int)msg);
if (!scanner_.get())
return seqError();
std::vector<int> values;
value_limit limit = VAL_LIMIT_RANGE;
int init = 0, now = 0;
GET_SANE_OPT_EX(int, scanner_, resolution, NULL, &values);
init = values[sane_opts::RANGE_POS_DEFAULT];
now = values[sane_opts::RANGE_POS_CURRENT];
switch (msg) {
case Msg::Get:
if (limit == VAL_LIMIT_RANGE)
{
data = Capability::createRange<CapType::IXResolution>(Fix32((float)values[sane_opts::RANGE_POS_LOWER])
, Fix32((float)values[sane_opts::RANGE_POS_UPPER])
, Fix32((float)values[sane_opts::RANGE_POS_STEP])
, Fix32((float)values[sane_opts::RANGE_POS_CURRENT])
, Fix32((float)values[sane_opts::RANGE_POS_DEFAULT]));
return success();
}
else if (limit == VAL_LIMIT_ENUM)
{
std::list<Fix32> vals;
Fix32 Now, Init;
UInt32 ni, ii;
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < values.size(); ++i)
{
Fix32 f;
float vf = (float)values[i];
copy_type(f, vf);
vals.push_back(f);
}
float nowf = (float)now, initf = (float)init;
copy_type(Now, nowf);
copy_type(Init, initf);
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:
data = Capability::createOneValue<CapType::IXResolution>(Fix32((float)now));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IXResolution>(Fix32((float)init));
return success();
case Msg::Reset:
data = Capability::createOneValue<CapType::IXResolution>(Fix32((float)init));
case Msg::Set: {
auto mech = data.currentItem<CapType::IXResolution>();
int ret = SCANNER_ERR_OK;
float resl = (float)mech;
int resli = (int)resl;
SET_SANE_OPT_EX(ret, scanner_, resolution, &resli);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
default:
return capBadOperation();
}
};
m_query[CapType::IYResolution] = msgSupportGetAllSetReset;
m_caps[CapType::IYResolution] = /*m_caps[CapType::IXResolution];*/ [this](Twpp::CapType type, Twpp::Msg msg, Capability& data)
{
Result ret = m_caps[CapType::IXResolution](type, msg, data);
if (data.type() == CapType::IXResolution)
data.dangerous_set_cap(CapType::IYResolution);
return ret;
};
m_query[CapType::IXNativeResolution] = msgSupportGetAll;
m_caps[CapType::IXNativeResolution] = std::bind(enmGet<Fix32>, _2, _3, Fix32(200.0));
m_query[CapType::IYNativeResolution] = msgSupportGetAll;
m_caps[CapType::IYNativeResolution] = m_caps[CapType::IXNativeResolution];
m_query[CapType::ISupportedSizes] = msgSupportGetAllSetReset;
m_caps[CapType::ISupportedSizes] = [this](Twpp::CapType type, Msg msg, Capability& data) {
log_attr_access((int)CapType::ISupportedSizes, (int)msg);
int now = 0,
init = 0;
std::vector<int> all;
GET_SANE_OPT_EX(int, scanner_, ex_paper, NULL, &all);
now = all[sane_opts::RANGE_POS_CURRENT];
init = all[sane_opts::RANGE_POS_DEFAULT];
if (msg == Msg::Set || msg == Msg::Reset)
{
if(msg == Msg::Set)
init = (int)data.currentItem<CapType::ISupportedSizes>();
else
data = Capability::createOneValue<CapType::ISupportedSizes>((Twpp::PaperSize)init);
SET_SANE_OPT_EX(now, scanner_, ex_paper, &init);
return now == SCANNER_ERR_OK ? success() : badValue();
}
std::list<Twpp::PaperSize> vals;
Twpp::PaperSize Now = (PaperSize)now,
Init = (PaperSize)init;
UInt32 ni = distance<int>(all, now),
ii = distance<int>(all, init);
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < all.size(); ++i)
vals.push_back((PaperSize)all[i]);
return cap_get_enum_values<Twpp::PaperSize, CapType::ISupportedSizes>(msg, data, vals, Now, Init, ni, ii);
};
m_query[CapType::IPhysicalWidth] = msgSupportGetAll;
m_caps[CapType::IPhysicalWidth] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IPhysicalWidth, (int)msg);
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
{
float init = 10.0f;
int cur = 200;
SANE_Parameters param;
memset(&param, 0, sizeof(param));
if (scanner_.get() && scanner_->get_first_image_header(&param, NULL, &cur))
init = param.bytes_per_line * 1.0f / cur;
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](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IPhysicalHeight, (int)msg);
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
{
float init = 10.0f;
int cur = 200;
SANE_Parameters param;
memset(&param, 0, sizeof(param));
if (scanner_.get() && scanner_->get_first_image_header(&param, NULL, &cur))
init = param.lines * 1.0f / cur;
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>, _2, _3, PixelFlavor::Chocolate);
m_query[CapType::IXferMech] = msgSupportGetAllSetReset;
m_caps[CapType::IXferMech] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IXferMech, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IXferMech>();
if (mech == XferMech::Native || mech == XferMech::Memory || mech == XferMech::File) {
m_capXferMech = mech;
scanner_->twain_set_transfer((twain_xfer)m_capXferMech);
{
char info[128] = { 0 }, * des[] = {"Native", "File", "Memory"};
sprintf(info, "set CapType::IXferMech = %s\r\n", des[(int)m_capXferMech]);
utils::log_info(info, 0);
}
return success();
}
else {
return badValue();
}
}
utils::log_mem_info("IXferMech data before:", &data, sizeof(data));
2023-07-10 07:28:45 +00:00
Result r = CapSupGetAllReset<XferMech, XferMech, CapType::IXferMech>(msg, data, { XferMech::Native, XferMech::File, XferMech::Memory }, m_capXferMech, XferMech::Native, (int)m_capXferMech, 0);
utils::log_mem_info("IXferMech data after:", &data, sizeof(data));
2023-07-10 07:28:45 +00:00
return r;
};
m_query[CapType::IPixelType] = msgSupportGetAllSetReset;
m_caps[CapType::IPixelType] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IPixelType, (int)msg);
if (!scanner_.get())
return seqError();
std::vector<int> values;
int init = 0, now = 0;
GET_SANE_OPT_EX(int, scanner_, ex_color_mode, NULL, &values);
now = values[sane_opts::RANGE_POS_CURRENT];
init = values[sane_opts::RANGE_POS_DEFAULT];
if (Msg::Reset == msg || Msg::Set == msg)
{
if(Msg::Set == msg)
init = (int)data.currentItem<CapType::IPixelType>();
{
char info[128] = { 0 }, * des[] = { "BlackWhite", "Gray", "Rgb" };
if((int)init < _countof(des))
sprintf(info, "set CapType::IPixelType = %s\r\n", des[(int)init]);
else
sprintf(info, "set CapType::IPixelType = 0x%x\r\n", (int)init);
utils::log_info(info, 0);
}
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_color_mode, &init);
data = Capability::createOneValue<CapType::IPixelType>((Twpp::PixelType)init);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
switch (msg) {
case Msg::Get:
if (1)
{
std::list<Twpp::PixelType> vals;
UInt32 ni = distance<int>(values, now), ii = distance<int>(values, init);
Twpp::PixelType Init = (Twpp::PixelType)init, Now = (Twpp::PixelType)now;
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < values.size(); ++i)
vals.push_back((Twpp::PixelType)values[i]);
return cap_get_enum_values<Twpp::PixelType, CapType::IPixelType>(msg, data, vals, Now, Init, ni, ii);
}
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IPixelType>((Twpp::PixelType)now);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IPixelType>((Twpp::PixelType)init);
return success();
}
return capBadOperation();
};
m_query[CapType::IAutomaticColorEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticColorEnabled] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticColorEnabled, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IAutomaticColorEnabled>();
int ret = SCANNER_ERR_OK, val = mech ? COLOR_AUTO_MATCH : COLOR_RGB;
SET_SANE_OPT_EX(ret, scanner_, ex_auto_color_type, &val);
return success();
}
std::vector<int> all;
GET_SANE_OPT_EX(int, scanner_, ex_auto_color_type, NULL, &all);
int twpt = all[sane_opts::RANGE_POS_CURRENT] == COLOR_AUTO_MATCH ? 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](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticColorNonColorPixelType, (int)msg);
if (msg == Msg::Set) {
int mech = (int)data.currentItem<CapType::IAutomaticColorNonColorPixelType>();
{
if ((UInt16)mech == 0 || (UInt16)mech == 1) {
int ret = SCANNER_ERR_OK,
val = mech;
SET_SANE_OPT_EX(ret, scanner_, ex_auto_color_type, &val);
if (ret == SCANNER_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](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IJpegQuality, (int)msg);
SANE_FinalImgFormat fif;
fif.img_format = SANE_IMAGE_TYPE_JPG;
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IJpegQuality>();
if ((int)mech <= 0 || (int)mech > 100)
return badValue();
m_jpegQuality = (int)mech;
return success();
//int ret = SCANNER_ERR_OK;
//fif.detail = (void*)mech;
//SET_SANE_OPT_EX(ret, scanner_, ex_final_format, &fif);
//return ret == SCANNER_ERR_OK ? success() : badValue();
}
//unsigned short q = 80;
//fif.detail = (void*)q;
//GET_SANE_OPT_EX(SANE_FinalImgFormat, scanner_, ex_final_format, &fif, NULL, NULL, NULL);
//if(fif.img_format == SANE_IMAGE_TYPE_JPG)
// q = (unsigned short)fif.detail;
//return CapSupGetAllResetEx<unsigned short, UInt16, CapType::IJpegQuality>(msg, data, q, 80);
unsigned short q = m_jpegQuality;
return CapSupGetAllResetEx<unsigned short, UInt16, CapType::IJpegQuality>(msg, data, q, (UInt16)80);
};
m_query[CapType::IOrientation] = msgSupportGetAllSetReset;
m_caps[CapType::IOrientation] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IOrientation, (int)msg);
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>();
bool lateral = mech == Orientation::Landscape;
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_paper_lateral, &lateral);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
std::vector<bool> values;
GET_SANE_OPT_EX(bool, scanner_, ex_paper_lateral, NULL, &values);
int lateral = values[sane_opts::RANGE_POS_CURRENT] ? (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](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IRotation, (int)msg);
if (Msg::Set == msg) {
auto res = data.currentItem<Fix32>();
float angle = res.toFloat();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_text_direction, &angle);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
std::vector<float> values;
GET_SANE_OPT_EX(float, scanner_, ex_text_direction, NULL, &values);
Fix32 Init = Fix32(values[sane_opts::RANGE_POS_DEFAULT]), Now = Fix32(values[sane_opts::RANGE_POS_CURRENT]);
std::list<Fix32> vls;
UInt32 i = distance<float>(values, values[sane_opts::RANGE_POS_DEFAULT]),
n = distance<float>(values, values[sane_opts::RANGE_POS_CURRENT]);
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < values.size(); ++i)
vls.push_back(Fix32(values[i]));
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>, _2, _3, Bool(true));
m_query[CapType::PaperDetectable] = msgSupportGetAll;
m_caps[CapType::PaperDetectable] = std::bind(oneValGet<Bool>, _2, _3, Bool(true));
m_query[CapType::FeederEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::FeederEnabled] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::FeederEnabled, (int)msg);
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::FeederEnabled>(msg, data, m_bFeederEnabled, Bool(true));
};
m_query[CapType::Duplex] = msgSupportGetAll;
m_caps[CapType::Duplex] = std::bind(oneValGet<Duplex>, _2, _3, Duplex::OnePass);
m_query[CapType::DuplexEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::DuplexEnabled] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::DuplexEnabled, (int)msg);
if (Msg::Set == msg) {
bool mech = data.currentItem<CapType::DuplexEnabled>();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_duplex, &mech);
utils::log_info(mech ? "Set1 Duplex is: true\r\n" : "Set1 Duplex is: false\r\n", 1);
int count = count_;
if (mech && count_ >= 2)
{
count /= 2;
SET_SANE_OPT_EX(ret, scanner_, scan_count, &count);
}
else if (!mech && count_ >= 2)
SET_SANE_OPT_EX(ret, scanner_, scan_count, &count);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
BYTE dup = 1;
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_duplex, NULL, &all);
dup = all[sane_opts::RANGE_POS_CURRENT];
utils::log_info(dup ? "Get Duplex is: true\r\n" : "Get Duplex is: false\r\n", 1);
int ret = SCANNER_ERR_OK;
int count = count_;
if (dup && count >= 2)
{
count /= 2;
SET_SANE_OPT_EX(ret, scanner_, scan_count, &count);
}
else if (!dup && count >= 2)
SET_SANE_OPT_EX(ret, scanner_, scan_count, &count)
return CapSupGetAllReset<BYTE, Bool, CapType::DuplexEnabled>(msg, data, dup, Bool(true));
};
m_query[CapType::AutoFeed] = msgSupportGetAllSetReset;
m_caps[CapType::AutoFeed] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::AutoFeed, (int)msg);
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](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IImageFileFormat, (int)msg);
SANE_FinalImgFormat now, init;
std::vector<SANE_FinalImgFormat> all;
GET_SANE_OPT_EX(SANE_FinalImgFormat, scanner_, ex_final_format, NULL, &all);
init = all[sane_opts::RANGE_POS_DEFAULT];
now = all[sane_opts::RANGE_POS_CURRENT];
if (Msg::Set == msg || Msg::Reset == msg) {
if (Msg::Set == msg)
{
auto fmt = data.currentItem<ImageFileFormat>();
if (fmt != Twpp::ImageFileFormat::Bmp &&
fmt != Twpp::ImageFileFormat::Jfif &&
fmt != Twpp::ImageFileFormat::Tiff)
return badValue();
init.img_format = (SANE_ImageType)fmt;
{
if (fmt == Twpp::ImageFileFormat::Bmp)
utils::log_info("set CapType::IImageFileFormat = Bmp\r\n", 1);
else if (fmt == Twpp::ImageFileFormat::Jfif)
utils::log_info("set CapType::IImageFileFormat = Jfif\r\n", 1);
else if (fmt == Twpp::ImageFileFormat::Tiff)
utils::log_info("set CapType::IImageFileFormat = Tiff\r\n", 1);
}
}
else
data = Capability::createOneValue<CapType::IImageFileFormat>((Twpp::ImageFileFormat)init.img_format);
m_fileXfer.setFormat((Twpp::ImageFileFormat)init.img_format);
return success();
//if(Msg::Set == msg)
// init.img_format = (SANE_ImageType)(int)data.currentItem<ImageFileFormat>();
//int ret = SCANNER_ERR_OK;
//SET_SANE_OPT_EX(ret, scanner_, ex_final_format, &init);
//return ret == SCANNER_ERR_OK ? success() : badValue();
}
// ImageFileFormat Now = (ImageFileFormat)(int)now.img_format, Init = (ImageFileFormat)(int)init.img_format;
ImageFileFormat Now = m_fileXfer.format() , Init = Twpp::ImageFileFormat::Bmp;
std::list<ImageFileFormat> vals;
UInt32 i = 0, // distance<SANE_FinalImgFormat>(all, init),
n = 0; // distance<SANE_FinalImgFormat>(all, now);
for (size_t ind = sane_opts::RANGE_POS_ENUM_BEGIN; ind < all.size(); ++ind)
{
vals.push_back((ImageFileFormat)(int)all[ind].img_format);
if ((int)all[ind].img_format == (int)Init) // init.img_format)
i = ind - sane_opts::RANGE_POS_ENUM_BEGIN;
if ((int)all[ind].img_format == (int)Now) //now.img_format)
n = ind - sane_opts::RANGE_POS_ENUM_BEGIN;
}
return cap_get_enum_values<ImageFileFormat, CapType::IImageFileFormat>(msg, data, vals, Now, Init, n, i);
};
m_query[CapType::IAutomaticDeskew] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticDeskew] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticDeskew, (int)msg);
if (Msg::Set == msg) {
auto atuodsw = data.currentItem<CapType::IAutomaticDeskew>();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, is_auto_deskew, (bool*)&atuodsw);
return ret == SCANNER_ERR_OK ? success() : seqError();
}
BYTE ato = 1;
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, is_auto_deskew, NULL, &all);
ato = all[sane_opts::RANGE_POS_CURRENT];
return CapSupGetAllReset<BYTE, bool, CapType::IAutomaticDeskew>(msg, data, ato, true);
};
m_query[CapType::IAutomaticRotate] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticRotate] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticRotate, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IAutomaticRotate>();
float direction = mech ? AUTO_MATIC_ROTATE : .0f;
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_text_direction, &direction);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
float direction = .0f;
BYTE am = 0;
std::vector<float> all;
GET_SANE_OPT_EX(float, scanner_, ex_text_direction, NULL, &all);
direction = all[sane_opts::RANGE_POS_CURRENT];
am = IS_DOUBLE_EQUAL(direction, AUTO_MATIC_ROTATE);
return CapSupGetAllReset<BYTE, bool, CapType::IAutomaticRotate>(msg, data, am, false);
};
m_query[CapType::SerialNumber] = msgSupportGetAll;
m_caps[CapType::SerialNumber] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::SerialNumber, (int)msg);
Str255 str;
std::vector<std::string> all;
GET_SANE_OPT_EX(std::string, scanner_, ex_serial, NULL, &all);
strcpy(str.data(), all[sane_opts::RANGE_POS_CURRENT].c_str());
return CapSupGetAll<Str255, Str255, CapType::SerialNumber>(msg, data, str, str);
};
if (SANE_ID(scan_when_paper_on) > 0)
{
m_query[CapType::AutoScan] = msgSupportGetAllSetReset;
m_caps[CapType::AutoScan] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::AutoScan, (int)msg);
if (Msg::Set == msg || Msg::Reset == msg) {
bool val = false;
if(Msg::Set == msg)
val = (bool)data.currentItem<CapType::AutoScan>();
int ret = SANE_STATUS_GOOD;
m_autoscan = val;
SET_SANE_OPT_EX(ret, scanner_, scan_when_paper_on, &val);
return ret == SANE_STATUS_GOOD ? success() : badValue();
}
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, scan_when_paper_on, NULL, &all);
m_autoscan = (bool)all[sane_opts::RANGE_POS_CURRENT];
//return oneValGetSet<Bool>(msg, data, (Bool)all[sane_opts::RANGE_POS_CURRENT], 0);
//data = Capability::createOneValue<Bool>(CapType::AutoScan, (BYTE)all[sane_opts::RANGE_POS_CURRENT]);
//return success();
return CapSupGetAllReset<Bool, Bool, CapType::AutoScan>(msg, data, m_autoscan, FALSE);
};
}
m_query[CapType::IAutoSize] = msgSupportGetAllSetReset;
m_caps[CapType::IAutoSize] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutoSize, (int)msg);
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>();
bool match = autosize == AutoSize::Auto;
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_auto_paper_size, &match);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_auto_paper_size, NULL, &all);
UInt16 size = all[sane_opts::RANGE_POS_CURRENT] ? (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](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticBorderDetection, (int)msg);
if (Msg::Set == msg) {
auto autodetectborder = data.currentItem<CapType::IAutomaticBorderDetection>();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, is_size_check, (bool*)&autodetectborder);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
Bool init = false,
erase = false;
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, is_size_check, NULL, &all);
init = (bool)all[sane_opts::RANGE_POS_DEFAULT];
erase = (bool)all[sane_opts::RANGE_POS_CURRENT];
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](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutoDiscardBlankPages, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IAutoDiscardBlankPages>();
bool discard = mech == DiscardBlankPages::Auto;
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_discard_blank_page, &discard);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_discard_blank_page, NULL, &all);
DiscardBlankPages autodiscradblank = all[sane_opts::RANGE_POS_CURRENT] ? 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](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CAP_TYPE_EX_DISCARD_BLANK_RECEIPT, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<DiscardBlankPages>();
bool discard = mech == DiscardBlankPages::Auto;
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_discard_blank_receipt, &discard);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_discard_blank_receipt, NULL, &all);
DiscardBlankPages autodiscradblank = all[sane_opts::RANGE_POS_CURRENT] ? DiscardBlankPages::Auto : DiscardBlankPages::Disabled;
return CapSupGetAllResetEx<DiscardBlankPages, DiscardBlankPages, (CapType)CapTypeEx::CAP_TYPE_EX_DISCARD_BLANK_RECEIPT>(msg, data, autodiscradblank, DiscardBlankPages::Disabled);
// return success();
};
m_query[CapType::IFilter] = msgSupportGetAllSetReset;
m_caps[CapType::IFilter] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IFilter, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IFilter>();
int ret = SCANNER_ERR_OK, val = to_sane_filter((Filter)mech);
SET_SANE_OPT_EX(ret, scanner_, ex_color_filter, &val);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
int cur = FILTER_NONE, def = FILTER_NONE;
std::vector<int> vals;
GET_SANE_OPT_EX(int, scanner_, ex_color_filter, NULL, &vals);
std::list<Filter> vs;
Filter now = from_sane_filter(vals[sane_opts::RANGE_POS_CURRENT]),
init = from_sane_filter(vals[sane_opts::RANGE_POS_DEFAULT]);
UInt32 curInd = distance<int>(vals, vals[sane_opts::RANGE_POS_CURRENT]),
defInd = distance<int>(vals, vals[sane_opts::RANGE_POS_DEFAULT]);;
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < vals.size(); ++i)
{
vs.push_back(from_sane_filter(vals[i]));
}
BYTE f = (BYTE)now;
return CapSupGetAllReset<BYTE, Filter, CapType::IFilter>(msg, data, vs, f, init, curInd, defInd);
};
m_query[CapType::IBrightness] = msgSupportGetAllSetReset;
m_caps[CapType::IBrightness] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IBrightness, (int)msg);
int init = 128, l = 1, u = 255, step = 1, now = 128;
int ret = SCANNER_ERR_OK;
std::vector<int> all;
GET_SANE_OPT_EX(int, scanner_, bright, NULL, &all);
init = all[sane_opts::RANGE_POS_DEFAULT];
now = all[sane_opts::RANGE_POS_CURRENT];
l = all[sane_opts::RANGE_POS_LOWER];
u = all[sane_opts::RANGE_POS_UPPER];
step = all[sane_opts::RANGE_POS_STEP];
float sf = trans_range((float)step, (float)l, (float)u, -1000.0f, 1000.0f, true),
nf = trans_range((float)now, (float)l, (float)u, -1000.0f, 1000.0f),
initf = trans_range((float)init, (float)l, (float)u, -1000.0f, 1000.0f);
switch (msg) {
case Msg::Get:
sf = 333.333f;
data = Capability::createRange<CapType::IBrightness>(Fix32(-1000.0f), Fix32(1000.0f), Fix32(sf), Fix32(nf), Fix32(initf));
return success();
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IBrightness>(Fix32(nf));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IBrightness>(Fix32(initf));
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IBrightness>();
if (mech > 1000.0f || mech < -1000.0f)
return badValue();
initf = mech.toFloat();
}
case Msg::Reset:
now = (int)(trans_range(initf, -1000.0f, 1000.0f, (float)l, (float)u) + .5f);
SET_SANE_OPT_EX(ret, scanner_, bright, &now);
if (Msg::Reset == msg)
{
initf = trans_range((float)now, (float)l, (float)u, -1000.0f, 1000.0f, true);
data = Capability::createOneValue<CapType::IBrightness>(Fix32(initf));
}
return ret == SCANNER_ERR_OK ? success() : badValue();
default:
return capBadOperation();
}
};
m_query[CapType::IContrast] = msgSupportGetAllSetReset;
m_caps[CapType::IContrast] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IContrast, (int)msg);
int init = 4, l = 1, u = 7, step = 1, now = 4;
int ret = SCANNER_ERR_OK;
std::vector<int> all;
GET_SANE_OPT_EX(int, scanner_, contrast, NULL, &all);
init = all[sane_opts::RANGE_POS_DEFAULT];
now = all[sane_opts::RANGE_POS_CURRENT];
l = all[sane_opts::RANGE_POS_LOWER];
u = all[sane_opts::RANGE_POS_UPPER];
step = all[sane_opts::RANGE_POS_STEP];
float sf = trans_range((float)step, (float)l, (float)u, -1000.0f, 1000.0f, true),
nf = trans_range((float)now, (float)l, (float)u, -1000.0f, 1000.0f),
initf = trans_range((float)init, (float)l, (float)u, -1000.0f, 1000.0f);
switch (msg) {
case Msg::Get:
// sf = 333.333f;
data = Capability::createRange<CapType::IContrast>(Fix32(-1000.0f), Fix32(1000.0f), Fix32(sf), Fix32(nf), Fix32(initf));
return success();
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IContrast>(Fix32(nf));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IContrast>(Fix32(initf));
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IContrast>();
if (mech > 1000.0f || mech < -1000.0f)
return badValue();
initf = mech.toFloat();
}
case Msg::Reset:
now = (int)(trans_range(initf, -1000.0f, 1000.0f, (float)l, (float)u) + .5f);
SET_SANE_OPT_EX(ret, scanner_, contrast, &now);
if (Msg::Reset == msg)
{
initf = trans_range((float)now, (float)l, (float)u, -1000.0f, 1000.0f, true);
data = Capability::createOneValue<CapType::IContrast>(Fix32(initf));
}
return ret == SCANNER_ERR_OK ? success() : badValue();
default:
return capBadOperation();
}
};
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO, (int)msg);
float init = .0f, l = .0f, u = .0f, step = .0f, now = .0f;
std::vector<float> all;
int ret = SCANNER_ERR_OK;
GET_SANE_OPT_EX(float, scanner_, search_hole_range, NULL, &all);
init = all[sane_opts::RANGE_POS_DEFAULT] * 100.0f;
now = all[sane_opts::RANGE_POS_CURRENT] * 100.0f;
l = all[sane_opts::RANGE_POS_LOWER] * 100.0f;
u = all[sane_opts::RANGE_POS_UPPER] * 100.0f;
step = all[sane_opts::RANGE_POS_STEP] * 100.0f;
switch (msg) {
case Msg::Get:
data = Capability::createRange<UInt32>((CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO, UInt32(l), UInt32(u), UInt32(step), UInt32(now), UInt32(init));
return success();
case Msg::GetCurrent:
data = Capability::createOneValue<UInt32>((CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO, UInt32(now));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<UInt32>((CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO, UInt32(init));
return success();
case Msg::Set: {
auto mech = data.currentItem<UInt32>();
if (mech > u || mech < l)
return badValue();
init = (float)mech;
}
case Msg::Reset:
init /= 100.0f;
SET_SANE_OPT_EX(ret, scanner_, search_hole_range, &init);
return ret == SCANNER_ERR_OK ? success() : badValue();
default:
return capBadOperation();
}
};
m_query[CapType::IGamma] = msgSupportGetAllSetReset;
m_caps[CapType::IGamma] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IGamma, (int)msg);
float init = .0f, l = .0f, u = .0f, step = .0f, now = .0f;
std::vector<float> all;
int ret = SCANNER_ERR_OK;
GET_SANE_OPT_EX(float, scanner_, gamma, NULL, &all);
init = all[sane_opts::RANGE_POS_DEFAULT];
now = all[sane_opts::RANGE_POS_CURRENT];
l = all[sane_opts::RANGE_POS_LOWER];
u = all[sane_opts::RANGE_POS_UPPER];
step = all[sane_opts::RANGE_POS_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:
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();
init = mech.toFloat();
}
case Msg::Reset:
SET_SANE_OPT_EX(ret, scanner_, gamma, &init);
return ret == SCANNER_ERR_OK ? success() : badValue();
default:
return capBadOperation();
}
};
m_query[CapType::CustomDsData] = msgSupportGetAll;
m_caps[CapType::CustomDsData] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::CustomDsData, (int)msg);
Bool init(true);
return CapSupGetAll<Bool, Bool, CapType::CustomDsData>(msg, data, init, init);
};
m_query[CapType::DoubleFeedDetection] = msgSupportGetAllSetReset;
m_caps[CapType::DoubleFeedDetection] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::DoubleFeedDetection, (int)msg);
if (Msg::Set == msg) {
auto val = data.currentItem<CapType::DoubleFeedDetection>();
int ret = SCANNER_ERR_OK;
bool enable = val == DoubleFeedDetection::Ultrasonic;
if (double_check_mode_ == DOUBLE_CHECK_ULTRASONIC)
{
enable = (bool)val;
utils::to_log(1, "DoubleFeedDetection parameter is boolean for Ultrasonic. set to %s\r\n", enable ? "TRUE" : "FALSE");
}
SET_SANE_OPT_EX(ret, scanner_, is_ultrasonic_check, &enable);
return ret == SCANNER_ERR_OK ? success() : seqError();
}
DoubleFeedDetection init = DoubleFeedDetection::Ultrasonic;
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, is_ultrasonic_check, NULL, &all);
if (double_check_mode_ == DOUBLE_CHECK_ULTRASONIC)
{
Bool ni(all[sane_opts::RANGE_POS_CURRENT]),
ii(all[sane_opts::RANGE_POS_DEFAULT]);
data = Capability::createEnumeration<Bool>(CapType::DoubleFeedDetection, { FALSE, TRUE }, ni, ii);
return success();
}
else
{
BYTE ato = !all[sane_opts::RANGE_POS_CURRENT];
init = all[sane_opts::RANGE_POS_DEFAULT] ? DoubleFeedDetection::Ultrasonic : DoubleFeedDetection::ByLength;
return CapSupGetAllReset<BYTE, DoubleFeedDetection, CapType::DoubleFeedDetection>(msg, data, ato, init);
}
};
m_query[CapType::IAutomaticCropUsesFrame] = msgSupportGetAll;
m_caps[CapType::IAutomaticCropUsesFrame] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticCropUsesFrame, (int)msg);
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_is_paper_auto_crop, NULL, &all);
BYTE crop = all[sane_opts::RANGE_POS_CURRENT];
return CapSupGetAll<BYTE, bool, CapType::IAutomaticCropUsesFrame>(msg, data, crop, false);
};
m_query[CapType::FeederLoaded] = msgSupportGetAll;
m_caps[CapType::FeederLoaded] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::FeederLoaded, (int)msg);
Bool paperon = scanner_->is_paper_on();
return CapSupGetAll<Bool, Bool, CapType::FeederLoaded>(msg, data, paperon, paperon);
};
if (SANE_ID(ex_is_page_fold) > 0)
{
m_query[CapType(CapTypeEx::CAP_TYPE_EX_FOLD)] = msgSupportGetAllSetReset;
m_caps[CapType(CapTypeEx::CAP_TYPE_EX_FOLD)] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_FOLD, (int)msg);
if (Msg::Set == msg || Msg::Reset == msg) {
bool fold = false;
if (msg == Msg::Set)
fold = (bool)data.currentItem<Int32>();;
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_is_page_fold, &fold);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_is_page_fold, NULL, &all);
BYTE fold = all[sane_opts::RANGE_POS_CURRENT];
return CapSupGetAllResetEx<BYTE, Int32, (CapType)CapTypeEx::CAP_TYPE_EX_FOLD>(msg, data, fold, 0);
};
}
if (SANE_ID(dogear_size) > 0)
{
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST)] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST, (int)msg);
int now = 10, init = 10, l = 0, u = 100, s = 10;
std::vector<int> all;
GET_SANE_OPT_EX(int, scanner_, dogear_size, NULL, &all);
init = all[sane_opts::RANGE_POS_DEFAULT];
now = all[sane_opts::RANGE_POS_CURRENT];
l = all[sane_opts::RANGE_POS_LOWER];
u = all[sane_opts::RANGE_POS_UPPER];
s = all[sane_opts::RANGE_POS_STEP];
if (Msg::Set == msg || Msg::Reset == msg) {
if (Msg::Set == msg)
{
auto mech = data.currentItem<UInt32>();
if (mech < 10 || mech > 300)
return badValue();
init = (int)(trans_range((float)mech, 10.0f, 300.0f, (float)l, (float)u) + .5f);
}
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, dogear_size, &init);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
UInt32 Now = UInt32(trans_range((float)now, (float)l, (float)u, 10.0f, 300.0f) + .5f),
Init = UInt32(trans_range((float)init, (float)l, (float)u, 10.0f, 300.0f) + .5f);
return CapSupGetAllResetEx<UInt32, UInt32, (CapType)CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST>(msg, data, Now, Init);
};
}
if (SANE_ID(ex_is_paper_auto_crop) > 0)
{
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_CROP_MODEL)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_CROP_MODEL)] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_CROP_MODEL, (int)msg);
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_is_paper_auto_crop, NULL, &all);
if (Msg::Set == msg || Msg::Reset == msg)
{
bool def = all[sane_opts::RANGE_POS_DEFAULT];
if (Msg::Set == msg)
def = data.currentItem<BYTE>() == 1;
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_is_paper_auto_crop, &def);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
BYTE crop = all[sane_opts::RANGE_POS_CURRENT];
return CapSupGetAll<BYTE, bool, CapType::IAutomaticCropUsesFrame>(msg, data, crop, all[sane_opts::RANGE_POS_DEFAULT]);
};
}
if (SANE_ID(ex_multiout_type) > 0)
{
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE, (int)msg);
int cur = MULTI_OUT_NONE, def = MULTI_OUT_NONE;
std::vector<int> all;
GET_SANE_OPT_EX(int, scanner_, ex_multiout_type, NULL, &all);
cur = all[sane_opts::RANGE_POS_CURRENT];
def = all[sane_opts::RANGE_POS_DEFAULT];
if (Msg::Set == msg || Msg::Reset == msg) {
auto mech = def;
if (msg == Msg::Set)
mech = data.currentItem<UInt32>();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_multiout_type, &mech);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
Int32 now = cur, init = def, ind = 0,
curInd = distance<int>(all, cur),
defInd = distance<int>(all, def);
std::list<Int32> vals;
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < all.size(); ++i)
vals.push_back(all[i]);
return CapSupGetAllResetEx<Int32, Int32, (CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE>(msg, data, vals, now, init, curInd, defInd);
};
}
if (SANE_ID(ex_to_be_scan) > 0)
{
m_query[CapType(CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN)] = msgSupportGetAllSetReset;
m_caps[CapType(CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN)] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN, (int)msg);
if (Msg::Set == msg || Msg::Reset == msg) {
auto tobe = false;
if (msg == Msg::Set)
tobe = data.currentItem<Int32>();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_to_be_scan, &tobe);
return ret == SCANNER_ERR_OK ? success() : seqError();
}
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_to_be_scan, NULL, &all);
BYTE tobe = all[sane_opts::RANGE_POS_CURRENT];
return CapSupGetAllResetEx<BYTE, Int32, (CapType)CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN>(msg, data, tobe, 0);
};
}
if (SANE_ID(ex_scan_with_hole) > 0)
{
m_query[CapType(CapTypeEx::CAP_TYPE_EX_SCAN_WITH_HOLE)] = msgSupportGetAllSetReset;
m_caps[CapType(CapTypeEx::CAP_TYPE_EX_SCAN_WITH_HOLE)] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_SCAN_WITH_HOLE, (int)msg);
if (Msg::Set == msg || Msg::Reset == msg) {
auto tobe = false;
if (msg == Msg::Set)
tobe = data.currentItem<Int32>();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_scan_with_hole, &tobe);
return ret == SCANNER_ERR_OK ? success() : seqError();
}
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_scan_with_hole, NULL, &all);
BYTE tobe = all[sane_opts::RANGE_POS_CURRENT];;
return CapSupGetAllResetEx<BYTE, Int32, (CapType)CapTypeEx::CAP_TYPE_EX_SCAN_WITH_HOLE>(msg, data, tobe, 0);
};
}
if (SANE_ID(ex_device_code) > 0)
{
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = msgSupportGetAll;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_ENCODE, (int)msg);
std::vector<std::string> all;
GET_SANE_OPT_EX(std::string, scanner_, ex_device_code, NULL, &all);
Str255 str;
str.setData(all[sane_opts::RANGE_POS_CURRENT].c_str(), 32);
data = Capability::createOneValue<Str255>((CapType)CapTypeEx::CAP_TYPE_EX_ENCODE, str);
return success();
};
}
if (SANE_ID(ex_power) > 0)
{
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_POWER_LEVEL)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_POWER_LEVEL)] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_POWER_LEVEL, (int)msg);
int cur = SANE_POWER_MINUTES_30, def = SANE_POWER_MINUTES_30;
std::vector<int> all;
GET_SANE_OPT_EX(int, scanner_, ex_power, NULL, &all);
cur = all[sane_opts::RANGE_POS_CURRENT];
def = all[sane_opts::RANGE_POS_DEFAULT];
if (Msg::Set == msg || Msg::Reset == msg) {
if (msg == Msg::Set)
def = data.currentItem<UInt32>();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_power, &def);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
UInt32 now = cur, init = def, ind = 0,
curInd = distance<int>(all, cur),
defInd = distance<int>(all, def);
std::list<UInt32> vals;
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < all.size(); ++i)
{
vals.push_back(all[i]);
}
return CapSupGetAllResetEx<UInt32, UInt32, (CapType)CapTypeEx::CAP_TYPE_EX_POWER_LEVEL>(msg, data, vals, now, init, curInd, defInd);
};
}
if (SANE_ID(ex_fill_background) > 0)
{
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD, (int)msg);
if (Msg::Set == msg) {
auto convex = data.currentItem<Bool>();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_fill_background, (bool*)&convex);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
bool val = false, cur = false;
Bool init = false,
erase = false;
std::vector<bool> all;
GET_SANE_OPT_EX(bool, scanner_, ex_fill_background, NULL, &all);
init = (bool)all[sane_opts::RANGE_POS_DEFAULT];
erase = (bool)all[sane_opts::RANGE_POS_CURRENT];
return CapSupGetAllResetEx<Bool, Bool, (CapType)CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD>(msg, data, { false,true }, erase, init, erase ? 1 : 0, 0);
};
}
if (SANE_ID(ex_sharpen) > 0)
{
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_SHARPEN, (int)msg);
int cur = MULTI_OUT_NONE, def = MULTI_OUT_NONE;
std::vector<int> all;
GET_SANE_OPT_EX(int, scanner_, ex_sharpen, NULL, &all);
cur = all[sane_opts::RANGE_POS_CURRENT];
def = all[sane_opts::RANGE_POS_DEFAULT];
if (Msg::Set == msg || Msg::Reset == msg) {
auto mech = def;
if (msg == Msg::Set)
mech = data.currentItem<UInt32>();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_sharpen, &mech);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
Int32 now = cur, init = def,
curInd = distance<int>(all, cur),
defInd = distance<int>(all, def);
std::list<Int32> vals;
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < all.size(); ++i)
vals.push_back(all[i]);
return CapSupGetAllResetEx<Int32, Int32, (CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN>(msg, data, vals, now, init, curInd, defInd);
};
}
if (SANE_ID(ex_color_enhance) > 0)
{
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR, (int)msg);
int cur = FILTER_NONE, def = FILTER_NONE;
std::vector<int> vals;
GET_SANE_OPT_EX(int, scanner_, ex_color_enhance, NULL, &vals);
cur = vals[sane_opts::RANGE_POS_CURRENT];
def = vals[sane_opts::RANGE_POS_DEFAULT];
if (Msg::Set == msg || Msg::Reset == msg) {
if (Msg::Set == msg)
def = data.currentItem<UInt32>();
int ret = SCANNER_ERR_OK;
SET_SANE_OPT_EX(ret, scanner_, ex_color_filter, &def);
return ret == SCANNER_ERR_OK ? success() : badValue();
}
std::list<Filter> vs;
Filter now = from_sane_filter(cur), init = from_sane_filter(def);
UInt32 curInd = distance<int>(vals, cur), defInd = distance<int>(vals, def);
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < vals.size(); ++i)
vs.push_back(from_sane_filter(vals[i]));
UInt32 val = (UInt32)now;
return CapSupGetAllResetEx<UInt32, Filter, (CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR>(msg, data, vs, val, init, curInd, defInd);
};
}
init_caps_from_sane_directly();
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION] = msgSupportGetAll;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION, (int)msg);
std::vector<std::string> all;
GET_SANE_OPT_EX(std::string, scanner_, ex_hardware_version, NULL, &all);
Str255 str;
strcpy(str.data(), all[sane_opts::RANGE_POS_CURRENT].c_str());
data = Capability::createOneValue<Str255>((CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION, str);
return success();
};
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_IP] = msgSupportGetAll;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_IP] = [this](Twpp::CapType type, Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_IP, (int)msg);
std::vector<std::string> all;
GET_SANE_OPT_EX(std::string, scanner_, ex_ip, NULL, &all);
Str255 str;
strcpy(str.data(), all[sane_opts::RANGE_POS_CURRENT].c_str());
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(name, cap) \
if(m_query.count((CapType)SANE_OPT_ID_##name)) \
{ \
m_query[(CapType)cap] = m_query[(CapType)SANE_OPT_ID_##name]; \
m_caps[(CapType)cap] = m_caps[CapType((int)SANE_OPT_ID_##name)]; \
org_func_[(int)cap] = (int)SANE_OPT_ID_##name; \
}
SET_EXISTING_EXTENSION(EXCHANGE, CapTypeEx::CAP_TYPE_EX_FLIP);
SET_EXISTING_EXTENSION(IS_ROTATE_BKG_180, CapTypeEx::CAP_TYPE_EX_ROTATE_BKG_180);
SET_EXISTING_EXTENSION(IS_FILL_COLOR, CapTypeEx::CAP_TYPE_EX_FILL_BLACK_BKG);
SET_EXISTING_EXTENSION(MARGIN, CapTypeEx::CAP_TYPE_EX_EDGE_IDENT);
SET_EXISTING_EXTENSION(ANTI_NOISE_LEVEL, CapTypeEx::CAP_TYPE_EX_ANTI_NOISE);
SET_EXISTING_EXTENSION(THRESHOLD, CapTypeEx::CAP_TYPE_EX_THRESHOLD);
SET_EXISTING_EXTENSION(RID_HOLE, CapTypeEx::CAP_TYPE_EX_FILL_HOLE);
SET_EXISTING_EXTENSION(NOISE_OPTIMIZE, CapTypeEx::CAP_TYPE_EX_DETACH_NOISE);
SET_EXISTING_EXTENSION(NOISE_SIZE, CapTypeEx::CAP_TYPE_EX_DETACH_NOISE_THRESHOLD);
SET_EXISTING_EXTENSION(RID_MULTIOUT_RED, CapTypeEx::CAP_TYPE_EX_RID_RED);
SET_EXISTING_EXTENSION(RID_ANSWER_SHEET_RED, CapTypeEx::CAP_TYPE_EX_RID_RED_HSV);
SET_EXISTING_EXTENSION(IS_CHECK_ASKEW, CapTypeEx::CAP_TYPE_EX_SCREW_DETECT);
SET_EXISTING_EXTENSION(ASKEW_RANGE, CapTypeEx::CAP_TYPE_EX_SCREW_DETECT_LEVEL);
SET_EXISTING_EXTENSION(IS_CHECK_STAPLE, CapTypeEx::CAP_TYPE_EX_STAPLE_DETECT);
SET_EXISTING_EXTENSION(IS_CHECK_DOG_EAR, CapTypeEx::CAP_TYPE_EX_DOGEAR_DETECT);
SET_EXISTING_EXTENSION(DARK_SAMPLE, CapTypeEx::CAP_TYPE_EX_DARK_SAMPLE);
SET_EXISTING_EXTENSION(SPLIT, CapTypeEx::CAP_TYPE_EX_IMAGE_SPLIT);
SET_EXISTING_EXTENSION(ERASE_BACKGROUND, CapTypeEx::CAP_TYPE_EX_FADE_BKG);
SET_EXISTING_EXTENSION(BKG_COLOR_RANGE, CapTypeEx::CAP_TYPE_EX_FADE_BKG_VALUE);
SET_EXISTING_EXTENSION(SIZE_CHECK, CapTypeEx::CAP_TYPE_EX_SIZE_DETECT);
SET_EXISTING_EXTENSION(IS_MULTI_OUT, CapTypeEx::CAP_TYPE_EX_MULTI_OUT);
m_query[(CapType)SANE_OPT_ID_DEVICE_SERIAL_NO] = m_query[CapType::SerialNumber];
m_caps[(CapType)SANE_OPT_ID_DEVICE_SERIAL_NO] = m_caps[CapType::SerialNumber];
org_func_[SANE_OPT_ID_DEVICE_SERIAL_NO] = (int)CapType::SerialNumber;
m_query[(CapType)SANE_OPT_ID_FIRMWARE_VERSION] = m_query[(CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION];
m_caps[(CapType)SANE_OPT_ID_FIRMWARE_VERSION] = m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION];
org_func_[SANE_OPT_ID_FIRMWARE_VERSION] = (int)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION;
m_query[(CapType)SANE_OPT_ID_DEVICE_IP_ADDR] = m_query[(CapType)CapTypeEx::CAP_TYPE_EX_IP];
m_caps[(CapType)SANE_OPT_ID_DEVICE_IP_ADDR] = m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_IP];
org_func_[SANE_OPT_ID_DEVICE_IP_ADDR] = (int)CapTypeEx::CAP_TYPE_EX_IP;
}
void huagao_ds::init_caps_from_sane_directly(void)
{
std::vector<uint32_t> ids;
scanner_->get_fixed_ids(got_fixed_id, &ids);
std::sort(ids.begin(), ids.end());
for (auto& v : ids)
{
value_type type = VAL_TYPE_NONE;
value_limit limit = VAL_LIMIT_NONE;
int bytes = 0;
bool rdo = false;
if (!scanner_->get_option_info(v, &type, &limit, &bytes))
continue;
rdo = (limit & VAL_LIMIT_READONLY) == VAL_LIMIT_READONLY;
limit = (value_limit)(limit & VAL_LIMIT_MASK);
if (type == VAL_TYPE_BOOL)
{
if (rdo)
{
m_query[(CapType)v] = msgSupportGetAll;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
std::vector<bool> all;
sane_opts::get_opts<bool> op(NULL, &all);
scanner_->get_value((int)type, sane_opts::set_opt_value<bool>, &op);
op.re_order();
type = data.type();
data = Capability::createOneValue<Bool>(type, Bool(all[sane_opts::RANGE_POS_CURRENT]));
return success();
};
}
else
{
m_query[(CapType)v] = msgSupportGetAllSetReset;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
std::vector<bool> all;
sane_opts::get_opts<bool> op(NULL, &all);
scanner_->get_value((int)type, sane_opts::set_opt_value<bool>, &op);
op.re_order();
if (msg == Msg::Set || msg == Msg::Reset)
{
bool init = all[sane_opts::RANGE_POS_DEFAULT];
if (msg == Msg::Set)
init = (bool)data.currentItem<Bool>();
int ret = scanner_->set_value((int)type, &init);
if (ret)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(ret) };
else
return success();
}
else if(msg == Msg::GetCurrent || msg == Msg::GetDefault)
{
Bool t;
if (msg == Msg::GetCurrent)
t = Bool(all[sane_opts::RANGE_POS_CURRENT]);
else
t = (Bool)all[sane_opts::RANGE_POS_DEFAULT];
type = data.type();
data = Capability::createOneValue<Bool>(type, t);
return success();
}
else
{
UInt32 ni = all[sane_opts::RANGE_POS_CURRENT] ? 1 : 0, ii = all[sane_opts::RANGE_POS_DEFAULT] ? 1 : 0;
type = data.type();
data = Capability::createEnumeration<Bool>(type, { FALSE, TRUE }, ni, ii);
return success();
}
};
}
}
else if (type == VAL_TYPE_INT)
{
// int -> Int32
if (rdo)
{
m_query[(CapType)v] = msgSupportGetAll;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
std::vector<int> all;
Int32 val;
sane_opts::get_opts<int> op(NULL, &all);
scanner_->get_value((int)type, sane_opts::set_opt_value<int>, &op);
op.re_order();
copy_type(val, all[sane_opts::RANGE_POS_CURRENT]);
type = data.type();
data = Capability::createOneValue<Int32>(type, val);
return success();
};
}
else
{
m_query[(CapType)v] = msgSupportGetAllSetReset;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
std::vector<int> all;
value_limit lmt;
sane_opts::get_opts<int> op(&lmt, &all);
scanner_->get_value((int)type, sane_opts::set_opt_value<int>, &op);
op.re_order();
if (msg == Msg::Set || msg == Msg::Reset)
{
int val = (int)data.currentItem<Int32>();
if (msg == Msg::Reset)
val = all[sane_opts::RANGE_POS_DEFAULT];
int ret = scanner_->set_value((int)type, &val);
type = data.type();
data = Capability::createOneValue<Int32>(type, (Int32)val);
if (ret)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(ret) };
else
return success();
}
else if (msg == Msg::GetCurrent || msg == Msg::GetDefault)
{
Int32 val;
if (msg == Msg::GetCurrent)
copy_type(val, all[sane_opts::RANGE_POS_CURRENT]);
else
copy_type(val, all[sane_opts::RANGE_POS_DEFAULT]);
type = data.type();
data = Capability::createOneValue<Int32>(type, val);
return success();
}
else
{
if (lmt == VAL_LIMIT_ENUM)
{
std::list<Int32> vals;
UInt32 ni = distance<int>(all, all[sane_opts::RANGE_POS_CURRENT]),
ii = distance<int>(all, all[sane_opts::RANGE_POS_DEFAULT]);
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < all.size(); ++i)
{
Int32 t;
copy_type(t, all[i]);
vals.push_back(t);
}
type = data.type();
data = Capability::createEnumeration<Int32>(type, vals, ni, ii);
}
else if (lmt == VAL_LIMIT_RANGE)
{
Int32 now, init, lower, upper, step;
copy_type(now, all[sane_opts::RANGE_POS_CURRENT]);
copy_type(init, all[sane_opts::RANGE_POS_DEFAULT]);
copy_type(lower, all[sane_opts::RANGE_POS_LOWER]);
copy_type(upper, all[sane_opts::RANGE_POS_UPPER]);
copy_type(step, all[sane_opts::RANGE_POS_STEP]);
type = data.type();
data = Capability::createRange<Int32>(type, lower, upper, step, now, init);
}
else
{
Int32 val;
copy_type(val, all[sane_opts::RANGE_POS_CURRENT]);
type = data.type();
data = Capability::createOneValue<Int32>(type, val);
}
return success();
}
};
}
}
else if (type == VAL_TYPE_FLOAT)
{
// float -> Fix32
if (rdo)
{
m_query[(CapType)v] = msgSupportGetAll;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
std::vector<float> all;
Fix32 val;
sane_opts::get_opts<float> op(NULL, &all);
scanner_->get_value((int)type, sane_opts::set_opt_value<float>, &op);
op.re_order();
copy_type(val, all[sane_opts::RANGE_POS_CURRENT]);
type = data.type();
data = Capability::createOneValue<Fix32>(type, val);
return success();
};
}
else
{
m_query[(CapType)v] = msgSupportGetAllSetReset;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
std::vector<float> all;
value_limit lmt;
sane_opts::get_opts<float> op(&lmt, &all);
scanner_->get_value((int)type, sane_opts::set_opt_value<float>, &op);
op.re_order();
if (msg == Msg::Set || msg == Msg::Reset)
{
float val = .0f;
copy_type(val, data.currentItem<Fix32>());
if (msg == Msg::Reset)
val = all[sane_opts::RANGE_POS_DEFAULT];
double dbv = val;
int ret = scanner_->set_value((int)type, &dbv);
Fix32 fv;
val = dbv;
copy_type(fv, val);
type = data.type();
data = Capability::createOneValue<Fix32>(type, fv);
if (ret)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(ret) };
else
return success();
}
else if (msg == Msg::GetCurrent || msg == Msg::GetDefault)
{
Fix32 val;
if (msg == Msg::GetCurrent)
copy_type(val, all[sane_opts::RANGE_POS_CURRENT]);
else
copy_type(val, all[sane_opts::RANGE_POS_DEFAULT]);
type = data.type();
data = Capability::createOneValue<Fix32>(type, val);
return success();
}
else
{
type = data.type();
if (lmt == VAL_LIMIT_ENUM)
{
std::list<Fix32> vals;
UInt32 ni = distance<float>(all, all[sane_opts::RANGE_POS_CURRENT]),
ii = distance<float>(all, all[sane_opts::RANGE_POS_DEFAULT]);
for (size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < all.size(); ++i)
{
Fix32 t;
copy_type(t, all[i]);
vals.push_back(t);
}
data = Capability::createEnumeration<Fix32>(type, vals, ni, ii);
}
else if (lmt == VAL_LIMIT_RANGE)
{
Fix32 now, init, lower, upper, step;
copy_type(now, all[sane_opts::RANGE_POS_CURRENT]);
copy_type(init, all[sane_opts::RANGE_POS_DEFAULT]);
copy_type(lower, all[sane_opts::RANGE_POS_LOWER]);
copy_type(upper, all[sane_opts::RANGE_POS_UPPER]);
copy_type(step, all[sane_opts::RANGE_POS_STEP]);
data = Capability::createRange<Fix32>(type, lower, upper, step, now, init);
}
else
{
Fix32 val;
copy_type(val, all[sane_opts::RANGE_POS_CURRENT]);
data = Capability::createOneValue<Fix32>(type, val);
}
return success();
}
};
}
}
else if (type == VAL_TYPE_STR)
{
// std::string -> Str255
if (v == SANE_OPT_ID_LOGIN || v == SANE_OPT_ID_LOGOUT)
{
m_query[(CapType)v] = MsgSupport::Set;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
if (msg != Msg::Set)
{
if (msg == Msg::Get)
{
data = Capability::createArray<Str32>(type, 2);
return success();
}
return { ReturnCode::Failure, ConditionCode::CapUnsupported };
}
Str32 n(data.array<Str32>().at(0)),
p(data.array<Str32>().at(1));
char buf[64] = { 0 };
int ret = 0;
strcpy(buf, n.data());
strcpy(buf + 32, p.data());
ret = scanner_->set_value((int)type, buf);
if (ret == SCANNER_ERR_OK)
return success();
return { RC::Failure, huagao_ds::condition_code_from_hg_error(ret) };
};
}
else if (v == SANE_OPT_ID_DRIVER_LOG || v == SANE_OPT_ID_DEVICE_LOG)
{
m_query[(CapType)v] = MsgSupport::GetCurrent | MsgSupport::Reset;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
if (msg == Msg::GetCurrent || msg == Msg::Get)
{
Str255 str;
if (msg == Msg::Get) { data = Capability::createOneValue<Str255>(type, str); return success(); }
std::string path("");
int len = 0;
copy_type(path, data.currentItem<Str255>());
len = path.length();
if (scanner_->get_value((int)type, &path[0], &len)) return success(); else return { RC::Failure, CC::OperationError };
}
else if (msg == Msg::Reset)
{
int tmp = 0, ret = scanner_->set_value((int)type, &tmp);
if (ret == SCANNER_ERR_OK)
return success();
return { RC::Failure, huagao_ds::condition_code_from_hg_error(ret) };
}
return { ReturnCode::Failure, ConditionCode::CapUnsupported };
};
}
else if (rdo)
{
m_query[(CapType)v] = msgSupportGetAll;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
std::vector<std::string> all;
Str255 val;
sane_opts::get_opts<std::string> op(NULL, &all);
scanner_->get_value((int)type, sane_opts::set_opt_value<std::string>, &op);
op.re_order();
copy_type(val, all[sane_opts::RANGE_POS_CURRENT]);
type = data.type();
data = Capability::createOneValue<Str255>(type, val);
return success();
};
}
else
{
m_query[(CapType)v] = msgSupportGetAllSetReset;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
std::vector<std::string> all;
value_limit lmt;
sane_opts::get_opts<std::string> op(&lmt, &all);
scanner_->get_value((int)type, sane_opts::set_opt_value<std::string>, &op);
op.re_order();
if (msg == Msg::Set || msg == Msg::Reset)
{
std::string val("");
if (msg == Msg::Set)
copy_type(val, data.currentItem<Str255>());
else
val = all[sane_opts::RANGE_POS_DEFAULT];
val.resize(255);
int ret = scanner_->set_value((int)type, &val[0]);
Str255 rv;
copy_type(rv, val);
type = data.type();
data = Capability::createOneValue<Str255>(type, rv);
if (ret)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(ret) };
else
return success();
}
else if (msg == Msg::GetCurrent || msg == Msg::GetDefault)
{
Str255 val;
if (msg == Msg::GetCurrent)
copy_type(val, all[sane_opts::RANGE_POS_CURRENT]);
else
copy_type(val, all[sane_opts::RANGE_POS_DEFAULT]);
type = data.type();
data = Capability::createOneValue<Str255>(type, val);
return success();
}
else
{
type = data.type();
if (lmt == VAL_LIMIT_ENUM)
{
std::list<Str255> vals;
UInt32 ni = distance<std::string>(all, all[sane_opts::RANGE_POS_CURRENT]),
ii = distance<std::string>(all, all[sane_opts::RANGE_POS_DEFAULT]);
for(size_t i = sane_opts::RANGE_POS_ENUM_BEGIN; i < all.size(); ++i)
{
Str255 t;
copy_type(t, all[i]);
vals.push_back(t);
}
data = Capability::createEnumeration<Str255>(type, vals, ni, ii);
}
else
{
Str255 val;
copy_type(val, all[sane_opts::RANGE_POS_CURRENT]);
data = Capability::createOneValue<Str255>(type, val);
}
return success();
}
};
}
}
else if (type == VAL_TYPE_STREAM)
{
if (rdo)
{
m_query[(CapType)v] = msgSupportGetAll;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
std::vector<std::string> all;
sane_opts::get_opts<std::string> op(NULL, &all);
scanner_->get_value((int)type, sane_opts::set_opt_value<std::string>, &op);
op.re_order();
type = data.type();
if (all[sane_opts::RANGE_POS_CURRENT].length())
{
size_t ind = 0;
data = Capability::createArray<Int8>(type, all[sane_opts::RANGE_POS_CURRENT].length());
for (auto& c : all[sane_opts::RANGE_POS_CURRENT])
data.array<Int8>()[ind++] = (Int8)c;
return success();
}
else
return bummer();
};
}
else
{
m_query[(CapType)v] = msgSupportGetAllSetReset;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
std::vector<std::string> all;
sane_opts::get_opts<std::string> op(NULL, &all);
scanner_->get_value((int)type, sane_opts::set_opt_value<std::string>, &op);
op.re_order();
if (msg == Msg::Set || msg == Msg::Reset)
{
if (data.array<Int8>().size() < all[sane_opts::RANGE_POS_CURRENT].length())
return badValue();
Int8* ptr = &data.array<Int8>().at(0);
int ret = scanner_->set_value((int)type, ptr);
if (ret)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(ret) };
else
return success();
}
else
{
if (all[sane_opts::RANGE_POS_CURRENT].length())
{
size_t ind = 0;
type = data.type();
data = Capability::createArray<Int8>(type, all[sane_opts::RANGE_POS_CURRENT].length());
for (auto& c : all[sane_opts::RANGE_POS_CURRENT])
data.array<Int8>()[ind++] = c;
return success();
}
else
return bummer();
}
};
}
}
else if (type == VAL_TYPE_BUTTON)
{
m_query[(CapType)v] = MsgSupport::Set;
m_caps[(CapType)v] = [this](Twpp::CapType type, Msg msg, Capability& data) -> Result {
if (msg == Msg::Set)
{
int val = 0,
ret = scanner_->set_value((int)type, &val);
if (ret)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(ret) };
else
return success();
}
return { ReturnCode::Failure, ConditionCode::BadProtocol };
};
}
}
}
std::string huagao_ds::get_config_file(void)
{
#if defined(WIN32) || defined(_WIN64)
char* tmp = getenv("LOCALAPPDATA");
if (tmp)
{
std::string str("");
std::string path(tmp);
path += std::string("\\") + PRODUCT_VENDOR + "Scan\\config\\debug.cfg";
return std::move(path);
}
else
{
char path[MAX_PATH] = { 0 }, * name = NULL;
GetModuleFileNameA(me_, path, _countof(path) - 1);
name = strrchr(path, '\\');
if (name++ == NULL)
name = path;
strcpy(name, "debug.cfg");
return path;
}
#else
return std::move(utils::get_local_data_path() + "/config/debug.cfg");
#endif
}
std::string huagao_ds::get_config_value(const char* sec, const char* key)
{
char v[256] = { 0 };
std::string cfg_f(get_config_file());
if(!cfg_f.empty())
GetPrivateProfileStringA(sec, key, "", v, _countof(v) - 1, get_config_file().c_str());
return v;
}
DWORD huagao_ds::get_config_number(const char* sec, const char* key, DWORD def, DWORD empty)
2023-07-10 07:28:45 +00:00
{
std::string cfg_f(get_config_file());
if (cfg_f.empty())
return empty;
2023-07-10 07:28:45 +00:00
else
return GetPrivateProfileIntA(sec, key, def, get_config_file().c_str());
2023-07-10 07:28:45 +00:00
}
int huagao_ds::handle_scanner_event(int ev, bool from_event_proc)
{
static int count_0 = 0;
ReturnCode rc = ReturnCode::Success;
int ret = 0;
if (ev == 0)
count_0++;
else
{
char msg[128] = { 0 };
if (count_0)
sprintf(msg, "[%x]handle_scanner_event(0x0 +%d)\r\nds::eventProcess(0x%x)\r\n", GetCurrentThreadId(), count_0, ev);
else
sprintf(msg, "[%x]handle_scanner_event(0x%x)\r\n", GetCurrentThreadId(), ev);
utils::log_info(msg, 0);
count_0 = 0;
}
switch (ev)
{
case SANE_EVENT_WORKING:
scanner_status_ = SCANNER_STATUS_SCANNING;
rc = notifyXferReady();
//if (!Twpp::success(rc))
//{
// char msg[128] = { 0 };
// sprintf(msg, _countof(msg) - 1, "[%x]Warning: change state to XferReady failed with error %d while in state(%d), STOP scanning ...\r\n", GetCurrentThreadId(), rc, state());
// utils::log_info(msg, 0);
// // we stop scanning here ...
// scanner_->stop();
//}
break;
case SANE_EVENT_UI_CLOSE_SETTING:
scanner_->ui_hide();
if (notify_close_ == NOTIFY_ALWAYS)
{
utils::to_log(1, "close setting ui and notify close immediately.\r\n");
rc = notifyCloseCancel();
}
else if (notify_close_ == NOTIFY_NONE)
{
utils::to_log(1, "close setting ui and notify close passively (wait eventProcess to do).\r\n");
notfify_close_ = true;
}
else // if (notify_close_ == NOTIFY_AUTO)
{
utils::to_log(1, "close setting ui and notify close in auto mode.\r\n");
//if (has_event_called_)
// notfify_close_ = true;
//else
// rc = notifyCloseCancel();
notfify_close_ = true;
if (notify_close_thread_.get() && notify_close_thread_->joinable())
notify_close_thread_->join();
notify_close_thread_.reset(new std::thread(&huagao_ds::notify_close_thread, this));
}
//if(main_thread_id_ == GetCurrentThreadId())
// rc = notifyCloseCancel();
//else
//{
// HANDLE thrd = OpenThread(THREAD_ALL_ACCESS, FALSE, main_thread_id_);
// int err = -1;
// if (thrd)
// {
// if (QueueUserAPC(&huagao_ds::notify_close, thrd, (ULONG_PTR)this))
// err = 0;
// else
// err = GetLastError();
// CloseHandle(thrd);
// }
// utils::to_log(3, "Notify close setting UI in different thread(%x), invoke 'notifyCloseCancel' in enable-thread %x(%x), result %d\r\n", GetCurrentThreadId(), main_thread_id_, thrd, err);
//}
//if (!Twpp::success(rc))
//{
// rc = notifyXferReady(); // 好分数需要再通知 FAINT :( - modified on 2022-10-20
// if (!Twpp::success(rc))
// {
// char msg[128] = { 0 }, unk[20] = { 0 };
// sprintf(msg, _countof(msg) - 1, "[%x]yscan: notifyXferReady failed after setting UI closed with error %d\r\n", GetCurrentThreadId(), rc);
// utils::log_info(msg, 0);
// }
// rc = notifyCloseCancel();
//}
show_setting_ = false;
break;
case SANE_EVENT_UI_CLOSE_CANCEL:
//scanner_->stop();
//notifyCloseCancel(); // 修复点击进度<E8BF9B>?取消"按钮UI不能正常结束的BUG - added on 2023-02-14
//break;
case SANE_EVENT_UI_CLOSE_NORMAL:
case SANE_EVENT_SCAN_FINISHED:
//scanner_->ui_hide();
scanner_status_ = SCANNER_STATUS_STOPPED; // notifyCloseCancel is not need, because it done in EndXfer
//if(show_setting_)
// notifyCloseCancel();
// notifyCloseOk();
break;
case SANE_EVENT_UI_SCAN_COMMAND:
scanner_->ui_show_progress(NULL, m_bIndicator);
scanner_status_ = SCANNER_STATUS_SCAN_1;
app_trigger_event_ = false;
if ((ret = scanner_->start()))
{
char msg[128] = { 0 }, unk[20] = { 0 };
sprintf(msg, "[%x - %s]Fatal: start scanning from setting UI failed with error %d\r\n", GetCurrentThreadId(), desc_state(state(), unk), ret);
utils::log_info(msg, 1);
scanner_status_ = SCANNER_STATUS_STOPPED;
if(bUiOnly_)
rc = notifyCloseCancel();
if (Twpp::success(rc))
{
scanner_status_ = SCANNER_STATUS_READY;
}
else
{
sprintf(msg, "[%x - %s]Warning: notifyCloseCancel failed with error %d after start scanning failed\r\n", GetCurrentThreadId(), desc_state(state(), unk), rc);
utils::log_info(msg, 1);
}
}
else
{
notifyXferReady(); // scan from UI, should notify this state mannually
}
break;
}
return 0;
}
int huagao_ds::get_scanned_image_count(DWORD timeout)
{
int cnt = scanner_->get_scanned_images(timeout);
//if (cnt == -1)
//{
// // This is a special value indicates the scanning is over
// cnt = 0;
// scanner_->ui_hide();
// notifyCloseCancel();
//}
return cnt;
}
void huagao_ds::trigger_ProcessEvent(Twpp::DataGroup dg, Twpp::Dat dat, Twpp::Msg msg)
{
ReturnCode rc;
if (state() == DsState::Enabled && scanner_status_ >= SCANNER_STATUS_SCAN_1) // in scanning events ...
{
// here ensure APP enter into XferImage process ...
if (!app_trigger_event_ && scanner_status_ == SCANNER_STATUS_STOPPED)
{
// scanning stopped, reset APP state to ready ...
scanner_status_ = SCANNER_STATUS_READY;
rc = notifyCloseCancel();
if (!Twpp::success(rc))
{
char info[128] = { 0 }, unk[20] = { 0 };
sprintf(info, "[%x]Warning: notifyCloseCancel failed with error %s!\r\n", GetCurrentThreadId(), desc_return_code(rc, unk));
utils::log_info(info, 1);
}
}
else
{
// start scanning, expect frist TRIPLE is ProcessEvent ...
if (dg == DataGroup::Control && dat == Dat::Event && msg == Msg::ProcessEvent && scanner_status_ == SCANNER_STATUS_SCAN_1)
{
app_trigger_event_ = true; // nothing else to do
utils::log_info("Good! first event is (Control, Event, ProcessEvent) after start scanning ^_^.\r\n", 1);
}
else if(!app_trigger_event_)
{
int ev = 0;
if (scanner_status_ == SCANNER_STATUS_SCAN_1)
utils::log_info("Sorry, first event is not (Control, Event, ProcessEvent) after start scanning, we takeover it!\r\n", 1);
if (scanner_.get())
{
ev = scanner_->get_event();
if (ev)
handle_scanner_event(ev, true);
}
}
}
}
else if (state() >= DsState::XferReady && scanner_status_ == SCANNER_STATUS_STOPPED)
{
// here ensure APP return to ready state ...
if (scanner_.get() && scanner_->get_scanned_images(0) == 0)
{
rc = notifyCloseCancel();
if (!Twpp::success(rc))
{
char info[128] = { 0 }, unk[20] = { 0 };
sprintf(info, "[%x]Warning: notifyCloseCancel failed with error %s when scanner is stopped!\r\n", GetCurrentThreadId(), desc_return_code(rc, unk));
utils::log_info(info, 1);
}
}
}
}
bool huagao_ds::take_and_reset_notify_close_flag(void)
{
std::lock_guard<std::mutex> lock(notify_close_lock_);
bool notify = notfify_close_;
if (notfify_close_)
notfify_close_ = false;
return notify;
}
void huagao_ds::notify_close_thread(void)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
if (take_and_reset_notify_close_flag())
{
notifyCloseCancel();
utils::to_log(1, "Trigger notifyCloseCancel in custom thread!\r\n");
}
else
{
utils::to_log(1, "Good! Trigger notifyCloseCancel in eventProcess ^_^\r\n");
}
}