mirror of http://192.168.1.51:8099/lmh188/twain3
2285 lines
81 KiB
C++
2285 lines
81 KiB
C++
#include <memory>
|
|
#include "huagaods.hpp"
|
|
#include "twglue.hpp"
|
|
#include "Config.h"
|
|
#include "GScanO200.h"
|
|
#include "GScanO3399.h"
|
|
#include "filetools.h"
|
|
//#include "Global.h"
|
|
#include "G4Tiff.h"
|
|
#include "GScanVirtual.h"
|
|
#include <list>
|
|
#include <map>
|
|
#include "DeviceHelper.h"
|
|
#include "ScannerUI.h"
|
|
#include <list>
|
|
#include <QString>
|
|
#include <QObject>
|
|
//#include "JsonConfig.h"
|
|
#include <iterator>
|
|
#include <QFile>
|
|
#include <iostream>
|
|
|
|
using namespace std;
|
|
using namespace Twpp;
|
|
using namespace std::placeholders;
|
|
|
|
namespace __range_to_initializer_list {
|
|
|
|
constexpr size_t DEFAULT_MAX_LENGTH = 128;
|
|
|
|
template <typename V> struct backingValue { static V value; };
|
|
template <typename V> V backingValue<V>::value;
|
|
|
|
template <typename V, typename... Vcount> struct backingList { static std::initializer_list<V> list; };
|
|
template <typename V, typename... Vcount>
|
|
std::initializer_list<V> backingList<V, Vcount...>::list = { (Vcount)backingValue<V>::value... };
|
|
|
|
template <size_t maxLength, typename It, typename V = typename It::value_type, typename... Vcount>
|
|
static typename std::enable_if< sizeof...(Vcount) >= maxLength,
|
|
std::initializer_list<V> >::type generate_n(It begin, It end, It current)
|
|
{
|
|
throw std::length_error("More than maxLength elements in range.");
|
|
}
|
|
|
|
template <size_t maxLength = DEFAULT_MAX_LENGTH, typename It, typename V = typename It::value_type, typename... Vcount>
|
|
static typename std::enable_if < sizeof...(Vcount) < maxLength,
|
|
std::initializer_list<V> > ::type generate_n(It begin, It end, It current)
|
|
{
|
|
if (current != end)
|
|
return generate_n<maxLength, It, V, V, Vcount...>(begin, end, ++current);
|
|
|
|
current = begin;
|
|
for (auto it = backingList<V, Vcount...>::list.begin();
|
|
it != backingList<V, Vcount...>::list.end();
|
|
++current, ++it)
|
|
*const_cast<V*>(&*it) = *current;
|
|
|
|
return backingList<V, Vcount...>::list;
|
|
}
|
|
|
|
}
|
|
|
|
template <typename It>
|
|
std::initializer_list<typename It::value_type> range_to_initializer_list(It begin, It end)
|
|
{
|
|
return __range_to_initializer_list::generate_n(begin, end, begin);
|
|
}
|
|
|
|
template <typename Vec>
|
|
std::initializer_list<typename Vec::value_type> range_to_initializer_list(Vec v)
|
|
{
|
|
return __range_to_initializer_list::generate_n(v.begin(), v.end(), v.begin());
|
|
}
|
|
|
|
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 T, Twpp::CapType cap>
|
|
Result CapSupGetAllEx(Msg msg, Capability& data, T& currvalue, T defaultvalue) {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
case Msg::GetCurrent:
|
|
case Msg::GetDefault:
|
|
data = Capability::createOneValue<T>(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::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, 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, 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, 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 };
|
|
}
|
|
}
|
|
|
|
|
|
//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_EnFold = 0x8037,
|
|
TwEx_StableDetectEnable = 0x8090,
|
|
TwEx_UVModel = 0x8093,
|
|
TwEx_SwitchFrontBack = 0x8094,
|
|
TwEx_HsvCorrect = 0x8095,
|
|
TwEx_DogEarDelection = 0x8096,
|
|
TwEx_FillBackgroundMode = 0x8097,
|
|
TwEx_CroporDesaskewIndent = 0x8098,
|
|
TwEx_CropNoise=0x8099,
|
|
TwEx_CroporDesaskewThreshold=0x8100,
|
|
TwEx_IDetachNoise = 0x8101,
|
|
TwEx_IDetachNoiseValue = 0x8102,
|
|
TwEx_SizeDetect=0x8103,
|
|
TwEx_LowPowerMode=0x8104,
|
|
TwEx_ENCODE=0x8105,
|
|
};
|
|
|
|
enum class PaperSizeEx : unsigned short {
|
|
K8 = 0x81,
|
|
K16 = 0x82,
|
|
};
|
|
|
|
|
|
TWPP_ENTRY(HuagaoDs)
|
|
|
|
static constexpr const Identity srcIdent(
|
|
Version(3, 3, Language::English, Country::CzechRepublic, "v3.3.1.6"),
|
|
DataGroup::Image,
|
|
"宁波华高信息科技有限公司",
|
|
"G200 Series",
|
|
"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 list<float> resList = { 100.0,150.0,200.0,240.0,300.0 ,600.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, std::string> noticeMsgMap = { {OPEN_COVER, "扫描仪开盖"},
|
|
{NO_FEED,"无纸!"},
|
|
{FEED_IN_ERROR,"搓纸失败!"},
|
|
{PAPER_JAM,"卡纸!"},
|
|
{DETECT_DOUBLE_FEED,"双张!"},
|
|
{DETECT_STAPLE,"订书针!"},
|
|
{PAPER_SKEW,"纸张歪斜!"},
|
|
{COUNT_MODE,"计数模式,请退出计数模式!"},
|
|
{HARDWARE_ERROR,"硬件错误"},
|
|
{FPGA_ERROR,"FPGA 异常"},
|
|
{DOG_EAR,"检测到折角"},
|
|
{DEVICE_OFF_LINE,"USB连接异常"},
|
|
{SIZE_ERROR,"幅面检测异常!"},
|
|
};
|
|
|
|
static std::unique_ptr<IGScan> scanner;
|
|
|
|
static ScannerUIPtr scannerUI;
|
|
#define CY
|
|
|
|
HuagaoDs::HuagaoDs()
|
|
{
|
|
#ifdef MY
|
|
scanner.reset(new GScanVirtual());
|
|
|
|
#elif defined CY
|
|
scanner.reset(new Scanner());
|
|
#else
|
|
scanner.reset(new GScanO200());
|
|
#endif
|
|
scannerUI = GUICreate::Instance();
|
|
//scannerUI.reset(new ScannerUI());
|
|
//initGScanCap();
|
|
}
|
|
|
|
HuagaoDs::~HuagaoDs()
|
|
{
|
|
scannerUI.reset();
|
|
}
|
|
|
|
|
|
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;
|
|
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 };
|
|
}
|
|
|
|
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::deviceEventGet(const Twpp::Identity& origin, Twpp::DeviceEvent& data)
|
|
{
|
|
//if (devEvent.size() > 0)
|
|
//{
|
|
// data = devEvent.front();
|
|
// devEvent.pop();
|
|
// return success();
|
|
//}
|
|
//return seqError();
|
|
return success();
|
|
}
|
|
|
|
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 (scannerUI)
|
|
scannerUI->postMessage();
|
|
|
|
event.setMessage(Msg::Null);
|
|
return {ReturnCode::NotDsEvent, ConditionCode::Success};
|
|
}
|
|
|
|
Result HuagaoDs::identityOpenDs(const Identity&){
|
|
QFile file;
|
|
file.setFileName(QString((Global::getSettingPath() + userJsonName).c_str()));
|
|
if (file.open(QIODevice::ReadOnly))
|
|
{
|
|
m_params = json::parse(file.readAll());
|
|
file.close();
|
|
}
|
|
else
|
|
{
|
|
file.setFileName(":/huagao.json");
|
|
if (file.open(QIODevice::ReadOnly))
|
|
{
|
|
m_params = json::parse(file.readAll());
|
|
file.close();
|
|
}
|
|
}
|
|
|
|
//scanner->open(0x3072, 0x0100);
|
|
#ifndef CY
|
|
int pid = scanner->open(0x3072);
|
|
if (pid > 0x200)
|
|
model = 1;
|
|
if (pid == 0x100)
|
|
Model = "G100";
|
|
else if (pid == 0x200)
|
|
Model = "G200";
|
|
else if (pid == 0x300)
|
|
Model = "G300";
|
|
else if (pid == 0x400)
|
|
Model = "G400";
|
|
else
|
|
{
|
|
if (scanner->open(0x064b) != 0x7823)
|
|
{
|
|
MessageBox(NULL, TEXT("未找到扫描仪!请检查电源或者USB连接线是否接通!"), TEXT("提示"), MB_OK);
|
|
return { ReturnCode::Failure,ConditionCode::CheckDeviceOnline };
|
|
}
|
|
Model = "G300";
|
|
model = 1;
|
|
}
|
|
#else
|
|
if (!scanner->open(0x3072))
|
|
{
|
|
MessageBox(NULL, TEXT("未找到扫描仪!请检查电源或者USB连接线是否接通!"), TEXT("提示"), MB_OK);
|
|
return { ReturnCode::Failure,ConditionCode::CheckDeviceOnline };
|
|
}
|
|
#endif // !CY
|
|
|
|
|
|
m_gcap.reset(new GScanCap(jsonToGscan(m_params, DEFAULT,Model)));
|
|
if (!bmpData.get())
|
|
bmpData.reset(new std::vector<unsigned char>);
|
|
bmpData->resize(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
|
|
BITMAPINFOHEADER& bmInfo = *((BITMAPINFOHEADER*)header());
|
|
bmInfo.biHeight = 2000;
|
|
bmInfo.biWidth = 2000;
|
|
bmInfo.biBitCount = m_gcap->pixelType == 2 ? 24 :( m_gcap->pixelType == 1 ? 8 : 0);
|
|
m_iBitdepth = m_gcap->pixelType == 2 ? 24 : (m_gcap->pixelType == 1 ? 8 : 0);
|
|
// 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){
|
|
if((msg==Msg::Get)or(Msg::GetCurrent==msg)or(Msg::GetDefault==msg)) {
|
|
data = Capability::createArray<CapType::SupportedCaps>(m_caps.size());
|
|
auto arr = data.array<CapType::SupportedCaps>();
|
|
UInt32 i = 0;
|
|
for (const auto& kv : m_caps){
|
|
arr[i] = kv.first;
|
|
i++;
|
|
}
|
|
return success();
|
|
}
|
|
else{
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
m_query[CapType::UiControllable] = msgSupportGetAll;
|
|
m_caps[CapType::UiControllable] = std::bind(oneValGet<Bool>, _1, _2, Bool(true));
|
|
|
|
m_query[CapType::DeviceOnline] = msgSupportGetAll;
|
|
//m_caps[CapType::DeviceOnline] = std::bind(enmGet<Bool>, _1, _2, Bool(scanner->IsConnected()));
|
|
m_caps[CapType::DeviceOnline] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
case Msg::GetCurrent:
|
|
case Msg::GetDefault:
|
|
data = Capability::createOneValue<CapType::DeviceOnline>((BOOL)scanner->IsConnected());
|
|
return {};
|
|
default:
|
|
return { ReturnCode::Failure, ConditionCode::CapBadOperation };
|
|
}
|
|
};
|
|
|
|
|
|
m_query[CapType::XferCount] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::XferCount] = [this](Msg msg, Capability& data) -> Result{
|
|
if (msg == Msg::Set){
|
|
auto item = data.currentItem<Int16>();
|
|
if (item > 65535 || item < -1||item==0){
|
|
return badValue();
|
|
}
|
|
m_gcap->scanCount = item;
|
|
return success();
|
|
}
|
|
Int16 scannum = m_gcap->scanCount;
|
|
auto ret = oneValGetSet<Int16>(msg, data, scannum, -1);
|
|
if (!Twpp::success(ret) && m_gcap->scanCount == 0){
|
|
m_gcap->scanCount = -1;
|
|
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_caps[CapType::ICompression] = [this](Msg msg, Capability& data)->Result{
|
|
if (Msg::Set == msg){
|
|
auto mech = data.currentItem<CapType::ICompression>();
|
|
if (Compression::None == mech || mech == Compression::Group4) {
|
|
m_compression = mech;
|
|
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);
|
|
};
|
|
|
|
m_query[CapType::IBitDepth] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::IBitDepth] = [this](Msg msg, Capability& data) -> Result {
|
|
if (Msg::Set == msg) {
|
|
auto mech = data.currentItem<CapType::IBitDepth>();
|
|
if (((mech == 1) && (m_gcap->pixelType == 0)) || ((mech == 8) && (m_gcap->pixelType == 1)) || ((mech == 24) && (m_gcap->pixelType == 2))) {
|
|
m_iBitdepth = (UINT16)mech;
|
|
return success();
|
|
}
|
|
return badValue();
|
|
}
|
|
return CapSupGetAllReset< UInt16, UInt16, CapType::IBitDepth>(msg, data, m_iBitdepth, 24);
|
|
};
|
|
|
|
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, [this]()->Fix32 {return Fix32(static_cast<float>(header()->biWidth) / m_params[Model][USER][RESOLUTION]); });
|
|
|
|
// m_query[CapType::IPhysicalHeight] = msgSupportGetAll;
|
|
// m_caps[CapType::IPhysicalHeight] = std::bind(oneValGet<Fix32>, _1, _2, [this]()->Fix32 {return Fix32(static_cast<float>(header()->biHeight) / m_params[Model][USER][RESOLUTION]); });
|
|
|
|
|
|
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 {
|
|
if (Msg::Set == msg) {
|
|
auto mech = data.currentItem<CapType::IPixelType>();
|
|
if (mech == PixelType::Rgb || mech == PixelType::Gray || mech == PixelType::BlackWhite)
|
|
{
|
|
m_gcap->pixelType = (ColorMode)mech;
|
|
if (m_gcap->pixelType ==(int) ColorMode::RGB){
|
|
m_gcap->imageProcess.filter = ColorFilter::FILTER_NONE;
|
|
//m_scanparam->enhance_color = (byte)Enchace_Color::Enhance_None;
|
|
m_gcap->imageProcess.automaticcolor = false;
|
|
}
|
|
else{
|
|
m_gcap->multiOutput = MultiOutput::Unused;//非彩色模式下多流输出不可用
|
|
//if (m_scanparam->pixtype == (int)PixelType::BlackWhite)
|
|
// m_scanparam->sharpen = SharpenBlur::Sharpen_None;
|
|
}
|
|
m_iBitdepth = mech == PixelType::Rgb ? 24 : (mech == PixelType::Gray ? 8 : 1);
|
|
return success();
|
|
}
|
|
return badValue();
|
|
}
|
|
return CapSupGetAllReset<ColorMode, PixelType, CapType::IPixelType>(msg, data, { PixelType::BlackWhite ,PixelType::Gray ,PixelType::Rgb }, m_gcap->pixelType
|
|
, PixelType::Rgb, m_gcap->pixelType, 2);
|
|
};
|
|
//add------------------jpeg质量等级---------------------
|
|
m_query[CapType::IJpegQuality] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::IJpegQuality] = [this](Msg msg, Capability& data)->Result {
|
|
if (Msg::Set == msg)
|
|
{
|
|
auto mech = data.currentItem<CapType::IJpegQuality>();
|
|
if ((int)mech < 0 || (int)mech > 100)
|
|
return badValue();
|
|
m_jpegQuality = (int)mech;
|
|
return success();
|
|
}
|
|
return CapSupGetAllResetEx<unsigned short, UInt16, CapType::IJpegQuality>(msg, data, m_jpegQuality, 80);
|
|
};
|
|
|
|
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 {
|
|
if (Msg::Set == msg) {
|
|
auto mech = data.currentItem<CapType::IXferMech>();
|
|
if (mech == XferMech::Native || mech == XferMech::Memory || mech == XferMech::File) {
|
|
m_capXferMech = mech;
|
|
return success();
|
|
}
|
|
else {
|
|
return badValue();
|
|
}
|
|
}
|
|
return CapSupGetAllReset< XferMech, XferMech, CapType::IXferMech>(msg, data, { XferMech::Native, XferMech::File, XferMech::Memory }, m_capXferMech, XferMech::Native, (int)m_capXferMech, 0);
|
|
};
|
|
m_query[CapType::IXResolution] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::IXResolution] = [this](Msg msg, Capability& data){
|
|
auto dpis_list = std::vector<Fix32>(m_params[Model][SYSTEM][DPI].begin(), m_params[Model][SYSTEM][DPI].end());
|
|
auto index = std::distance(std::begin(dpis_list), std::find(dpis_list.begin(), dpis_list.end(), Fix32((float)m_gcap->resolution)));
|
|
switch (msg){
|
|
case Msg::Get: {
|
|
data = Capability::createEnumeration(data.type(), range_to_initializer_list(dpis_list), index == dpis_list.size() ? 2 : index, 2);
|
|
return success();
|
|
}
|
|
case Msg::GetCurrent: {
|
|
data = Capability::createOneValue(data.type(), Fix32(float(m_gcap->resolution)));
|
|
return success();
|
|
}
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:{
|
|
m_gcap->resolution = 200.0f;
|
|
data = Capability::createOneValue(data.type(), Fix32(200.0));
|
|
return success();
|
|
}
|
|
case Msg::Set:{
|
|
auto res = data.currentItem<Fix32>();
|
|
if (std::find(dpis_list.begin(), dpis_list.end(), res)!=dpis_list.end()) {
|
|
m_gcap->resolution = (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_caps[CapType::IXNativeResolution] = std::bind(enmGet<Fix32>, _1, _2, []()->Fix32 {return 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) {
|
|
std::initializer_list<UInt16> papersize_list = range_to_initializer_list(std::vector<UInt16>(m_params[Model][SYSTEM][PAPERSIZE].begin(), m_params[Model][SYSTEM][PAPERSIZE].end()));
|
|
auto index = std::distance(std::begin(papersize_list), std::find(papersize_list.begin(), papersize_list.end(), json_cast(m_params[Model][USER][PAPERSIZE]).to_uint16()));
|
|
if (Msg::Set == msg) {
|
|
auto res = data.currentItem<UInt16>();
|
|
std::initializer_list<UInt16> papersize_list = range_to_initializer_list(std::vector<UInt16>(m_params[Model][SYSTEM][PAPERSIZE].begin(), m_params[Model][SYSTEM][PAPERSIZE].end()));
|
|
if (std::find(papersize_list.begin(), papersize_list.end(), res) != papersize_list.end()) {
|
|
m_gcap->paperSize = (TwSS)res;
|
|
if (res == TwSS::None || res == TwSS::USStatement)
|
|
m_gcap->paperAlign = PaperAlign::Rot0;
|
|
if (res == TwSS::USStatement) {
|
|
m_autosize = res == (UInt16)AutoSize::None;
|
|
m_autoboarderdetcet = res == false;
|
|
m_gcap->imageProcess.autoCrop = false;
|
|
}
|
|
else {
|
|
m_autosize = res == TwSS::None ? (UInt16)AutoSize::Auto : (UInt16)AutoSize::None;
|
|
m_autoboarderdetcet = res == TwSS::None;
|
|
m_gcap->imageProcess.autoCrop = res == TwSS::None ? true : false;
|
|
}
|
|
return success();
|
|
}
|
|
return badValue();
|
|
}
|
|
return CapSupGetAllResetEx<TwSS, UInt16, CapType::ISupportedSizes>(msg, data, papersize_list, m_gcap->paperSize, TwSS::A3, index,
|
|
std::distance(std::begin(papersize_list), std::find(papersize_list.begin(), papersize_list.end(), TwSS::A3)));
|
|
};
|
|
|
|
m_query[CapType::IOrientation] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::IOrientation] = [this](Msg msg, Capability& data) -> Result {
|
|
if (Msg::Set == msg) {
|
|
auto mech = data.currentItem<CapType::IOrientation>();
|
|
if(mech== Orientation::Landscape|| mech == Orientation::Portrait){
|
|
m_gcap->paperAlign =(PaperAlign)mech;
|
|
return success();
|
|
}
|
|
return badValue();
|
|
}
|
|
return CapSupGetAllReset<PaperAlign, Orientation, CapType::IOrientation>(msg, data, { Orientation::Portrait, Orientation::Landscape }, m_gcap->paperAlign, Orientation::Portrait,
|
|
m_gcap->paperAlign == 0 ? 0 : 1, 0);
|
|
};
|
|
|
|
m_query[CapType::IRotation] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::IRotation] = [this](Msg msg, Capability& data) -> Result {
|
|
std::initializer_list<Fix32> Orientation_list = { Fix32(0.0f),Fix32(90.0f),Fix32(180.0f),Fix32(270.0f) };
|
|
switch (msg) {
|
|
case Msg::Get:{
|
|
if (m_gcap->imageProcess.orentation > 3)
|
|
data = Capability::createEnumeration<CapType::IRotation>(Orientation_list, 0, 0);
|
|
else
|
|
data = Capability::createEnumeration<CapType::IRotation>(Orientation_list, (int)m_gcap->imageProcess.orentation,0);
|
|
return success();
|
|
}
|
|
case Msg::GetCurrent:
|
|
if (m_gcap->imageProcess.orentation > 3)
|
|
data = Capability::createOneValue<CapType::IRotation>(0.0f);
|
|
else
|
|
data = Capability::createOneValue<CapType::IRotation>(*(Orientation_list.begin() + m_gcap->imageProcess.orentation));
|
|
return success();
|
|
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.orentation = Orentation::ROTATE_NONE;
|
|
data = Capability::createOneValue<CapType::IRotation>(Fix32(0.0));
|
|
return success();
|
|
|
|
case Msg::Set: {
|
|
auto res = data.currentItem<Fix32>();
|
|
if (std::find(Orientation_list.begin(), Orientation_list.end(), res) != Orientation_list.end()) {
|
|
float ROTATE = (float)res;
|
|
m_gcap->imageProcess.orentation = (Orentation)std::distance(Orientation_list.begin(), std::find(Orientation_list.begin(), Orientation_list.end(), Fix32(res)));
|
|
return success();
|
|
}
|
|
return badValue();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
if (model != 0)
|
|
{
|
|
scanner->Get_Scanner_PaperOn(); //针对G300 G400 USB通信第一次无法read_bulk 起到激活USB的作用
|
|
}
|
|
|
|
|
|
|
|
|
|
m_query[CapType::SerialNumber] = msgSupportGetAll;
|
|
//m_caps[CapType::SerialNumber] = std::bind(oneValGetString, _1, _2, scanner->GetSerialNum());
|
|
m_caps[CapType::SerialNumber] = [this](Msg msg, Capability& data)->Result {
|
|
Str255 str;
|
|
str.setData(scanner->GetSerialNum(model).c_str(), scanner->GetSerialNum(model).size());
|
|
return CapSupGetAll<Str255, Str255, CapType::SerialNumber>(msg, data, str, str);
|
|
};
|
|
|
|
|
|
m_query[(CapType)(CapTypeEx::TwEx_HardwareVersion)] = msgSupportGetAll;
|
|
//m_caps[(CapType)(CapTypeEx::TwEx_HardwareVersion)] = std::bind(oneValGetString, _1, _2, scanner->GetFWVersion());
|
|
m_caps[(CapType)(CapTypeEx::TwEx_HardwareVersion)] = [this](Msg msg, Capability& data)->Result {
|
|
Str255 str;
|
|
str.setData(scanner->GetFWVersion(model).c_str(), scanner->GetFWVersion(model).size());
|
|
return CapSupGetAllEx<Str255, (CapType)CapTypeEx::TwEx_HardwareVersion>(msg, data, str, str);
|
|
};
|
|
|
|
m_query[CapType::FeederLoaded] = msgSupportGetAll;
|
|
m_caps[CapType::FeederLoaded] = [this](Msg msg, Capability& data) -> Result {
|
|
return CapSupGetAll<Bool, Bool, CapType::FeederLoaded>(msg, data, Bool(scanner->Get_Scanner_PaperOn()), Bool(scanner->Get_Scanner_PaperOn()));
|
|
};
|
|
|
|
m_query[CapType::Indicators] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::Indicators] = [this](Msg msg, Capability& data) -> Result {
|
|
if (Msg::Set == msg) {
|
|
auto show = data.currentItem<CapType::Indicators>();
|
|
m_bIndicator = show;
|
|
return success();
|
|
}
|
|
return CapSupGetAllReset<bool, Bool, CapType::Indicators>(msg, data, { FALSE,TRUE }, m_bIndicator, TRUE, m_bIndicator ? 1 : 0, 1);
|
|
};
|
|
|
|
m_query[CapType::CustomDsData] = msgSupportGetAll;
|
|
m_caps[CapType::CustomDsData] = [this](Msg msg, Capability& data) -> Result {
|
|
return CapSupGetAllEx<Bool, CapType::CustomDsData>(msg, data, Bool(true), Bool(true));
|
|
};
|
|
|
|
m_query[CapType::EnableDsUiOnly] = msgSupportGetAll;
|
|
m_caps[CapType::EnableDsUiOnly] = std::bind(enmGet<Bool>, _1, _2, Bool(true));
|
|
//m_caps[CapType::EnableDsUiOnly] = std::bind(enmGet<Bool>, _1, _2, []()->BOOL {return true; });
|
|
m_query[CapType::PaperDetectable] = msgSupportGetAll;
|
|
m_caps[CapType::PaperDetectable] = std::bind(enmGet<Bool>, _1, _2, Bool(true));
|
|
//m_caps[CapType::PaperDetectable] = std::bind(enmGet<Bool>, _1, _2, []()->BOOL {return true; });
|
|
m_query[CapType::FeederEnabled] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::FeederEnabled] = [this](Msg msg, Capability& data) -> Result {
|
|
if (Msg::Set == msg) {
|
|
auto mech = data.currentItem<CapType::FeederEnabled>();
|
|
m_bFeederEnabled = mech;
|
|
return success();
|
|
}
|
|
return CapSupGetAllReset<bool, Bool, CapType::PaperDetectable>(msg, data, m_bFeederEnabled, Bool(true));
|
|
};
|
|
|
|
m_query[CapType::Duplex] = msgSupportGetAll;
|
|
//m_caps[CapType::Duplex] = std::bind(oneValGet<Duplex>, _1, _2, []()->Duplex {return Duplex::OnePass; });
|
|
m_caps[CapType::Duplex] = std::bind(oneValGet<Duplex>, _1, _2, Duplex::OnePass);
|
|
m_query[CapType::DuplexEnabled] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::DuplexEnabled] = [this](Msg msg, Capability& data) -> Result {
|
|
if (Msg::Set == msg) {
|
|
auto mech = data.currentItem<CapType::DuplexEnabled>();
|
|
m_gcap->scanSide.duplex = mech != 0 ? true : false;
|
|
m_gcap->scanSide.discardBlank = m_gcap->scanSide.discardBlankVince = m_gcap->scanSide.fold = false;
|
|
if (!mech)
|
|
m_gcap->imageProcess.backRotate180 = false;//单面背面旋转180°不可用
|
|
return success();
|
|
}
|
|
return CapSupGetAllReset<int, bool, CapType::DuplexEnabled>(msg, data, m_gcap->scanSide.duplex, true);
|
|
};
|
|
|
|
m_query[CapType::AutoFeed] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::AutoFeed] = [this](Msg msg, Capability& data) -> Result {
|
|
if (Msg::Set == msg) {
|
|
auto mech = data.currentItem<CapType::AutoFeed>();
|
|
m_bAutoFeed = mech;
|
|
return success();
|
|
}
|
|
return CapSupGetAllReset<bool, Bool, CapType::AutoFeed>(msg, data, { false,true }, m_bAutoFeed, true, m_bAutoFeed ? 1 : 0, 1);
|
|
};
|
|
|
|
m_query[CapType::IImageFileFormat] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::IImageFileFormat] = [this](Msg msg, Capability& data) -> Result {
|
|
if (Msg::Set == msg) {
|
|
auto mech = data.currentItem<CapType::IImageFileFormat>();
|
|
if (mech == ImageFileFormat::Bmp || mech == ImageFileFormat::Tiff||mech == ImageFileFormat::Jfif) {
|
|
m_capImageFileFormat =mech;
|
|
return success();
|
|
}
|
|
else {
|
|
return badValue();
|
|
}
|
|
}
|
|
return CapSupGetAllReset< ImageFileFormat, ImageFileFormat, CapType::IImageFileFormat>(msg, data, { ImageFileFormat::Tiff ,ImageFileFormat::Jfif ,ImageFileFormat::Bmp }, m_capImageFileFormat
|
|
, ImageFileFormat::Bmp, m_capImageFileFormat == ImageFileFormat::Jfif ? 1 : int(m_capImageFileFormat), 2);
|
|
};
|
|
|
|
//custom define
|
|
m_query[CapType::IAutomaticDeskew] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::IAutomaticDeskew] = [this](Msg msg, Capability& data)->Result {
|
|
if( Msg::Set==msg) {
|
|
auto atuodsw = data.currentItem<CapType::IAutomaticDeskew>();
|
|
m_gcap->hardwareParam.skewDetection.enable = atuodsw != 0 ? 1 : 0;
|
|
return success();
|
|
}
|
|
return CapSupGetAllReset<int, bool, CapType::IAutomaticDeskew>(msg, data, m_gcap->hardwareParam.skewDetection.enable, true);
|
|
};
|
|
|
|
m_query[(CapType)(CapTypeEx::TwEx_SwitchFrontBack)] = msgSupportGetAllSetReset;
|
|
m_caps[(CapType)(CapTypeEx::TwEx_SwitchFrontBack)] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
data = Capability::createEnumeration<Bool>((CapType)((CapType)(CapTypeEx::TwEx_SwitchFrontBack)), { Bool(),Bool(true) }, Bool(m_gcap->scanSide.switchFrontBack), 0);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetCurrent:
|
|
m_gcap->scanSide.switchFrontBack = false;
|
|
data = Capability::createOneValue<Bool>((CapType)((CapType)(CapTypeEx::TwEx_SwitchFrontBack)), (Bool)m_gcap->scanSide.switchFrontBack);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
data = Capability::createOneValue<Bool>((CapType)((CapType)(CapTypeEx::TwEx_SwitchFrontBack)), Bool(false));
|
|
return success();
|
|
case Msg::Set: {
|
|
bool mech = data.currentItem<Bool>();
|
|
m_gcap->scanSide.switchFrontBack = mech;
|
|
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_gcap->imageProcess.orentation == Orentation::AUTOTEXT_DETECT));
|
|
return success();
|
|
// fallthrough
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<CapType::IAutomaticRotate>(m_gcap->imageProcess.orentation == Orentation::AUTOTEXT_DETECT);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.orentation = Orentation::ROTATE_NONE;
|
|
data = Capability::createOneValue<CapType::IAutomaticRotate>(false);
|
|
return success();
|
|
|
|
case Msg::Set: {
|
|
auto mech = data.currentItem<CapType::IAutomaticRotate>();
|
|
if (mech != 0)
|
|
m_gcap->imageProcess.orentation = Orentation::AUTOTEXT_DETECT;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
m_query[CapType::IAutomaticCropUsesFrame] = msgSupportGetAll;
|
|
m_caps[CapType::IAutomaticCropUsesFrame] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
data = Capability::Capability::createOneValue<CapType::IAutomaticCropUsesFrame>(m_gcap->imageProcess.autoCrop);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetCurrent:
|
|
m_gcap->imageProcess.autoCrop = false;
|
|
data = Capability::createOneValue<CapType::IAutomaticCropUsesFrame>(m_gcap->imageProcess.autoCrop);
|
|
return success();
|
|
|
|
case Msg::GetDefault:
|
|
data = Capability::createOneValue<CapType::IAutomaticCropUsesFrame>(false);
|
|
return success();
|
|
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
m_query[CapType::AutoScan] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::AutoScan] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
data = Capability::createEnumeration<CapType::AutoScan>(
|
|
{ Bool(), Bool(true) }, m_autoscan);
|
|
return success();
|
|
case Msg::Reset:
|
|
m_autoscan = true;
|
|
data = Capability::createOneValue<CapType::AutoScan>(m_autoscan);
|
|
return success();
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<CapType::AutoScan>(m_autoscan);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
data = Capability::createOneValue<CapType::AutoScan>(true);
|
|
return success();
|
|
|
|
case Msg::Set: {
|
|
auto autoscan = data.currentItem<CapType::AutoScan>();
|
|
m_autoscan = autoscan;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
m_query[CapType::IAutoSize] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::IAutoSize] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
data = Capability::createEnumeration<CapType::IAutoSize>(
|
|
{ AutoSize::None, AutoSize::Auto}, (UInt16)m_autosize, 0);
|
|
return success();
|
|
// fallthrough
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<CapType::IAutoSize>((AutoSize)m_autosize);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetDefault:
|
|
m_autosize = (UInt16)AutoSize::None;
|
|
data = Capability::createOneValue<CapType::IAutoSize>(AutoSize::None);
|
|
return success();
|
|
|
|
case Msg::Set: {
|
|
auto autosize = data.currentItem<CapType::IAutoSize>();
|
|
if (autosize == AutoSize::Auto)
|
|
{
|
|
if (json_cast(m_gcap->paperSize).to_int()==(int)TwSS::None){
|
|
m_gcap->imageProcess.autoCrop = false;
|
|
m_autoboarderdetcet = false;
|
|
}
|
|
else{
|
|
|
|
m_gcap->imageProcess.autoCrop = true;
|
|
m_gcap->paperSize = TwSS::None;
|
|
m_gcap->paperAlign = PaperAlign::Rot0;
|
|
m_autoboarderdetcet = true;
|
|
}
|
|
}
|
|
else{
|
|
m_autoboarderdetcet = false;
|
|
m_gcap->imageProcess.autoCrop = false;
|
|
}
|
|
m_autosize = (UInt16)autosize;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
m_query[CapType::IAutomaticBorderDetection] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::IAutomaticBorderDetection] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<CapType::IAutomaticBorderDetection>(m_autoboarderdetcet);
|
|
return success();
|
|
case Msg::Reset:
|
|
m_autoboarderdetcet = false;
|
|
data = Capability::createOneValue<CapType::IAutomaticBorderDetection>(m_autoboarderdetcet);
|
|
return success();
|
|
|
|
case Msg::GetDefault:
|
|
data = Capability::createOneValue<CapType::IAutomaticBorderDetection>(false);
|
|
return success();
|
|
|
|
case Msg::Set: {
|
|
auto autodetectborder = data.currentItem<CapType::IAutomaticBorderDetection>();
|
|
if (autodetectborder&&(m_gcap->paperSize!=TwSS::USStatement)){
|
|
m_gcap->imageProcess.autoCrop = true;
|
|
m_gcap->paperSize = TwSS::None;
|
|
m_gcap->paperAlign = PaperAlign::Rot0;
|
|
m_autosize = (UInt16)AutoSize::Auto;
|
|
}
|
|
else{
|
|
m_autosize = (UInt16)AutoSize::None;
|
|
}
|
|
m_autoboarderdetcet = autodetectborder;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
m_query[CapType(CapTypeEx::TwEx_EnFold)] = msgSupportGetAllSetReset;
|
|
m_caps[CapType(CapTypeEx::TwEx_EnFold)] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
data = Capability::createEnumeration<Int32>(CapType(CapTypeEx::TwEx_EnFold), {0,1}, m_gcap->scanSide.fold, 0);
|
|
return success();
|
|
case Msg::Reset:
|
|
m_gcap->scanSide.fold = false;//默认不对折
|
|
data = Capability::createOneValue<Int32>(CapType(CapTypeEx::TwEx_EnFold), m_gcap->scanSide.fold);
|
|
return success();
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Int32>(CapType(CapTypeEx::TwEx_EnFold), m_gcap->scanSide.fold);
|
|
return success();
|
|
|
|
case Msg::GetDefault:
|
|
m_gcap->scanSide.fold = false;
|
|
data = Capability::createOneValue<Int32>(CapType(CapTypeEx::TwEx_EnFold),0);
|
|
return success();
|
|
|
|
case Msg::Set: {
|
|
auto autocrop = data.currentItem<Int32>();
|
|
m_gcap->scanSide.fold = (int)autocrop != 0 ? true : false;
|
|
if ((Int32)autocrop != 0){
|
|
m_gcap->scanSide.fold = true;
|
|
m_gcap->hardwareParam.skewDetection.enable = true;//合并可用时 默认自动纠偏
|
|
m_gcap->scanSide.discardBlank = m_gcap->scanSide.discardBlankVince = false;
|
|
}
|
|
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::createOneValue<CapType::IAutoDiscardBlankPages>(m_gcap->scanSide.discardBlank ? DiscardBlankPages::Auto : DiscardBlankPages::Disabled);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetDefault:
|
|
m_gcap->scanSide.discardBlank = false;
|
|
data = Capability::createOneValue<CapType::IAutoDiscardBlankPages>(DiscardBlankPages::Disabled);
|
|
return success();
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<CapType::IAutoDiscardBlankPages>(m_gcap->scanSide.discardBlank ? DiscardBlankPages::Auto : DiscardBlankPages::Disabled);
|
|
return success();
|
|
|
|
case Msg::Set: {
|
|
auto mech = data.currentItem<CapType::IAutoDiscardBlankPages>();
|
|
if ((mech != DiscardBlankPages::Auto) || (mech != DiscardBlankPages::Disabled))
|
|
return badValue();
|
|
|
|
m_gcap->scanSide.discardBlank = (Int32)mech == (Int32)DiscardBlankPages::Auto;
|
|
m_gcap->scanSide.duplex = true;
|
|
m_gcap->scanSide.fold = false;
|
|
m_gcap->scanSide.discardBlankVince = false;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
/*costom caps*/
|
|
//跳过空白页发票
|
|
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_gcap->scanSide.discardBlankVince), 0);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetDefault:
|
|
m_gcap->scanSide.discardBlankVince = false;
|
|
data = Capability::createOneValue<Bool>((CapType)((CapType)(CapTypeEx::TwEx_IAutoDiscardBlankVince)), Bool(false));
|
|
return success();
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Bool>((CapType)((CapType)(CapTypeEx::TwEx_IAutoDiscardBlankVince)), m_gcap->scanSide.discardBlankVince);
|
|
return success();
|
|
case Msg::Set: {
|
|
bool mech = data.currentItem<Bool>();
|
|
m_gcap->scanSide.discardBlankVince = mech;
|
|
m_gcap->scanSide.duplex = true;
|
|
m_gcap->scanSide.fold = false;
|
|
if (mech)
|
|
m_gcap->scanSide.discardBlank = false;
|
|
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_gcap->imageProcess.backRotate180), 0);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetDefault:
|
|
m_gcap->imageProcess.backRotate180 = false;
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IBackRotate180), Bool(false));
|
|
return success();
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IBackRotate180), m_gcap->imageProcess.backRotate180);
|
|
return success();
|
|
case Msg::Set: {
|
|
bool mech = data.currentItem<Bool>();
|
|
m_gcap->imageProcess.backRotate180 = mech;
|
|
if (mech)
|
|
m_gcap->scanSide.duplex = true;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
//填黑框
|
|
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_gcap->imageProcess.fillBlackRect), 1);
|
|
return success();
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IFillBackground), m_gcap->imageProcess.fillBlackRect);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetDefault:
|
|
m_gcap->imageProcess.fillBlackRect = true;
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IFillBackground), Bool(true));
|
|
|
|
return success();
|
|
case Msg::Set: {
|
|
bool mech = data.currentItem<Bool>();
|
|
m_gcap->imageProcess.fillBlackRect = mech;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
//裁剪纠偏轮廓缩进像素
|
|
m_query[(CapType)(CapTypeEx::TwEx_CroporDesaskewIndent)] = msgSupportGetAllSetReset;
|
|
m_caps[(CapType)(CapTypeEx::TwEx_CroporDesaskewIndent)] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<UInt8>((CapType)(CapTypeEx::TwEx_CroporDesaskewIndent), m_gcap->imageProcess.indent);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetDefault:
|
|
m_gcap->imageProcess.indent = 5;
|
|
data = Capability::createOneValue<UInt8>((CapType)(CapTypeEx::TwEx_CroporDesaskewIndent), UInt8(5));
|
|
return success();
|
|
case Msg::Set: {
|
|
auto mech = data.currentItem<UInt8>();
|
|
|
|
if (mech > 30 || mech < 5)
|
|
return badValue();
|
|
m_gcap->imageProcess.indent = mech;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
//自动裁剪降噪像素
|
|
m_query[(CapType)(CapTypeEx::TwEx_CropNoise)] = msgSupportGetAllSetReset;
|
|
m_caps[(CapType)(CapTypeEx::TwEx_CropNoise)] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<UInt8>((CapType)(CapTypeEx::TwEx_CropNoise), m_gcap->imageProcess.noise);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetDefault:
|
|
m_gcap->imageProcess.noise = 40;
|
|
data = Capability::createOneValue<UInt8>((CapType)(CapTypeEx::TwEx_CropNoise), UInt8(40));
|
|
return success();
|
|
case Msg::Set: {
|
|
auto mech = data.currentItem<UInt8>();
|
|
|
|
if (mech > 50 || mech < 30)
|
|
return badValue();
|
|
m_gcap->imageProcess.noise = mech;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
//自动裁切和纠偏的二值化阀值
|
|
m_query[(CapType)(CapTypeEx::TwEx_CroporDesaskewThreshold)] = msgSupportGetAllSetReset;
|
|
m_caps[(CapType)(CapTypeEx::TwEx_CroporDesaskewThreshold)] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<UInt8>((CapType)(CapTypeEx::TwEx_CroporDesaskewThreshold), m_gcap->imageProcess.AutoCrop_threshold);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetDefault:
|
|
m_gcap->imageProcess.AutoCrop_threshold = 40;
|
|
data = Capability::createOneValue<UInt8>((CapType)(CapTypeEx::TwEx_CroporDesaskewThreshold), UInt8(40));
|
|
return success();
|
|
case Msg::Set: {
|
|
auto mech = data.currentItem<UInt8>();
|
|
|
|
if (mech > 50 || mech < 30)
|
|
return badValue();
|
|
m_gcap->imageProcess.AutoCrop_threshold = mech;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
//黑框填充方式
|
|
m_query[(CapType)(CapTypeEx::TwEx_FillBackgroundMode)] = msgSupportGetAllSetReset;
|
|
m_caps[(CapType)(CapTypeEx::TwEx_FillBackgroundMode)] = [this](Msg msg, Capability& data)->Result {
|
|
if (Msg::Set == msg) {
|
|
auto mech = data.currentItem<Bool>();
|
|
m_gcap->imageProcess.is_convex = mech;
|
|
return success();
|
|
}
|
|
return CapSupGetAllResetEx<bool, Bool, (CapType)CapTypeEx::TwEx_FillBackgroundMode>(msg, data, m_gcap->imageProcess.is_convex, Bool(true));
|
|
};
|
|
//填穿孔
|
|
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_gcap->imageProcess.fillHole.enable), 0);
|
|
return success();
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IFillHole), m_gcap->imageProcess.fillHole.enable);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.fillHole.enable = false;
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IFillHole), Bool(false));
|
|
return success();
|
|
case Msg::Set: {
|
|
bool mech = data.currentItem<Bool>();
|
|
m_gcap->imageProcess.fillHole.enable = 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_gcap->imageProcess.fillHole.ratio);
|
|
return success();
|
|
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Int32>((CapType)(CapTypeEx::TwEx_IFillHoleRatio),m_gcap->imageProcess.fillHole.ratio);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.fillHole.ratio = 10;
|
|
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_gcap->imageProcess.fillHole.ratio = mech;
|
|
return success();
|
|
}
|
|
return badValue();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
//多流除红
|
|
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) }, m_gcap->imageProcess.multiOutFilterRed, false);
|
|
return success();
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IMultiOutputRed), m_gcap->imageProcess.multiOutFilterRed);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.multiOutFilterRed = false;
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_IMultiOutputRed), Bool(false));
|
|
return success();
|
|
case Msg::Set: {
|
|
auto mech = data.currentItem<Bool>();
|
|
if (m_gcap->pixelType == (ColorMode)PixelType::Rgb)
|
|
{
|
|
if (mech)
|
|
m_gcap->imageProcess.multiOutFilterRed = true;
|
|
else
|
|
m_gcap->imageProcess.multiOutFilterRed = false;
|
|
}
|
|
else
|
|
{
|
|
m_gcap->imageProcess.multiOutFilterRed = false;//非彩色 不能使用多流除红
|
|
}
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
//答题卡除红
|
|
m_query[(CapType)(CapTypeEx::TwEx_HsvCorrect)] = msgSupportGetAllSetReset;
|
|
m_caps[(CapType)(CapTypeEx::TwEx_HsvCorrect)] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
data = Capability::createEnumeration<Bool>((CapType)(CapTypeEx::TwEx_HsvCorrect), { Bool(),Bool(true) }, m_gcap->imageProcess.answerSheetFilterRed, 0);
|
|
return success();
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_HsvCorrect), m_gcap->imageProcess.answerSheetFilterRed);
|
|
return success();
|
|
case Msg::Reset:
|
|
case Msg::GetDefault:
|
|
m_gcap->imageProcess.answerSheetFilterRed = false;
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_HsvCorrect), Bool(false));
|
|
return success();
|
|
case Msg::Set: {
|
|
bool mech = data.currentItem<Bool>();
|
|
m_gcap->imageProcess.answerSheetFilterRed = 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_gcap->imageProcess.filter,3);
|
|
return success();
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<CapType::IFilter>((Filter)m_gcap->imageProcess.filter);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.filter = ColorFilter::FILTER_NONE;
|
|
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_gcap->imageProcess.filter = (ColorFilter)mech;
|
|
return success();
|
|
}
|
|
return badValue();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
//颜色增强
|
|
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<ColorFilter>((CapType)(CapTypeEx::TwEx_IEnhanceColor),
|
|
{ ColorFilter::FILTER_NONE,
|
|
ColorFilter::ENHANCE_RED,
|
|
ColorFilter::ENHANCE_GREEN,
|
|
ColorFilter::ENHANCE_BLUE },
|
|
m_gcap->imageProcess.filter,0);
|
|
return success();
|
|
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Int16>((CapType)(CapTypeEx::TwEx_IEnhanceColor), (ColorFilter)(m_gcap->imageProcess.filter));
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.filter = ColorFilter::FILTER_NONE;
|
|
data = Capability::createOneValue<Int16>((CapType)(CapTypeEx::TwEx_IEnhanceColor), ColorFilter::FILTER_NONE);
|
|
return success();
|
|
case Msg::Set: {
|
|
auto mech = data.currentItem<Int16>();
|
|
if (m_gcap->pixelType == (Int16)PixelType::Rgb){
|
|
m_gcap->imageProcess.filter = ColorFilter::FILTER_NONE;
|
|
}
|
|
else{
|
|
if (mech == ColorFilter::FILTER_NONE || mech == ColorFilter::ENHANCE_RED || mech == ColorFilter::ENHANCE_GREEN || mech == ColorFilter::ENHANCE_BLUE)
|
|
{
|
|
m_gcap->imageProcess.filter = (ColorFilter)mech;
|
|
if (mech != ColorFilter::FILTER_NONE)
|
|
m_gcap->imageProcess.filter = ColorFilter::FILTER_NONE;
|
|
return success();
|
|
}
|
|
}
|
|
return badValue();
|
|
}
|
|
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<SharpenType>((CapType)(CapTypeEx::TwEx_IEnhanceColor),
|
|
{ SharpenType::STNone,
|
|
SharpenType::Sharpen,
|
|
SharpenType::SharpenMore,
|
|
SharpenType::Blur,
|
|
SharpenType::BlurMore },
|
|
m_gcap->imageProcess.sharpenType,0);
|
|
return success();
|
|
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Int16>((CapType)(CapTypeEx::TwEx_Sharpen), m_gcap->imageProcess.sharpenType);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.sharpenType = SharpenType::STNone;
|
|
data = Capability::createOneValue<Int16>((CapType)(CapTypeEx::TwEx_Sharpen), SharpenType::STNone);
|
|
return success();
|
|
case Msg::Set: {
|
|
auto mech = data.currentItem<Int16>();
|
|
if (m_gcap->pixelType == ColorMode::BlackWhite)
|
|
return badValue();
|
|
m_gcap->imageProcess.sharpenType = (SharpenType)mech;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
/*亮度 对比度 gamma range类型 Range 类型*/
|
|
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_gcap->imageProcess.brightness), Fix32(0.0));
|
|
return success();
|
|
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<CapType::IBrightness>(Fix32(m_gcap->imageProcess.brightness));
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.brightness = 0.0;
|
|
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_gcap->imageProcess.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_gcap->imageProcess.contrast), Fix32(0.0));
|
|
return success();
|
|
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<CapType::IContrast>(Fix32(m_gcap->imageProcess.contrast));
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.contrast = 0;
|
|
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_gcap->imageProcess.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_gcap->imageProcess.gamma), Fix32(1.0));
|
|
return success();
|
|
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<CapType::IGamma>(Fix32(m_gcap->imageProcess.gamma));
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->imageProcess.gamma = 1.0f;
|
|
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_gcap->imageProcess.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();
|
|
// }
|
|
//};
|
|
|
|
/*以下为硬件协议*/
|
|
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_gcap->hardwareParam.skewDetection.enable), 0);
|
|
return success();
|
|
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_ScrewDetectEnable), (Bool)m_gcap->hardwareParam.skewDetection.enable);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->hardwareParam.skewDetection.enable = 0;
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_ScrewDetectEnable), Bool(false));
|
|
return success();
|
|
case Msg::Set: {
|
|
bool mech = data.currentItem<Bool>();
|
|
m_gcap->hardwareParam.skewDetection.enable = mech ? true : false;
|
|
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_gcap->hardwareParam.skewDetection.level);
|
|
return success();
|
|
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<UInt8>((CapType)(CapTypeEx::TwEx_ScrewLevel), m_gcap->hardwareParam.skewDetection.level);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->hardwareParam.skewDetection.level = 3;
|
|
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_gcap->hardwareParam.skewDetection.level = mech;
|
|
return success();
|
|
}
|
|
return badValue();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
//装订检测
|
|
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_gcap->hardwareParam.bindingDetection), 0);
|
|
return success();
|
|
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_StableDetectEnable), (Bool)m_gcap->hardwareParam.bindingDetection);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->hardwareParam.bindingDetection = false;
|
|
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_StableDetectEnable), Bool(false));
|
|
return success();
|
|
case Msg::Set: {
|
|
bool mech = data.currentItem<Bool>();
|
|
m_gcap->hardwareParam.bindingDetection = mech ? true : false;
|
|
return success();
|
|
}
|
|
default:
|
|
return capBadOperation();
|
|
}
|
|
};
|
|
|
|
//双张检测 与官方标准定义有所差异 此协议修改为bool型
|
|
m_query[CapType::DoubleFeedDetection] = msgSupportGetAllSetReset;
|
|
m_caps[CapType::DoubleFeedDetection] = [this](Msg msg, Capability& data)->Result {
|
|
switch (msg) {
|
|
case Msg::Get:
|
|
case Msg::GetCurrent:
|
|
data = Capability::createOneValue<Bool>(CapType::DoubleFeedDetection, (Bool)m_gcap->hardwareParam.doubleFeedDetection);
|
|
return success();
|
|
case Msg::GetDefault:
|
|
case Msg::Reset:
|
|
m_gcap->hardwareParam.doubleFeedDetection = false;
|
|
data = Capability::createOneValue<Bool>(CapType::DoubleFeedDetection, Bool(false));
|
|
return success();
|
|
case Msg::Set: {
|
|
bool mech = data.currentItem<Bool>();
|
|
m_gcap->hardwareParam.doubleFeedDetection = mech ? true : false;
|
|
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
|
|
scanner.reset();
|
|
scannerUI.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
|
|
cv::Mat image;
|
|
int ret = GetBmpData(*bmpData.get(), *scanner,m_gcap->scanCount);
|
|
|
|
if (ret !=0) {
|
|
scanner->Set_ErrorCode(0);
|
|
scannerUI->hideindicator();
|
|
if (ret != -1) {
|
|
if (scanner->is_scan() == 0)
|
|
scanner->Stop_scan();
|
|
//QMessageBox::warning(NULL, QObject::tr("Warning"), QString::fromLocal8Bit(noticeMsgMap[ret].c_str()), QMessageBox::StandardButton::Ok);
|
|
FileTools::showmsg("错误", noticeMsgMap[ret]);
|
|
}
|
|
m_pendingXfers = 0;
|
|
|
|
}
|
|
else {
|
|
m_pendingXfers = 1;
|
|
}
|
|
|
|
data.setCount(m_pendingXfers);
|
|
return success();
|
|
}
|
|
|
|
Result HuagaoDs::pendingXfersReset(const Identity&, PendingXfers& data){
|
|
data.setCount(0);
|
|
if (scanner.get())
|
|
{
|
|
scanner->Stop_scan();
|
|
scanner->reset();
|
|
scanner->ResetScanner();
|
|
}
|
|
scannerUI->hideindicator();
|
|
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){
|
|
|
|
scannerUI->closeTwainUI();
|
|
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 ed only in enabled state
|
|
// with hidden UI, the usual workflow DsState::Enabled -> notifyXferReady() -> DsState::XferReady is a single step
|
|
auto ret = startScan(*m_gcap);
|
|
if (ret.status().condition() == Twpp::CC::NoMedia)
|
|
return ret;
|
|
return success();
|
|
}
|
|
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&, Twpp::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((Fix32)m_gcap->resolution);
|
|
data.setYResolution((Fix32)m_gcap->resolution);
|
|
data.compression(m_compression);
|
|
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
|
|
if (m_pendingXfers == 0)
|
|
return success();
|
|
auto dib = header();
|
|
|
|
data.setDocumentNumber(1);
|
|
data.setFrameNumber(1);
|
|
data.setPageNumber(1);
|
|
data.setFrame(Frame(0, 0, static_cast<float>(dib->biWidth) /m_gcap->resolution, static_cast<float>(dib->biHeight) / m_gcap->resolution));
|
|
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
|
|
}
|
|
cv::Mat mat;
|
|
vector<uchar> cmpdata;
|
|
if (m_compression == Compression::Group4)
|
|
{
|
|
mat = cv::imdecode(*bmpData.get(), cv::IMREAD_GRAYSCALE);
|
|
G4Tiff gt(mat,G4Tiff::Mode::MemoryMode,"",120,m_gcap->resolution);
|
|
gt.GetCompressedData(cmpdata);
|
|
}
|
|
|
|
data.setBytesPerRow(bpl);
|
|
data.setColumns(static_cast<UInt32>(dib->biWidth));
|
|
data.setRows(rows);
|
|
data.setBytesWritten(m_compression==Compression::None?bpl*rows: cmpdata.size());
|
|
data.setXOffset(0);
|
|
data.setYOffset(m_memXferYOff);
|
|
data.setCompression(m_compression);
|
|
|
|
auto lock = data.memory().data();
|
|
char* out = lock.data();
|
|
// bottom-up BMP -> top-down memory transfer
|
|
if (m_compression == Compression::None)
|
|
{
|
|
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;
|
|
|
|
if (dib->biBitCount == 24)
|
|
{
|
|
//BGR BMP -> RGB memory transfer
|
|
for (; line + 3 < out; line += 3) {
|
|
std::swap(line[0], line[2]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::copy(cmpdata.data(), cmpdata.data() + cmpdata.size(), out);
|
|
}
|
|
|
|
m_memXferYOff += rows;
|
|
|
|
if (m_memXferYOff >= static_cast<UInt32>(std::abs(dib->biHeight))) {
|
|
m_pendingXfers = 0;
|
|
m_memXferYOff = 0;
|
|
bmpData.reset(new std::vector<unsigned char>);
|
|
return { ReturnCode::XferDone, ConditionCode::Success };
|
|
}
|
|
|
|
return success();
|
|
}
|
|
#ifdef LOG_NORMAL
|
|
static int xtfer = 0;
|
|
#endif
|
|
|
|
|
|
Twpp::Result HuagaoDs::imageFileXferGet(const Twpp::Identity& origin)
|
|
{
|
|
if (!m_pendingXfers)
|
|
return seqError();
|
|
string filename = m_fileXfer.filePath().string();
|
|
switch (m_fileXfer.format())
|
|
{
|
|
case ImageFileFormat::Bmp: {
|
|
|
|
FILE* pfile = fopen(filename.c_str(), "wb");
|
|
if (pfile) {
|
|
if (bmpData->size() > 0) {
|
|
fwrite(bmpData->data(), 1, bmpData->size(), pfile);
|
|
bmpData.reset(new std::vector<unsigned char>);
|
|
fclose(pfile);
|
|
return Result(ReturnCode::XferDone, ConditionCode::Success);
|
|
}
|
|
}
|
|
return Result(ReturnCode::Failure, ConditionCode::BadValue);
|
|
}
|
|
case ImageFileFormat::Tiff:
|
|
case ImageFileFormat::Jfif: {
|
|
|
|
BITMAPINFOHEADER& bmpinfo = *((BITMAPINFOHEADER*)header());
|
|
int decodetype;
|
|
if (bmpinfo.biBitCount == 24)
|
|
decodetype = cv::IMREAD_COLOR;
|
|
else
|
|
decodetype = cv::IMREAD_GRAYSCALE;
|
|
|
|
|
|
cv::Mat ims = cv::imdecode(*bmpData.get(), decodetype);
|
|
|
|
if (m_compression == Compression::Group4&& m_fileXfer.format()==ImageFileFormat::Tiff){
|
|
if (!ims.empty() && ims.channels() == 3)
|
|
cvtColor(ims, ims, cv::COLOR_BGR2GRAY);
|
|
G4Tiff gsave(ims, G4Tiff::Mode::FileMode, filename, 120, m_gcap->resolution);
|
|
gsave.SaveG4Tiff();
|
|
}
|
|
else{
|
|
std::vector<int> compression_params;
|
|
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
|
|
compression_params.push_back(m_jpegQuality);
|
|
cv::imwrite(filename, ims, compression_params);
|
|
}
|
|
bmpData.reset(new std::vector<unsigned char>);
|
|
ims.release();
|
|
return Result(ReturnCode::XferDone, ConditionCode::Success);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return badProtocol();
|
|
}
|
|
|
|
Result HuagaoDs::setupFileXferGet(const Twpp::Identity& origin, Twpp::SetupFileXfer& data)
|
|
{
|
|
data.setFilePath(m_fileXfer.filePath());
|
|
data.setFormat(m_fileXfer.format());
|
|
return success();
|
|
}
|
|
|
|
|
|
Result HuagaoDs::setupFileXferGetDefault(const Twpp::Identity& origin, Twpp::SetupFileXfer& data)
|
|
{
|
|
Str255 str("HGTwain.bmp");
|
|
data.setFilePath(str);
|
|
data.setFormat(ImageFileFormat::Bmp);
|
|
return success();
|
|
}
|
|
|
|
|
|
Result HuagaoDs::setupFileXferSet(const Twpp::Identity& origin, Twpp::SetupFileXfer& data)
|
|
{
|
|
m_fileXfer.setFilePath(data.filePath());
|
|
m_fileXfer.setFormat(data.format());
|
|
return success();
|
|
}
|
|
|
|
|
|
Result HuagaoDs::setupFileXferReset(const Twpp::Identity& origin, Twpp::SetupFileXfer& data)
|
|
{
|
|
m_fileXfer.setFormat(Twpp::ImageFileFormat::Bmp);
|
|
std::string templateName = "HG";
|
|
std::string tempPath = _mktemp((char*)templateName.c_str());
|
|
if (!tempPath.empty()) {
|
|
Str255 str;
|
|
str.setData(tempPath.c_str(), tempPath.size());
|
|
m_fileXfer.setFilePath(str);
|
|
return success();
|
|
}
|
|
return badProtocol();
|
|
}
|
|
Twpp::Result HuagaoDs::customDataGet(const Twpp::Identity& origin, Twpp::CustomData& data)
|
|
{
|
|
std::string file = m_params.dump();
|
|
data = CustomData(file.length());
|
|
auto pdata = data.lock<unsigned char>();
|
|
memcpy(pdata.data(), file.c_str(), file.length());
|
|
return success();
|
|
}
|
|
|
|
Result HuagaoDs::customDataSet(const Twpp::Identity& origin, Twpp::CustomData& data)
|
|
{
|
|
|
|
std::string str;
|
|
str.resize(data.size());
|
|
auto pdata = data.lock<unsigned char>();
|
|
memcpy((void*)str.c_str(), pdata, data.size());
|
|
m_params = json::parse(str);
|
|
return success();
|
|
|
|
}
|
|
|
|
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());
|
|
|
|
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){
|
|
auto getfwversion = [=]()->std::string{
|
|
return scanner->GetFWVersion(model);
|
|
};
|
|
auto getserialnum = [=]()->std::string{
|
|
return scanner->GetSerialNum(model);
|
|
};
|
|
auto scanFunction = [this](const GScanCap& caps) {
|
|
m_pendingXfers = 1;
|
|
|
|
if (startScan(caps) == success()) {
|
|
//JsonConfig json;
|
|
//json.WriteToJson(m_scanparam.get(), Global::appJsonName);
|
|
notifyXferReady();
|
|
}
|
|
else {
|
|
m_pendingXfers = 0;
|
|
}
|
|
};
|
|
//!< ui only to confirm button push
|
|
auto confirmFunction = [this](const GScanCap& caps) {
|
|
notifyCloseOk();
|
|
};
|
|
|
|
//!< cancel button push
|
|
auto cancelFunction = [this]() {
|
|
notifyCloseCancel();
|
|
};
|
|
auto stopFunc = [this]() {
|
|
if (scanner.get())
|
|
scanner->Stop_scan();
|
|
};
|
|
scannerUI->getjsonstring(m_params.dump());
|
|
scannerUI->showTwainUI(ui.parent().raw(), bUiOnly,
|
|
Func(scanFunction, confirmFunction, cancelFunction ,stopFunc,getfwversion,getserialnum ),
|
|
Model, ui.modalUi());
|
|
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;
|
|
}
|
|
|
|
Twpp::Result HuagaoDs::startScan(const GScanCap& param)
|
|
{
|
|
if (!scanner->IsConnected())
|
|
return checkDeviceOnline();
|
|
|
|
scanner->ResetScanner();
|
|
scanner->setmode(model);
|
|
scanner->config_params(const_cast<GScanCap&>(param),model);
|
|
scannerUI->is_showindicator(m_bIndicator);
|
|
scannerUI->showindicator();
|
|
scanner->Scanner_StartScan(param.scanCount,model);
|
|
if (bmpData->size() > 0)
|
|
bmpData->clear();
|
|
int retCode = GetBmpData(*bmpData.get(), *scanner, param.resolution);
|
|
if (retCode!=0) {
|
|
scanner->Set_ErrorCode(0);
|
|
scannerUI->hideindicator();
|
|
if (retCode != -1)
|
|
{
|
|
//if (scanner->is_scan() == 0)
|
|
// scanner->Stop_scan();
|
|
//QMessageBox::warning(NULL, QObject::tr("Warning"), QString::fromLocal8Bit(noticeMsgMap[retCode].c_str()), QMessageBox::StandardButton::Ok);
|
|
FileTools::showmsg("错误", noticeMsgMap[retCode]);
|
|
}
|
|
return seqError();
|
|
}
|
|
|
|
if (bmpData->size()>0) {
|
|
return success();
|
|
}
|
|
else {
|
|
scannerUI->hideindicator();
|
|
return seqError();
|
|
}
|
|
return success();
|
|
}
|
|
|
|
#if TWPP_DETAIL_OS_WIN
|
|
static HANDLE Mmutex;
|
|
BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) {
|
|
switch (reason) {
|
|
case DLL_PROCESS_ATTACH:
|
|
// anything you want to execute when the source is loaded
|
|
Mmutex = CreateMutex(NULL, FALSE, "HuagoQtTwain");
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
{
|
|
CloseHandle(Mmutex);
|
|
Mmutex = NULL;
|
|
//::MessageBox(NULL, "设备已被其他程序占用,请关闭占用程序之后再重试!", "错误", MB_OK);
|
|
FileTools::showmsg("错误","设备已被其他程序占用,请关闭占用程序之后再重试!");
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
// anything you want to execute when the source is unloaded
|
|
if (Mmutex)
|
|
CloseHandle(Mmutex);
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#endif
|