#include #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 #include #include "DeviceHelper.h" #include "ScannerUI.h" #include #include #include //#include "JsonConfig.h" #include #include #include using namespace std; using namespace Twpp; using namespace std::placeholders; namespace __range_to_initializer_list { constexpr size_t DEFAULT_MAX_LENGTH = 128; template struct backingValue { static V value; }; template V backingValue::value; template struct backingList { static std::initializer_list list; }; template std::initializer_list backingList::list = { (Vcount)backingValue::value... }; template static typename std::enable_if< sizeof...(Vcount) >= maxLength, std::initializer_list >::type generate_n(It begin, It end, It current) { throw std::length_error("More than maxLength elements in range."); } template static typename std::enable_if < sizeof...(Vcount) < maxLength, std::initializer_list > ::type generate_n(It begin, It end, It current) { if (current != end) return generate_n(begin, end, ++current); current = begin; for (auto it = backingList::list.begin(); it != backingList::list.end(); ++current, ++it) *const_cast(&*it) = *current; return backingList::list; } } template std::initializer_list range_to_initializer_list(It begin, It end) { return __range_to_initializer_list::generate_n(begin, end, begin); } template std::initializer_list range_to_initializer_list(Vec v) { return __range_to_initializer_list::generate_n(v.begin(), v.end(), v.begin()); } template Result CapSupGetAll(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) { switch (msg) { case Msg::Get: case Msg::GetCurrent: case Msg::GetDefault: data = Capability::createOneValue((T2)defaultvalue); return { ReturnCode::Success, ConditionCode::Success }; default: return { ReturnCode::Failure, ConditionCode::CapBadOperation }; } } template Result CapSupGetAllEx(Msg msg, Capability& data, T& currvalue, T defaultvalue) { switch (msg) { case Msg::Get: case Msg::GetCurrent: case Msg::GetDefault: data = Capability::createOneValue(cap, defaultvalue); return { ReturnCode::Success, ConditionCode::Success }; default: return { ReturnCode::Failure, ConditionCode::CapBadOperation }; } } template Result CapSupGetAllReset(Msg msg, Capability& data, std::initializer_list values, T1& currvalue, T2 defaultvalue, UInt32 currindex, UInt32 defaultindex) { switch (msg) { case Msg::Get: data = Capability::createEnumeration(values, currindex, defaultindex); return { ReturnCode::Success, ConditionCode::Success }; case Msg::GetCurrent: data = Capability::createOneValue((T2)currvalue); return { ReturnCode::Success, ConditionCode::Success }; case Msg::Reset: case Msg::GetDefault: currvalue = (T1)defaultvalue; data = Capability::createOneValue(defaultvalue); return { ReturnCode::Success, ConditionCode::Success }; default: return { ReturnCode::Failure, ConditionCode::CapBadOperation }; } } template Result CapSupGetAllReset(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) { switch (msg) { case Msg::Get: case Msg::GetCurrent: data = Capability::createOneValue((T2)currvalue); return { ReturnCode::Success, ConditionCode::Success }; case Msg::Reset: case Msg::GetDefault: currvalue = (T1)defaultvalue; data = Capability::createOneValue(defaultvalue); return { ReturnCode::Success, ConditionCode::Success }; default: return { ReturnCode::Failure, ConditionCode::CapBadOperation }; } } template Result CapSupGetAllResetEx(Msg msg, Capability& data, std::initializer_list 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 Result CapSupGetAllResetEx(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 }; } } //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 resList = { 100.0,150.0,200.0,240.0,300.0 ,600.0}; static list 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 imageRotateList = {0.0,90.0,180.0,270.0}; static map 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 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 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 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 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(); return {}; default: return {ReturnCode::Failure, ConditionCode::CapBadOperation}; } } template 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() == def ? Result() : Result(ReturnCode::Failure, ConditionCode::BadValue); default: return {ReturnCode::Failure, ConditionCode::CapBadOperation}; } } template 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() == 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); 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(m_caps.size()); auto arr = data.array(); 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, _1, _2, Bool(true)); m_query[CapType::DeviceOnline] = msgSupportGetAll; //m_caps[CapType::DeviceOnline] = std::bind(enmGet, _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((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(); if (item > 65535 || item < -1||item==0){ return badValue(); } m_gcap->scanCount = item; return success(); } Int16 scannum = m_gcap->scanCount; auto ret = oneValGetSet(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, _1, _2, Compression::None); m_caps[CapType::ICompression] = [this](Msg msg, Capability& data)->Result{ if (Msg::Set == msg){ auto mech = data.currentItem(); 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(); 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, _1, _2, BitOrder::MsbFirst); m_query[CapType::IPlanarChunky] = msgSupportGetAllSetReset; m_caps[CapType::IPlanarChunky] = std::bind(enmGetSetConst, _1, _2, PlanarChunky::Chunky); // m_query[CapType::IPhysicalWidth] = msgSupportGetAll; //m_caps[CapType::IPhysicalWidth] = std::bind(oneValGet, _1, _2, [this]()->Fix32 {return Fix32(static_cast(header()->biWidth) / m_params[Model][USER][RESOLUTION]); }); // m_query[CapType::IPhysicalHeight] = msgSupportGetAll; // m_caps[CapType::IPhysicalHeight] = std::bind(oneValGet, _1, _2, [this]()->Fix32 {return Fix32(static_cast(header()->biHeight) / m_params[Model][USER][RESOLUTION]); }); m_query[CapType::IPixelFlavor] = msgSupportGetAllSetReset; m_caps[CapType::IPixelFlavor] = std::bind(enmGetSetConst, _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(); 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(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(); if ((int)mech < 0 || (int)mech > 100) return badValue(); m_jpegQuality = (int)mech; return success(); } return CapSupGetAllResetEx(msg, data, m_jpegQuality, 80); }; m_query[CapType::IUnits] = msgSupportGetAllSetReset; m_caps[CapType::IUnits] = std::bind(enmGetSetConst, _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(); 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(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(); 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, _1, _2, Fix32(200.0)); //m_caps[CapType::IXNativeResolution] = std::bind(enmGet, _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, _1, _2, Bool(scanner->Get_Scanner_PaperOn()));*/ m_query[CapType::ISupportedSizes] = msgSupportGetAllSetReset; m_caps[CapType::ISupportedSizes] = [this](Msg msg, Capability& data) { std::initializer_list papersize_list = range_to_initializer_list(std::vector(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(); std::initializer_list papersize_list = range_to_initializer_list(std::vector(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(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(); if(mech== Orientation::Landscape|| mech == Orientation::Portrait){ m_gcap->paperAlign =(PaperAlign)mech; return success(); } return badValue(); } return CapSupGetAllReset(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 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(Orientation_list, 0, 0); else data = Capability::createEnumeration(Orientation_list, (int)m_gcap->imageProcess.orentation,0); return success(); } case Msg::GetCurrent: if (m_gcap->imageProcess.orentation > 3) data = Capability::createOneValue(0.0f); else data = Capability::createOneValue(*(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(Fix32(0.0)); return success(); case Msg::Set: { auto res = data.currentItem(); 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(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(msg, data, str, str); }; m_query[CapType::FeederLoaded] = msgSupportGetAll; m_caps[CapType::FeederLoaded] = [this](Msg msg, Capability& data) -> Result { return CapSupGetAll(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(); m_bIndicator = show; return success(); } return CapSupGetAllReset(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(msg, data, Bool(true), Bool(true)); }; m_query[CapType::EnableDsUiOnly] = msgSupportGetAll; m_caps[CapType::EnableDsUiOnly] = std::bind(enmGet, _1, _2, Bool(true)); //m_caps[CapType::EnableDsUiOnly] = std::bind(enmGet, _1, _2, []()->BOOL {return true; }); m_query[CapType::PaperDetectable] = msgSupportGetAll; m_caps[CapType::PaperDetectable] = std::bind(enmGet, _1, _2, Bool(true)); //m_caps[CapType::PaperDetectable] = std::bind(enmGet, _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(); m_bFeederEnabled = mech; return success(); } return CapSupGetAllReset(msg, data, m_bFeederEnabled, Bool(true)); }; m_query[CapType::Duplex] = msgSupportGetAll; //m_caps[CapType::Duplex] = std::bind(oneValGet, _1, _2, []()->Duplex {return Duplex::OnePass; }); m_caps[CapType::Duplex] = std::bind(oneValGet, _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(); 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(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(); m_bAutoFeed = mech; return success(); } return CapSupGetAllReset(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(); 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(); m_gcap->hardwareParam.skewDetection.enable = atuodsw != 0 ? 1 : 0; return success(); } return CapSupGetAllReset(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((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((CapType)((CapType)(CapTypeEx::TwEx_SwitchFrontBack)), (Bool)m_gcap->scanSide.switchFrontBack); return success(); case Msg::GetDefault: data = Capability::createOneValue((CapType)((CapType)(CapTypeEx::TwEx_SwitchFrontBack)), Bool(false)); return success(); case Msg::Set: { bool mech = data.currentItem(); 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( { Bool(), Bool(true) }, Bool(m_gcap->imageProcess.orentation == Orentation::AUTOTEXT_DETECT)); return success(); // fallthrough case Msg::GetCurrent: data = Capability::createOneValue(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(false); return success(); case Msg::Set: { auto mech = data.currentItem(); 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(m_gcap->imageProcess.autoCrop); return success(); case Msg::Reset: case Msg::GetCurrent: m_gcap->imageProcess.autoCrop = false; data = Capability::createOneValue(m_gcap->imageProcess.autoCrop); return success(); case Msg::GetDefault: data = Capability::createOneValue(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( { Bool(), Bool(true) }, m_autoscan); return success(); case Msg::Reset: m_autoscan = true; data = Capability::createOneValue(m_autoscan); return success(); case Msg::GetCurrent: data = Capability::createOneValue(m_autoscan); return success(); case Msg::GetDefault: data = Capability::createOneValue(true); return success(); case Msg::Set: { auto autoscan = data.currentItem(); 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( { AutoSize::None, AutoSize::Auto}, (UInt16)m_autosize, 0); return success(); // fallthrough case Msg::GetCurrent: data = Capability::createOneValue((AutoSize)m_autosize); return success(); case Msg::Reset: case Msg::GetDefault: m_autosize = (UInt16)AutoSize::None; data = Capability::createOneValue(AutoSize::None); return success(); case Msg::Set: { auto autosize = data.currentItem(); 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(m_autoboarderdetcet); return success(); case Msg::Reset: m_autoboarderdetcet = false; data = Capability::createOneValue(m_autoboarderdetcet); return success(); case Msg::GetDefault: data = Capability::createOneValue(false); return success(); case Msg::Set: { auto autodetectborder = data.currentItem(); 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(CapType(CapTypeEx::TwEx_EnFold), {0,1}, m_gcap->scanSide.fold, 0); return success(); case Msg::Reset: m_gcap->scanSide.fold = false;//默认不对折 data = Capability::createOneValue(CapType(CapTypeEx::TwEx_EnFold), m_gcap->scanSide.fold); return success(); case Msg::GetCurrent: data = Capability::createOneValue(CapType(CapTypeEx::TwEx_EnFold), m_gcap->scanSide.fold); return success(); case Msg::GetDefault: m_gcap->scanSide.fold = false; data = Capability::createOneValue(CapType(CapTypeEx::TwEx_EnFold),0); return success(); case Msg::Set: { auto autocrop = data.currentItem(); 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(m_gcap->scanSide.discardBlank ? DiscardBlankPages::Auto : DiscardBlankPages::Disabled); return success(); case Msg::Reset: case Msg::GetDefault: m_gcap->scanSide.discardBlank = false; data = Capability::createOneValue(DiscardBlankPages::Disabled); return success(); case Msg::GetCurrent: data = Capability::createOneValue(m_gcap->scanSide.discardBlank ? DiscardBlankPages::Auto : DiscardBlankPages::Disabled); return success(); case Msg::Set: { auto mech = data.currentItem(); 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((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((CapType)((CapType)(CapTypeEx::TwEx_IAutoDiscardBlankVince)), Bool(false)); return success(); case Msg::GetCurrent: data = Capability::createOneValue((CapType)((CapType)(CapTypeEx::TwEx_IAutoDiscardBlankVince)), m_gcap->scanSide.discardBlankVince); return success(); case Msg::Set: { bool mech = data.currentItem(); 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((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((CapType)(CapTypeEx::TwEx_IBackRotate180), Bool(false)); return success(); case Msg::GetCurrent: data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_IBackRotate180), m_gcap->imageProcess.backRotate180); return success(); case Msg::Set: { bool mech = data.currentItem(); 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((CapType)(CapTypeEx::TwEx_IFillBackground), { Bool(),Bool(true) }, Bool(m_gcap->imageProcess.fillBlackRect), 1); return success(); case Msg::GetCurrent: data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_IFillBackground), m_gcap->imageProcess.fillBlackRect); return success(); case Msg::Reset: case Msg::GetDefault: m_gcap->imageProcess.fillBlackRect = true; data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_IFillBackground), Bool(true)); return success(); case Msg::Set: { bool mech = data.currentItem(); 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((CapType)(CapTypeEx::TwEx_CroporDesaskewIndent), m_gcap->imageProcess.indent); return success(); case Msg::Reset: case Msg::GetDefault: m_gcap->imageProcess.indent = 5; data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_CroporDesaskewIndent), UInt8(5)); return success(); case Msg::Set: { auto mech = data.currentItem(); 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((CapType)(CapTypeEx::TwEx_CropNoise), m_gcap->imageProcess.noise); return success(); case Msg::Reset: case Msg::GetDefault: m_gcap->imageProcess.noise = 40; data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_CropNoise), UInt8(40)); return success(); case Msg::Set: { auto mech = data.currentItem(); 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((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((CapType)(CapTypeEx::TwEx_CroporDesaskewThreshold), UInt8(40)); return success(); case Msg::Set: { auto mech = data.currentItem(); 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(); m_gcap->imageProcess.is_convex = mech; return success(); } return CapSupGetAllResetEx(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((CapType)(CapTypeEx::TwEx_IFillHole), { Bool(),Bool(true) }, Bool(m_gcap->imageProcess.fillHole.enable), 0); return success(); case Msg::GetCurrent: data = Capability::createOneValue((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((CapType)(CapTypeEx::TwEx_IFillHole), Bool(false)); return success(); case Msg::Set: { bool mech = data.currentItem(); 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((CapType)(CapTypeEx::TwEx_IFillHoleRatio), m_gcap->imageProcess.fillHole.ratio); return success(); case Msg::GetCurrent: data = Capability::createOneValue((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((CapType)(CapTypeEx::TwEx_IFillHoleRatio), Int32(10)); return success(); case Msg::Set: { auto mech = data.currentItem(); 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((CapType)(CapTypeEx::TwEx_IMultiOutputRed), { Bool(),Bool(true) }, m_gcap->imageProcess.multiOutFilterRed, false); return success(); case Msg::GetCurrent: data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_IMultiOutputRed), m_gcap->imageProcess.multiOutFilterRed); return success(); case Msg::GetDefault: case Msg::Reset: m_gcap->imageProcess.multiOutFilterRed = false; data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_IMultiOutputRed), Bool(false)); return success(); case Msg::Set: { auto mech = data.currentItem(); 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((CapType)(CapTypeEx::TwEx_HsvCorrect), { Bool(),Bool(true) }, m_gcap->imageProcess.answerSheetFilterRed, 0); return success(); case Msg::GetCurrent: data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_HsvCorrect), m_gcap->imageProcess.answerSheetFilterRed); return success(); case Msg::Reset: case Msg::GetDefault: m_gcap->imageProcess.answerSheetFilterRed = false; data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_HsvCorrect), Bool(false)); return success(); case Msg::Set: { bool mech = data.currentItem(); 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({ Filter::Red,Filter::Green,Filter::Blue,Filter::None }, m_gcap->imageProcess.filter,3); return success(); case Msg::GetCurrent: data = Capability::createOneValue((Filter)m_gcap->imageProcess.filter); return success(); case Msg::GetDefault: case Msg::Reset: m_gcap->imageProcess.filter = ColorFilter::FILTER_NONE; data = Capability::createOneValue(Filter::None); return success(); case Msg::Set: { auto mech = data.currentItem(); 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((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((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((CapType)(CapTypeEx::TwEx_IEnhanceColor), ColorFilter::FILTER_NONE); return success(); case Msg::Set: { auto mech = data.currentItem(); 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((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((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((CapType)(CapTypeEx::TwEx_Sharpen), SharpenType::STNone); return success(); case Msg::Set: { auto mech = data.currentItem(); 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(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(Fix32(m_gcap->imageProcess.brightness)); return success(); case Msg::GetDefault: case Msg::Reset: m_gcap->imageProcess.brightness = 0.0; data = Capability::createOneValue(Fix32(0.0f)); return success(); case Msg::Set: { auto mech = data.currentItem(); 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(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(Fix32(m_gcap->imageProcess.contrast)); return success(); case Msg::GetDefault: case Msg::Reset: m_gcap->imageProcess.contrast = 0; data = Capability::createOneValue(Fix32(0.0f)); return success(); case Msg::Set: { auto mech = data.currentItem(); 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(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(Fix32(m_gcap->imageProcess.gamma)); return success(); case Msg::GetDefault: case Msg::Reset: m_gcap->imageProcess.gamma = 1.0f; data = Capability::createOneValue(Fix32(0.0f)); return success(); case Msg::Set: { auto mech = data.currentItem(); 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((CapType)(CapTypeEx::TwEx_DBAreaNum), m_scanparam->areanum); // return success(); // case Msg::Reset: // m_scanparam->areanum = 8; // case Msg::GetCurrent: // data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_DBAreaNum), m_scanparam->areanum); // return success(); // case Msg::GetDefault: // data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_DBAreaNum), UInt16(8)); // return success(); // case Msg::Set: { // auto mech = data.currentItem(); // 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((CapType)(CapTypeEx::TwEx_DBDevnMax), m_scanparam->devnmax); // return success(); // case Msg::Reset: // m_scanparam->devnmax = 200; // case Msg::GetCurrent: // data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_DBDevnMax), m_scanparam->devnmax); // return success(); // case Msg::GetDefault: // data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_DBDevnMax), UInt16(200)); // return success(); // case Msg::Set: { // auto mech = data.currentItem(); // 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((CapType)(CapTypeEx::TwEx_ScrewDetectEnable), { Bool(),Bool(true) }, Bool(m_gcap->hardwareParam.skewDetection.enable), 0); return success(); case Msg::GetCurrent: data = Capability::createOneValue((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((CapType)(CapTypeEx::TwEx_ScrewDetectEnable), Bool(false)); return success(); case Msg::Set: { bool mech = data.currentItem(); 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((CapType)(CapTypeEx::TwEx_ScrewLevel), m_gcap->hardwareParam.skewDetection.level); return success(); case Msg::GetCurrent: data = Capability::createOneValue((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((CapType)(CapTypeEx::TwEx_ScrewLevel), UInt8(3)); return success(); case Msg::Set: { auto mech = data.currentItem(); 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((CapType)(CapTypeEx::TwEx_StableDetectEnable), { Bool(),Bool(true) }, Bool(m_gcap->hardwareParam.bindingDetection), 0); return success(); case Msg::GetCurrent: data = Capability::createOneValue((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((CapType)(CapTypeEx::TwEx_StableDetectEnable), Bool(false)); return success(); case Msg::Set: { bool mech = data.currentItem(); 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(CapType::DoubleFeedDetection, (Bool)m_gcap->hardwareParam.doubleFeedDetection); return success(); case Msg::GetDefault: case Msg::Reset: m_gcap->hardwareParam.doubleFeedDetection = false; data = Capability::createOneValue(CapType::DoubleFeedDetection, Bool(false)); return success(); case Msg::Set: { bool mech = data.currentItem(); 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(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(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(dib->biWidth) /m_gcap->resolution, static_cast(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(maxRows, static_cast(dib->biHeight) - m_memXferYOff); if (rows == 0) { return seqError(); // image already transfered in this session } cv::Mat mat; vector 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(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(std::abs(dib->biHeight))) { m_pendingXfers = 0; m_memXferYOff = 0; bmpData.reset(new std::vector); 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); 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 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); 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(); 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(); 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().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(bmpData->data() + sizeof(BITMAPFILEHEADER)); } UInt32 HuagaoDs::bytesPerLine() const noexcept{ auto dib = header(); return static_cast(dib->biWidth * dib->biBitCount + 31) / 32 * 4; } UInt32 HuagaoDs::bmpSize() const noexcept{ return static_cast(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(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