#pragma once // // For: interface definition for SANE to TWAIN // // Date: 2022-06-08 // #include #include #include #include #include #include #define COM_API_DECLARE(ret, decl) virtual ret decl = 0 #define COM_API_DECLARE_NON_PURE(ret, decl) virtual ret decl #define COM_API_OVERRIDE(ret, decl) virtual ret decl override #define COM_API_IMPLEMENT(cls, ret, decl) ret cls::decl #define SANE_OPTION_ID_API(opt) COM_API_DECLARE(int, sane_opt_id_##opt(void)) // -1 is none #define SANE_OPTION_ID_OVERRIDE(opt) COM_API_OVERRIDE(int, sane_opt_id_##opt(void)) #define SANE_OPTION_IMPLEMENT(cls, opt) int cls::sane_opt_id_##opt(void) #define SANE_OPTION_ID_API_EX(opt) COM_API_DECLARE(int, sane_opt_id_ex_##opt(void)) // -1 is none #define SANE_OPTION_ID_OVERRIDE_EX(opt) COM_API_OVERRIDE(int, sane_opt_id_ex_##opt(void)) #define SANE_OPTION_IMPLEMENT_EX(cls, opt) int cls::sane_opt_id_ex_##opt(void) #define ALIGN_MEMORY(n, align) ((n + align - 1) / (align) * (align)) #define _TO_UNICODE_(str) L##str #define UNICODE_STR(str) _TO_UNICODE_(str) #define TWPT_AUTOMATIC_COLOR 0x0a0c #define AUTO_MATIC_ROTATE 123.456f #define IS_DOUBLE_EQUAL(a, b) fabs((a) - (b)) < .000001 enum value_limit { VAL_LIMIT_NONE = 0, // VAL_LIMIT_ENUM, // VAL_LIMIT_RANGE, // VAL_LIMIT_MASK = 0x0ff, VAL_LIMIT_READONLY = 0x100, }; enum value_role { VAL_ROLE_NONE = 0, // this value is no role but an item of the option only VAL_ROLE_DEFAULT = 0x01, // this value is the default value of the option VAL_ROLE_CURRENT = 0x02, // this value is the current value of the option VAL_ROLE_LOWER = 0x04, // the lower value of a VAL_LIMIT_RANGE VAL_ROLE_UPPER = 0x08, // the upper value of a VAL_LIMIT_RANGE VAL_ROLE_STEP = 0x10, // the step value of a VAL_LIMIT_RANGE }; enum value_type { VAL_TYPE_NONE = 0, VAL_TYPE_BOOL, // bool VAL_TYPE_INT, // int VAL_TYPE_FLOAT, // float VAL_TYPE_STR, // char* VAL_TYPE_STREAM, // uint8_t[], must give array length VAL_TYPE_BUTTON, // a button }; enum color_value // 除最后一项外,其余与Twpp::PixelType值保持一致 { COLOR_BW = 0, COLOR_GRAY, COLOR_RGB, COLOR_AUTO_MATCH = TWPT_AUTOMATIC_COLOR, }; enum paper_value // 与Twpp::PaperSize保持一致 { PAPER_A4 = 1, PAPER_16K = 1, PAPER_LETTER = 3, PAPER_LEGAL = 4, PAPER_A5 = 5, PAPER_B4 = 6, PAPER_B6 = 7, PAPER_A3 = 11, PAPER_8K = 11, PAPER_A6 = 13, PAPER_B5 = 29, PAPER_STATEMENT = 52, // 匹配原始尺寸 PAPER_MAXSIZE = 54, // 最大扫描尺寸 // 以下为未匹配选项 PAPER_DOUBLE_LETTER = 103, PAPER_MAXSIZE_CROP = 154, // 最大扫描尺寸自动裁切 PAPER_TRIPPLE = 111, // 三联试卷 }; enum filter_value // 除色选项 { FILTER_NONE = 0, FILTER_RED, FILTER_GREEN, FILTER_BLUE, }; enum enhance_value // 颜色增强选项 { ENHANCE_NONE = 0, ENHANCE_RED, ENHANCE_GREEN, ENHANCE_BLUE, }; enum sharpen_value { SHARPEN_NONE = 0, SHARPEN_SHARPEN, SHARPEN_SHARPEN_MORE, SHARPEN_BLUR, SHARPEN_BLUR_MORE, }; enum multiout_value { MULTI_OUT_NONE = -1, MULTI_OUT_ALL, MULTI_OUT_COLOR_GRAY, MULTI_OUT_COLOR_BW, MULTI_OUT_GRAY_BW, }; enum twain_xfer { TWAIN_XFER_Native = 0, // BITMAPINFOHEADER + bits TWAIN_XFER_File = 1, // BITMAPFILEHEADER + TWAIN_XFER_Native TWAIN_XFER_Memory = 2, // to be implementing ... }; typedef bool(*set_opt_value)(void* val, value_role role, value_limit limit, void* param); class IRef { public: COM_API_DECLARE(long, add_ref(void)); COM_API_DECLARE(long, release(void)); }; class IScanImg : public IRef // 为兼容TWAIN传输方式,位图全部转换为完整的位图文件内容,TWAIN协议层在获取数据时,根据不同传输方式跳过对应的文件头即可 - 2023-07-03 { public: COM_API_DECLARE(int, width(void)); COM_API_DECLARE(int, line_bytes(void)); COM_API_DECLARE(int, height(void)); COM_API_DECLARE(int, depth(void)); COM_API_DECLARE(int, channel(void)); COM_API_DECLARE(int, dpi(void)); COM_API_DECLARE(SANE_Frame, type(void)); COM_API_DECLARE(unsigned int, bytes(void)); COM_API_DECLARE(unsigned int, header_size(void)); COM_API_DECLARE(unsigned char*, data(unsigned long long off, unsigned int *bytes)); COM_API_DECLARE(int, read(void* buf, size_t* bytes, unsigned long long off = 0)); COM_API_DECLARE(const char*, file(void)); COM_API_DECLARE(void, keep_file(bool keep)); COM_API_DECLARE(void, copy_header(SANE_Parameters* head)); COM_API_DECLARE(int, image_status(void)); COM_API_DECLARE(size_t, get_bits_offset(void)); }; class ISaneInvoker : public IRef { public: COM_API_DECLARE(int, start(void)); COM_API_DECLARE(int, stop(void)); COM_API_DECLARE(int, get_event(void)); COM_API_DECLARE(void, set_event_callback(int(* handle_ev)(int, void*) = nullptr, void* para = nullptr)); COM_API_DECLARE(bool, wait_image(DWORD milliseconds = -1)); COM_API_DECLARE(int, get_scanned_images(DWORD milliseconds = 0)); COM_API_DECLARE(IScanImg*, take_first_image(twain_xfer xfer = TWAIN_XFER_Native)); // call 'release' on returned value, plz COM_API_DECLARE(bool, get_first_image_header(SANE_Parameters* header, size_t* bytes = nullptr, int *dpi = nullptr)); COM_API_DECLARE(bool, discard_first_image(void)); COM_API_DECLARE(int, convert_image(SANE_ImageFormatConvert* conv)); COM_API_DECLARE(bool, is_online(void)); COM_API_DECLARE(bool, is_paper_on(void)); COM_API_DECLARE(int, last_error(void)); COM_API_DECLARE(int, image_fetched(IScanImg* tx)); // notify the image 'tx' has fetched by APP // ui ... COM_API_DECLARE(bool, ui_is_ok(void)); COM_API_DECLARE(bool, ui_show_setting(HWND parent, bool with_scan, bool indicator = true)); COM_API_DECLARE(bool, ui_show_progress(HWND parent, bool bIndicator)); COM_API_DECLARE(void, ui_hide(void)); // twain COM_API_DECLARE(void, twain_set_transfer(twain_xfer xfer)); COM_API_DECLARE(void, twain_set_compression(SANE_CompressionType compression, void* detail = nullptr)); COM_API_DECLARE(int, twain_get_config(char* buf, size_t* len)); COM_API_DECLARE(int, twain_set_config(char* buf, size_t len)); // Function: 获取配置项信息 // // Parameter: sn - 配置项索引 - sane_option_id // // type - 配置项数据类型 // // limit - 配置项限制类型 // // bytes - *type 为 VAL_TYPE_STR时,需要的最小空间字节数 COM_API_DECLARE(bool, get_option_info(int sn, value_type* type, value_limit* limit, int *bytes, bool* readonly)); COM_API_DECLARE(int, get_fixed_ids(bool(* cb)(uint32_t id, void* param), void* param)); COM_API_DECLARE(bool, get_value(int sn, set_opt_value func, void* param)); COM_API_DECLARE(bool, get_value(int sn, void* data, int* len)); // get operation with in-parameter COM_API_DECLARE(int, set_value(int sn, void* val)); }; struct delete_scanner { void operator()(ISaneInvoker* p) { p->release(); } }; namespace sane_opts { enum { RANGE_POS_CURRENT = 0, RANGE_POS_DEFAULT, RANGE_POS_ENUM_BEGIN, RANGE_POS_LOWER = RANGE_POS_ENUM_BEGIN, RANGE_POS_UPPER, RANGE_POS_STEP, }; template class get_opts { public: // 0 - cur val; 1 - def val; // // LIST: 2 - elements ... // // RANGE: 2 - lower; 3 - upper; 4 - step T range[5]; value_limit lmt_; std::vector* lvs_; value_limit* limit_; public: get_opts(value_limit* limit, std::vector* ls) : limit_(limit), lvs_(ls) {} ~get_opts() {} void re_order(void) { if (limit_) *limit_ = lmt_; if (lmt_ == VAL_LIMIT_RANGE || lmt_ == VAL_LIMIT_NONE) { if (lvs_) { lvs_->clear(); for (size_t i = 0; i < _countof(range); ++i) lvs_->push_back(range[i]); } } else if(lvs_) { lvs_->insert(lvs_->begin(), range[RANGE_POS_DEFAULT]); lvs_->insert(lvs_->begin(), range[RANGE_POS_CURRENT]); } } }; template bool set_opt_value(void* val, value_role role, value_limit limit, void* param) { get_opts* v = (get_opts*)param; bool go = true; v->lmt_ = limit; if (role & VAL_ROLE_CURRENT) { v->range[RANGE_POS_CURRENT] = *(T*)val; } if (role & VAL_ROLE_DEFAULT) { v->range[RANGE_POS_DEFAULT] = *(T*)val; } if (role & VAL_ROLE_LOWER) { v->range[RANGE_POS_LOWER] = *(T*)val; } if (role & VAL_ROLE_UPPER) { v->range[RANGE_POS_UPPER] = *(T*)val; } if (role & VAL_ROLE_STEP) { v->range[RANGE_POS_STEP] = *(T*)val; } else if (v->lvs_) v->lvs_->push_back(*(T*)val); return go; } } #define GET_SANE_OPT(type, object, id_name, limit, vct) \ { \ sane_opts::get_opts op(limit, vct); \ object->get_value(SANE_OPT_ID_##id_name, sane_opts::set_opt_value, &op); \ op.re_order(); \ } #define SET_SANE_OPT(ret, object, id_name, val) \ { \ ret = object->set_value(SANE_OPT_ID_##id_name, val); \ } extern "C" { bool is_scanner_online(const char* model); ISaneInvoker* open_scanner(const char* model, int* err); int uninitialize_sane(void* reserve); } // 标准TWAIN属性值与SANE属性值之间的转换 namespace s2t { // 页面 与 双面转换 bool page_is_duplex(const char* sane_val); std::string page_from_duplex(bool duplex); // 页面 与 丢弃空白页 bool discard_blank_from_sane(const char* sane_val); std::string discard_blank_to_sane(bool discard); // 页面 与 丢弃空白发票 bool discard_blank_receipt_from_sane(const char* sane_val); std::string discard_blank_receipt_to_sane(bool discard); // 页面 与 对折 bool fold_from_sane(const char* sane_val); std::string fold_to_sane(bool fold); // 语言 int language_to_twain(const char* sane_val); std::string language_from_twain(int twain); // 位深 与 颜色模式 int bits_from_sane(const char* color_mode); std::string bits_to_sane(int bits); // PixelType 与 颜色模式 int pixel_type_from_sane(const char* color_mode); std::string pixel_type_to_sane(int pixel); // 自动颜色匹配 与 颜色模式 bool color_mode_is_auto(const char* color_mode); std::string color_mode_from_auto(bool auto_mode); // 支持的尺寸 与 纸张 int paper_size_from_sane(const char* sane_val); std::string paper_size_to_sane(int paper); // 横向 与 纸张 bool lateral_from_sane(const char* sane_val, bool* support_lateral); std::string lateral_to_sane(const char* sane_val, bool lateral); // 如果sane_val不支持横向则返回sane_val,确定是否支持横向请调用lateral_from_sane // 自动尺寸 与 纸张 bool auto_size_from_sane(const char* sane_val); std::string auto_size_to_sane(bool autos); // 自动裁切 与 纸张 bool auto_crop_from_sane(const char* sane_val); std::string auto_crop_to_sane(bool autos); // 旋转角度 与 送纸方向 double rotation_from_sane(const char* sane_val); std::string rotation_to_sane(double rot); bool auto_rotation_from_sane(const char* sane_val); std::string auto_rotation_to_sane(bool autor); // 滤波 与 除色与增强 void filter_from_sane(const std::vector& sane/*sane_opts::RANGE_POS*/, std::vector& twain, bool filter/*true - filter; false - enhance*/); std::string filter_to_sane(int filter); std::string enhance_to_sane(int enhance); // 多流输出 int multi_out_from_sane(const char* sane_val); std::string multi_out_to_sane(int mo); // 休眠时间兼容老版本协议 int power_from_sane(const char* sane_val); std::string power_to_sane(int power); // 背景填充方式 设置凸多边形 bool convex_from_sane(const char* sane_val); std::string convex_to_sane(bool convex); // 锐化 int sharpen_from_sane(const char* sane_val); std::string sharpen_to_sane(int sharpen); };