twain3.0/huagao/huagaods.cpp

1884 lines
68 KiB
C++
Raw Normal View History

#include "stdafx.h"
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#include <memory>
#include "huagaods.hpp"
#include "twglue.hpp"
#include "resource.h"
#include "CTwainUI.h"
#include "CIndicatorDlg.h"
#include "Device/PublicFunc.h"
#include "Device/GScanO200.h"
#include "Device/filetools.h"
#include "Device/GScanVirtual.h"
#include <list>
#include <map>
#include "Device/JsonConfig.h"
//custom define caps enum
enum class CapTypeEx : unsigned short {
Base = 0x8000,//custom caps enum value must bigger than CapTypeEx::Base value,otherwise might make conflict
TwEx_IMultiOutputRed = 0x8026,
TwEx_IFillHole = 0x8018,
TwEx_IFillHoleRatio = 0x8092,
TwEx_IFillBackground = 0x8004,
TwEx_IBackRotate180 = 0x8005,
TwEx_IAutoDiscardBlankVince = 0x8091,
TwEx_IEnhanceColor = 0x8007,
TwEx_HardwareVersion = 0x8025,
TwEx_ScrewDetectEnable = 0x8006,
TwEx_ScrewLevel = 0x8021,
TwEx_Sharpen = 0x8022,
TwEx_DBAreaNum =0x8027,
TwEx_DBDevnMax = 0x8028,
TwEx_StableDetectEnable = 0x8090
};
using namespace Twpp;
using namespace std::placeholders;
#define TWPP_ENTRY_MFC(SourceClass)\
extern "C" TWPP_DETAIL_EXPORT Twpp::ReturnCode TWPP_DETAIL_CALLSTYLE \
DS_Entry(Twpp::Identity* origin, Twpp::DataGroup dg, Twpp::Dat dat, Twpp::Msg msg, void* data){\
AFX_MANAGE_STATE(AfxGetStaticModuleState()); \
static_assert(\
std::is_base_of<Twpp::SourceFromThis<SourceClass, false>, SourceClass>::value ||\
std::is_base_of<Twpp::SourceFromThis<SourceClass, true>, SourceClass>::value,\
"Class " #SourceClass " is not derived from SourceFromThis."\
);\
return SourceClass::entry(origin, dg, dat, msg, data);\
}
TWPP_ENTRY_MFC(HuagaoDs)
static constexpr const Identity srcIdent(
2020-04-03 01:31:18 +00:00
Version(3, 3, Language::English, Country::CzechRepublic, "v3.3.1.6"),
DataGroup::Image,
"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD>Ƽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>޹<EFBFBD>˾",
"G200 Series",
2020-04-03 01:31:18 +00:00
"HUAGOSCAN TWAIN"
#if defined(_MSC_VER)
""
#elif defined(__GNUC__)
" GCC"
#elif defined(__clang__)
" CLang"
#endif
);
// lets just simulate uniform resolution for both axes
static constexpr UInt32 RESOLUTIONX = 85;
static std::unique_ptr<CWinApp> application(new CWinApp());
static list<float> resList = { 100.0,150.0,200.0,240.0,300.0 };
static list<UInt16> paperSizeList = { (UInt16)PaperSize::A3,(UInt16)PaperSize::A4,(UInt16)PaperSize::A5,(UInt16)PaperSize::A6,
(UInt16)PaperSize::IsoB4,(UInt16)PaperSize::IsoB5,(UInt16)PaperSize::IsoB6,
(UInt16)PaperSize::UsLetter,(UInt16)PaperSize::UsLegal,(UInt16)PaperSize::UsLedger,
(UInt16)PaperSize::MaxSize,(UInt16)PaperSize::None,(UInt16)PaperSize::UsStatement };
static list<float> imageRotateList = {0.0,90.0,180.0,270.0};
static map<unsigned int, CString> noticeMsgMap = { {OPEN_COVER,_T("ɨ<EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><EFBFBD><EFBFBD>")},
{NO_FEED,_T("<EFBFBD><EFBFBD>ֽ<EFBFBD><EFBFBD>")},
{FEED_IN_ERROR,_T("<EFBFBD><EFBFBD>ֽʧ<EFBFBD>ܣ<EFBFBD>")},
{PAPER_JAM,_T("<EFBFBD><EFBFBD>ֽ<EFBFBD><EFBFBD>")},
{DETECT_DOUBLE_FEED,_T("˫<EFBFBD>ţ<EFBFBD>")},
{DETECT_STAPLE,_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")},
{PAPER_SKEW,_T("ֽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD>")},
{COUNT_MODE,_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˳<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ<EFBFBD><EFBFBD>")},
{HARDWARE_ERROR,_T("Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")},
{FPGA_ERROR,_T("FPGA <20>")},
{USB_DISCONNECTED,_T("USB<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")}
};
static void DeleteWnd(CDialog* pWnd) {
if (pWnd && pWnd->GetSafeHwnd()) {
pWnd->DestroyWindow();
delete pWnd;
}
}
static std::unique_ptr<CDialog, void(*)(CDialog*)> guiTwain(nullptr, DeleteWnd);
#if TWPP_DETAIL_OS_WIN
static std::unique_ptr<CDialog, void(*)(CDialog*)> guiBridge(nullptr, DeleteWnd);
#endif
static std::unique_ptr<CDialogEx, void(*)(CDialog*)> guiIndicator(nullptr, DeleteWnd);
#ifndef HG_VIRTUAL
static std::unique_ptr<IGScan> scanner(new GScanO200());
#else
static std::unique_ptr<IGScan> scanner(new GScanVirtual());
#endif
HuagaoDs::HuagaoDs()
: m_scanparam(new GScanCap)
{
/*string ss1= getOSInfo();
string ss2=getManufactureID();
string ss3=getCpuType();
string ss4= getMemoryInfo();
DWORD dwNum;
CString aas[10];
GetDiskInfo(dwNum,aas);*/
initGScanCap();
}
HuagaoDs::~HuagaoDs()
{
}
const Identity& HuagaoDs::defaultIdentity() noexcept{
// remember, we return a reference, therefore the identity must not be placed on the stack of this method
return srcIdent;
}
Result HuagaoDs::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
return Base::call(origin, dg, dat, msg, data);
} catch (const CapabilityException&){
return badValue();
}
}
// some helper functions to handle capability stuff
template<typename T>
static Result oneValGet(Msg msg, Capability& data, const T& value){
switch (msg){
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
data = Capability::createOneValue(data.type(), value);
return {};
default:
return {ReturnCode::Failure, ConditionCode::CapBadOperation};
}
}
static Result oneValGetString(Msg msg, Capability& data, std::string value) {
Str255 str;
str.setData(value.c_str(), value.size());
return oneValGet(msg, data, str);
}
template<typename T>
static Result enmGet(Msg msg, Capability& data, const T& value){
switch (msg){
case Msg::Get:
data = Capability::createEnumeration(data.type(), {value});
return {};
case Msg::GetCurrent:
case Msg::GetDefault:
data = Capability::createOneValue(data.type(), value);
return {};
default:
return {ReturnCode::Failure, ConditionCode::CapBadOperation};
}
}
template<typename T>
static Result oneValGetSet(Msg msg, Capability& data, T& value, const T& def){
switch (msg){
case Msg::Reset:
value = def;
// fallthrough
case Msg::Get:
case Msg::GetCurrent:
data = Capability::createOneValue(data.type(), value);
return {};
case Msg::GetDefault:
data = Capability::createOneValue(data.type(), def);
return {};
case Msg::Set:
value = data.currentItem<T>();
return {};
default:
return {ReturnCode::Failure, ConditionCode::CapBadOperation};
}
}
template<typename T>
static Result oneValGetSetConst(Msg msg, Capability& data, const T& def){
switch (msg){
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault:
case Msg::Reset:
data = Capability::createOneValue(data.type(), def);
return {};
case Msg::Set:
return data.currentItem<T>() == def ?
Result() : Result(ReturnCode::Failure, ConditionCode::BadValue);
default:
return {ReturnCode::Failure, ConditionCode::CapBadOperation};
}
}
template<typename T>
static Result enmGetSetConst(Msg msg, Capability& data, const T& def){
switch (msg){
case Msg::Get:
data = Capability::createEnumeration(data.type(), {def});
return {};
case Msg::GetCurrent:
case Msg::GetDefault:
case Msg::Reset:
data = Capability::createOneValue(data.type(), def);
return {};
case Msg::Set:
return data.currentItem<T>() == def ?
Result() : Result(ReturnCode::Failure, ConditionCode::BadValue);
default:
return {ReturnCode::Failure, ConditionCode::CapBadOperation};
}
}
/// Shortcut for Result(RC::Failure, CC::CheckDeviceOnline).
static constexpr Result checkDeviceOnline() noexcept {
return { ReturnCode::Failure,ConditionCode::CheckDeviceOnline };
}
//void HuagaoDs::updateScanParam()
//{
//
//}
Result HuagaoDs::capCommon(const Identity&, Msg msg, Capability& data){
auto it = m_caps.find(data.type());
if (it != m_caps.end()){
return (it->second)(msg, data);
}
return capUnsupported();
}
Result HuagaoDs::capabilityGet(const Identity& origin, Capability& data){
return capCommon(origin, Msg::Get, data);
}
Result HuagaoDs::capabilityGetCurrent(const Identity& origin, Capability& data){
return capCommon(origin, Msg::GetCurrent, data);
}
Result HuagaoDs::capabilityGetDefault(const Identity& origin, Capability& data){
return capCommon(origin, Msg::GetDefault, data);
}
Result HuagaoDs::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 HuagaoDs::capabilityReset(const Identity& origin, Capability& data){
return capCommon(origin, Msg::Reset, data);
}
Result HuagaoDs::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 HuagaoDs::capabilitySet(const Identity& origin, Capability& data){
return capCommon(origin, Msg::Set, data);
}
Result HuagaoDs::eventProcess(const Identity&, Event& event){
// Qt needs to process its events, otherwise the GUI will appear frozen
// this is Windows-only method, Linux and macOS behave differently
if (guiTwain) {
// // QApplication::processEvents(); - TODO: needs more investigation; results in freeze when attempting to scan using old DSM
// QApplication::sendPostedEvents();
guiTwain->SendMessage((UINT)(event.message()));
}
event.setMessage(Msg::Null);
return {ReturnCode::NotDsEvent, ConditionCode::Success};
}
Result HuagaoDs::identityOpenDs(const Identity&){
bmpData.resize(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
BITMAPINFOHEADER& bmInfo = *((BITMAPINFOHEADER*)header());
bmInfo.biHeight = 2000;
bmInfo.biWidth = 2000;
bmInfo.biBitCount = 24;
updataGscanCap();
scanner->open(0x064B, 0x7823);
if (!scanner->IsConnected()) {
MessageBox(NULL, _T("δ<EFBFBD>ҵ<EFBFBD>ɨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD>USB<53><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>ͨ!"), _T("<EFBFBD><EFBFBD>ʾ"), MB_SYSTEMMODAL | MB_OK | MB_ICONINFORMATION);
return checkDeviceOnline();
}
// init caps
// there are caps a minimal source must support
// query -> says which operations a cap supports
// caps -> has handler for each specific cap
m_query[CapType::SupportedCaps] = msgSupportGetAll;
m_caps[CapType::SupportedCaps] = [this](Msg msg, Capability& data){
switch (msg){
case Msg::Get:
case Msg::GetCurrent:
case Msg::GetDefault: {
data = Capability::createArray<CapType::SupportedCaps>(m_caps.size());
auto arr = data.array<CapType::SupportedCaps>();
UInt32 i = 0;
for (const auto& kv : m_caps){
arr[i] = kv.first;
i++;
}
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::UiControllable] = msgSupportGetAll;
m_caps[CapType::UiControllable] = std::bind(enmGet<Bool>, _1, _2, Bool(true));
m_query[CapType::DeviceOnline] = msgSupportGetAll;
m_caps[CapType::DeviceOnline] = std::bind(enmGet<Bool>, _1, _2, Bool(scanner->IsConnected()));
m_query[CapType::XferCount] = msgSupportGetAllSetReset;
m_caps[CapType::XferCount] = [this](Msg msg, Capability& data) -> Result{
if (msg == Msg::Set){
auto item = data.currentItem<Int16>();
if (item > 65535 || item < -1){
return badValue();
}
m_capXferCount = item;
return success();
}
auto ret = oneValGetSet<Int16>(msg, data, m_capXferCount, -1);
if (Twpp::success(ret) && m_capXferCount == 0){
m_capXferCount = -1;
m_scanparam->scannum = m_capXferCount;
return {ReturnCode::CheckStatus, ConditionCode::BadValue};
}
return ret;
};
m_query[CapType::ICompression] = msgSupportGetAllSetReset;
m_caps[CapType::ICompression] = std::bind(enmGetSetConst<Compression>, _1, _2, Compression::None);
m_query[CapType::IBitDepth] = msgSupportGetAllSetReset;
m_caps[CapType::IBitDepth] = std::bind(enmGetSetConst<UInt16>, _1, _2, UInt16(header()->biBitCount));
m_query[CapType::IBitOrder] = msgSupportGetAllSetReset;
m_caps[CapType::IBitOrder] = std::bind(enmGetSetConst<BitOrder>, _1, _2, BitOrder::MsbFirst);
m_query[CapType::IPlanarChunky] = msgSupportGetAllSetReset;
m_caps[CapType::IPlanarChunky] = std::bind(enmGetSetConst<PlanarChunky>, _1, _2, PlanarChunky::Chunky);
m_query[CapType::IPhysicalWidth] = msgSupportGetAll;
m_caps[CapType::IPhysicalWidth] = std::bind(oneValGet<Fix32>, _1, _2, Fix32(static_cast<float>(header()->biWidth) / RESOLUTIONX));
m_query[CapType::IPhysicalHeight] = msgSupportGetAll;
m_caps[CapType::IPhysicalHeight] = std::bind(oneValGet<Fix32>, _1, _2, Fix32(static_cast<float>(header()->biHeight) / RESOLUTIONX));
m_query[CapType::IPixelFlavor] = msgSupportGetAllSetReset;
m_caps[CapType::IPixelFlavor] = std::bind(enmGetSetConst<PixelFlavor>, _1, _2, PixelFlavor::Chocolate);
m_query[CapType::IPixelType] = msgSupportGetAllSetReset;
m_caps[CapType::IPixelType] = [this](Msg msg, Capability& data) -> Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::IPixelType>(
{ PixelType::BlackWhite, PixelType::Gray, PixelType::Rgb}, (int)(m_scanparam->pixtype), (int)PixelType::Gray);
return success();
case Msg::Reset:
m_scanparam->pixtype = (byte)PixelType::Gray;
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IPixelType>((PixelType)(m_scanparam->pixtype));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IPixelType>(PixelType::Gray);
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IPixelType>();
m_scanparam->pixtype = (int)mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::IUnits] = msgSupportGetAllSetReset;
m_caps[CapType::IUnits] = std::bind(enmGetSetConst<Unit>, _1, _2, Unit::Inches);
m_query[CapType::IXferMech] = msgSupportGetAllSetReset;
m_caps[CapType::IXferMech] = [this](Msg msg, Capability& data) -> Result{
switch (msg){
case Msg::Get:
data = Capability::createEnumeration<CapType::IXferMech>(
{XferMech::Native, XferMech::Memory}, m_capXferMech == XferMech::Native ? 0 : 1, 0);
return success();
case Msg::Reset:
m_capXferMech = XferMech::Native;
// fallthrough
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IXferMech>(m_capXferMech);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IXferMech>(XferMech::Native);
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IXferMech>();
if (mech == XferMech::Native || mech == XferMech::Memory){
m_capXferMech = mech;
return success();
} else {
return badValue();
}
}
default:
return capBadOperation();
}
};
m_query[CapType::IXResolution] = msgSupportGetAllSetReset;
m_caps[CapType::IXResolution] = [this](Msg msg, Capability& data){
switch (msg){
case Msg::Get: {
int index = -1;
std::list<float>::iterator it = resList.begin();
int i = 0;
for (it,i; it != resList.end(); ++it, i++) {
if (*it == m_scanparam->resolution_dst) {
index = i;
break;
}
}
data = Capability::createEnumeration(data.type(), { Fix32(100.0),Fix32(150.0),Fix32(200.0),Fix32(240.0),Fix32(300.0) }, index==-1?2:index, 2);
return success();
}
case Msg::GetCurrent: {
data = Capability::createOneValue(data.type(), Fix32(m_scanparam->resolution_dst));
return success();
}
case Msg::GetDefault:
case Msg::Reset:{
data = Capability::createOneValue(data.type(), Fix32(200.0));
return success();
}
case Msg::Set:{
auto res = data.currentItem<Fix32>();
std::list<float>::iterator resIter= resList.begin();
bool contains = false;
for (resIter; resIter != resList.end(); resIter++) {
if (*resIter == res) {
contains = true;
break;
}
}
if (contains) {
m_scanparam->resolution_dst = (float)res;
return success();
}
return badValue();
}
default:
return capBadOperation();
}
};
m_query[CapType::IYResolution] = msgSupportGetAllSetReset;
m_caps[CapType::IYResolution] = m_caps[CapType::IXResolution];
m_query[CapType::IXNativeResolution] = msgSupportGetAll;
m_caps[CapType::IXNativeResolution] = std::bind(enmGet<Fix32>, _1, _2, Fix32(200.0));
m_query[CapType::IYNativeResolution] = msgSupportGetAll;
m_caps[CapType::IYNativeResolution] = m_caps[CapType::IXNativeResolution];
m_query[CapType::FeederLoaded] = msgSupportGetAll;
m_caps[CapType::FeederLoaded] = std::bind(enmGet<Bool>, _1, _2, Bool(scanner->Get_Scanner_PaperOn()));
m_query[CapType::ISupportedSizes] = msgSupportGetAllSetReset;
m_caps[CapType::ISupportedSizes] = [this](Msg msg, Capability& data) {
switch (msg) {
case Msg::Get: {
int index = -1;
std::list<UInt16>::iterator it = paperSizeList.begin();
int i = 0;
for (it, i; it != paperSizeList.end(); ++it, i++) {
if (*it == m_scanparam->papertype) {
index = i;
break;
}
}
data = Capability::createEnumeration(data.type(), { PaperSize::A3,PaperSize::A4,PaperSize::A5,
PaperSize::A6,PaperSize::IsoB4,PaperSize::IsoB5,
PaperSize::IsoB6,PaperSize::UsLetter,PaperSize::UsLegal,
PaperSize::UsLedger,PaperSize::MaxSize,PaperSize::None},
index == -1 ? 0 : index,
0);
return success();
}
case Msg::GetCurrent:
data = Capability::createOneValue(data.type(), UInt16(m_scanparam->papertype));
return success();
case Msg::GetDefault:
case Msg::Reset:
data = Capability::createOneValue(data.type(), UInt16(PaperSize::A3));
return success();
case Msg::Set: {
auto res = data.currentItem<UInt16>();
std::list<UInt16>::iterator resIter = paperSizeList.begin();
bool contains = false;
for (resIter; resIter != paperSizeList.end(); resIter++) {
if (*resIter == res) {
contains = true;
break;
}
}
if (contains) {
m_scanparam->papertype = (byte)res;
return success();
}
return badValue();
}
default:
return capBadOperation();
}
};
m_query[CapType::IOrientation] = msgSupportGetAllSetReset;
m_caps[CapType::IOrientation] = [this](Msg msg, Capability& data) -> Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::IOrientation>(
{ Orientation::Portrait, Orientation::Landscape,Orientation::AutoText}, m_scanparam->paperAlign,0);
return success();
case Msg::Reset:
m_scanparam->paperAlign = PaperAlign::Rot0;
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IOrientation>((Orientation)(m_scanparam->paperAlign));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IOrientation>(Orientation::Portrait);
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IOrientation>();
if(mech== Orientation::Landscape|| mech == Orientation::Portrait|| mech== Orientation::AutoText){
m_scanparam->paperAlign =(PaperAlign)mech;
return success();
}
return badValue();
}
default:
return capBadOperation();
}
};
m_query[CapType::IRotation] = msgSupportGetAllSetReset;
m_caps[CapType::IRotation] = [this](Msg msg, Capability& data) -> Result {
switch (msg) {
case Msg::Get:{
int index = -1;
std::list<float>::iterator it = imageRotateList.begin();
int i = 0;
for (it, i; it != imageRotateList.end(); ++it, i++) {
if (*it == m_scanparam->imageRotateDegree) {
index = i;
break;
}
}
data = Capability::createEnumeration<CapType::IRotation>(
{Fix32(0.0),Fix32(90.0),Fix32(180.0),Fix32(270.0)},
index==-1?0:index,
0);
return success();
}
case Msg::Reset:
m_scanparam->imageRotateDegree = 0.0;
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IRotation>(Fix32(m_scanparam->imageRotateDegree));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IRotation>(Fix32(0.0));
return success();
case Msg::Set: {
auto res = data.currentItem<Fix32>();
std::list<float>::iterator resIter = imageRotateList.begin();
bool contains = false;
for (resIter; resIter != imageRotateList.end(); resIter++) {
if (*resIter == res) {
contains = true;
break;
}
}
if (contains) {
m_scanparam->imageRotateDegree = (float)res;
return success();
}
return badValue();
}
default:
return capBadOperation();
}
};
m_query[CapType::SerialNumber] = msgSupportGetAll;
m_caps[CapType::SerialNumber] = std::bind(oneValGetString,_1,_2,scanner->GetSerialNum());
m_query[(CapType)(CapTypeEx::TwEx_HardwareVersion)] = msgSupportGetAll;
m_caps[(CapType)(CapTypeEx::TwEx_HardwareVersion)] = std::bind(oneValGetString, _1, _2, scanner->GetFWVersion());
m_query[CapType::Indicators] = msgSupportGetAllSetReset;
m_caps[CapType::Indicators] = [this](Msg msg, Capability& data) -> Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::Indicators>(
{ Bool(), Bool(true)}, Bool(m_bIndicator));
return success();
case Msg::Reset:
m_bIndicator = true;
// fallthrough
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::Indicators>(m_bIndicator);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::Indicators>(false);
return success();
case Msg::Set: {
auto show = data.currentItem<CapType::Indicators>();
m_bIndicator = show;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::EnableDsUiOnly] = msgSupportGetAll;
m_caps[CapType::EnableDsUiOnly] = std::bind(enmGet<Bool>, _1, _2, Bool(true));
m_query[CapType::PaperDetectable] = msgSupportGetAll;
m_caps[CapType::PaperDetectable] = std::bind(enmGet<Bool>, _1, _2, Bool(true));
m_query[CapType::FeederEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::FeederEnabled] = [this](Msg msg, Capability& data) -> Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::FeederEnabled>(
{ Bool(), Bool(true) }, Bool(m_bFeederEnabled));
return success();
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::FeederEnabled>(m_bFeederEnabled);
return success();
case Msg::Reset:
case Msg::GetDefault:
data = Capability::createOneValue<CapType::FeederEnabled>(true);
m_bFeederEnabled = true;
return success();
case Msg::Set: {
auto feederen = data.currentItem<CapType::FeederEnabled>();
m_bFeederEnabled = feederen;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::Duplex] = msgSupportGetAll;
m_caps[CapType::Duplex] = std::bind(oneValGet<Duplex>, _1, _2, Duplex::OnePass);
m_query[CapType::DuplexEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::DuplexEnabled] = [this](Msg msg, Capability& data) -> Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::DuplexEnabled>(
{ Bool(), Bool(true) }, Bool(m_scanparam->is_duplex));
return success();
case Msg::Reset:
m_scanparam->is_duplex = true;
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::DuplexEnabled>(m_scanparam->is_duplex);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::DuplexEnabled>(false);
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::DuplexEnabled>();
m_scanparam->is_duplex=mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::AutoFeed] = msgSupportGetAllSetReset;
m_caps[CapType::AutoFeed] = [this](Msg msg, Capability& data) -> Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::AutoFeed>(
{ Bool(), Bool(true) }, Bool(m_bAutoFeed));
return success();
case Msg::Reset:
m_bAutoFeed = true;
// fallthrough
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::AutoFeed>(m_bAutoFeed);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::AutoFeed>(true);
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::AutoFeed>();
m_bAutoFeed = mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::IImageFileFormat] = msgSupportGetAllSetReset;
m_caps[CapType::IImageFileFormat] = [this](Msg msg, Capability& data) -> Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::IImageFileFormat>(
{ ImageFileFormat::Bmp, ImageFileFormat::Tiff}, m_capImageFileFormat == ImageFileFormat::Bmp? 0 : 1, 0);
return success();
case Msg::Reset:
m_capImageFileFormat =ImageFileFormat::Bmp;
// fallthrough
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IImageFileFormat>(m_capImageFileFormat);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IImageFileFormat>(ImageFileFormat::Bmp);
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IImageFileFormat>();
if (mech == ImageFileFormat::Bmp || mech == ImageFileFormat::Tiff) {
m_capImageFileFormat =mech;
return success();
}
else {
return badValue();
}
}
default:
return capBadOperation();
}
};
//custom define
m_query[CapType::IAutomaticDeskew] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticDeskew] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::IAutomaticDeskew>(
{ Bool(), Bool(true) }, Bool(m_scanparam->autodescrew));
return success();
case Msg::Reset:
m_scanparam->autodescrew = true;
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IAutomaticDeskew>(m_scanparam->autodescrew);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IAutomaticDeskew>(true);
return success();
case Msg::Set: {
auto atuodsw = data.currentItem<CapType::IAutomaticDeskew>();
m_scanparam->autodescrew = (bool)atuodsw;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::IAutomaticRotate] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticRotate] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::IAutomaticRotate>(
{ Bool(), Bool(true) }, Bool(m_scanparam->is_autotext));
case Msg::Reset:
m_scanparam->is_autotext = false;
// fallthrough
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IAutomaticRotate>(m_scanparam->is_autotext);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IAutomaticRotate>(false);
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IAutomaticRotate>();
m_scanparam->is_autotext = (bool)mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::IAutomaticCropUsesFrame] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticCropUsesFrame] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::IAutomaticCropUsesFrame>(
{ Bool(), Bool(true) }, Bool(m_scanparam->is_autocrop));
return success();
case Msg::Reset:
m_scanparam->is_autocrop = false;
// fallthrough
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IAutomaticCropUsesFrame>(m_scanparam->is_autocrop);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IAutomaticCropUsesFrame>(false);
return success();
case Msg::Set: {
auto autocrop = data.currentItem<CapType::IAutomaticCropUsesFrame>();
m_scanparam->is_autocrop = (bool)autocrop;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::IAutoDiscardBlankPages] = msgSupportGetAllSetReset;
m_caps[CapType::IAutoDiscardBlankPages] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::IAutoDiscardBlankPages>({ DiscardBlankPages::Disabled,DiscardBlankPages::Auto},
m_scanparam->is_autodiscradblank_normal?1:0,
0);
return success();
case Msg::Reset:
m_scanparam->is_autodiscradblank_normal = false;
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IAutoDiscardBlankPages>(m_scanparam->is_autodiscradblank_normal? DiscardBlankPages::Auto: DiscardBlankPages::Disabled);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IAutoDiscardBlankPages>(DiscardBlankPages::Disabled);
return success();
case Msg::Set:{
auto mech = data.currentItem<CapType::IAutoDiscardBlankPages>();
m_scanparam->is_autodiscradblank_normal = mech == DiscardBlankPages::Auto;
return success();
}
default:
return capBadOperation();
}
};
/*costom caps*/
//<2F><><EFBFBD><EFBFBD><EFBFBD>հ<EFBFBD>ҳ<EFBFBD><D2B3>Ʊ
m_query[(CapType)(CapTypeEx::TwEx_IAutoDiscardBlankVince)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_IAutoDiscardBlankVince)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<Bool>((CapType)((CapType)(CapTypeEx::TwEx_IAutoDiscardBlankVince)), { Bool(),Bool(true) }, Bool(m_scanparam->is_autodiscradblank_vince), 0);
return success();
case Msg::Reset:
m_scanparam->is_autodiscradblank_vince = false;
case Msg::GetCurrent:
data = Capability::createOneValue<Bool>((CapType)((CapType)(CapTypeEx::TwEx_IAutoDiscardBlankVince)), m_scanparam->is_autodiscradblank_vince);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Bool>((CapType)((CapType)(CapTypeEx::TwEx_IAutoDiscardBlankVince)), Bool(false));
return success();
case Msg::Set: {
auto mech = data.currentItem<Bool>();
m_scanparam->is_autodiscradblank_vince = mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[(CapType)(CapTypeEx::TwEx_IBackRotate180)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_IBackRotate180)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<Bool>((CapType)(CapTypeEx::TwEx_IBackRotate180), { Bool(),Bool(true) }, Bool(m_scanparam->is_backrotate180), 0);
return success();
case Msg::Reset:
m_scanparam->is_backrotate180 = false;
case Msg::GetCurrent:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IBackRotate180), m_scanparam->is_backrotate180);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IBackRotate180), Bool(false));
return success();
case Msg::Set: {
auto mech = data.currentItem<Bool>();
m_scanparam->is_backrotate180 = mech;
return success();
}
default:
return capBadOperation();
}
};
//<2F><><EFBFBD>ڿ<EFBFBD>
m_query[(CapType)(CapTypeEx::TwEx_IFillBackground)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_IFillBackground)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<Bool>((CapType)(CapTypeEx::TwEx_IFillBackground), { Bool(),Bool(true) }, Bool(m_scanparam->fillbackground), 0);
return success();
case Msg::Reset:
m_scanparam->fillbackground = false;
case Msg::GetCurrent:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IFillBackground), m_scanparam->fillbackground);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IFillBackground), Bool(false));
return success();
case Msg::Set: {
auto mech = data.currentItem<Bool>();
m_scanparam->fillbackground = mech;
return success();
}
default:
return capBadOperation();
}
};
//<2F><EFBFBD><EEB4A9>
m_query[(CapType)(CapTypeEx::TwEx_IFillHole)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_IFillHole)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<Bool>((CapType)(CapTypeEx::TwEx_IFillHole), { Bool(),Bool(true) }, Bool(m_scanparam->fillhole.is_fillhole), 0);
return success();
case Msg::Reset:
m_scanparam->fillhole.is_fillhole = false;
case Msg::GetCurrent:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IFillHole), m_scanparam->fillhole.is_fillhole);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IFillHole), Bool(false));
return success();
case Msg::Set: {
auto mech = data.currentItem<Bool>();
m_scanparam->fillhole.is_fillhole = mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[(CapType)(CapTypeEx::TwEx_IFillHoleRatio)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_IFillHoleRatio)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createOneValue<Int32>((CapType)(CapTypeEx::TwEx_IFillHoleRatio), m_scanparam->fillhole.fillholeratio);
return success();
case Msg::Reset:
m_scanparam->fillhole.fillholeratio = 10;
case Msg::GetCurrent:
data = Capability::createOneValue<Int32>((CapType)(CapTypeEx::TwEx_IFillHoleRatio), m_scanparam->fillhole.fillholeratio);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Int32>((CapType)(CapTypeEx::TwEx_IFillHoleRatio), Int32(10));
return success();
case Msg::Set: {
auto mech = data.currentItem<Int32>();
if (mech > 0 && mech < 50) {
m_scanparam->fillhole.fillholeratio = (float)mech;
return success();
}
return badValue();
}
default:
return capBadOperation();
}
};
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
m_query[(CapType)(CapTypeEx::TwEx_IMultiOutputRed)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_IMultiOutputRed)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<Bool>((CapType)(CapTypeEx::TwEx_IMultiOutputRed), { Bool(),Bool(true) }, Bool(m_scanparam->multi_output_red), 0);
return success();
case Msg::Reset:
m_scanparam->multi_output_red = false;
case Msg::GetCurrent:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IMultiOutputRed), m_scanparam->multi_output_red);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IMultiOutputRed), Bool(false));
return success();
case Msg::Set: {
auto mech = data.currentItem<Bool>();
m_scanparam->multi_output_red = mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::IFilter] = msgSupportGetAllSetReset;
m_caps[CapType::IFilter] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<CapType::IFilter>({Filter::Red,Filter::Green,Filter::Blue,Filter::None },
m_scanparam->filter,
0);
return success();
case Msg::Reset:
m_scanparam->filter = (byte)Filter::None;
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IFilter>((Filter)m_scanparam->filter);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IFilter>(Filter::None);
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IFilter>();
if(mech == Filter::None|| mech == Filter::Red||mech == Filter::Green ||mech ==Filter::Blue){
m_scanparam->filter =(byte) mech;
return success();
}
return badValue();
}
default:
return capBadOperation();
}
};
//<2F><>ɫ<EFBFBD><C9AB>ǿ
m_query[(CapType)(CapTypeEx::TwEx_IEnhanceColor)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_IEnhanceColor)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<Enchace_Color>((CapType)(CapTypeEx::TwEx_IEnhanceColor), { Enchace_Color::Enhance_None,Enchace_Color::Enhance_Red,Enchace_Color::Enhance_Green,Enchace_Color::Enhance_Blue},m_scanparam->enhance_color,0);
return success();
case Msg::Reset:
m_scanparam->enhance_color = Enchace_Color::Enhance_None;
case Msg::GetCurrent:
data = Capability::createOneValue<Int16>((CapType)(CapTypeEx::TwEx_IEnhanceColor), (Enchace_Color)(m_scanparam->enhance_color));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Int16>((CapType)(CapTypeEx::TwEx_IEnhanceColor), Enchace_Color::Enhance_None);
return success();
case Msg::Set: {
auto mech = data.currentItem<Int16>();
m_scanparam->enhance_color =(byte)mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[(CapType)(CapTypeEx::TwEx_Sharpen)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_Sharpen)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<SharpenBlur>((CapType)(CapTypeEx::TwEx_IEnhanceColor), { SharpenBlur::Sharpen_None,SharpenBlur::Sharpen_Normal,SharpenBlur::Sharpen_More,SharpenBlur::Sharpen_Blur,SharpenBlur::Sharpen_Blur_More }, m_scanparam->sharpen, 0);
return success();
case Msg::Reset:
m_scanparam->sharpen = SharpenBlur::Sharpen_None;
case Msg::GetCurrent:
data = Capability::createOneValue<Int16>((CapType)(CapTypeEx::TwEx_Sharpen), (SharpenBlur)(m_scanparam->sharpen));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Int16>((CapType)(CapTypeEx::TwEx_Sharpen), SharpenBlur::Sharpen_None);
return success();
case Msg::Set: {
auto mech = data.currentItem<Int16>();
m_scanparam->sharpen = (byte)mech;
return success();
}
default:
return capBadOperation();
}
};
/*<2A><><EFBFBD><EFBFBD> <20>Աȶ<D4B1> gamma range<67><65><EFBFBD><EFBFBD> Range <20><><EFBFBD><EFBFBD>*/
m_query[CapType::IBrightness] = msgSupportGetAllSetReset;
m_caps[CapType::IBrightness] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data=Capability::createRange<CapType::IBrightness>(Fix32(-1000.0f), Fix32(1000.0f), Fix32(333.3f), Fix32(m_scanparam->brightness), Fix32(0.0));
return success();
case Msg::Reset:
m_scanparam->brightness =0.0f;
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IBrightness>(Fix32(m_scanparam->brightness));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IBrightness>(Fix32(0.0f));
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IBrightness>();
if (mech > 1000.0f || mech < -1000.0f)
return badValue();
m_scanparam->brightness = (float)mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::IContrast] = msgSupportGetAllSetReset;
m_caps[CapType::IContrast] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createRange<CapType::IContrast>(Fix32(-1000.0f), Fix32(1000.0f), Fix32(333.3f), Fix32(m_scanparam->contrast), Fix32(0.0));
return success();
case Msg::Reset:
m_scanparam->contrast = 0.0f;
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IContrast>(Fix32(m_scanparam->contrast));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IContrast>(Fix32(0.0f));
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IContrast>();
if (mech > 1000.0f || mech < -1000.0f)
return badValue();
m_scanparam->contrast = (float)mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[CapType::IGamma] = msgSupportGetAllSetReset;
m_caps[CapType::IGamma] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createRange<CapType::IGamma>(Fix32(0.0f), Fix32(5.0f), Fix32(1.0f), Fix32(m_scanparam->gamma), Fix32(1.0));
return success();
case Msg::Reset:
m_scanparam->gamma = 1.0f;
case Msg::GetCurrent:
data = Capability::createOneValue<CapType::IGamma>(Fix32(m_scanparam->gamma));
return success();
case Msg::GetDefault:
data = Capability::createOneValue<CapType::IGamma>(Fix32(0.0f));
return success();
case Msg::Set: {
auto mech = data.currentItem<CapType::IGamma>();
if (mech > 5.0f || mech < 0.0f)
return badValue();
m_scanparam->gamma = (float)mech;
return success();
}
default:
return capBadOperation();
}
};
//m_query[(CapType)(CapTypeEx::TwEx_DBAreaNum)] = msgSupportGetAllSetReset;
//m_caps[(CapType)(CapTypeEx::TwEx_DBAreaNum)] = [this](Msg msg, Capability& data)->Result {
// switch (msg) {
// case Msg::Get:
// data = Capability::createOneValue<UInt16>((CapType)(CapTypeEx::TwEx_DBAreaNum), m_scanparam->areanum);
// return success();
// case Msg::Reset:
// m_scanparam->areanum = 8;
// case Msg::GetCurrent:
// data = Capability::createOneValue<UInt16>((CapType)(CapTypeEx::TwEx_DBAreaNum), m_scanparam->areanum);
// return success();
// case Msg::GetDefault:
// data = Capability::createOneValue<UInt16>((CapType)(CapTypeEx::TwEx_DBAreaNum), UInt16(8));
// return success();
// case Msg::Set: {
// auto mech = data.currentItem<UInt16>();
// if (mech >= 5 && mech <= 40) {
// m_scanparam->areanum = mech;
// return success();
// }
// return badValue();
// }
// default:
// return capBadOperation();
// }
//};
//m_query[(CapType)(CapTypeEx::TwEx_DBDevnMax)] = msgSupportGetAllSetReset;
//m_caps[(CapType)(CapTypeEx::TwEx_DBDevnMax)] = [this](Msg msg, Capability& data)->Result {
// switch (msg) {
// case Msg::Get:
// data = Capability::createOneValue<UInt16>((CapType)(CapTypeEx::TwEx_DBDevnMax), m_scanparam->devnmax);
// return success();
// case Msg::Reset:
// m_scanparam->devnmax = 200;
// case Msg::GetCurrent:
// data = Capability::createOneValue<UInt16>((CapType)(CapTypeEx::TwEx_DBDevnMax), m_scanparam->devnmax);
// return success();
// case Msg::GetDefault:
// data = Capability::createOneValue<UInt16>((CapType)(CapTypeEx::TwEx_DBDevnMax), UInt16(200));
// return success();
// case Msg::Set: {
// auto mech = data.currentItem<UInt16>();
// if (mech >= 150 && mech <= 400) {
// m_scanparam->devnmax = mech;
// return success();
// }
// return badValue();
// }
// default:
// return capBadOperation();
// }
//};
/*<2A><><EFBFBD><EFBFBD>ΪӲ<CEAA><D3B2>Э<EFBFBD><D0AD>*/
m_query[(CapType)(CapTypeEx::TwEx_ScrewDetectEnable)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_ScrewDetectEnable)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<Bool>((CapType)(CapTypeEx::TwEx_ScrewDetectEnable), { Bool(),Bool(true) }, Bool(m_scanparam->hardwarecaps.en_skrewdetect), 0);
return success();
case Msg::Reset:
m_scanparam->hardwarecaps.en_skrewdetect = false;
case Msg::GetCurrent:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_ScrewDetectEnable), m_scanparam->hardwarecaps.en_skrewdetect);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_ScrewDetectEnable), Bool(false));
return success();
case Msg::Set: {
auto mech = data.currentItem<Bool>();
m_scanparam->hardwarecaps.en_skrewdetect = mech;
return success();
}
default:
return capBadOperation();
}
};
m_query[(CapType)(CapTypeEx::TwEx_ScrewLevel)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_ScrewLevel)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createOneValue<UInt8>((CapType)(CapTypeEx::TwEx_ScrewLevel), m_scanparam->hardwarecaps.skrewdetectlevel);
return success();
case Msg::Reset:
m_scanparam->hardwarecaps.skrewdetectlevel = 3;
case Msg::GetCurrent:
data = Capability::createOneValue<UInt8>((CapType)(CapTypeEx::TwEx_ScrewLevel), m_scanparam->hardwarecaps.skrewdetectlevel);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<UInt8>((CapType)(CapTypeEx::TwEx_ScrewLevel), UInt8(3));
return success();
case Msg::Set: {
auto mech = data.currentItem<UInt8>();
if (mech >= 1 && mech <= 5) {
m_scanparam->hardwarecaps.skrewdetectlevel = mech;
return success();
}
return badValue();
}
default:
return capBadOperation();
}
};
//װ<><D7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
m_query[(CapType)(CapTypeEx::TwEx_StableDetectEnable)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_StableDetectEnable)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<Bool>((CapType)(CapTypeEx::TwEx_StableDetectEnable), { Bool(),Bool(true) }, Bool(m_scanparam->hardwarecaps.en_stapledetect), 0);
return success();
case Msg::Reset:
m_scanparam->hardwarecaps.en_stapledetect = false;
case Msg::GetCurrent:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_StableDetectEnable), m_scanparam->hardwarecaps.en_stapledetect);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_StableDetectEnable), Bool(false));
return success();
case Msg::Set: {
auto mech = data.currentItem<Bool>();
m_scanparam->hardwarecaps.en_stapledetect = mech;
return success();
}
default:
return capBadOperation();
}
};
//˫<>ż<EFBFBD><C5BC><EFBFBD> <20><><EFBFBD>ٷ<EFBFBD><D9B7><EFBFBD>׼<EFBFBD><D7BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>Э<EFBFBD><D0AD><EFBFBD>޸<EFBFBD>Ϊbool<6F><6C>
m_query[CapType::DoubleFeedDetection] = msgSupportGetAllSetReset;
m_caps[CapType::DoubleFeedDetection] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<Bool>(CapType::DoubleFeedDetection, { Bool(),Bool(true) }, Bool(m_scanparam->hardwarecaps.en_doublefeed), 0);
return success();
case Msg::Reset:
m_scanparam->hardwarecaps.en_doublefeed = false;
case Msg::GetCurrent:
data = Capability::createOneValue<Bool>(CapType::DoubleFeedDetection, m_scanparam->hardwarecaps.en_doublefeed);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Bool>(CapType::DoubleFeedDetection, Bool(false));
return success();
case Msg::Set: {
auto mech = data.currentItem<Bool>();
m_scanparam->hardwarecaps.en_doublefeed = mech;
return success();
}
default:
return capBadOperation();
}
};
return success();
}
Result HuagaoDs::identityCloseDs(const Identity&){
// no need to explicitly release any resources if using RAII
// TWPP will free the whole source on its own after this method
guiIndicator.reset();
guiTwain.reset();
guiBridge.reset();
scanner.reset();
return success();
}
Result HuagaoDs::pendingXfersGet(const Identity&, PendingXfers& data){
data.setCount(m_pendingXfers);
return success();
}
Result HuagaoDs::pendingXfersEnd(const Identity&, PendingXfers& data){
//!< end xfer if set count 0
int ret= scanner->aquire_bmpdata(bmpData);
if (ret !=0) {
scanner->Set_ErrorCode(0);
guiIndicator.reset();
if (ret != -1) {
MessageBox(guiTwain ? guiTwain->m_hWnd : NULL, noticeMsgMap[ret], _T("<EFBFBD><EFBFBD>ʾ"), MB_SYSTEMMODAL | MB_OK | MB_ICONINFORMATION);
}
m_pendingXfers = 0;
if (guiTwain.get()) {
((CTwainUI*)(guiTwain.get()))->EnableID_OKorID_Cancel(true);
}
}
else {
m_pendingXfers = 1;
}
#ifdef LOG_NORMAL
FileTools::write_log("out.txt", "m_pendingXfers " + std::to_string(m_pendingXfers));
#endif // LOG_NORMAL
data.setCount(m_pendingXfers);
return success();
}
Result HuagaoDs::pendingXfersReset(const Identity&, PendingXfers& data){
data.setCount(0);
return success();
}
Result HuagaoDs::setupMemXferGet(const Identity&, SetupMemXfer& data){
auto bpl = bytesPerLine();
auto max = bpl * static_cast<UInt32>(header()->biHeight);
data.setMinSize(bpl);
data.setPreferredSize(max);
data.setMaxSize(max);
return success();
}
Result HuagaoDs::userInterfaceDisable(const Identity&, UserInterface& ui){
guiTwain.reset();
#if TWPP_DETAIL_OS_WIN
guiBridge.reset();
#endif
return success();
}
Result HuagaoDs::userInterfaceEnable(const Identity&, UserInterface& ui){
m_pendingXfers = 1;
m_memXferYOff = 0;
if (!ui.showUi()){
// this is an exception when we want to set state explicitly, notifyXferReady can be called only in enabled state
// with hidden UI, the usual workflow DsState::Enabled -> notifyXferReady() -> DsState::XferReady is a single step
2020-04-03 01:31:18 +00:00
updataGscanCap();
setState(DsState::Enabled);
if(startScan() == success()){
m_pendingXfers = 1;
auto notified = notifyXferReady();
return success();
}
else {
m_pendingXfers = 0;
setState(DsState::Open);
return seqError();
}
}
return showTwainUI(ui);
}
Result HuagaoDs::userInterfaceEnableUiOnly(const Identity&, UserInterface& ui){
// as a minimal source, we do not support GUI that just saves settings
return showTwainUI(ui, true);
}
Result HuagaoDs::imageInfoGet(const Identity&, ImageInfo& data){
// our image does not change
auto dib = header();
data.setBitsPerPixel(static_cast<Int16>(dib->biBitCount));
data.setHeight(dib->biHeight);
//dib->biClrUseddib->biClrUsed==2?T
data.setPixelType(dib->biClrUsed == 2 ? PixelType::BlackWhite : (dib->biClrUsed == 256 ? PixelType::Gray : PixelType::Rgb));
data.setPlanar(false);
data.setWidth(dib->biWidth);
data.setXResolution(m_scanparam->resolution_dst);
data.setYResolution(m_scanparam->resolution_dst);
switch (dib->biClrUsed)
{
case 2:
case 256:
data.setSamplesPerPixel(1);
data.bitsPerSample()[0] = 8;
break;
case 0:
data.setSamplesPerPixel(3);
data.bitsPerSample()[0] = 8;
data.bitsPerSample()[1] = 8;
data.bitsPerSample()[2] = 8;
default:
break;
}
return success();
}
Result HuagaoDs::imageLayoutGet(const Identity&, ImageLayout& data){
// our image does not change
auto dib = header();
data.setDocumentNumber(1);
data.setFrameNumber(1);
data.setPageNumber(1);
data.setFrame(Frame(0, 0, static_cast<float>(dib->biWidth) / RESOLUTIONX, static_cast<float>(dib->biHeight) / RESOLUTIONX));
return success();
}
Result HuagaoDs::imageLayoutGetDefault(const Identity& origin, ImageLayout& data){
return imageLayoutGet(origin, data);
}
Result HuagaoDs::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 HuagaoDs::imageLayoutReset(const Identity& origin, ImageLayout& data){
return imageLayoutGet(origin, data);
}
Result HuagaoDs::imageMemXferGet(const Identity& origin, ImageMemXfer& data){
if (!m_pendingXfers){
return seqError();
}
// we can call our TWPP methods, but be careful about states
SetupMemXfer setup;
setupMemXferGet(origin, setup);
// just a simple stored BMP image
auto dib = header();
auto bpl = bytesPerLine();
auto memSize = data.memory().size();
if (memSize > setup.maxSize() || memSize < setup.minSize()){
return badValue();
}
auto maxRows = memSize / bpl;
auto rows = std::min<UInt32>(maxRows, static_cast<UInt32>(dib->biHeight) - m_memXferYOff);
if (rows == 0){
return seqError(); // image already transfered in this session
}
data.setBytesPerRow(bpl);
data.setColumns(static_cast<UInt32>(dib->biWidth));
data.setRows(rows);
data.setBytesWritten(rows * bpl);
data.setXOffset(0);
data.setYOffset(m_memXferYOff);
data.setCompression(Compression::None);
auto lock = data.memory().data();
char* out = lock.data();
// bottom-up BMP -> top-down memory transfer
auto begin = bmpEnd() - (bpl * (m_memXferYOff + 1));
for (UInt32 i = 0; i < rows; i++){
// copy bytes
std::copy(begin, begin + bpl, out);
char* line = out;
out += bpl;
begin -= bpl;
// BGR BMP -> RGB memory transfer
for ( ; line + 3 < out; line += 3){
std::swap(line[0], line[2]);
}
}
m_memXferYOff += rows;
if (m_memXferYOff >= static_cast<UInt32>(std::abs(dib->biHeight))){
m_pendingXfers = 0;
return {ReturnCode::XferDone, ConditionCode::Success};
}
return success();
}
#ifdef LOG_NORMAL
static int xtfer = 0;
#endif
Result HuagaoDs::imageNativeXferGet(const Identity&, ImageNativeXfer& data){
if (!m_pendingXfers){
return seqError();
}
if (data)
data.release();
// it does not get easier than that if we already have BMP
data = ImageNativeXfer(bmpSize());
std::copy(bmpBegin(), bmpEnd(), data.data<char>().data());
#ifdef LOG_NORMAL
FileTools::write_log("out.txt", "imageNativeXferGet "+ std::to_string(++xtfer));
#endif // LOG
return {ReturnCode::XferDone, ConditionCode::Success};
}
Twpp::Result HuagaoDs::pendingXfersStopFeeder(const Identity& origin, PendingXfers& data)
{
if (!scanner.get())
return seqError();
if (scanner->IsConnected()) {
scanner->Stop_scan();
}
data.setCount(scanner->Get_IsImageQueueEmpty() ? 0 : 1);
return success();
}
Twpp::Result HuagaoDs::showTwainUI(Twpp::UserInterface& ui, bool bUiOnly)
{
// as a minimal source, we do not support GUI that just saves settings
if (ui.parent()) {
guiBridge.reset(new CDialog());
HWND appWindow = static_cast<HWND>(ui.parent().raw());
guiBridge->Create(IDD_BACK, CWnd::FromHandle(appWindow));
HWND bridgeWindow = guiBridge->GetSafeHwnd();
long bridgeFlags = GetWindowLong(bridgeWindow, GWL_STYLE);
SetWindowLong(bridgeWindow, GWL_STYLE, bridgeFlags | WS_CHILD);
SetParent(bridgeWindow, appWindow);
//if (ui.modalUi()) {
// long appFlags = GetWindowLong(appWindow, GWL_STYLE);
// SetWindowLong(appWindow, GWL_STYLE, appFlags | WS_DISABLED);
//}
}
//!< show ui to scan button push
auto scanFunction = [this](const GScanCap& caps) {
m_pendingXfers = 1;
m_scanparam.reset(new GScanCap(caps));
//scanner->config_params(*m_scanparam);
if (startScan() == success()) {
notifyXferReady();
}
else {
m_pendingXfers = 0;
}
};
//!< ui only to confirm button push
auto confirmFunction = [this](const GScanCap& caps) {
m_scanparam.reset(new GScanCap(caps));
notifyCloseOk();
};
//!< cancel button push
auto cancelFunction = [this]() {
notifyCloseCancel();
};
CWnd* parent = guiBridge.get();
TwGlue glue = {scanFunction, cancelFunction };
TwGlue glueUiOnly = {confirmFunction, cancelFunction };
std::string serialnum = scanner->GetSerialNum();
std::string hardwareversion = scanner->GetFWVersion();
guiTwain.reset(new CTwainUI(bUiOnly ? glueUiOnly : glue, bUiOnly?"ȷ<EFBFBD><EFBFBD>":"ɨ<EFBFBD><EFBFBD>", hardwareversion, serialnum));
guiTwain->Create(IDD_TWAINUI, parent);
guiTwain->ShowWindow(SW_SHOWNORMAL);
return success();
}
const BITMAPINFOHEADER* HuagaoDs::header() const noexcept{
return reinterpret_cast<const BITMAPINFOHEADER*>(bmpData.data() + sizeof(BITMAPFILEHEADER));
}
UInt32 HuagaoDs::bytesPerLine() const noexcept{
auto dib = header();
return static_cast<UInt32>(dib->biWidth * dib->biBitCount + 31) / 32 * 4;
}
UInt32 HuagaoDs::bmpSize() const noexcept{
return static_cast<UInt32>(bmpData.size()) - sizeof(BITMAPFILEHEADER);
}
const char* HuagaoDs::bmpBegin() const noexcept{
return (const char*)bmpData.cbegin()._Ptr + sizeof(BITMAPFILEHEADER);
}
const char* HuagaoDs::bmpEnd() const noexcept{
return (const char*)bmpData.cend()._Ptr;
}
void HuagaoDs::initGScanCap()
{
m_scanparam->autodescrew = 1;
m_scanparam->brightness = 0.0f;
m_scanparam->contrast = 0.0f;
m_scanparam->fillbackground = 1;
m_scanparam->fillhole.is_fillhole = 1;
m_scanparam->fillhole.fillholeratio = 0.1f;
m_scanparam->filter = (byte)Filter::None;
m_scanparam->sharpen = (byte)SharpenBlur::Sharpen_None;
m_scanparam->gamma = 1.0;
m_scanparam->hardwarecaps.capturepixtype = (int)(PixelType::Gray);
m_scanparam->hardwarecaps.en_doublefeed = 1;
m_scanparam->hardwarecaps.en_skrewdetect = 0;
m_scanparam->hardwarecaps.en_stapledetect = 0;
m_scanparam->hardwarecaps.skrewdetectlevel = 3;
m_scanparam->is_autocontrast = 0;
m_scanparam->is_autocrop = 0;
m_scanparam->is_autodiscradblank_normal = 0;
m_scanparam->is_autodiscradblank_vince = 0;
//m_scanparam->areanum = 8;
//m_scanparam->devnmax = 200;
m_scanparam->is_backrotate180 = 0;
m_scanparam->is_duplex = 1;
m_scanparam->multi_output_red = 0;
m_scanparam->papertype = 11;//A3
m_scanparam->paperAlign = PaperAlign::Rot0;
m_scanparam->resolution_native = 200.0f;
m_scanparam->resolution_dst = 200.0f;
m_scanparam->scannum = -1;
m_scanparam->is_autotext = 0;
m_scanparam->enhance_color = 0;
m_scanparam->pixtype= (int)(PixelType::Gray);
ScanRect rect = { 0 };//to be define
m_scanparam->scanrect = rect;
m_scanparam->threshold = 128.0f;
}
void HuagaoDs::updataGscanCap()
{
JsonConfig js;
CONFIGPARAMS cfs=js.ReadDefaultConfig();
m_scanparam->autodescrew = cfs.EnAutoDescrew?1:0;
m_scanparam->brightness = cfs.Brightness;
m_scanparam->contrast = cfs.Contrast;
m_scanparam->fillbackground = cfs.EnFillBlack?1:0;
m_scanparam->fillhole.is_fillhole = cfs.EnOutHole?1:0;
m_scanparam->fillhole.fillholeratio = cfs.OutHoleRatio;
m_scanparam->sharpen = (SharpenBlur)cfs.Sharpen;
if (cfs.Filter) {
if (cfs.Filter <= 3) {
m_scanparam->filter = filterMaps[cfs.Filter];
m_scanparam->enhance_color = 0;//<2F><>ɫ<EFBFBD><C9AB>ǿ none
}
else {
m_scanparam->filter = (byte)Filter::None;//<2F><><EFBFBD><EFBFBD>ɫ
m_scanparam->enhance_color = filterMaps[cfs.Filter];
}
}
else {
m_scanparam->filter = (byte)Filter::None;
m_scanparam->enhance_color = EnchaceColor::Enhance_None;
}
m_scanparam->gamma =cfs.Gamma;
m_scanparam->hardwarecaps.en_doublefeed = cfs.EnUltrasonicDetect?1:0;
m_scanparam->hardwarecaps.en_skrewdetect = cfs.EnScrewDetect?1:0;
m_scanparam->hardwarecaps.en_stapledetect = cfs.EnBindingDetect?1:0;
m_scanparam->hardwarecaps.skrewdetectlevel = cfs.ScrewDetectLevel;
m_scanparam->is_autocontrast = cfs.EnAutoContrast?1:0;
m_scanparam->is_autocrop = cfs.EnAutoCrop?1:0;
m_scanparam->is_autodiscradblank_normal = cfs.EnDiscardBlank?1:0;
m_scanparam->is_autodiscradblank_vince = cfs.EnDiscardBlankVince?1:0;
m_scanparam->is_backrotate180 = cfs.EnBackRotate180?1:0;
m_scanparam->is_duplex = cfs.Duplex>=1?1:0;
m_scanparam->multi_output_red = cfs.EnMultiOutPutR?1:0;
PaperStatus ps = paperStatusMap[cfs.PaperSize];
m_scanparam->papertype = ps.Paper;//A3
m_scanparam->paperAlign =(PaperAlign)ps.Orentate;
m_scanparam->resolution_dst = resolutions[cfs.Resolution];
2020-04-03 01:31:18 +00:00
#ifdef REAL300DPI
m_scanparam->resolution_native = m_scanparam->resolution_dst > 240.0f ? 300.0f : 200.0f;
#else // REAL300DPI
m_scanparam->resolution_native = 200.0f;
#endif
m_scanparam->scannum = cfs.ScanCount;
m_scanparam->is_autotext = cfs.Orentation==4?1:0;
if (cfs.Orentation != 4) {
m_scanparam->imageRotateDegree = rotateDegrees[cfs.Orentation];
}
m_scanparam->pixtype = colorModes[cfs.Pixtype];
if (cfs.Filter || cfs.EnMultiOutPutR) {
m_scanparam->hardwarecaps.capturepixtype = (byte)(PixelType::Rgb);
}
else {
m_scanparam->hardwarecaps.capturepixtype = m_scanparam->pixtype;
}
ScanRect rect = { 0 };//to be define
m_scanparam->scanrect = rect;
m_scanparam->threshold = 128.0f;
}
Twpp::Result HuagaoDs::startScan()
{
if (!scanner->IsConnected())
return checkDeviceOnline();
scanner->ResetScanner();
scanner->config_params(*m_scanparam);
if (m_bIndicator) {
//!< cancel button push
auto stopFunc = [this]() {
scanner->Stop_scan();
guiIndicator.reset();//ȡ<><C8A1>ɨ<EFBFBD><C9A8> <20>رս<D8B1><D5BD><EFBFBD>ָʾ<D6B8><CABE>
};
guiIndicator.reset(new CIndicatorDlg(stopFunc));
guiIndicator->Create(IDD_INDICATOR, guiTwain ? guiTwain.get() : guiBridge.get());
guiIndicator->ShowWindow(SW_SHOWNORMAL);
}
scanner->Scanner_StartScan(m_scanparam->scannum);
if (bmpData.size() > 0)
bmpData.clear();
if(guiTwain.get()){
((CTwainUI*)(guiTwain.get()))->EnableID_OKorID_Cancel(false);
}
int retCode = scanner->aquire_bmpdata(bmpData);
if (retCode!=0) {
scanner->Set_ErrorCode(0);
guiIndicator.reset();
if(retCode!=-1)
MessageBox(guiTwain? guiTwain->m_hWnd:NULL, noticeMsgMap[retCode], _T("<EFBFBD><EFBFBD>ʾ"), MB_SYSTEMMODAL | MB_OK | MB_ICONINFORMATION);
if (guiTwain.get()) {
((CTwainUI*)(guiTwain.get()))->EnableID_OKorID_Cancel(true);
}
return seqError();
}
if (bmpData.size()>0) {
return success();
}
else {
guiIndicator.reset();
if (guiTwain.get()) {
((CTwainUI*)(guiTwain.get()))->EnableID_OKorID_Cancel(true);
}
return seqError();
}
}