From 12ba0f89793f228eab9dade821558850718baad0 Mon Sep 17 00:00:00 2001 From: gb <741021719@qq.com> Date: Wed, 15 Jun 2022 11:04:40 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84TWAIN=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- device/device.def | 2 +- device/{hgscanner.vcxproj => scanner.vcxproj} | 2 +- ...cxproj.filters => scanner.vcxproj.filters} | 0 huagaotwain/huagaotwain.h | 446 ----- huagaotwain/sane_option_trans.cpp | 630 ------ huagaotwain/sane_option_trans.h | 230 --- protocol/sane.def | 18 - {huagaotwain => sane}/huagaotwain.cpp | 14 +- sane/huagaotwain.h | 12 + sane/s2t_api.h | 393 ++++ sane/sane.def | 6 + protocol/hgsane.vcxproj => sane/sane.vcxproj | 15 +- .../sane.vcxproj.filters | 24 + sane/sane.vcxproj.user | 4 + sane/sane_option_trans.cpp | 294 +++ sane/sane_option_trans.h | 41 + sane/scanned_img.cpp | 143 ++ sane/scanned_img.h | 51 + sane/scanner.cpp | 1767 +++++++++++++++++ sane/scanner.h | 270 +++ {huagaotwain => sane}/ui.cpp | 0 {huagaotwain => sane}/ui.h | 0 sln/hgscanner.sln | 25 +- {huagaotwain => twain}/dllmain.cpp | 1 - {huagaotwain => twain}/huagaotwain.rc | 0 twain/load_sane.cpp | 176 ++ twain/load_sane.h | 19 + {huagaotwain => twain}/pch.cpp | 0 {huagaotwain => twain}/pch.h | 0 {huagaotwain => twain}/resource.h | 0 {huagaotwain => twain}/targetver.h | 0 {huagaotwain => twain}/twain.def | 0 .../twain.vcxproj | 17 +- .../twain.vcxproj.filters | 50 +- twain/twain.vcxproj.user | 4 + {huagaotwain => twain}/twain/huagaods.cpp | 1276 ++++++++---- {huagaotwain => twain}/twain/huagaods.hpp | 5 +- {huagaotwain => twain}/twain/twain_2.4.h | 0 {huagaotwain => twain}/twain/twpp.hpp | 0 .../twain/twpp/application.hpp | 0 {huagaotwain => twain}/twain/twpp/audio.hpp | 0 .../twain/twpp/capability.hpp | 21 + {huagaotwain => twain}/twain/twpp/cie.hpp | 0 .../twain/twpp/curveresponse.hpp | 0 .../twain/twpp/customdata.hpp | 0 .../twain/twpp/datasource.hpp | 0 .../twain/twpp/deviceevent.hpp | 0 .../twain/twpp/element8.hpp | 0 {huagaotwain => twain}/twain/twpp/enums.hpp | 0 {huagaotwain => twain}/twain/twpp/env.hpp | 0 {huagaotwain => twain}/twain/twpp/event.hpp | 0 .../twain/twpp/exception.hpp | 0 .../twain/twpp/extimageinfo.hpp | 0 .../twain/twpp/filesystem.hpp | 0 {huagaotwain => twain}/twain/twpp/fix32.hpp | 0 {huagaotwain => twain}/twain/twpp/frame.hpp | 0 .../twain/twpp/identity.hpp | 0 .../twain/twpp/imageinfo.hpp | 0 .../twain/twpp/imagelayout.hpp | 0 .../twain/twpp/imagememxfer.hpp | 0 .../twain/twpp/imagenativexfer.hpp | 0 .../twain/twpp/internal.hpp | 0 .../twain/twpp/jpegcompression.hpp | 0 {huagaotwain => twain}/twain/twpp/memory.hpp | 0 .../twain/twpp/memoryops.hpp | 0 .../twain/twpp/palette8.hpp | 0 .../twain/twpp/passthrough.hpp | 0 .../twain/twpp/pendingxfers.hpp | 0 .../twain/twpp/setupfilexfer.hpp | 0 .../twain/twpp/setupmemxfer.hpp | 0 {huagaotwain => twain}/twain/twpp/status.hpp | 0 {huagaotwain => twain}/twain/twpp/strings.hpp | 0 {huagaotwain => twain}/twain/twpp/twglue.hpp | 0 {huagaotwain => twain}/twain/twpp/types.hpp | 0 .../twain/twpp/typesops.hpp | 0 .../twain/twpp/userinterface.hpp | 0 {huagaotwain => twain}/twain/twpp/utils.hpp | 0 77 files changed, 4159 insertions(+), 1797 deletions(-) rename device/{hgscanner.vcxproj => scanner.vcxproj} (99%) rename device/{hgscanner.vcxproj.filters => scanner.vcxproj.filters} (100%) delete mode 100644 huagaotwain/huagaotwain.h delete mode 100644 huagaotwain/sane_option_trans.cpp delete mode 100644 huagaotwain/sane_option_trans.h delete mode 100644 protocol/sane.def rename {huagaotwain => sane}/huagaotwain.cpp (99%) create mode 100644 sane/huagaotwain.h create mode 100644 sane/s2t_api.h create mode 100644 sane/sane.def rename protocol/hgsane.vcxproj => sane/sane.vcxproj (94%) rename protocol/hgsane.vcxproj.filters => sane/sane.vcxproj.filters (79%) create mode 100644 sane/sane.vcxproj.user create mode 100644 sane/sane_option_trans.cpp create mode 100644 sane/sane_option_trans.h create mode 100644 sane/scanned_img.cpp create mode 100644 sane/scanned_img.h create mode 100644 sane/scanner.cpp create mode 100644 sane/scanner.h rename {huagaotwain => sane}/ui.cpp (100%) rename {huagaotwain => sane}/ui.h (100%) rename {huagaotwain => twain}/dllmain.cpp (94%) rename {huagaotwain => twain}/huagaotwain.rc (100%) create mode 100644 twain/load_sane.cpp create mode 100644 twain/load_sane.h rename {huagaotwain => twain}/pch.cpp (100%) rename {huagaotwain => twain}/pch.h (100%) rename {huagaotwain => twain}/resource.h (100%) rename {huagaotwain => twain}/targetver.h (100%) rename {huagaotwain => twain}/twain.def (100%) rename huagaotwain/huagaotwain.vcxproj => twain/twain.vcxproj (93%) rename huagaotwain/huagaotwain.vcxproj.filters => twain/twain.vcxproj.filters (83%) create mode 100644 twain/twain.vcxproj.user rename {huagaotwain => twain}/twain/huagaods.cpp (61%) rename {huagaotwain => twain}/twain/huagaods.hpp (97%) rename {huagaotwain => twain}/twain/twain_2.4.h (100%) rename {huagaotwain => twain}/twain/twpp.hpp (100%) rename {huagaotwain => twain}/twain/twpp/application.hpp (100%) rename {huagaotwain => twain}/twain/twpp/audio.hpp (100%) rename {huagaotwain => twain}/twain/twpp/capability.hpp (98%) rename {huagaotwain => twain}/twain/twpp/cie.hpp (100%) rename {huagaotwain => twain}/twain/twpp/curveresponse.hpp (100%) rename {huagaotwain => twain}/twain/twpp/customdata.hpp (100%) rename {huagaotwain => twain}/twain/twpp/datasource.hpp (100%) rename {huagaotwain => twain}/twain/twpp/deviceevent.hpp (100%) rename {huagaotwain => twain}/twain/twpp/element8.hpp (100%) rename {huagaotwain => twain}/twain/twpp/enums.hpp (100%) rename {huagaotwain => twain}/twain/twpp/env.hpp (100%) rename {huagaotwain => twain}/twain/twpp/event.hpp (100%) rename {huagaotwain => twain}/twain/twpp/exception.hpp (100%) rename {huagaotwain => twain}/twain/twpp/extimageinfo.hpp (100%) rename {huagaotwain => twain}/twain/twpp/filesystem.hpp (100%) rename {huagaotwain => twain}/twain/twpp/fix32.hpp (100%) rename {huagaotwain => twain}/twain/twpp/frame.hpp (100%) rename {huagaotwain => twain}/twain/twpp/identity.hpp (100%) rename {huagaotwain => twain}/twain/twpp/imageinfo.hpp (100%) rename {huagaotwain => twain}/twain/twpp/imagelayout.hpp (100%) rename {huagaotwain => twain}/twain/twpp/imagememxfer.hpp (100%) rename {huagaotwain => twain}/twain/twpp/imagenativexfer.hpp (100%) rename {huagaotwain => twain}/twain/twpp/internal.hpp (100%) rename {huagaotwain => twain}/twain/twpp/jpegcompression.hpp (100%) rename {huagaotwain => twain}/twain/twpp/memory.hpp (100%) rename {huagaotwain => twain}/twain/twpp/memoryops.hpp (100%) rename {huagaotwain => twain}/twain/twpp/palette8.hpp (100%) rename {huagaotwain => twain}/twain/twpp/passthrough.hpp (100%) rename {huagaotwain => twain}/twain/twpp/pendingxfers.hpp (100%) rename {huagaotwain => twain}/twain/twpp/setupfilexfer.hpp (100%) rename {huagaotwain => twain}/twain/twpp/setupmemxfer.hpp (100%) rename {huagaotwain => twain}/twain/twpp/status.hpp (100%) rename {huagaotwain => twain}/twain/twpp/strings.hpp (100%) rename {huagaotwain => twain}/twain/twpp/twglue.hpp (100%) rename {huagaotwain => twain}/twain/twpp/types.hpp (100%) rename {huagaotwain => twain}/twain/twpp/typesops.hpp (100%) rename {huagaotwain => twain}/twain/twpp/userinterface.hpp (100%) rename {huagaotwain => twain}/twain/twpp/utils.hpp (100%) diff --git a/device/device.def b/device/device.def index 5dc1d1e..d4f5f41 100644 --- a/device/device.def +++ b/device/device.def @@ -1,4 +1,4 @@ -LIBRARY hgscanner +LIBRARY scanner EXPORTS hg_scanner_initialize hg_scanner_uninitialize diff --git a/device/hgscanner.vcxproj b/device/scanner.vcxproj similarity index 99% rename from device/hgscanner.vcxproj rename to device/scanner.vcxproj index 0743560..217a3cb 100644 --- a/device/hgscanner.vcxproj +++ b/device/scanner.vcxproj @@ -22,7 +22,7 @@ 16.0 Win32Proj {9ed4b425-73e0-423e-9712-455e777481b4} - hgscanner + scanner 10.0 diff --git a/device/hgscanner.vcxproj.filters b/device/scanner.vcxproj.filters similarity index 100% rename from device/hgscanner.vcxproj.filters rename to device/scanner.vcxproj.filters diff --git a/huagaotwain/huagaotwain.h b/huagaotwain/huagaotwain.h deleted file mode 100644 index 0e25600..0000000 --- a/huagaotwain/huagaotwain.h +++ /dev/null @@ -1,446 +0,0 @@ -#pragma once -#include "huagao/hgscanner_error.h" -#include -#include -#include -#include -#include "sane_option_trans.h" - - -class sane_invoker; -class scanner; -struct _dev; - - -class refer -{ - volatile long ref_; - -public: - refer() : ref_(1) - {} -protected: - virtual ~refer() - {} - -public: - long add_ref(void) - { - return InterlockedIncrement(&ref_); - } - long release(void) - { - long ref = InterlockedDecrement(&ref_); - - if (ref <= 0) - delete this; - - return ref; - } -}; - -class scanned_img -{ - SANE_Parameters param_; - std::vector data_; - - std::string file_header(SANE_FinalImgFormat* header, float resolution); - -public: - scanned_img(SANE_Image* img, SANE_FinalImgFormat* header); - ~scanned_img(); - -public: - int width(void); - int line_bytes(void); - int height(void); - int depth(void); - int channel(void); - SANE_Frame type(void); - unsigned int bytes(void); - unsigned char* bits(void); - void copy_header(SANE_Parameters* head); -}; - -extern HMODULE me_; -namespace local_utility -{ - std::wstring reg_read(HKEY root, const wchar_t* path, const wchar_t* name); - std::wstring reg_get_app_installing_path(void); -} - -class scanner : public refer -{ - SANE_Handle hdev_; - sane_invoker* host_; - std::string name_; - std::string type_; - std::string vendor_; - std::string product_; - bool online_; - int option_count_; - std::mutex lock_img_; - std::vector img_; - SANE_FinalImgFormat *fmt_; - - typedef struct _sane_option - { - int ind; - const SANE_Option_Descriptor* desc; - union - { - bool bv; - int iv; - double dv; - std::string* sv; - }val; - bool operator==(int id) - { - return ind == id; - } - }SANEOPTION; - std::vector options_; - - float dpi_; - HANDLE wait_img_; - volatile bool scanning_; - int err_; - std::string desc_; - - void load_options(void); - void init_image_format(void); - std::string get_string(int opt, int bytes); - bool get_boolean(int opt); - int get_integer(int opt); - double get_double(int opt); - int set_string(int opt, std::string& val, int size, SANE_Int* afterdo = NULL); - - enum twain_essential - { - TWAIN_RESOLUTION, - TWAIN_PAPER_SIZE, - }; - - int opt_ind_dpi_; - int opt_ind_color_mode_; - int opt_ind_paper_; - int opt_ind_scann_count_; // MAKELONG(count, scan_continue) - int opt_ind_text_direction_; - int opt_ind_page_; - int opt_ind_auto_descrew_; - int opt_ind_erase_black_frame_; - int opt_ind_filter_; - int opt_ind_bright_; - int opt_ind_contrast_; - int opt_ind_gamma_; - int opt_ind_ultrasonic_; - int opt_ind_flip_; - int opt_ind_rotate_bkg_; - int opt_ind_fill_blank_bkg_; - int opt_ind_edge_ident_; - int opt_ind_threshold_; - int opt_ind_bkg_filling_method_; - int opt_ind_fill_hole_; - int opt_ind_fill_hole_ratio_; - int opt_ind_noise_; - int opt_ind_noise_threshold_; - int opt_ind_rid_red_; - int opt_ind_rid_red_hsv_; - int opt_ind_sharpen_; - int opt_ind_screw_detect_; - int opt_ind_screw_detect_level_; - int opt_ind_staple_; - int opt_ind_dogear_; - int opt_ind_dark_sample_; - int opt_ind_split_; - int opt_ind_fade_bkg_; - int opt_ind_fade_bkg_val_; - int opt_ind_size_detect_; - int opt_ind_multi_out_; - - SANE_ImageType img_fmt_; - int jpeg_quality_; - - SANE_CompressionType compression_; - bool auto_crop_; - - void(*event_cb_)(int, void*, unsigned int*, void*); - void* cb_param_; - -public: - scanner(sane_invoker* host, struct _dev& dev); - - static std::string type(SANE_Value_Type st); - static value_limit limit(SANE_Constraint_Type st); - -protected: - ~scanner(); - -public: - int close(void); - int start(void); - int stop(void); - void set_event_callback(void(*cb)(int, void*, unsigned int*, void*), void* param); - bool wait_image(DWORD milliseconds = -1); - int get_scanned_images(DWORD milliseconds = 0); - scanned_img* take_first_image(void); // delete returned value, plz - bool get_first_image_header(SANE_Parameters* header); - int last_error(void); - - SANE_Handle handle(void); - bool is_online(void); - void set_online(bool online); - - void put_image(SANE_Image* img, unsigned int* len); - void scan_finished(const char* desc, int err); - - // up to sane, we set the CAP_xxx according to settings display in UI ... - bool get_value_info(int sn, std::string& type, value_limit& limit); - bool get_value(int sn, std::list& values, std::string& now, std::string& init); - bool get_value(int sn, std::list& values, float& now, float& init); - bool get_value(int sn, std::list& values, bool& now, bool& init); - bool get_value(int sn, int& now, int& init, int* lower = NULL, int* upper = NULL, int* step = NULL); - bool get_value(int sn, float& now, float& init, float* lower = NULL, float* upper = NULL, float* step = NULL); - - int set_value(int sn, std::string val); - int set_value(int sn, bool val); - int set_value(int sn, int val); - int set_value(int sn, double val); - - // attribute for twain ... -public: - int twain_set_resolution(float dpi); - float twain_get_resolution(float* init = NULL, std::vector* values = NULL, value_limit* limit = NULL); - - int twain_set_color_mode(int twain_pixel_type); - int twain_get_color_mode(int* init = NULL, std::vector* values = NULL, value_limit* limit = NULL); - int twain_set_auto_color_type(int type); - - int twain_get_paper_ind(void); - int twain_set_paper_lateral(bool lateral); - bool twain_is_paper_lateral(void); - int twain_set_paper_auto_match_size(bool match); - bool twain_is_paper_auto_match_size(void); - - int twain_set_scan_count(int count); - int twain_get_scan_count(void); - - int twain_set_final_format(SANE_ImageType type, void* param); - int twain_get_jpeg_quality(void); - SANE_ImageType get_final_format(void); - - int twain_set_final_compression(int compression); - int twain_get_final_compression(int *init = NULL, std::vector* values = NULL); - - int twain_set_text_direction(double degree); - double twain_get_text_direction(double* init = NULL, std::list* vals = NULL, value_limit* limit = NULL); - int twain_set_text_auto_matic(bool am); - bool twain_is_text_auto_matic(void); - - int twain_set_page_duplex(bool dup); - bool twain_is_page_duplex(void); - int twain_set_page_discarding_blank_page(bool discard, bool receipt); - bool twain_is_page_discarding_blank_page(bool receipt); - int twain_set_page_fold(bool fold); - bool twain_is_page_fold(void); - - int twain_set_auto_descrew(bool enable); - bool twain_is_auto_descrew(void); - - int twain_set_erase_black_frame(bool erase); - bool twain_is_erase_black_frame(bool* init); - - int twain_set_filter(int tw_filter, bool enhance); - int twain_get_filter(bool enhance); - - int twain_set_bright(double bright); - double twain_get_bright(double* init = NULL, double* lower = NULL, double* upper = NULL, double* step = NULL); - - int twain_set_contrast(double bright); - double twain_get_contrast(double* init = NULL, double* lower = NULL, double* upper = NULL, double* step = NULL); - - int twain_set_gamma(double bright); - double twain_get_gamma(double* init = NULL, double* lower = NULL, double* upper = NULL, double* step = NULL); - - int twain_set_ultrasonic_check(bool check); - bool twain_is_ultrasonic_check(bool* init = NULL); - - bool twain_is_auto_crop(void); - bool twain_is_paper_on(void); - int twain_get_device_code(char* buf, unsigned int len); - - int twain_set_sharpen(int sharpen); - int twain_get_sharpen(void); - - int twain_get_serial_num(char buf[256]); - int twain_get_hareware_version(char buf[256]); - int twain_get_ip(char buf[256]); - - int twain_get_dogear_distance(void); - int twain_set_dogear_distance(int dist); - - int twain_set_power_level(int level); - int twain_get_power_level(void); - - int twain_set_to_be_scan(bool yes); - bool twain_get_to_be_scan(void); - - int twain_set_scan_with_hole(bool yes); - bool twain_get_scan_with_hole(void); - - int twain_set_multioutput_type(int type); - int twain_get_multioutput_type(void); - - int twain_get_flip_ind(void); - int twain_get_rotate_bkg_ind(void); - int twain_get_fill_black_bkg_ind(void); - int twain_get_edge_ident_ind(void); - int twain_get_threshold_ind(void); - int twain_bkg_filling_method_ind(void); - int twain_fill_hole_ind(void); - int twain_fill_hole_ratio_ind(void); - int twain_detach_noise_ind(void); - int twain_detach_noise_threshold_ind(void); - int twain_rid_red_ind(void); - int twain_rid_red_hsv_ind(void); - int twain_screw_detect_ind(void); - int twain_screw_detect_level_ind(void); - int twain_staple_detect_ind(void); - int twain_dogear_detect_ind(void); - int twain_dark_sample_ind(void); - int twain_image_split_ind(void); - int twain_fade_bkground_ind(void); - int twain_fade_bkground_val_ind(void); - int twain_size_detect_ind(void); -}; -struct delete_scanner -{ - void operator()(scanner* p) - { - p->release(); - } -}; -typedef struct _dev -{ - scanner* scanner; - std::string name; - std::string type; - std::string vendor; - std::string product; - - struct _dev() - { - scanner = NULL; - name = type = vendor = product = ""; - } - bool operator==(const char* n) - { - return name == n; - } - bool operator==(SANE_Handle h) - { - return scanner && scanner->handle() == h; - } -}SANEDEV; - - - - -class sane_invoker -{ - bool ok_; - std::wstring cfg_file_; - SANE_Int ver_; - HMODULE sane_; - HANDLE first_cb_; - SANEAPI sane_api_; - - std::mutex lock_dev_; - std::vector devices_; - - SANE_Status (*real_sane_init_)(SANE_Int* version_code, SANE_Auth_Callback authorize); - void (*real_sane_exit_)(void); - SANE_Status(*real_sane_get_devices_)(const SANE_Device*** device_list, SANE_Bool local_only); - SANE_Status(*real_sane_open_)(SANE_String_Const devicename, SANE_Handle* handle); - void (*real_sane_close_)(SANE_Handle handle); - const SANE_Option_Descriptor* (*real_sane_get_option_descriptor_)(SANE_Handle handle, SANE_Int option); - SANE_Status(*real_sane_control_option_)(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info); - SANE_Status(*real_sane_get_parameters_)(SANE_Handle handle, SANE_Parameters* params); - SANE_Status(*real_sane_start_)(SANE_Handle handle); - SANE_Status(*real_sane_read_)(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length); - void (*real_sane_cancel_)(SANE_Handle handle); - SANE_Status(*real_sane_set_io_mode_)(SANE_Handle handle, SANE_Bool non_blocking); - SANE_Status(*real_sane_get_select_fd_)(SANE_Handle handle, SANE_Int* fd); - SANE_String_Const(*real_sane_strstatus_)(SANE_Status status); - SANE_Status(*real_sane_init_ex_)(SANE_Int* version_code, sane_callback cb, void* param); - SANE_Status(*real_sane_io_control_)(SANE_Handle h, unsigned long code, void* data, unsigned* len); - - void(*log_)(int, const char*); - - bool load_sane(void); - int handle_sane_event(SANE_Handle hdev, int code, void* data, unsigned int* len); - void get_online_devices(std::vector& devs); - int get_online_device_count(void); - scanner* find_scanner(SANE_Handle hdev); - scanner* open(const char* name, int* err); - - static void no_log(int, const char*); - static int sane_callback_handler( // 注册回调的对象,需要保证该回调是多线程安全的 - SANE_Handle hdev // 产生事件的设备句柄 - , int code // 回调事件代码 - , void* data // 回调事件数据,根据事件代码有所不同,参照具体事件定义 - , unsigned int* len // 数据长度(字节),或者event_data的缓冲区长度,详细请看相应的事件代码 - , void* param // 用户自定义数据,与调用sane_init_ex传入时的保持一致 - ); // 返回值依不同的事件代码而定,通常为“0” - - static sane_invoker* inst_; - -protected: - sane_invoker(const wchar_t* path); - ~sane_invoker(); - -public: - static int load_dll(const wchar_t* path_dll, HMODULE* dll); - static bool initialize(HMODULE me); - static void uninitialize(void); - static std::string u2m(const wchar_t* u, int page = CP_ACP); - static std::wstring m2u(const char* m, int page = CP_ACP); - static std::string u2ansi(const wchar_t* u); - static std::string u2utf8(const wchar_t* u); - static std::string utf82ansi(const char* utf8); - static std::string ansi2utf8(const char* ansi); - static std::wstring utf82u(const char* utf8); - static std::wstring ansi2u(const char* ansi); - static void log_debug_info(const char* info); -#ifdef VLOG_OK - static void __cdecl log_debug_info(int bytes, const char* fmt, ...); -#endif - - static SANE_Status invoke_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize); - static void invoke_sane_exit(void); - static SANE_Status invoke_sane_get_devices(const SANE_Device*** device_list, SANE_Bool local_only); - static SANE_Status invoke_sane_open(SANE_String_Const devicename, SANE_Handle* handle); - static void invoke_sane_close(SANE_Handle handle); - static const SANE_Option_Descriptor* invoke_sane_get_option_descriptor(SANE_Handle handle, SANE_Int option); - static SANE_Status invoke_sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info); - static SANE_Status invoke_sane_get_parameters(SANE_Handle handle, SANE_Parameters* params); - static SANE_Status invoke_sane_start(SANE_Handle handle); - static SANE_Status invoke_sane_read(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length); - static void invoke_sane_cancel(SANE_Handle handle); - static SANE_Status invoke_sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking); - static SANE_Status invoke_sane_get_select_fd(SANE_Handle handle, SANE_Int* fd); - static SANE_String_Const invoke_sane_strstatus(SANE_Status status); - static SANE_Status invoke_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param); - static SANE_Status invoke_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len); - - static LPSANEAPI get_api(void); - -public: - static bool is_ok(void); - static std::string version(LPDWORD v = NULL); - static void get_devices(std::vector& devs); - static scanner* open_scanner(const char* name, int* err); - static int online_devices(void); -}; - - diff --git a/huagaotwain/sane_option_trans.cpp b/huagaotwain/sane_option_trans.cpp deleted file mode 100644 index 1216bff..0000000 --- a/huagaotwain/sane_option_trans.cpp +++ /dev/null @@ -1,630 +0,0 @@ -#include "sane_option_trans.h" -#include -#include "./twain/twain_2.4.h" - - -namespace sane_trans -{ - bool get_value_list(const SANE_Option_Descriptor* desc, std::list* values) - { - if (desc->type != SANE_TYPE_STRING) - return false; - if (desc->constraint_type != SANE_CONSTRAINT_STRING_LIST) - return false; - - const SANE_String_Const* str = desc->constraint.string_list; - int ind = 0; - while (str[ind]) - values->push_back(str[ind++]); - - return true; - } - bool get_value_list(const SANE_Option_Descriptor* desc, std::list* values) - { - if (desc->type != SANE_TYPE_INT && desc->type != SANE_TYPE_FIXED) - return false; - if (desc->constraint_type != SANE_CONSTRAINT_WORD_LIST) - return false; - - const SANE_Word* val = desc->constraint.word_list; - if (desc->type == SANE_TYPE_FIXED) - { - for (int i = 0; i < val[0]; ++i) - values->push_back(SANE_UNFIX(val[i + 1])); - } - else - { - for (int i = 0; i < val[0]; ++i) - values->push_back(val[i + 1]); - } - - return true; - } - bool get_value_range(const SANE_Option_Descriptor* desc, double* lower, double* upper) - { - if (desc->type != SANE_TYPE_INT && desc->type != SANE_TYPE_FIXED) - return false; - if (desc->constraint_type != SANE_CONSTRAINT_RANGE) - return false; - - if (desc->type == SANE_TYPE_FIXED) - { - *lower = SANE_UNFIX(desc->constraint.range->min); - *upper = SANE_UNFIX(desc->constraint.range->max); - } - else - { - *lower = desc->constraint.range->min; - *upper = desc->constraint.range->max; - } - - return true; - } -} - - -namespace color_mode -{ - static char g_name[] = { "\351\242\234\350\211\262\346\250\241\345\274\217" }; // 颜色模式 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - struct - { - int tw_pixel; - char op_val[80]; - }g_ops[] = { {TWPT_BW, { "\351\273\221\347\231\275" }}, // 黑白 - {TWPT_GRAY, { "256\347\272\247\347\201\260\345\272\246" }}, // 256级灰度 - {TWPT_RGB, { "24\344\275\215\345\275\251\350\211\262" }}, // 24位彩色 - {TWPT_AUTOMATIC_COLOR, {"\351\242\234\350\211\262\350\207\252\345\212\250\350\257\206\345\210\253"}} // 颜色自动识别 - }; - int to_twain_pixel_type(const char* op_val) - { - for (size_t i = 0; i < _countof(g_ops); ++i) - { - if (strcmp(g_ops[i].op_val, op_val) == 0) - return g_ops[i].tw_pixel; - } - - return TWPT_RGB; - } - std::string from_twain_pixel_type(int twpt) - { - for (size_t i = 0; i < _countof(g_ops); ++i) - { - if (g_ops[i].tw_pixel == twpt) - return g_ops[i].op_val; - } - - return g_ops[_countof(g_ops) - 1].op_val; - } -} - -namespace dpi -{ - static char g_name[] = { "\345\210\206\350\276\250\347\216\207" }; // 分辨率 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace paper -{ - static char g_name[] = { "\347\272\270\345\274\240\345\260\272\345\257\270" }; // 纸张尺寸 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - static char g_lateral[] = { "\346\250\252\345\220\221" }; - bool is_lateral(const char* paper_val) - { - return strstr(paper_val, g_lateral) != NULL; - } - std::string lateral_title(void) - { - return g_lateral; - } - - static char g_auto_size[] = { "\345\214\271\351\205\215\345\216\237\345\247\213\345\260\272\345\257\270" }; // 匹配原始尺寸 - bool is_auto_size(const char* paper_val) - { - return strstr(paper_val, g_auto_size) != NULL; - } - std::string auto_size_title(void) - { - return g_auto_size; - } - - static char g_auto_crop[] = { "\346\234\200\345\244\247\346\211\253\346\217\217\345\260\272\345\257\270\350\207\252\345\212\250\350\243\201\345\210\207" }; // 最大扫描尺寸自动裁切 - bool is_auto_crop(const char* paper_val) - { - return strstr(paper_val, g_auto_crop) != NULL; - } -} - -namespace scan_count -{ - static char g_parent[] = { "\346\211\253\346\217\217\345\274\240\346\225\260" };// 扫描张数 - bool is_parent(const char* desc_title) - { - return strcmp(g_parent, desc_title) == 0; - } - static char g_name[] = { "\346\211\253\346\217\217\346\225\260\351\207\217" }; // 扫描数量 - bool is_me(const char* desc_title) - { - return strstr(desc_title, g_name); - } - std::string scan_continous_val(void) - { - return "\350\277\236\347\273\255\346\211\253\346\217\217"; // 连续扫描 - } -} - -namespace text_direction -{ - static char g_direction[] = { "\346\226\207\347\250\277\346\226\271\345\220\221" }; // 文稿方向 - bool is_me(const char* desc_title) - { - return strcmp(desc_title, g_direction) == 0; - } - struct - { - double angle; - std::string op_val; - }g_ops[] = { {.0f, "0\302\260"} - , {90.0f, "90\302\260"} - , {180.0f, "180\302\260"} - , {270.0f, "270\302\260"} - }; - static char g_auto_dir[] = { "\350\207\252\345\212\250\346\226\207\346\234\254\346\226\271\345\220\221\350\257\206\345\210\253\302\260" }; // 自动文本方向识别° - double to_twain_angle(const char* opt_val) - { - for (size_t i = 0; i < _countof(g_ops); ++i) - { - if (g_ops[i].op_val == opt_val) - return g_ops[i].angle; - } - - return g_ops[0].angle; - } - std::string from_twain_angle(double angle) - { - for (size_t i = 0; i < _countof(g_ops); ++i) - { - if (IS_DOUBLE_EQUAL(g_ops[i].angle, angle)) - return g_ops[i].op_val; - } - - return g_ops[0].op_val; - } - bool is_auto(const char* opt_val) - { - return strcmp(opt_val, g_auto_dir) == 0; - } - std::string auto_val(void) - { - return g_auto_dir; - } -} - -namespace page -{ - static char g_name[] = { "\346\211\253\346\217\217\351\241\265\351\235\242" }; // 扫描页面 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - static char g_not_duplex[] = { "\345\215\225\351\235\242" }; // 单面 - static char g_duplex[] = { "\345\217\214\351\235\242" }; // 双面 - bool is_duplex(const char* opval) - { - return strcmp(opval, g_duplex) == 0; - } - std::string from_duplex(bool duplex) - { - return duplex ? g_duplex : g_not_duplex; - } - - static char g_discard_blank[] = { "\350\267\263\350\277\207\347\251\272\347\231\275\351\241\265\357\274\210\351\200\232\347\224\250\357\274\211" }; // 跳过空白页(通用) - static char g_discard_blank_receipt[] = { "\350\267\263\350\277\207\347\251\272\347\231\275\351\241\265\357\274\210\345\217\221\347\245\250\347\272\270\357\274\211" }; // 跳过空白页(发票纸) - bool is_discard_blank_page(const char* opval, bool receipt) - { - return receipt ? strcmp(g_discard_blank_receipt, opval) == 0 : - strcmp(g_discard_blank, opval) == 0; - } - std::string discard_blank_page_title(bool receipt) - { - return receipt ? g_discard_blank_receipt : g_discard_blank; - } - - static char g_fold[] = { "\345\257\271\346\212\230" }; // 对折 - bool is_fold(const char* opval) - { - return strcmp(g_fold, opval) == 0; - } - std::string fold_page_title(void) - { - return g_fold; - } - -} - -namespace auto_descrew -{ - static char g_name[] = { "\350\207\252\345\212\250\347\272\240\345\201\217" }; // 自动纠偏 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace erase_black_frame -{ - static char g_name[] = { "\346\266\210\351\231\244\351\273\221\346\241\206" }; // 消除黑框 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace filter -{ - static char g_name[] = { "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262" }; // 灰度或黑白图像 - 除色 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - struct - { - int twfilter; - std::string opt_val; - }g_ops[] = { {TWFT_RED, "\351\231\244\347\272\242\350\211\262"} // 除红色 - , {TWFT_GREEN, "\351\231\244\347\273\277\350\211\262"} // 除绿色 - , {TWFT_BLUE, "\351\231\244\350\223\235\350\211\262"} // 除蓝色 - , {TWFT_NONE, "\344\270\215\351\231\244\350\211\262"} // 不除色 - - // 颜色增强 - // , {ENHANCE_COLOR_NONE, "\351\231\244\347\273\277\350\211\262"} // 不增强 - , {ENHANCE_COLOR_RED, "\347\272\242\350\211\262\345\242\236\345\274\272"} // 红色增强 - , {ENHANCE_COLOR_GREEN,"\347\273\277\350\211\262\345\242\236\345\274\272"} // 绿色增强 - , {ENHANCE_COLOR_BLUE, "\350\223\235\350\211\262\345\242\236\345\274\272"} // 蓝色增强 - }; - static int g_enhance_base = 4; - int to_filter_type(const char* opt_val, bool enhance) - { - if (enhance) - { - for (size_t i = g_enhance_base; i < _countof(g_ops); ++i) - { - if (g_ops[i].opt_val == opt_val) - return g_ops[i].twfilter; - } - - return ENHANCE_COLOR_NONE; - } - - for (size_t i = 0; i < g_enhance_base; ++i) - { - if (g_ops[i].opt_val == opt_val) - return g_ops[i].twfilter; - } - - return TWFT_NONE; - } - std::string from_filter_type(int filter, bool enhance) - { - if (enhance) - { - for (size_t i = g_enhance_base; i < _countof(g_ops); ++i) - { - if (g_ops[i].twfilter == filter) - return g_ops[i].opt_val; - } - } - else - { - for (size_t i = 0; i < g_enhance_base; ++i) - { - if (g_ops[i].twfilter == filter) - return g_ops[i].opt_val; - } - } - - return g_ops[g_enhance_base - 1].opt_val; - } -} - -namespace bright -{ - static char g_name[] = { "\344\272\256\345\272\246" }; // 亮度 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} -namespace contrast -{ - static char g_name[] = { "\345\257\271\346\257\224\345\272\246" }; // 对比度 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} -namespace gamma -{ - static char g_name[] = { "\344\274\275\347\216\233" }; // 伽玛 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace ultrasonic -{ - static char g_name[] = { "\350\266\205\345\243\260\346\263\242\346\243\200\346\265\213" }; // 超声波检测 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace flip -{ - static char g_name[] = { "\344\272\244\346\215\242\346\255\243\345\217\215\351\235\242" }; // 交换正反面 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace rotate_bg -{ - static char g_name[] = { "\350\203\214\351\235\242\346\227\213\350\275\254180\302\260" }; // 背面旋转180° - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace fill_black_border -{ - static char g_name[] = { "\346\266\210\351\231\244\351\273\221\346\241\206" }; // 消除黑框 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace edge_ident -{ - static char g_name[] = { "\350\276\271\347\274\230\347\274\251\350\277\233" }; // 边缘缩进 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace threshold -{ - static char g_name[] = { "\351\230\210\345\200\274" }; // 阈值 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace bkg_filling_method -{ - static char g_name[] = { "\350\203\214\346\231\257\345\241\253\345\205\205\346\226\271\345\274\217" }; // 背景填充方式 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - static char g_convex[] = { "\345\207\270\345\244\232\350\276\271\345\275\242" };// 凸多边形 - bool is_convex(const char* opval) - { - return strcmp(opval, g_convex) == 0; - } -} - -namespace fill_hole -{ - static char g_name[] = { "\347\251\277\345\255\224\347\247\273\351\231\244" }; // 穿孔移除 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - static char g_ratio[] = { "\347\251\277\345\255\224\346\220\234\347\264\242\350\214\203\345\233\264\345\215\240\345\271\205\351\235\242\346\257\224\344\276\213" }; // 穿孔搜索范围占幅面比例 - bool is_ratio(const char* desc_title) - { - return strstr(desc_title, g_ratio) != NULL; - } -} - -namespace noise -{ - static char g_name[] = { "\351\273\221\347\231\275\345\233\276\345\203\217\345\231\252\347\202\271\344\274\230\345\214\226" }; // 黑白图像噪点优化 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - static char g_threshold[] = { "\345\231\252\347\202\271\344\274\230\345\214\226\345\260\272\345\257\270" }; // 噪点优化尺寸 - bool is_threshold(const char* desc_title) - { - return strstr(desc_title, g_threshold) != NULL; - } -} - -namespace rid_red -{ - static char g_name[] = { "24\344\275\215\345\275\251\350\211\262\345\233\276\345\203\217 - \345\244\232\346\265\201\350\276\223\345\207\272\351\231\244\347\272\242" }; // 24位彩色图像 - 多流输出除红 - static char g_hsv[] = { "24\344\275\215\345\275\251\350\211\262\345\233\276\345\203\217 - \347\255\224\351\242\230\345\215\241\351\231\244\347\272\242" }; // 24位彩色图像 - 答题卡除红 - bool is_me(const char* desc_title, bool hsv) - { - return strcmp(hsv ? g_hsv : g_name, desc_title) == 0; - } -} - -namespace sharpen -{ - static char g_name[] = { "\351\224\220\345\214\226\344\270\216\346\250\241\347\263\212" }; // 锐化与模糊 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - struct - { - int type; - std::string op_val; - }g_ops[] = { {SHARPEN_NONE, "\346\227\240"} // 无 - , {SHARPEN_NORMAL, "\351\224\220\345\214\226"} // 锐化 - , {SHARPEN_MORE, "\350\277\233\344\270\200\346\255\245\351\224\220\345\214\226"} // 进一步锐化 - , {SHARPEN_BLUR, "\346\250\241\347\263\212"} // 模糊 - , {SHARPEN_BLUR_MORE, "\350\277\233\344\270\200\346\255\245\346\250\241\347\263\212"} // 进一步模糊 - }; - int to_type(const char* opval) - { - for (size_t i = 0; i < _countof(g_ops); ++i) - { - if (g_ops[i].op_val == opval) - return g_ops[i].type; - } - - return SHARPEN_NONE; - } - std::string from_type(int type) - { - for (size_t i = 0; i < _countof(g_ops); ++i) - { - if (g_ops[i].type == type) - return g_ops[i].op_val; - } - - return g_ops[0].op_val; - } -} - -namespace screw -{ - static char g_name[] = { "\346\255\252\346\226\234\346\243\200\346\265\213" }; // 歪斜检测 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - static char g_level[] = { "\346\255\252\346\226\234\346\243\200\346\265\213\345\244\215\346\235\202\345\272\246" }; // 歪斜检测复杂度 - bool is_level(const char* desc_title) - { - return strstr(desc_title, g_level) != NULL; - } -} - -namespace staple -{ - static char g_name[] = { "\350\243\205\350\256\242\346\243\200\346\265\213" }; // 装订检测 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace dogear -{ - static char g_name[] = { "\346\212\230\350\247\222\346\243\200\346\265\213" }; // 折角检测 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace sample -{ - static char g_name[] = { "\346\267\261\350\211\262\346\240\267\345\274\240" }; // 深色样张 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace split -{ - static char g_name[] = { "\345\233\276\345\203\217\346\213\206\345\210\206" }; // 图像拆分 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace fade_bkg -{ - static char g_name[] = { "\350\203\214\346\231\257\347\247\273\351\231\244" }; // 背景移除 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - static char g_val[] = { "\350\203\214\346\231\257\350\211\262\345\275\251\346\265\256\345\212\250\350\214\203\345\233\264" }; // 背景色彩浮动范围 - bool is_value(const char* desc_title) - { - return strstr(desc_title, g_val) != NULL; - } -} - -namespace size_detect -{ - static char g_name[] = { "\345\260\272\345\257\270\346\243\200\346\265\213" }; // 尺寸检测 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } -} - -namespace multi_out -{ - static char g_name[] = { "24\344\275\215\345\275\251\350\211\262\345\233\276\345\203\217-\345\244\232\346\265\201\350\276\223\345\207\272" }; // 24位彩色图像-多流输出 - bool is_me(const char* desc_title) - { - return strcmp(g_name, desc_title) == 0; - } - - struct - { - int type; - std::string op_val; - }g_ops[] = { {MULTI_OUT_NONE, "\344\270\215\351\200\211\346\213\251\350\276\223\345\207\272\346\250\241\345\274\217"} // 不选择输出模式 - , {MULTI_OUT_ALL, "\345\275\251\350\211\262+\347\201\260\345\272\246+\351\273\221\347\231\275"} // 彩色+灰度+黑白 - , {MULTI_OUT_COLOR_GRAY, "\345\275\251\350\211\262+\347\201\260\345\272\246"} // 彩色+灰度 - , {MULTI_OUT_COLOR_BW, "\345\275\251\350\211\262+\351\273\221\347\231\275"} // 彩色+黑白 - , {MULTI_OUT_GRAY_BW, "\347\201\260\345\272\246+\351\273\221\347\231\275"} // 灰度+黑白 - }; - int to_twain_type(const char* opval) - { - for (int i = 0; i < _countof(g_ops); ++i) - { - if (g_ops[i].op_val == opval) - return g_ops[i].type; - } - - return MULTI_OUT_NONE; - } - std::string from_twain_type(int type) - { - for (int i = 0; i < _countof(g_ops); ++i) - { - if (g_ops[i].type == type) - return g_ops[i].op_val; - } - - return g_ops[0].op_val; - } -} diff --git a/huagaotwain/sane_option_trans.h b/huagaotwain/sane_option_trans.h deleted file mode 100644 index e551fa2..0000000 --- a/huagaotwain/sane_option_trans.h +++ /dev/null @@ -1,230 +0,0 @@ -// utilities for transfroming options between TWAIN and sane ... -// -// Date: 2022-04-14 -// - -#pragma once - -#include "sane/sane_ex.h" -#include -#include -#include - -#define TWPT_AUTOMATIC_COLOR 0x0a0c -#define IS_DOUBLE_EQUAL(a, b) fabs((a) - (b)) < .000001 - -#define ENHANCE_COLOR_NONE 0 -#define ENHANCE_COLOR_RED 1 -#define ENHANCE_COLOR_GREEN 2 -#define ENHANCE_COLOR_BLUE 3 - -#define SHARPEN_NONE 0 -#define SHARPEN_NORMAL 1 -#define SHARPEN_MORE 2 -#define SHARPEN_BLUR 3 -#define SHARPEN_BLUR_MORE 4 - -#define MULTI_OUT_NONE -1 -#define MULTI_OUT_ALL 0 -#define MULTI_OUT_COLOR_GRAY 1 -#define MULTI_OUT_COLOR_BW 2 -#define MULTI_OUT_GRAY_BW 3 - -enum value_limit -{ - VAL_LIMIT_NONE = 0, // - VAL_LIMIT_ENUM, // - VAL_LIMIT_RANGE, // -}; - -namespace sane_trans -{ - bool get_value_list(const SANE_Option_Descriptor* desc, std::list* values); - bool get_value_list(const SANE_Option_Descriptor* desc, std::list* values); - bool get_value_range(const SANE_Option_Descriptor* desc, double* lower, double* upper); -} - - -namespace color_mode -{ - bool is_me(const char* desc_title); - int to_twain_pixel_type(const char* op_val); - std::string from_twain_pixel_type(int twpt); -} - -namespace dpi -{ - bool is_me(const char* desc_title); -} - -namespace paper -{ - bool is_me(const char* desc_title); - bool is_lateral(const char* paper_val); - std::string lateral_title(void); - bool is_auto_size(const char* paper_val); - std::string auto_size_title(void); - bool is_auto_crop(const char* paper_val); -} - -namespace scan_count -{ - bool is_parent(const char* desc_title); - bool is_me(const char* desc_title); - std::string scan_continous_val(void); -} - -namespace text_direction -{ - bool is_me(const char* desc_title); - double to_twain_angle(const char* opt_val); - std::string from_twain_angle(double angle); - - bool is_auto(const char* opt_val); - std::string auto_val(void); -} - -namespace page -{ - bool is_me(const char* desc_title); - bool is_duplex(const char* opval); - std::string from_duplex(bool duplex); - bool is_discard_blank_page(const char* opval, bool receipt); - std::string discard_blank_page_title(bool receipt); - bool is_fold(const char* opval); - std::string fold_page_title(void); -} - -namespace auto_descrew -{ - bool is_me(const char* desc_title); -} - -namespace erase_black_frame -{ - bool is_me(const char* desc_title); -} - -namespace filter -{ - bool is_me(const char* desc_title); - int to_filter_type(const char* opt_val, bool enhance); - std::string from_filter_type(int filter, bool enhance); -} - -namespace bright -{ - bool is_me(const char* desc_title); -} -namespace contrast -{ - bool is_me(const char* desc_title); -} -namespace gamma -{ - bool is_me(const char* desc_title); -} - -namespace ultrasonic -{ - bool is_me(const char* desc_title); -} - -namespace flip -{ - bool is_me(const char* desc_title); -} - -namespace rotate_bg -{ - bool is_me(const char* desc_title); -} - -namespace fill_black_border -{ - bool is_me(const char* desc_title); -} - -namespace edge_ident -{ - bool is_me(const char* desc_title); -} - -namespace threshold -{ - bool is_me(const char* desc_title); -} - -namespace bkg_filling_method -{ - bool is_me(const char* desc_title); - bool is_convex(const char* opval); -} - -namespace fill_hole -{ - bool is_me(const char* desc_title); - bool is_ratio(const char* desc_title); -} - -namespace noise -{ - bool is_me(const char* desc_title); - bool is_threshold(const char* desc_title); -} - -namespace rid_red -{ - bool is_me(const char* desc_title, bool hsv/*是否为答题卡除红*/); -} - -namespace sharpen -{ - bool is_me(const char* desc_title); - int to_type(const char* opval); - std::string from_type(int type); -} - -namespace screw -{ - bool is_me(const char* desc_title); - bool is_level(const char* desc_title); -} - -namespace staple -{ - bool is_me(const char* desc_title); -} - -namespace dogear -{ - bool is_me(const char* desc_title); -} - -namespace sample -{ - bool is_me(const char* desc_title); -} - -namespace split -{ - bool is_me(const char* desc_title); -} - -namespace fade_bkg -{ - bool is_me(const char* desc_title); - bool is_value(const char* desc_title); -} - -namespace size_detect -{ - bool is_me(const char* desc_title); -} - -namespace multi_out -{ - bool is_me(const char* desc_title); - int to_twain_type(const char* opval); - std::string from_twain_type(int type); -} diff --git a/protocol/sane.def b/protocol/sane.def deleted file mode 100644 index 669ddba..0000000 --- a/protocol/sane.def +++ /dev/null @@ -1,18 +0,0 @@ -LIBRARY hgsane -EXPORTS - sane_hgsane_init - sane_hgsane_exit - sane_hgsane_get_devices - sane_hgsane_open - sane_hgsane_close - sane_hgsane_get_option_descriptor - sane_hgsane_control_option - sane_hgsane_get_parameters - sane_hgsane_start - sane_hgsane_read - sane_hgsane_cancel - sane_hgsane_set_io_mode - sane_hgsane_get_select_fd - sane_hgsane_strstatus - sane_hgsane_init_ex - sane_hgsane_io_control \ No newline at end of file diff --git a/huagaotwain/huagaotwain.cpp b/sane/huagaotwain.cpp similarity index 99% rename from huagaotwain/huagaotwain.cpp rename to sane/huagaotwain.cpp index 2be9a65..7dda641 100644 --- a/huagaotwain/huagaotwain.cpp +++ b/sane/huagaotwain.cpp @@ -1,8 +1,6 @@ #include "pch.h" #include "huagaotwain.h" #include "huagao/hgscanner_error.h" -#include "./twain/twain_2.4.h" -#include "../../code_device/sdk/hginclude/hg_log.h" #define STR(s) #s #define PASTE_STR(a, b) STR(a##b) @@ -46,7 +44,15 @@ namespace local_utility } std::wstring reg_get_app_installing_path(void) { - return reg_read(HKEY_LOCAL_MACHINE, L"SOFTWARE\\HuaGoScan", L"AppDirectory"); +#ifdef OEM_HANWANG + std::wstring path(L"SOFTWARE\\HwScanner"); +#elif defined(OEM_LISICHENG) + std::wstring path(L"SOFTWARE\\LscScanner"); +#else + std::wstring path(L"SOFTWARE\\HuaGoScan"); +#endif + + return reg_read(HKEY_LOCAL_MACHINE, path.c_str(), L"AppDirectory"); } } @@ -498,7 +504,7 @@ std::wstring sane_invoker::ansi2u(const char* ansi) void sane_invoker::log_debug_info(const char* info) { if (sane_invoker::inst_) - sane_invoker::inst_->log_(LOG_LEVEL_DEBUG_INFO, info); + sane_invoker::inst_->log_(/*LOG_LEVEL_DEBUG_INFO*/1, info); else OutputDebugStringA(info); } diff --git a/sane/huagaotwain.h b/sane/huagaotwain.h new file mode 100644 index 0000000..cfb5d21 --- /dev/null +++ b/sane/huagaotwain.h @@ -0,0 +1,12 @@ +#pragma once +#include "huagao/hgscanner_error.h" +#include +#include +#include +#include +#include "sane_option_trans.h" +#include "s2t_api.h" + + + + diff --git a/sane/s2t_api.h b/sane/s2t_api.h new file mode 100644 index 0000000..995d4b4 --- /dev/null +++ b/sane/s2t_api.h @@ -0,0 +1,393 @@ +#pragma once + +// +// For: interface definition for SANE to TWAIN +// +// Date: 2022-06-08 +// + +#include +#include +#include +#include + +#define COM_API_DECLARE(ret, decl) virtual ret __stdcall decl = 0 +#define COM_API_DECLARE_NON_PURE(ret, decl) virtual ret __stdcall decl +#define COM_API_OVERRIDE(ret, decl) virtual ret __stdcall decl override +#define COM_API_IMPLEMENT(cls, ret, decl) ret __stdcall 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 __stdcall 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 __stdcall 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, // +}; +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_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, +}; + +typedef bool(__stdcall* set_opt_value)(void* val, value_role role, void* param); // return false to stop the callback +__declspec(novtable) struct IRef +{ + COM_API_DECLARE(long, add_ref(void)); + COM_API_DECLARE(long, release(void)); +}; +__declspec(novtable) struct IScanImg : public IRef +{ + 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(SANE_Frame, type(void)); + COM_API_DECLARE(unsigned int, bytes(void)); + COM_API_DECLARE(unsigned char*, bits(void)); + COM_API_DECLARE(void, copy_header(SANE_Parameters* head)); +}; +__declspec(novtable) struct ISaneInvoker : public IRef +{ + COM_API_DECLARE(int, start(void)); + COM_API_DECLARE(int, stop(void)); + COM_API_DECLARE(void, set_event_callback(void(*cb)(int ev_type, void* data, unsigned int* len, void* param), void* param)); + 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(void)); // call 'release' on returned value, plz + COM_API_DECLARE(bool, get_first_image_header(SANE_Parameters* header)); + COM_API_DECLARE(bool, is_online(void)); + COM_API_DECLARE(bool, is_paper_on(void)); + + // Function: 获取配置项信息 + // + // Parameter: sn - 配置项索引 + // + // type - 配置项数据类型 + // + // limit - 配置项限制类型 + // + // bytes - *type 为 VAL_TYPE_STR时,需要的最小空间字节数 + COM_API_DECLARE(bool, get_option_info(int sn, value_type* type, value_limit* limit, int *bytes)); + + COM_API_DECLARE(bool, get_value(int sn, set_opt_value, void* param)); + COM_API_DECLARE(int, set_value(int sn, void* val)); + + // SANE options ID ... + SANE_OPTION_ID_API(is_multiout); + SANE_OPTION_ID_API(multiout_type); + SANE_OPTION_ID_API(color_mode); + SANE_OPTION_ID_API(erase_color); + SANE_OPTION_ID_API(erase_multiout_red); + SANE_OPTION_ID_API(erase_paper_red); + SANE_OPTION_ID_API(is_erase_background); + SANE_OPTION_ID_API(background_color_range); + SANE_OPTION_ID_API(sharpen); + SANE_OPTION_ID_API(erase_morr); + SANE_OPTION_ID_API(erase_grids); // 除网纹 + SANE_OPTION_ID_API(error_extend); + SANE_OPTION_ID_API(is_noise_modify); + SANE_OPTION_ID_API(noise_threshold); + SANE_OPTION_ID_API(paper); + SANE_OPTION_ID_API(is_custom_area); + SANE_OPTION_ID_API(curstom_area_l); + SANE_OPTION_ID_API(curstom_area_r); + SANE_OPTION_ID_API(curstom_area_t); + SANE_OPTION_ID_API(curstom_area_b); + SANE_OPTION_ID_API(is_size_check); + SANE_OPTION_ID_API(page); + SANE_OPTION_ID_API(blank_page_threshold); // 跳过空白页灵敏度 + SANE_OPTION_ID_API(resolution); + SANE_OPTION_ID_API(image_quality); + SANE_OPTION_ID_API(is_swap); // 交换正反面 + SANE_OPTION_ID_API(is_split); // 图像拆分 + SANE_OPTION_ID_API(is_auto_deskew); // 自动纠偏 + SANE_OPTION_ID_API(is_custom_gamma); + SANE_OPTION_ID_API(bright); + SANE_OPTION_ID_API(contrast); + SANE_OPTION_ID_API(gamma); + SANE_OPTION_ID_API(is_erase_black_frame); // bool + SANE_OPTION_ID_API(deep_sample); + SANE_OPTION_ID_API(threshold); + SANE_OPTION_ID_API(anti_noise); // 抗噪等级 + SANE_OPTION_ID_API(margin); + SANE_OPTION_ID_API(fill_background); + SANE_OPTION_ID_API(is_anti_permeate); + SANE_OPTION_ID_API(anti_permeate_level); + SANE_OPTION_ID_API(is_erase_hole); + SANE_OPTION_ID_API(search_hole_range); + SANE_OPTION_ID_API(is_filling_color); // 色彩填充 + SANE_OPTION_ID_API(is_ultrasonic_check); + SANE_OPTION_ID_API(is_check_staple); + SANE_OPTION_ID_API(scan_mode); // 扫描张数 + SANE_OPTION_ID_API(scan_count); // 扫描数量 + SANE_OPTION_ID_API(text_direction); + SANE_OPTION_ID_API(is_rotate_bkg180); + SANE_OPTION_ID_API(is_check_dogear); + SANE_OPTION_ID_API(dogear_size); + SANE_OPTION_ID_API(is_check_skew); + SANE_OPTION_ID_API(skew_range); + + // SANE-ex option ID: + SANE_OPTION_ID_API_EX(multiout_type); // int + SANE_OPTION_ID_API_EX(auto_color_type); // int + SANE_OPTION_ID_API_EX(color_mode); // int + SANE_OPTION_ID_API_EX(sharpen); // int + SANE_OPTION_ID_API_EX(paper); // paper_value + SANE_OPTION_ID_API_EX(paper_lateral); // bool + SANE_OPTION_ID_API_EX(auto_paper_size); // bool + SANE_OPTION_ID_API_EX(is_paper_auto_crop); // bool + SANE_OPTION_ID_API_EX(text_direction); // float 90, 180, ..., -1 is auto-text-direction + SANE_OPTION_ID_API_EX(duplex); // bool + SANE_OPTION_ID_API_EX(fill_background); // bool true - 凸多边形 + SANE_OPTION_ID_API_EX(discard_blank_page); // bool + SANE_OPTION_ID_API_EX(discard_blank_receipt); // bool + SANE_OPTION_ID_API_EX(is_page_fold); // bool + SANE_OPTION_ID_API_EX(color_filter); // int (filter_value) + SANE_OPTION_ID_API_EX(color_enhance); // int (enhance_value) + + SANE_OPTION_ID_API_EX(final_compression); // int + SANE_OPTION_ID_API_EX(final_format); // SANE_FinalImgFormat + SANE_OPTION_ID_API_EX(serial); // std::string + SANE_OPTION_ID_API_EX(to_be_scan); // bool + SANE_OPTION_ID_API_EX(scan_with_hole); // bool + SANE_OPTION_ID_API_EX(device_code); // std::string + SANE_OPTION_ID_API_EX(power); // int + SANE_OPTION_ID_API_EX(hardware_version); // std::string + SANE_OPTION_ID_API_EX(ip); // std::string + + // ui ... + COM_API_DECLARE(void, ui_show_main(void)); + COM_API_DECLARE(void, ui_show_setting(bool with_scan)); + COM_API_DECLARE(void, ui_show_progress(void)); + COM_API_DECLARE(void, ui_hide(void)); + COM_API_DECLARE(void, ui_handle_sane_event(int sane_ev, void* data, unsigned int* len)); + COM_API_DECLARE(bool, ui_is_ok(void)); + COM_API_DECLARE(bool, ui_is_progress_ui_showing(void)); +}; + +struct delete_scanner +{ + void operator()(ISaneInvoker* p) + { + p->release(); + } +}; + +#include +#include +namespace sane_opts +{ + template + class get_opts + { + public: + T* init_; + T* cur_; + T* lower_; + T* upper_; + T* step_; + std::vector* vvs_; + std::list* lvs_; + + public: + get_opts(T* cur = NULL, T* init = NULL, std::vector* vs = NULL, std::list* ls = NULL, T* lower = NULL, T* upper = NULL, T* step = NULL) + : init_(init), cur_(cur), vvs_(vs), lvs_(ls) + , lower_(lower), upper_(upper), step_(step) + {} + ~get_opts() + {} + }; + + template + bool __stdcall set_opt_value(void* val, value_role role, void* param) + { + get_opts* v = (get_opts*)param; + bool go = true; + + if (role & VAL_ROLE_CURRENT) + { + if (v->cur_) + { + *v->cur_ = *(T*)val; + } + } + if (role & VAL_ROLE_DEFAULT) + { + if (v->init_) + { + *v->init_ = *(T*)val; + } + } + if (role & VAL_ROLE_LOWER) + { + if (v->lower_) + *v->lower_ = *(T*)val; + } + if (role & VAL_ROLE_UPPER) + { + if (v->upper_) + *v->upper_ = *(T*)val; + } + if (role & VAL_ROLE_STEP) + { + if (v->step_) + *v->step_ = *(T*)val; + + return go; + } + + if (v->vvs_) + v->vvs_->push_back(*(T*)val); + else if (v->lvs_) + v->lvs_->push_back(*(T*)val); + + return go; + } +} + +#define GET_SANE_OPT(type, object, id_name, cur, init, vec, lst) \ + { \ + int ind = object->sane_opt_id_##id_name##(); \ + if(ind > 0) \ + { \ + sane_opts::get_opts op(cur, init, vec, lst); \ + object->get_value(ind, sane_opts::set_opt_value, &op);\ + } \ + } +#define GET_SANE_OPT_RANGE(type, object, id_name, cur, init, low, up, step) \ + { \ + int ind = object->sane_opt_id_##id_name##(); \ + if(ind > 0) \ + { \ + sane_opts::get_opts op(cur, init, NULL, NULL, low, up, step); \ + object->get_value(ind, sane_opts::set_opt_value, &op);\ + } \ + } +#define SET_SANE_OPT(ret, object, id_name, val) \ + { \ + int ind = object->sane_opt_id_##id_name##(); \ + if(ind > 0) \ + ret = object->set_value(ind, val); \ + else \ + ret = SCANNER_ERR_INVALID_PARAMETER; \ + } + +typedef unsigned int SCANNERID; +#define MAKE_SCANNER_ID(pid, vid) MAKELONG(pid, vid) +#define GET_SCANNER_PID(sid) LOWORD(sid) +#define GET_SCANNER_VID(sid) HIWORD(sid) + +#ifdef EXPORT_SANE_API +__declspec(dllexport) +#else +__declspec(dllimport) +#endif +int __stdcall initialize(void* reserve); +#ifdef EXPORT_SANE_API +__declspec(dllexport) +#else +__declspec(dllimport) +#endif +int __stdcall open_scanner(SCANNERID scanner_id, ISaneInvoker** invoker); +#ifdef EXPORT_SANE_API +__declspec(dllexport) +#else +__declspec(dllimport) +#endif +bool __stdcall is_scanner_online(SCANNERID scanner_id); +#ifdef EXPORT_SANE_API +__declspec(dllexport) +#else +__declspec(dllimport) +#endif +int __stdcall uninitialize(void* reserve); + + diff --git a/sane/sane.def b/sane/sane.def new file mode 100644 index 0000000..deda82a --- /dev/null +++ b/sane/sane.def @@ -0,0 +1,6 @@ +LIBRARY sane +EXPORTS + initialize + open_scanner + is_scanner_online + uninitialize diff --git a/protocol/hgsane.vcxproj b/sane/sane.vcxproj similarity index 94% rename from protocol/hgsane.vcxproj rename to sane/sane.vcxproj index 6c8578a..cea4c71 100644 --- a/protocol/hgsane.vcxproj +++ b/sane/sane.vcxproj @@ -22,9 +22,9 @@ 16.0 Win32Proj {6eec8a02-7f98-4422-8ed6-2434d43bd1e1} - hgsane + sane 10.0 - hgsane + sane @@ -103,7 +103,7 @@ Level3 true - BACKEND_NAME=hgsane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + BACKEND_NAME=sane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 4996 @@ -128,7 +128,7 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$ true true true - BACKEND_NAME=hgsane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + BACKEND_NAME=sane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 4996 @@ -197,6 +197,9 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$ + + + @@ -211,6 +214,10 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$ + + + + diff --git a/protocol/hgsane.vcxproj.filters b/sane/sane.vcxproj.filters similarity index 79% rename from protocol/hgsane.vcxproj.filters rename to sane/sane.vcxproj.filters index 9800114..87f970f 100644 --- a/protocol/hgsane.vcxproj.filters +++ b/sane/sane.vcxproj.filters @@ -13,6 +13,9 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + {8ae15a45-410d-4611-b852-f82b64bb1fcc} + @@ -30,6 +33,15 @@ 源文件 + + sane2twain + + + sane2twain + + + sane2twain + @@ -68,6 +80,18 @@ 头文件 + + sane2twain + + + sane2twain + + + sane2twain + + + sane2twain + diff --git a/sane/sane.vcxproj.user b/sane/sane.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/sane/sane.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sane/sane_option_trans.cpp b/sane/sane_option_trans.cpp new file mode 100644 index 0000000..bf5f82d --- /dev/null +++ b/sane/sane_option_trans.cpp @@ -0,0 +1,294 @@ +#include "sane_option_trans.h" +#include +#include + +namespace sane_opt_trans +{ + static struct + { + int twain_id; + const char* opt_val; + } + g_color_mode_map[] = {{COLOR_BW, OPTION_VALUE_YSMS_HB} + , {COLOR_GRAY, OPTION_VALUE_YSMS_256JHD} + , {COLOR_RGB, OPTION_VALUE_YSMS_24WCS} + , {COLOR_AUTO_MATCH, OPTION_VALUE_YSMS_YSZDSB} + }, + g_multiout_map[] = { {MULTI_OUT_NONE, "\346\227\240"} + , {MULTI_OUT_ALL, OPTION_VALUE_DLSC_CS_HD_HB} + , {MULTI_OUT_COLOR_GRAY, OPTION_VALUE_DLSC_CS_HD} + , {MULTI_OUT_COLOR_BW, OPTION_VALUE_DLSC_CS_HB} + , {MULTI_OUT_GRAY_BW, OPTION_VALUE_DLSC_HD_HB} + }, + g_enhance_map[] = { {ENHANCE_NONE, OPTION_VALUE_HDHHBTX_CS_BCS} + , {ENHANCE_RED, OPTION_VALUE_HDHHBTX_CS_HSZQ} + , {ENHANCE_GREEN, OPTION_VALUE_HDHHBTX_CS_LSZQ} + , {ENHANCE_BLUE, OPTION_VALUE_HDHHBTX_CS_LANSEZENGQIANG} + }, + g_filter_map[] = { {FILTER_NONE, OPTION_VALUE_HDHHBTX_CS_BCS} + , {FILTER_RED, OPTION_VALUE_HDHHBTX_CS_CHS} + , {FILTER_GREEN, OPTION_VALUE_HDHHBTX_CS_CLS} + , {FILTER_BLUE, OPTION_VALUE_HDHHBTX_CS_CHULANSE} + }, + g_auto_color_map[] = { {0, OPTION_VALUE_YSMS_HB} + , {1, OPTION_VALUE_YSMS_256JHD} + }, + g_sharpen_map[] = { {SHARPEN_NONE, OPTION_VALUE_RHYMH_W} + , {SHARPEN_SHARPEN, OPTION_VALUE_RHYMH_RH} + , {SHARPEN_SHARPEN_MORE, OPTION_VALUE_RHYMH_JYBRH} + , {SHARPEN_BLUR, OPTION_VALUE_RHYMH_MH} + , {SHARPEN_BLUR_MORE, OPTION_VALUE_RHYMH_JYBMH} + }, + g_paper_map[] = { {PAPER_LETTER, OPTION_VALUE_ZZCC_Letter} + , {PAPER_LEGAL, OPTION_VALUE_ZZCC_LEGAL} + //, {PAPER_8K, OPTION_VALUE_ZZCC_8K} + //, {PAPER_16K, OPTION_VALUE_ZZCC_16K} + , {PAPER_A3, OPTION_VALUE_ZZCC_A3} + , {PAPER_A4, OPTION_VALUE_ZZCC_A4} + , {PAPER_A5, OPTION_VALUE_ZZCC_A5} + , {PAPER_A6, OPTION_VALUE_ZZCC_A6} + , {PAPER_B4, OPTION_VALUE_ZZCC_B4} + , {PAPER_B5, OPTION_VALUE_ZZCC_B5} + , {PAPER_B6, OPTION_VALUE_ZZCC_B6} + , {PAPER_STATEMENT, OPTION_VALUE_ZZCC_PPYSCC} + , {PAPER_MAXSIZE, OPTION_VALUE_ZZCC_ZDSMCC} + , {PAPER_MAXSIZE_CROP, OPTION_VALUE_ZZCC_ZDSMCCZDCQ} + , {PAPER_DOUBLE_LETTER, OPTION_VALUE_ZZCC_DoubleLetter} + , {PAPER_TRIPPLE, OPTION_VALUE_ZZCC_SLSJ} + } + ; +#define VALUE_FROM_TWAIN(arr, val) \ + for (int i = 0; i < _countof(arr); ++i) \ + { \ + if (arr[i].twain_id == val) \ + return arr[i].opt_val; \ + } +#define VALUE_TO_TWAIN(arr, val) \ + for (int i = 0; i < _countof(arr); ++i) \ + { \ + if (strcmp(arr[i].opt_val, val) == 0) \ + return arr[i].twain_id; \ + } + + const char* color_mode_from_twain(int val) + { + VALUE_FROM_TWAIN(g_color_mode_map, val); + + return OPTION_VALUE_YSMS_YSZDSB; + } + int color_mode_to_twain(const char* val) + { + VALUE_TO_TWAIN(g_color_mode_map, val); + + return COLOR_AUTO_MATCH; + } + + const char* multiout_value_from_twain(int val) + { + VALUE_FROM_TWAIN(g_multiout_map, val); + + return NULL; + } + int multiout_value_to_twain(const char* val) + { + VALUE_TO_TWAIN(g_multiout_map, val); + + return -1; + } + + const char* filter_enhance_value_from_twain(int val, bool filter) + { + if (filter) + { + for (int i = 0; i < _countof(g_filter_map); ++i) + { + if (g_filter_map[i].twain_id == val) + return g_filter_map[i].opt_val; + } + } + else + { + for (int i = 0; i < _countof(g_enhance_map); ++i) + { + if (g_enhance_map[i].twain_id == val) + return g_enhance_map[i].opt_val; + } + } + + return OPTION_VALUE_HDHHBTX_CS_BCS; + } + int filter_enhance_value_to_twain(const char* val, bool* is_filter) + { + bool type = false; + + if (!is_filter) + is_filter = &type; + + *is_filter = true; + for (int i = 0; i < _countof(g_filter_map); ++i) + { + if (strcmp(g_filter_map[i].opt_val, val) == 0) + return g_filter_map[i].twain_id; + } + *is_filter = false; + for (int i = 0; i < _countof(g_enhance_map); ++i) + { + if (strcmp(g_enhance_map[i].opt_val, val) == 0) + return g_enhance_map[i].twain_id; + } + + return ENHANCE_NONE; + } + + const char* text_direction_from_twain(float val) + { + while (val < .0f) + val += 360.0f; + while (val > 360.0f) + val -= 360.0f; + + if (60.0f < val && val < 120.0f) + return OPTION_VALUE_WGFX_90; + else if (150.0f < val && val < 210.0f) + return OPTION_VALUE_WGFX_180; + else if (240.0f < val && val < 300.0f) + return OPTION_VALUE_WGFX__90; + else if (330.0f < val || val < 30.0f) + return OPTION_VALUE_WGFX_0; + else + return OPTION_VALUE_WGFX_ZDWBFXSB; + } + float text_direction_to_twain(const char* val) + { + if (strcmp(val, OPTION_VALUE_WGFX_90) == 0) + return 90.0f; + else if (strcmp(val, OPTION_VALUE_WGFX_180) == 0) + return 180.0f; + else if (strcmp(val, OPTION_VALUE_WGFX__90) == 0) + return 270.0f; + else if (strcmp(val, OPTION_VALUE_WGFX_0) == 0) + return .0f; + else + return AUTO_MATIC_ROTATE; + } + + struct + { + const char* normal; + const char* lateral; + }g_lateral_map[] = + { {OPTION_VALUE_ZZCC_A4, OPTION_VALUE_ZZCC_A4HX} + , {OPTION_VALUE_ZZCC_16K, OPTION_VALUE_ZZCC_16KHX} + , {OPTION_VALUE_ZZCC_A5, OPTION_VALUE_ZZCC_A5HX} + , {OPTION_VALUE_ZZCC_A6, OPTION_VALUE_ZZCC_A6HX} + , {OPTION_VALUE_ZZCC_B5, OPTION_VALUE_ZZCC_B5HX} + , {OPTION_VALUE_ZZCC_B6, OPTION_VALUE_ZZCC_B6HX} + , {OPTION_VALUE_ZZCC_Letter, OPTION_VALUE_ZZCC_LetterHX} + }; + + const char* paper_from_twain(int val) + { + VALUE_FROM_TWAIN(g_paper_map, val); + + return NULL; + } + int paper_to_twain(const char* val) + { + VALUE_TO_TWAIN(g_paper_map, val); + + return -1; + } + const char* switch_paper_lateral(const char* val) + { + for (int i = 0; i < _countof(g_lateral_map); ++i) + { + if (strcmp(g_lateral_map[i].normal, val) == 0) + return g_lateral_map[i].lateral; + else if (strcmp(g_lateral_map[i].lateral, val) == 0) + return g_lateral_map[i].normal; + } + + return NULL; + } + bool is_paper_lateral(const char* val) + { + for (int i = 0; i < _countof(g_lateral_map); ++i) + { + if (strcmp(g_lateral_map[i].lateral, val) == 0) + return true; + } + + return false; + } + + const char* auto_color_type_from_twain(int val) + { + VALUE_FROM_TWAIN(g_auto_color_map, val); + + return OPTION_VALUE_YSMS_24WCS; + } + int auto_color_type_to_twain(const char* val) + { + VALUE_TO_TWAIN(g_auto_color_map, val); + + return -1; + } + + const char* sharpen_from_twain(int val) + { + VALUE_FROM_TWAIN(g_sharpen_map, val); + + return OPTION_VALUE_RHYMH_W; + } + int sharpen_to_twain(const char* val) + { + VALUE_TO_TWAIN(g_sharpen_map, val); + + return SHARPEN_NONE; + } + + struct { + int twain; + int sane; + } + g_compression_map[] = { {0, SANE_COMPRESSION_NONE} + , {5, SANE_COMPRESSION_GROUP4} + } + ; +#define INT_FROM_TWAIN(arr, val) \ + for (int i = 0; i < _countof(arr); ++i) \ + { \ + if (arr[i].twain == val) \ + return arr[i].sane; \ + } +#define INT_TO_TWAIN(arr, val) \ + for (int i = 0; i < _countof(arr); ++i) \ + { \ + if (arr[i].sane == val) \ + return arr[i].twain; \ + } + + int compression_from_twain(int val) + { + INT_FROM_TWAIN(g_compression_map, val); + + return SANE_COMPRESSION_NONE; + } + int compression_to_twain(int val) + { + INT_TO_TWAIN(g_compression_map, val); + + return 0; + } + std::vector support_image_types(void) + { + std::vector it; + + it.push_back(SANE_IMAGE_TYPE_BMP); + it.push_back(SANE_IMAGE_TYPE_TIFF); + it.push_back(SANE_IMAGE_TYPE_JFIF); + + return it; + } +} + diff --git a/sane/sane_option_trans.h b/sane/sane_option_trans.h new file mode 100644 index 0000000..72dbac2 --- /dev/null +++ b/sane/sane_option_trans.h @@ -0,0 +1,41 @@ +// utilities for transfroming options between TWAIN and sane ... +// +// Date: 2022-04-14 +// + +#pragma once + +#include "s2t_api.h" + +namespace sane_opt_trans +{ + const char* color_mode_from_twain(int val); + int color_mode_to_twain(const char* val); + + const char* multiout_value_from_twain(int val); + int multiout_value_to_twain(const char* val); + + const char* filter_enhance_value_from_twain(int val, bool filter); + int filter_enhance_value_to_twain(const char* val, bool* is_filter); + + const char* text_direction_from_twain(float val); + float text_direction_to_twain(const char* val); + + const char* paper_from_twain(int val); + int paper_to_twain(const char* val); + + const char* switch_paper_lateral(const char* val); + bool is_paper_lateral(const char* val); + + const char* auto_color_type_from_twain(int val); + int auto_color_type_to_twain(const char* val); + + const char* sharpen_from_twain(int val); + int sharpen_to_twain(const char* val); + + int compression_from_twain(int val); + int compression_to_twain(int val); + + std::vector support_image_types(void); +} + diff --git a/sane/scanned_img.cpp b/sane/scanned_img.cpp new file mode 100644 index 0000000..bdf2f17 --- /dev/null +++ b/sane/scanned_img.cpp @@ -0,0 +1,143 @@ +#include "scanned_img.h" + +#include + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class refer +refer::refer() : ref_(1) +{} +refer::~refer() +{} + +COM_API_IMPLEMENT(refer, long, add_ref(void)) +{ + return InterlockedIncrement(&ref_); +} +COM_API_IMPLEMENT(refer, long, release(void)) +{ + long ref = InterlockedDecrement(&ref_); + + if (ref == 0) + delete this; + + return ref; +} + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class scanned_img +scanned_img::scanned_img(SANE_Parameters head, unsigned char* data) : head_(head) +{ + size_t bytes = line_bytes() * height(); + std::string h(file_header(SANE_IMAGE_TYPE_BMP, 200.0f)); + unsigned char* src = data + head.bytes_per_line * head.lines - head.bytes_per_line, + * dst = NULL; + + bytes_ = bytes + h.length(); + data_ = new unsigned char[bytes_]; + memcpy(data_, h.c_str(), h.length()); + dst = data_ + h.length(); + + if (head.format == SANE_FRAME_RGB) + { + for (int i = 0; i < height(); ++i) + { + for (int j = 0; j < head.pixels_per_line; ++j) + { + dst[j * 3 + 0] = src[j * 3 + 2]; + dst[j * 3 + 1] = src[j * 3 + 1]; + dst[j * 3 + 2] = src[j * 3 + 0]; + } + src -= head.bytes_per_line; + dst += line_bytes(); + } + } + else + { + for (int i = 0; i < height(); ++i, dst += line_bytes(), src -= head.bytes_per_line) + memcpy(dst, src, head.bytes_per_line); + } +} +scanned_img::~scanned_img() +{ + if (data_) + delete[] data_; +} + +std::string scanned_img::file_header(SANE_ImageType type, float resolution) +{ + std::string h(""); + + if (type == SANE_IMAGE_TYPE_BMP) + { + BITMAPINFOHEADER bih = { 0 }; + + bih.biSize = sizeof(bih); + bih.biWidth = width(); + bih.biBitCount = depth(); + bih.biSizeImage = line_bytes() * height(); + bih.biPlanes = 1; + bih.biHeight = height(); + bih.biCompression = BI_RGB; + bih.biXPelsPerMeter = bih.biYPelsPerMeter = resolution * 39.37f + .5f; + + h = std::string((char*)&bih, sizeof(bih)); + } + + return h; +} + +// IRef +COM_API_IMPLEMENT(scanned_img, long, add_ref(void)) +{ + return refer::add_ref(); +} +COM_API_IMPLEMENT(scanned_img, long, release(void)) +{ + return refer::release(); +} + +// IScanImg +COM_API_IMPLEMENT(scanned_img, int, width(void)) +{ + return head_.pixels_per_line; +} +COM_API_IMPLEMENT(scanned_img, int, line_bytes(void)) +{ + return (head_.bytes_per_line + 3) / 4 * 4; +} +COM_API_IMPLEMENT(scanned_img, int, height(void)) +{ + return head_.lines; +} +COM_API_IMPLEMENT(scanned_img, int, depth(void)) +{ + if (head_.format == SANE_FRAME_RGB) + return head_.depth * 3; + else + return head_.depth; + +} +COM_API_IMPLEMENT(scanned_img, int, channel(void)) +{ + return head_.format == SANE_FRAME_RGB ? 3 : 1; +} +COM_API_IMPLEMENT(scanned_img, SANE_Frame, type(void)) +{ + return head_.format; +} +COM_API_IMPLEMENT(scanned_img, unsigned int, bytes(void)) +{ + return bytes_; +} +COM_API_IMPLEMENT(scanned_img, unsigned char*, bits(void)) +{ + return data_; +} +COM_API_IMPLEMENT(scanned_img, void, copy_header(SANE_Parameters* head)) +{ + *head = head_; +} diff --git a/sane/scanned_img.h b/sane/scanned_img.h new file mode 100644 index 0000000..af45c83 --- /dev/null +++ b/sane/scanned_img.h @@ -0,0 +1,51 @@ +#pragma once +#include "s2t_api.h" + + +class refer : public IRef +{ + volatile long ref_; + +protected: + refer(); + virtual ~refer(); + + // IRef +public: + COM_API_OVERRIDE(long, add_ref(void)); + COM_API_OVERRIDE(long, release(void)); +}; + +class scanned_img : public IScanImg, virtual public refer +{ + SANE_Parameters head_; + unsigned char* data_; + unsigned int bytes_; + + std::string file_header(SANE_ImageType type, float resolution); + +public: + scanned_img(SANE_Parameters head, unsigned char* data); + + +protected: + ~scanned_img(); + + // IRef +public: + COM_API_OVERRIDE(long, add_ref(void)); + COM_API_OVERRIDE(long, release(void)); + + // IScanImg +public: + COM_API_OVERRIDE(int, width(void)); + COM_API_OVERRIDE(int, line_bytes(void)); + COM_API_OVERRIDE(int, height(void)); + COM_API_OVERRIDE(int, depth(void)); + COM_API_OVERRIDE(int, channel(void)); + COM_API_OVERRIDE(SANE_Frame, type(void)); + COM_API_OVERRIDE(unsigned int, bytes(void)); + COM_API_OVERRIDE(unsigned char*, bits(void)); + COM_API_OVERRIDE(void, copy_header(SANE_Parameters* head)); +}; + diff --git a/sane/scanner.cpp b/sane/scanner.cpp new file mode 100644 index 0000000..13fe82d --- /dev/null +++ b/sane/scanner.cpp @@ -0,0 +1,1767 @@ +#include "scanner.h" + +#include +#include "../sdk/hginclude/huagaoxxx_warraper_ex.h" +#include +#include "../../code_device/hgsane/sane_hg_mdw.h" +#include "sane_option_trans.h" +#include + + +static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt); + +#define SET_SANE_OPT_ID(id, id_name, title, val, extension) \ + if(compare_sane_opt(OPTION_TITLE_##title, val)) \ + { \ + id_name##_id_ = id; \ + extension(id); \ + } + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class scanner +scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START) +{ + err_ = open(); +} +scanner::~scanner() +{} + +std::string scanner::get_scanner_name(SCANNERID id) +{ + ScannerInfo* devs = NULL; + long count = 0; + std::string name(""); + + if (hg_scanner_enum(devs, &count, true) == SCANNER_ERR_INSUFFICIENT_MEMORY) + { + count++; + devs = new ScannerInfo[count]; + if (hg_scanner_enum(devs, &count, true) == SCANNER_ERR_OK) + { + for (int i = 0; i < count; ++i) + { + if (devs[i].vid == GET_SCANNER_VID(id) && + devs[i].pid == GET_SCANNER_PID(id)) + { + name = devs[i].name; + break; + } + } + } + delete[] devs; + } + + return name; +} +value_type scanner::from_sane_type(SANE_Value_Type type) +{ + if (type == SANE_TYPE_BOOL) + return VAL_TYPE_BOOL; + else if (type == SANE_TYPE_INT) + return VAL_TYPE_INT; + else if (type == SANE_TYPE_FIXED) + return VAL_TYPE_FLOAT; + else if (type == SANE_TYPE_STRING) + return VAL_TYPE_STR; + else + return VAL_TYPE_NONE; +} +value_limit scanner::from_sane_constraint(SANE_Constraint_Type type) +{ + if (type == SANE_CONSTRAINT_RANGE) + return VAL_LIMIT_RANGE; + else if (type == SANE_CONSTRAINT_STRING_LIST || type == SANE_CONSTRAINT_WORD_LIST) + return VAL_LIMIT_ENUM; + else + return VAL_LIMIT_NONE; +} + +int __stdcall scanner::to_int(SANE_Int v) +{ + return v; +} +float __stdcall scanner::to_float(SANE_Fixed v) +{ + return SANE_UNFIX(v); +} + +// IRef +COM_API_IMPLEMENT(scanner, long, add_ref(void)) +{ + return refer::add_ref(); +} +COM_API_IMPLEMENT(scanner, long, release(void)) +{ + return refer::release(); +} + +int scanner::open(void) +{ + int ret = close(); + std::string name(scanner::get_scanner_name(id_)); + + if (name.empty()) + return SCANNER_ERR_DEVICE_NOT_FOUND; + + ret = hg_sane_middleware::instance()->open_device(name.c_str(), &handle_); + if (ret == SANE_STATUS_GOOD) + { + ret = init_options_id(); + } + + return ret; +} +int scanner::close(void) +{ + if (handle_) + hg_sane_middleware::instance()->close_device(handle_); + handle_ = NULL; + ex_id_ = EXTENSION_ID_BASE; + + return SCANNER_ERR_OK; +} +int scanner::init_options_id(void) +{ + SANE_Int op_id = 1; + const SANE_Option_Descriptor* desc = NULL; + int ret = SCANNER_ERR_OK; + +#define SET_OPT_ID(var, predef, func) \ + SET_SANE_OPT_ID(op_id, var, predef, desc->title, func) + + while ((desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, op_id))) + { + SET_OPT_ID(is_multiout, DLSC, extension_none) + else SET_OPT_ID(multiout_type, DLSCLX, extension_multiout_type) + else SET_OPT_ID(color_mode, YSMS, extension_color_mode) + else SET_OPT_ID(erase_color, HDHHBTX_CS, extension_erase_color) + else SET_OPT_ID(erase_multiout_red, 24WCSTX_DLSCCH, extension_none) + else SET_OPT_ID(erase_paper_red, 24WCSTX_DTKCH, extension_none) + else SET_OPT_ID(is_erase_background, BJYC, extension_none) + else SET_OPT_ID(background_color_range, BJSCFDFW, extension_none) + else SET_OPT_ID(sharpen, RHYMH, extension_sharpen) + else SET_OPT_ID(erase_morr, QCMW, extension_none) + else SET_OPT_ID(erase_grids, CWW, extension_none) + else SET_OPT_ID(error_extend, CWKS, extension_none) + else SET_OPT_ID(is_noise_modify, HBTXZDYH, extension_none) + else SET_OPT_ID(noise_threshold, ZDYHCC, extension_none) + else SET_OPT_ID(paper, ZZCC, extension_paper) + else SET_OPT_ID(is_custom_area, ZDYSMQY, extension_none) + else SET_OPT_ID(curstom_area_l, SMQYZCmm, extension_none) + else SET_OPT_ID(curstom_area_r, SMQYYCmm, extension_none) + else SET_OPT_ID(curstom_area_t, SMQYSCmm, extension_none) + else SET_OPT_ID(curstom_area_b, SMQYXCmm, extension_none) + else SET_OPT_ID(is_size_check, CCJC, extension_none) + else SET_OPT_ID(page, SMYM, extension_page) + else SET_OPT_ID(blank_page_threshold, TGKBYLMD, extension_none) + else SET_OPT_ID(resolution, FBL, extension_none) + else SET_OPT_ID(image_quality, HZ, extension_none) + else SET_OPT_ID(is_swap, JHZFM, extension_none) + else SET_OPT_ID(is_split, TXCF, extension_none) + else SET_OPT_ID(is_auto_deskew, ZDJP, extension_none) + else SET_OPT_ID(is_custom_gamma, QYSDQX, extension_none) + else SET_OPT_ID(bright, LDZ, extension_none) + else SET_OPT_ID(contrast, DBD, extension_none) + else SET_OPT_ID(gamma, JMZ, extension_none) + else SET_OPT_ID(is_erase_black_frame, XCHK, extension_none) + else SET_OPT_ID(deep_sample, SSYZ, extension_none) + else SET_OPT_ID(threshold, YZ, extension_none) + else SET_OPT_ID(anti_noise, BJKZDJ, extension_none) + else SET_OPT_ID(margin, BYSJ, extension_none) + else SET_OPT_ID(fill_background, BJTCFS, extension_fill_bkg_method) + else SET_OPT_ID(is_anti_permeate, FZST, extension_none) + else SET_OPT_ID(anti_permeate_level, FZSTDJ, extension_none) + else SET_OPT_ID(is_erase_hole, CKYC, extension_none) + else SET_OPT_ID(search_hole_range, CKSSFWZFMBL, extension_none) + else SET_OPT_ID(is_filling_color, SCTC, extension_none) + else SET_OPT_ID(is_ultrasonic_check, CSBJC, extension_none) + else SET_OPT_ID(is_check_staple, ZDJC, extension_none) + else SET_OPT_ID(scan_mode, SMZS, extension_none) + else SET_OPT_ID(scan_count, SMSL, extension_none) + else SET_OPT_ID(text_direction, WGFX, extension_text_direction) + else SET_OPT_ID(is_rotate_bkg180, BMXZ180, extension_none) + else SET_OPT_ID(is_check_dogear, ZJJC, extension_none) + else SET_OPT_ID(dogear_size, ZJDX, extension_none) + else SET_OPT_ID(is_check_skew, WXJC, extension_none) + else SET_OPT_ID(skew_range, WXRRD, extension_none) + op_id++; + } + +#define EX_APPENDIX_API(name) \ + { \ + EXAPI ea; \ + ea.ind = ex_##name##_id_ = ex_id_++; \ + ea.ex_api = &scanner::handle_ex_##name; \ + ex_opts_.push_back(ea); \ + } + EX_APPENDIX_API(final_compression); + EX_APPENDIX_API(final_format); + EX_APPENDIX_API(serial); + EX_APPENDIX_API(to_be_scan); + EX_APPENDIX_API(scan_with_hole); + EX_APPENDIX_API(device_code); + EX_APPENDIX_API(power); + EX_APPENDIX_API(hardware_version); + EX_APPENDIX_API(ip); + + return ret; +} +int scanner::control_read_string(int code, std::string& ret) +{ + char* buf = NULL; + unsigned len = 0; + int err = hg_sane_middleware::instance()->io_control(handle_, code, buf, &len); + + ret = ""; + if (err == SANE_STATUS_NO_MEM) + { + len += 4; + buf = new char[len]; + memset(buf, 0, len); + err = hg_sane_middleware::instance()->io_control(handle_, code, buf, &len); + if (err == SANE_STATUS_GOOD) + ret = buf; + delete[] buf; + } + + return err; +} + +void scanner::extension_none(int id) +{ +} +void scanner::extension_multiout_type(int id) +{ + EXAPI ea; + + ex_multiout_type_id_ = ex_id_++; + ea.ind = ex_multiout_type_id_; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_multiout; + + ex_opts_.push_back(ea); +} +void scanner::extension_color_mode(int id) +{ + EXAPI ea; + + ea.ind = ex_color_mode_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_color_mode; + ex_opts_.push_back(ea); + + ex_auto_color_type_id_ = ex_id_++; + ea.base_ind = id; + ea.ind = ex_auto_color_type_id_; + ea.ex_api = &scanner::handle_ex_auto_color_type; + ex_opts_.push_back(ea); +} +void scanner::extension_sharpen(int id) +{ + EXAPI ea; + + ex_sharpen_id_ = ex_id_++; + ea.base_ind = id; + ea.ind = ex_sharpen_id_; + ea.ex_api = &scanner::handle_ex_sharpen; + + ex_opts_.push_back(ea); +} +void scanner::extension_paper(int id) +{ + EXAPI ea; + + ea.ind = ex_paper_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_paper; + ex_opts_.push_back(ea); + + ea.ind = ex_paper_lateral_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_paper_lateral; + ex_opts_.push_back(ea); + + ea.ind = ex_auto_paper_size_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_auto_paper_size; + ex_opts_.push_back(ea); + + ea.ind = ex_is_paper_auto_crop_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_auto_paper_crop; + ex_opts_.push_back(ea); +} +void scanner::extension_fill_bkg_method(int id) +{ + EXAPI ea; + + ea.ind = ex_fill_background_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_fill_background; + ex_opts_.push_back(ea); +} +void scanner::extension_text_direction(int id) +{ + EXAPI ea; + + ea.ind = ex_text_direction_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_text_direction; + ex_opts_.push_back(ea); +} +void scanner::extension_page(int id) +{ + EXAPI ea; + + ea.ind = ex_duplex_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_duplex; + ex_opts_.push_back(ea); + + ea.ind = ex_discard_blank_page_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_discard_blank_page; + ex_opts_.push_back(ea); + + ea.ind = ex_discard_blank_receipt_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_discard_blank_receipt; + ex_opts_.push_back(ea); + + ea.ind = ex_is_page_fold_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_page_fold; + ex_opts_.push_back(ea); +} +void scanner::extension_erase_color(int id) +{ + EXAPI ea; + + ea.ind = ex_color_filter_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_color_filter; + ex_opts_.push_back(ea); + + ea.ind = ex_color_enhance_id_ = ex_id_++; + ea.base_ind = id; + ea.ex_api = &scanner::handle_ex_color_enhance; + ex_opts_.push_back(ea); +} +bool scanner::get_option_value_with_parent(int sn, set_opt_value setv, void* param) // return true if handled +{ + bool handled = true; + + if (sn == scan_count_id_) + { + SANE_Option_Descriptor* parent = hg_sane_middleware::instance()->get_option_descriptor(handle_, scan_mode_id_); + char* buf = new char[parent->size + 4]; + + memset(buf, 0, parent->size); + hg_sane_middleware::instance()->get_cur_value(handle_, scan_mode_id_, buf); + handled = compare_sane_opt(OPTION_VALUE_SMZS_LXSM, buf); + delete[] buf; + if (handled) + { + int count = -1; + value_role role = VAL_ROLE_CURRENT; + buf = (char*)hg_sane_middleware::instance()->get_def_value(handle_, scan_mode_id_); + if (compare_sane_opt(OPTION_VALUE_SMZS_LXSM, buf)) + role = value_role(role | VAL_ROLE_DEFAULT); + local_utility::free_memory(buf); + + setv(&count, value_role(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT), param); + } + } + else + handled = false; + + return handled; +} +bool scanner::set_option_value_with_parent(int sn, void* data, int* err) // return true if handled +{ + bool handled = true; + + if (sn == scan_count_id_) + { + SANE_Option_Descriptor* parent = hg_sane_middleware::instance()->get_option_descriptor(handle_, scan_mode_id_); + char* val = new char[parent->size + 4]; + SANE_Int after = 0; + + memset(val, 0, parent->size + 4); + hg_sane_middleware::instance()->get_cur_value(handle_, scan_mode_id_, val); + if (compare_sane_opt(OPTION_VALUE_SMZS_LXSM, val)) + { + if (*(int*)data != -1) + { + strcpy(val, OPTION_VALUE_SMZS_SMZDZS); + *err = hg_sane_middleware::instance()->set_option(handle_, scan_mode_id_, SANE_ACTION_SET_VALUE, val, &after); + } + } + else if (*(int*)data == -1) + { + strcpy(val, OPTION_VALUE_SMZS_LXSM); + *err = hg_sane_middleware::instance()->set_option(handle_, scan_mode_id_, SANE_ACTION_SET_VALUE, val, &after); + } + handled = false; + } + else + { + handled = false; + } + + return handled; +} +int scanner::set_option_value(int sn, SANE_Value_Type type, int size, void* data) +{ + char* buf = NULL; + SANE_Bool sb = SANE_FALSE; + SANE_Int si = 0, after = 0; + SANE_Fixed sf = 0; + int ret = SCANNER_ERR_OK; + + if (type == SANE_TYPE_BOOL) + { + sb = *(bool*)data ? SANE_TRUE : SANE_FALSE; + data = &sb; + } + else if (type == SANE_TYPE_INT) + { + si = *(int*)data; + data = &si; + } + else if (type == SANE_TYPE_FIXED) + { + sf = SANE_FIX(*(float*)data); + data = &sf; + } + else + { + buf = new char[size + 4]; + memset(buf, 0, size + 4); + strcpy(buf, (char*)data); + data = buf; + } + ret = hg_sane_middleware::instance()->set_option(handle_, sn, SANE_ACTION_SET_VALUE, data, &after); + if (buf) + delete[] buf; + + return ret; +} + +scanner::EXAPIPOS scanner::find_ex_api(int op_id) +{ + return std::find(ex_opts_.begin(), ex_opts_.end(), op_id); +} + +EX_OPTION_HANDLER_IMPL(multiout) +{ + int ret = SCANNER_ERR_OK; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + + if (setv) + { + char* cur = new char[desc->size], + * def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); + int now = 0, // sane_opt_trans::multiout_value_to_twain(cur) + init = sane_opt_trans::multiout_value_to_twain(def), + val = 0; + + local_utility::free_memory(def); + memset(cur, 0, desc->size); + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, cur); + now = sane_opt_trans::multiout_value_to_twain(cur); + delete[] cur; + + { + // parent item ... + SANE_Bool enable = SANE_TRUE; + if (hg_sane_middleware::instance()->get_cur_value(handle_, is_multiout_id_, &enable)) + { + if (!enable) + now = MULTI_OUT_NONE; + } + } + + do + { + if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST) + { + // we have no 'MULTI_OUT_NONE' item in this option, this is used as is_multiout_id_ + val = MULTI_OUT_NONE; + value_role role = val == now ? VAL_ROLE_CURRENT : VAL_ROLE_NONE; + if (!setv(&val, role, data)) + break; + for (int i = 0; desc->constraint.string_list[i]; ++i) + { + value_role role = VAL_ROLE_NONE; + val = sane_opt_trans::multiout_value_to_twain(desc->constraint.string_list[i]); + if (val == now) + role = VAL_ROLE_CURRENT; + if (val == init) + role = value_role(role | VAL_ROLE_DEFAULT); + if (!setv(&val, role, data)) + break; + } + } + else + set_cur_and_def_value(now, init, setv, data); + } while (0); + } + else + { + char* val = new char[desc->size]; + const char* in = sane_opt_trans::multiout_value_from_twain(*(int*)data); + SANE_Int after = 0; + + if (in && strcmp(in, "\346\227\240")) + { + // enable multi-out ... + *((SANE_Bool*)val) = SANE_TRUE; + ret = hg_sane_middleware::instance()->set_option(handle_, is_multiout_id_, SANE_ACTION_SET_VALUE, val, &after); + strcpy(val, in); + } + else + { + // disable multi-out, let multiout type side + base_id = is_multiout_id_; + *((SANE_Bool*)val) = SANE_FALSE; + } + if (ret == SANE_STATUS_GOOD) + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, val, &after); + delete[] val; + ret = local_utility::sane_statu_2_scanner_err(ret); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(auto_color_type) +{ + int ret = SCANNER_ERR_OK; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + int len = desc->size + 4; + char* buf = new char[len]; + + memset(buf, 0, len); + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + if (setv) + { + len = sane_opt_trans::auto_color_type_to_twain(buf); + setv(&len, VAL_ROLE_CURRENT, data); + } + else + { + SANE_Int after = 0; + + strcpy(buf, sane_opt_trans::auto_color_type_from_twain(*(int*)data)); + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(color_mode) +{ + int ret = SCANNER_ERR_OK; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + + if (setv) + { + char* cur = new char[desc->size], + * def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); + int now = 0, // sane_opt_trans::multiout_value_to_twain(cur) + init = sane_opt_trans::color_mode_to_twain(def), + val = 0; + + local_utility::free_memory(def); + memset(cur, 0, desc->size); + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, cur); + now = sane_opt_trans::color_mode_to_twain(cur); + delete[] cur; + + do + { + if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST) + { + for (int i = 0; desc->constraint.string_list[i]; ++i) + { + value_role role = VAL_ROLE_NONE; + val = sane_opt_trans::color_mode_to_twain(desc->constraint.string_list[i]); + if (val == now) + role = VAL_ROLE_CURRENT; + if (val == init) + role = value_role(role | VAL_ROLE_DEFAULT); + if (!setv(&val, role, data)) + break; + } + } + else + set_cur_and_def_value(now, init, setv, data); + } while (0); + } + else + { + char* val = new char[desc->size]; + const char* in = sane_opt_trans::color_mode_from_twain(*(int*)data); + SANE_Int after = 0; + + strcpy(val, in); + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, val, &after); + delete[] val; + ret = local_utility::sane_statu_2_scanner_err(ret); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(sharpen) +{ + int ret = SCANNER_ERR_OK; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + + if (setv) + { + char* cur = new char[desc->size], + * def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); + int now = 0, // sane_opt_trans::multiout_value_to_twain(cur) + init = sane_opt_trans::sharpen_to_twain(def), + val = 0; + + local_utility::free_memory(def); + memset(cur, 0, desc->size); + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, cur); + now = sane_opt_trans::sharpen_to_twain(cur); + delete[] cur; + + do + { + if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST) + { + for (int i = 0; desc->constraint.string_list[i]; ++i) + { + value_role role = VAL_ROLE_NONE; + val = sane_opt_trans::sharpen_to_twain(desc->constraint.string_list[i]); + if (val == now) + role = VAL_ROLE_CURRENT; + if (val == init) + role = value_role(role | VAL_ROLE_DEFAULT); + if (!setv(&val, role, data)) + break; + } + } + else + set_cur_and_def_value(now, init, setv, data); + } while (0); + } + else + { + char* val = new char[desc->size]; + const char* in = sane_opt_trans::sharpen_from_twain(*(int*)data); + SANE_Int after = 0; + + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, val, &after); + delete[] val; + ret = local_utility::sane_statu_2_scanner_err(ret); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(paper) +{ + int ret = SCANNER_ERR_OK; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + int len = desc->size + 4; + char* buf = new char[len]; + + memset(buf, 0, len); + if (setv) + { + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + char* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); + int now = sane_opt_trans::paper_to_twain(buf), + init = sane_opt_trans::paper_to_twain(def), + val = 0; + do + { + if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST) + { + for (int i = 0; desc->constraint.string_list[i]; ++i) + { + value_role role = VAL_ROLE_NONE; + val = sane_opt_trans::paper_to_twain(desc->constraint.string_list[i]); + if (val == -1) + continue; + if (val == now) + role = VAL_ROLE_CURRENT; + if (val == init) + role = value_role(role | VAL_ROLE_DEFAULT); + if (!setv(&val, role, data)) + break; + } + } + else + set_cur_and_def_value(now, init, setv, data); + } while (0); + } + else if (sane_opt_trans::paper_from_twain(*(int*)data)) + { + SANE_Int after = 0; + strcpy(buf, sane_opt_trans::paper_from_twain(*(int*)data)); + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + } + else + ret = SCANNER_ERR_INVALID_PARAMETER; + + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(paper_lateral) +{ + int ret = SCANNER_ERR_OK; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + int len = desc->size + 4; + char* buf = new char[len]; + const char* lateral_swap = NULL; + bool lateral = false; + + memset(buf, 0, len); + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + lateral_swap = sane_opt_trans::switch_paper_lateral(buf); + lateral = sane_opt_trans::is_paper_lateral(buf); + if (setv) + { + setv(&lateral, VAL_ROLE_CURRENT, data); + } + else if (lateral_swap) + { + SANE_Int after = 0; + if (lateral != *(bool*)data) + { + strcpy(buf, lateral_swap); + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + } + else + ret = SCANNER_ERR_DEVICE_NOT_SUPPORT; + + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(auto_paper_size) +{ + int ret = SCANNER_ERR_OK; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + int len = desc->size + 4; + char* buf = new char[len]; + + memset(buf, 0, len); + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + if (setv) + { + bool yes = strcmp(buf, OPTION_VALUE_ZZCC_PPYSCC) == 0; + setv(&yes, VAL_ROLE_CURRENT, data); + } + else + { + SANE_Int after = 0; + strcpy(buf, *(bool*)data ? OPTION_VALUE_ZZCC_PPYSCC : OPTION_VALUE_ZZCC_A4); + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(auto_paper_crop) +{ + int ret = SCANNER_ERR_OK; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + int len = desc->size + 4; + char* buf = new char[len]; + + memset(buf, 0, len); + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + if (setv) + { + bool yes = strcmp(buf, OPTION_VALUE_ZZCC_ZDSMCCZDCQ) == 0; + setv(&yes, VAL_ROLE_CURRENT, data); + } + else + { + SANE_Int after = 0; + strcpy(buf, *(bool*)data ? OPTION_VALUE_ZZCC_ZDSMCCZDCQ : OPTION_VALUE_ZZCC_ZDSMCC); + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(text_direction) +{ + int ret = SCANNER_ERR_OK; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + int len = desc->size + 4; + char* buf = new char[len]; + + memset(buf, 0, len); + if (setv) + { + char* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); + float now = .0f, init = sane_opt_trans::text_direction_to_twain(def), val = .0f; + + local_utility::free_memory(def); + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + now = sane_opt_trans::text_direction_to_twain(buf); + do + { + if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST) + { + for (int i = 0; desc->constraint.string_list[i]; ++i) + { + value_role role = VAL_ROLE_NONE; + val = sane_opt_trans::text_direction_to_twain(desc->constraint.string_list[i]); + if (IS_DOUBLE_EQUAL(val, now)) + role = VAL_ROLE_CURRENT; + if (IS_DOUBLE_EQUAL(val, init)) + role = value_role(role | VAL_ROLE_DEFAULT); + if (!setv(&val, role, data)) + break; + } + } + else + set_cur_and_def_value(now, init, setv, data); + } while (0); + } + else + { + SANE_Int after = 0; + + strcpy(buf, sane_opt_trans::text_direction_from_twain(*(float*)data)); + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(duplex) +{ + int ret = SCANNER_ERR_OK; + bool val = *(bool*)data; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + unsigned len = desc->size + 4; + char* buf = new char[len]; + + memset(buf, 0, len); + if (setv) + { + void* init = hg_sane_middleware::instance()->get_def_value(handle_, base_id); + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + val = strcmp(buf, OPTION_VALUE_SMYM_SM) == 0; + if (val && strcmp((char*)init, OPTION_VALUE_SMYM_SM) == 0 || + !val && strcmp((char*)init, OPTION_VALUE_SMYM_DM) == 0) + setv(&val, value_role(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT), data); + else if (setv(&val, VAL_ROLE_CURRENT, data)) + { + if (strcmp((char*)init, OPTION_VALUE_SMYM_SM) == 0) + { + val = true; + setv(&val, VAL_ROLE_DEFAULT, data); + } + if (strcmp((char*)init, OPTION_VALUE_SMYM_DM) == 0) + { + val = false; + setv(&val, VAL_ROLE_DEFAULT, data); + } + } + } + else + { + strcpy(buf, val ? OPTION_VALUE_SMYM_SM : OPTION_VALUE_SMYM_DM); + SANE_Int after = 0; + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(fill_background) +{ + int ret = SCANNER_ERR_OK; + bool val = *(bool*)data; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + unsigned len = desc->size + 4; + char* buf = new char[len]; + + memset(buf, 0, len); + if (setv) + { + char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + val = strcmp(buf, OPTION_VALUE_SMYM_SM) == 0; + set_cur_and_def_value(strcmp(buf, OPTION_VALUE_BJTCFS_TDBX) == 0, strcmp(init, OPTION_VALUE_BJTCFS_TDBX) == 0, setv, data); + local_utility::free_memory(init); + } + else + { + strcpy(buf, val ? OPTION_VALUE_BJTCFS_TDBX : OPTION_VALUE_BJTCFS_ADBX); + SANE_Int after = 0; + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(discard_blank_page) +{ + int ret = SCANNER_ERR_OK; + bool val = *(bool*)data; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + unsigned len = desc->size + 4; + char* buf = new char[len]; + + memset(buf, 0, len); + if (setv) + { + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + val = strcmp(buf, OPTION_VALUE_SMYM_TGKBYTY) == 0; + setv(&val, VAL_ROLE_CURRENT, data); + } + else + { + if (val) + strcpy(buf, OPTION_VALUE_SMYM_TGKBYTY); + else + { + char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); + strcpy(buf, init); + local_utility::free_memory(init); + } + SANE_Int after = 0; + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(discard_blank_receipt) +{ + int ret = SCANNER_ERR_OK; + bool val = *(bool*)data; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + unsigned len = desc->size + 4; + char* buf = new char[len]; + + memset(buf, 0, len); + if (setv) + { + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + val = strcmp(buf, OPTION_VALUE_SMYM_TGKBYFPZ) == 0; + setv(&val, VAL_ROLE_CURRENT, data); + } + else + { + if (val) + strcpy(buf, OPTION_VALUE_SMYM_TGKBYFPZ); + else + { + char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); + strcpy(buf, init); + local_utility::free_memory(init); + } + SANE_Int after = 0; + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(page_fold) +{ + int ret = SCANNER_ERR_OK; + bool val = *(bool*)data; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + unsigned len = desc->size + 4; + char* buf = new char[len]; + + memset(buf, 0, len); + if (setv) + { + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + val = strcmp(buf, OPTION_VALUE_SMYM_DZ) == 0; + setv(&val, VAL_ROLE_CURRENT, data); + } + else + { + if (val) + strcpy(buf, OPTION_VALUE_SMYM_DZ); + else + { + char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); + strcpy(buf, init); + local_utility::free_memory(init); + } + SANE_Int after = 0; + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + + return ret; +} +EX_OPTION_HANDLER_IMPL(color_filter) // int (filter_value) +{ + int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + char* buf = NULL; + unsigned int len = 0; + + if (desc) + { + len = desc->size + 4; + buf = new char[len]; + memset(buf, 0, len); + if (setv) + { + bool filter = false; + int val = FILTER_NONE, now = FILTER_NONE; + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + now = sane_opt_trans::filter_enhance_value_to_twain(buf, &filter); + if (!filter) + now = val; + do + { + if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST) + { + for (int i = 0; desc->constraint.string_list[i]; ++i) + { + value_role role = VAL_ROLE_NONE; + int v = sane_opt_trans::filter_enhance_value_to_twain(desc->constraint.string_list[i], &filter); + if (!filter && v != FILTER_NONE) + continue; + if (v == now) + role = VAL_ROLE_CURRENT; + if (v == val) + role = value_role(role | VAL_ROLE_DEFAULT); + if (!setv(&v, role, data)) + break; + } + } + }while (0); + } + else + { + const char* val = sane_opt_trans::filter_enhance_value_from_twain(*((int*)data), true); + SANE_Int after = 0; + + strcpy(buf, val); + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(color_enhance) // int (enhance_value) +{ + int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); + char* buf = NULL; + unsigned int len = 0; + + if (desc) + { + len = desc->size + 4; + buf = new char[len]; + memset(buf, 0, len); + if (setv) + { + bool filter = false; + int val = ENHANCE_NONE, now = ENHANCE_NONE; + hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); + now = sane_opt_trans::filter_enhance_value_to_twain(buf, &filter); + if (filter) + now = val; + do + { + if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST) + { + for (int i = 0; desc->constraint.string_list[i]; ++i) + { + value_role role = VAL_ROLE_NONE; + int v = sane_opt_trans::filter_enhance_value_to_twain(desc->constraint.string_list[i], &filter); + if (filter && v != ENHANCE_NONE) + continue; + if (v == now) + role = VAL_ROLE_CURRENT; + if (v == val) + role = value_role(role | VAL_ROLE_DEFAULT); + if (!setv(&v, role, data)) + break; + } + } + } while (0); + } + else + { + const char* val = sane_opt_trans::filter_enhance_value_from_twain(*((int*)data), false); + SANE_Int after = 0; + + strcpy(buf, val); + ret = hg_sane_middleware::instance()->set_option(handle_, base_id, SANE_ACTION_SET_VALUE, buf, &after); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + delete[] buf; + } + + return ret; +} + +EX_OPTION_HANDLER_IMPL(final_compression) +{ + int ret = SCANNER_ERR_OK; + int* compression = (int*)data; + unsigned int len = sizeof(*compression); + + if (setv) + { + int val = 0; + ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_COMPRESSION, &val, &len); + if (ret == SANE_STATUS_GOOD) + { + int i = SANE_COMPRESSION_FIRST; + for (; i < SANE_COMPRESSION_LAST; ++i) + { + value_role role = VAL_ROLE_NONE; + if (i == val) + role = VAL_ROLE_CURRENT; + if (i == SANE_COMPRESSION_NONE) + role = value_role(role | VAL_ROLE_DEFAULT); + int v = sane_opt_trans::compression_to_twain(i); + if (!setv(&v, role, data)) + break; + } + } + } + else + { + int val = sane_opt_trans::compression_from_twain(*(int*)data); + len = sizeof(val); + ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_FINAL_COMPRESSION, &val, &len); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(final_format) +{ + int ret = SCANNER_ERR_OK; + SANE_FinalImgFormat ff; + unsigned int len = sizeof(ff); + + if (setv) + { + ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_IMAGE_FORMAT, &ff, &len); + if (ret == SANE_STATUS_GOOD) + { + int now = ff.img_format, init = SANE_IMAGE_TYPE_BMP; + std::vector all(sane_opt_trans::support_image_types()); + for (int i = 0; i < all.size(); ++i) + { + value_role role = VAL_ROLE_NONE; + ff.img_format = (SANE_ImageType)all[i]; + if (ff.img_format == now) + role = VAL_ROLE_CURRENT; + if (ff.img_format == init) + role = value_role(role | VAL_ROLE_DEFAULT); + if (!setv(&ff, role, data)) + break; + } + } + } + else + { + ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_FINAL_IMAGE_FORMAT, data, &len); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(serial) +{ + int ret = SCANNER_ERR_INVALID_PARAMETER; + if (setv) + { + std::string val(""); + + ret = control_read_string(IO_CTRL_CODE_GET_SERIAL, val); + if (ret == SANE_STATUS_GOOD) + setv(&val, VAL_ROLE_CURRENT, data); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(to_be_scan) +{ + int ret = SCANNER_ERR_OK; + SANE_Bool wait_paper = SANE_FALSE; + unsigned int len = sizeof(wait_paper); + + if (setv) + { + ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_SCAN_WHEN_PAPER_ON, &wait_paper, &len); + if (ret == SANE_STATUS_GOOD) + { + bool val = wait_paper == SANE_TRUE; + setv(&val, VAL_ROLE_CURRENT, data); + } + } + else + { + wait_paper = *((bool*)data) ? SANE_TRUE : SANE_FALSE; + ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_SCAN_WHEN_PAPER_ON, &wait_paper, &len); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(scan_with_hole) +{ + int ret = SCANNER_ERR_OK; + SANE_Bool with_hole = SANE_FALSE; + unsigned int len = sizeof(with_hole); + + if (setv) + { + ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_SCAN_WITH_HOLE, &with_hole, &len); + if (ret == SANE_STATUS_GOOD) + { + bool val = with_hole == SANE_TRUE; + setv(&val, VAL_ROLE_CURRENT, data); + } + } + else + { + with_hole = *((bool*)data) ? SANE_TRUE : SANE_FALSE; + ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_SCAN_WITH_HOLE, &with_hole, &len); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(device_code) +{ + int ret = SCANNER_ERR_INVALID_PARAMETER; + if (setv) + { + std::string val(""); + + ret = control_read_string(IO_CTRL_CODE_GET_DEVICE_CODE, val); + if (ret == SANE_STATUS_GOOD) + setv(&val, VAL_ROLE_CURRENT, data); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(power) +{ + int ret = SCANNER_ERR_OK; + + if (setv) + { + SANE_Power now = SANE_POWER_MINUTES_30, init = SANE_POWER_MINUTES_30; + unsigned int len = sizeof(now); + + hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_POWER_LEVEL, &now, &len); + for (int i = SANE_POWER_FIRST; i < SANE_POWER_LAST; ++i) + { + value_role role = VAL_ROLE_NONE; + if (i == now) + role = VAL_ROLE_CURRENT; + if (i == init) + role = value_role(role | VAL_ROLE_DEFAULT); + + SANE_Power power = (SANE_Power)i; + if (!setv(&power, role, data)) + break; + } + } + else + { + SANE_Power power = *((SANE_Power*)data); + unsigned int len = sizeof(power); + ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_POWER_LEVEL, &power, &len); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(hardware_version) +{ + int ret = SCANNER_ERR_INVALID_PARAMETER; + if (setv) + { + std::string val(""); + + ret = control_read_string(IO_CTRL_CODE_GET_HARDWARE_VERSION, val); + if (ret == SANE_STATUS_GOOD) + setv(&val, VAL_ROLE_CURRENT, data); + } + + return ret; +} +EX_OPTION_HANDLER_IMPL(ip) +{ + int ret = SCANNER_ERR_INVALID_PARAMETER; + if (setv) + { + std::string val(""); + + ret = control_read_string(IO_CTRL_CODE_GET_IP, val); + if (ret == SANE_STATUS_GOOD) + setv(&val, VAL_ROLE_CURRENT, data); + } + + return ret; +} + +// ISaneInvoker +COM_API_IMPLEMENT(scanner, int, start(void)) +{ + int ret = hg_sane_middleware::instance()->start(handle_, NULL); + + // the third-APPs in linux will call 'stop' after every start, but it not happens in windows-apps, so we handle this as following ... + if(ret == SANE_STATUS_NO_DOCS && prev_start_result_ == SANE_STATUS_GOOD) + ret = hg_sane_middleware::instance()->start(handle_, NULL); + + prev_start_result_ = ret; + + return ret; +} +COM_API_IMPLEMENT(scanner, int, stop(void)) +{ + return hg_sane_middleware::instance()->stop(handle_); +} +COM_API_IMPLEMENT(scanner, void, set_event_callback(void(*cb)(int ev_type, void* data, unsigned int* len, void* param), void* param)) +{ +} +COM_API_IMPLEMENT(scanner, bool, wait_image(DWORD milliseconds)) +{ + int count = get_scanned_images(milliseconds); + + return count > 0; +} +COM_API_IMPLEMENT(scanner, int, get_scanned_images(DWORD milliseconds)) +{ + unsigned int count = 0; + + hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_IMAGE_QUEUE_COUNT, NULL, &count); + if (count == 0 && milliseconds) + { + while (count == 0) + { + Sleep(10); + if (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_IMAGE_QUEUE_COUNT, NULL, &count) + != SCANNER_ERR_OK) + break; + if (milliseconds != -1) + { + if (milliseconds <= 10) + break; + + milliseconds -= 10; + } + } + } + + return count; +} +COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(void)) +{ + scanned_img* img = NULL; + SANE_Parameters head; + + if (hg_sane_middleware::instance()->get_image_parameters(handle_, &head) == SANE_STATUS_GOOD) + { + int off = 0, size = head.bytes_per_line * head.lines, rcv = size; + unsigned char* buf = new unsigned char[size]; + + while (hg_sane_middleware::instance()->read(handle_, buf + off, &rcv) == SANE_STATUS_GOOD) + { + off += rcv; + if (off >= size) + break; + rcv = size - off; + } + + img = new scanned_img(head, buf); + delete[] buf; + } + + return dynamic_cast(img); +} +COM_API_IMPLEMENT(scanner, bool, get_first_image_header(SANE_Parameters* header)) +{ + return hg_sane_middleware::instance()->get_image_parameters(handle_, header) == SANE_STATUS_GOOD; +} +COM_API_IMPLEMENT(scanner, bool, is_online(void)) +{ + return !scanner::get_scanner_name(id_).empty(); +} +COM_API_IMPLEMENT(scanner, bool, is_paper_on(void)) +{ + SANE_Bool on = SANE_FALSE; + unsigned int len = sizeof(on); + + if (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_PAPER_ON, &on, &len) == SANE_STATUS_GOOD) + return on == SANE_TRUE; + else + return false; +} +COM_API_IMPLEMENT(scanner, bool, get_option_info(int sn, value_type* type, value_limit* limit, int* bytes)) +{ + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, sn); + bool ret = false; + + if (desc) + { + if (type) + *type = scanner::from_sane_type(desc->type); + if (limit) + *limit = scanner::from_sane_constraint(desc->constraint_type); + if (bytes) + *bytes = desc->size; + + ret = true; + } + + return ret; +} +COM_API_IMPLEMENT(scanner, bool, get_value(int sn, set_opt_value setval, void* param)) +{ + EXAPIPOS ex = find_ex_api(sn); + int ret = SANE_STATUS_INVAL; + SANE_Int after = 0; + + if (ex == ex_opts_.end()) + { + if (get_option_value_with_parent(sn, setval, param)) + return true; + + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, sn); + void* init = hg_sane_middleware::instance()->get_def_value(handle_, sn); + ret = SANE_STATUS_GOOD; + if (desc->type == SANE_TYPE_BOOL) + { + SANE_Bool v = SANE_FALSE; + bool val = false; + + hg_sane_middleware::instance()->get_cur_value(handle_, sn, &v); + val = v == SANE_TRUE; + set_cur_and_def_value(val, *(SANE_Bool*)init == SANE_TRUE, setval, param); + } + else if (desc->type == SANE_TYPE_INT) + { + SANE_Int cur = 0, def = *(SANE_Int*)init; + int val = 0; + + hg_sane_middleware::instance()->get_cur_value(handle_, sn, &cur); + val = cur; + do + { + if (desc->constraint_type == SANE_CONSTRAINT_RANGE) + { + set_value_range(cur, def, desc->constraint.range->min, desc->constraint.range->max, desc->constraint.range->quant, setval, param, scanner::to_int); + } + else if (desc->constraint_type == SANE_CONSTRAINT_WORD_LIST) + { + const SANE_Word* v = desc->constraint.word_list; + for (int i = 0; i < v[0]; ++i) + { + value_role role = VAL_ROLE_NONE; + if (v[i + 1] == cur) + role = value_role(role | VAL_ROLE_CURRENT); + if (v[i + 1] == *(SANE_Int*)init) + role = value_role(role | VAL_ROLE_DEFAULT); + val = v[i + 1]; + if (!setval(&val, role, param)) + break; + } + } + else + set_cur_and_def_value(val, *(SANE_Int*)init, setval, param); + + }while (0); + } + else if (desc->type == SANE_TYPE_FIXED) + { + SANE_Fixed cur = 0, def = *(SANE_Fixed*)init; + float val = .0f; + + hg_sane_middleware::instance()->get_cur_value(handle_, sn, &cur); + do + { + if (desc->constraint_type == SANE_CONSTRAINT_RANGE) + { + set_value_range(cur, def, desc->constraint.range->min, desc->constraint.range->max, desc->constraint.range->quant, setval, param, scanner::to_float); + } + else if (desc->constraint_type == SANE_CONSTRAINT_WORD_LIST) + { + const SANE_Word* v = desc->constraint.word_list; + for (int i = 0; i < v[0]; ++i) + { + value_role role = VAL_ROLE_NONE; + if (v[i + 1] == cur) + role = value_role(role | VAL_ROLE_CURRENT); + if (v[i + 1] == def) + role = value_role(role | VAL_ROLE_DEFAULT); + val = SANE_UNFIX(v[i + 1]); + if (!setval(&val, role, param)) + break; + } + } + else + set_cur_and_def_value(val, SANE_UNFIX(*(SANE_Fixed*)init), setval, param); + } while (0); + } + else if (desc->type == SANE_TYPE_STRING) + { + char* buf = new char[desc->size + 4]; + std::string val(""), def((char*)init); + + memset(buf, 0, desc->size + 4); + hg_sane_middleware::instance()->get_cur_value(handle_, sn, buf); + val = buf; + do + { + if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST) + { + for (int i = 0; desc->constraint.string_list[i]; ++i) + { + value_role role = VAL_ROLE_NONE; + if (strcmp(desc->constraint.string_list[i], buf) == 0) + role = value_role(role | VAL_ROLE_CURRENT); + if (strcmp(desc->constraint.string_list[i], (char*)init) == 0) + role = value_role(role | VAL_ROLE_DEFAULT); + + val = desc->constraint.string_list[i]; + if (!setval(&val, role, param)) + break; + } + } + else + set_cur_and_def_value(val, def, setval, param); + } while (0); + delete[] buf; + } + else + { + ret = SANE_STATUS_INVAL; + } + local_utility::free_memory(init); + } + else + { + ret = (this->*ex->ex_api)(ex->base_ind, param, setval); + } + + return ret == SANE_STATUS_GOOD; +} +COM_API_IMPLEMENT(scanner, int, set_value(int sn, void* val)) +{ + EXAPIPOS ex = find_ex_api(sn); + int ret = SANE_STATUS_INVAL; + SANE_Int after = 0; + SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, sn); + + if (ex == ex_opts_.end()) + { + if (!set_option_value_with_parent(sn, val, &ret)) + ret = set_option_value(sn, desc->type, desc->size, val); + ret = local_utility::sane_statu_2_scanner_err(ret); + } + else + { + ret = (this->*ex->ex_api)(ex->base_ind, val, NULL); + } + + return ret; +} + +// SANE options ID ... +SANE_OPTION_ID_IMPLEMENT(is_multiout) +SANE_OPTION_ID_IMPLEMENT(multiout_type) +SANE_OPTION_ID_IMPLEMENT(color_mode) +SANE_OPTION_ID_IMPLEMENT(erase_color) +SANE_OPTION_ID_IMPLEMENT(erase_multiout_red) +SANE_OPTION_ID_IMPLEMENT(erase_paper_red) +SANE_OPTION_ID_IMPLEMENT(is_erase_background) +SANE_OPTION_ID_IMPLEMENT(background_color_range) +SANE_OPTION_ID_IMPLEMENT(sharpen) +SANE_OPTION_ID_IMPLEMENT(erase_morr) +SANE_OPTION_ID_IMPLEMENT(erase_grids) +SANE_OPTION_ID_IMPLEMENT(error_extend) +SANE_OPTION_ID_IMPLEMENT(is_noise_modify) +SANE_OPTION_ID_IMPLEMENT(noise_threshold) +SANE_OPTION_ID_IMPLEMENT(paper) +SANE_OPTION_ID_IMPLEMENT(is_custom_area) +SANE_OPTION_ID_IMPLEMENT(curstom_area_l) +SANE_OPTION_ID_IMPLEMENT(curstom_area_r) +SANE_OPTION_ID_IMPLEMENT(curstom_area_t) +SANE_OPTION_ID_IMPLEMENT(curstom_area_b) +SANE_OPTION_ID_IMPLEMENT(is_size_check) +SANE_OPTION_ID_IMPLEMENT(page) +SANE_OPTION_ID_IMPLEMENT(blank_page_threshold) +SANE_OPTION_ID_IMPLEMENT(resolution) +SANE_OPTION_ID_IMPLEMENT(image_quality) +SANE_OPTION_ID_IMPLEMENT(is_swap) +SANE_OPTION_ID_IMPLEMENT(is_split) +SANE_OPTION_ID_IMPLEMENT(is_auto_deskew) +SANE_OPTION_ID_IMPLEMENT(is_custom_gamma) +SANE_OPTION_ID_IMPLEMENT(bright) +SANE_OPTION_ID_IMPLEMENT(contrast) +SANE_OPTION_ID_IMPLEMENT(gamma) +SANE_OPTION_ID_IMPLEMENT(is_erase_black_frame) +SANE_OPTION_ID_IMPLEMENT(deep_sample) +SANE_OPTION_ID_IMPLEMENT(threshold) +SANE_OPTION_ID_IMPLEMENT(anti_noise) +SANE_OPTION_ID_IMPLEMENT(margin) +SANE_OPTION_ID_IMPLEMENT(fill_background) +SANE_OPTION_ID_IMPLEMENT(is_anti_permeate) +SANE_OPTION_ID_IMPLEMENT(anti_permeate_level) +SANE_OPTION_ID_IMPLEMENT(is_erase_hole) +SANE_OPTION_ID_IMPLEMENT(search_hole_range) +SANE_OPTION_ID_IMPLEMENT(is_filling_color) +SANE_OPTION_ID_IMPLEMENT(is_ultrasonic_check) +SANE_OPTION_ID_IMPLEMENT(is_check_staple) +SANE_OPTION_ID_IMPLEMENT(scan_mode) +SANE_OPTION_ID_IMPLEMENT(scan_count) +SANE_OPTION_ID_IMPLEMENT(text_direction) +SANE_OPTION_ID_IMPLEMENT(is_rotate_bkg180) +SANE_OPTION_ID_IMPLEMENT(is_check_dogear) +SANE_OPTION_ID_IMPLEMENT(dogear_size) +SANE_OPTION_ID_IMPLEMENT(is_check_skew) +SANE_OPTION_ID_IMPLEMENT(skew_range) + +// SANE-ex option ID: +SANE_OPTION_ID_IMPLEMENT(ex_multiout_type) +SANE_OPTION_ID_IMPLEMENT(ex_auto_color_type) +SANE_OPTION_ID_IMPLEMENT(ex_color_mode) +SANE_OPTION_ID_IMPLEMENT(ex_sharpen) +SANE_OPTION_ID_IMPLEMENT(ex_paper) +SANE_OPTION_ID_IMPLEMENT(ex_paper_lateral) +SANE_OPTION_ID_IMPLEMENT(ex_auto_paper_size) +SANE_OPTION_ID_IMPLEMENT(ex_is_paper_auto_crop) +SANE_OPTION_ID_IMPLEMENT(ex_text_direction) +SANE_OPTION_ID_IMPLEMENT(ex_duplex) +SANE_OPTION_ID_IMPLEMENT(ex_fill_background) +SANE_OPTION_ID_IMPLEMENT(ex_discard_blank_page) +SANE_OPTION_ID_IMPLEMENT(ex_discard_blank_receipt) +SANE_OPTION_ID_IMPLEMENT(ex_is_page_fold) +SANE_OPTION_ID_IMPLEMENT(ex_color_filter) +SANE_OPTION_ID_IMPLEMENT(ex_color_enhance) +SANE_OPTION_ID_IMPLEMENT(ex_final_compression) +SANE_OPTION_ID_IMPLEMENT(ex_final_format) +SANE_OPTION_ID_IMPLEMENT(ex_serial) +SANE_OPTION_ID_IMPLEMENT(ex_to_be_scan) +SANE_OPTION_ID_IMPLEMENT(ex_scan_with_hole) +SANE_OPTION_ID_IMPLEMENT(ex_device_code) +SANE_OPTION_ID_IMPLEMENT(ex_power) +SANE_OPTION_ID_IMPLEMENT(ex_hardware_version) +SANE_OPTION_ID_IMPLEMENT(ex_ip) + +// ui ... +COM_API_IMPLEMENT(scanner, void, ui_show_main(void)) +{ +} +COM_API_IMPLEMENT(scanner, void, ui_show_setting(bool with_scan)) +{ +} +COM_API_IMPLEMENT(scanner, void, ui_show_progress(void)) +{ +} +COM_API_IMPLEMENT(scanner, void, ui_hide(void)) +{ +} +COM_API_IMPLEMENT(scanner, void, ui_handle_sane_event(int sane_ev, void* data, unsigned int* len)) +{ +} +COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void)) +{ + return false; +} +COM_API_IMPLEMENT(scanner, bool, ui_is_progress_ui_showing(void)) +{ + return false; +} + + + + + + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// exports +#ifdef EXPORT_SANE_API +__declspec(dllexport) +#else +__declspec(dllimport) +#endif +int __stdcall initialize(void* reserve) +{ + hg_sane_middleware::instance(); + + return SANE_STATUS_GOOD; +} +#ifdef EXPORT_SANE_API +__declspec(dllexport) +#else +__declspec(dllimport) +#endif +int __stdcall open_scanner(SCANNERID scanner_id, ISaneInvoker** invoker) +{ + if (!invoker) + return SCANNER_ERR_INVALID_PARAMETER; + + if (!is_scanner_online(scanner_id)) + return SCANNER_ERR_DEVICE_NOT_FOUND; + + scanner* scn = new scanner(scanner_id); + *invoker = dynamic_cast(scn); + + return 0; +} +#ifdef EXPORT_SANE_API +__declspec(dllexport) +#else +__declspec(dllimport) +#endif +bool __stdcall is_scanner_online(SCANNERID scanner_id) +{ + return !scanner::get_scanner_name(scanner_id).empty(); +} +#ifdef EXPORT_SANE_API +__declspec(dllexport) +#else +__declspec(dllimport) +#endif +int __stdcall uninitialize(void* reserve) +{ + hg_sane_middleware::clear(); + + return 0; +} + + diff --git a/sane/scanner.h b/sane/scanner.h new file mode 100644 index 0000000..47f783d --- /dev/null +++ b/sane/scanner.h @@ -0,0 +1,270 @@ +#pragma once + +#include "scanned_img.h" +#include +#include + + +#define SANE_OPTION_ID(name) \ + SANE_OPTION_ID_OVERRIDE(name); \ + int name##_id_ = -1; +#define SANE_OPTION_ID_IMPLEMENT(name) \ + SANE_OPTION_IMPLEMENT(scanner, name) \ + { \ + return name##_id_; \ + } + +#define EX_HANDLER_PROTO(name) \ + int name(int base_id, void* data, set_opt_value setv) +#define EX_OPTION_HANDLER_DECL(name) EX_HANDLER_PROTO(handle_ex_##name) +#define EX_OPTION_HANDLER_IMPL(name) EX_HANDLER_PROTO(scanner::handle_ex_##name) + +#define EXTENSION_ID_BASE 0x300 + +class scanner : public ISaneInvoker, virtual public refer +{ + SANE_Handle handle_; + SCANNERID id_; + int err_; + int ex_id_; + int prev_start_result_; + + int open(void); + int close(void); + int init_options_id(void); + int control_read_string(int code, std::string& ret); + + void extension_none(int id); + void extension_multiout_type(int id); + void extension_color_mode(int id); + void extension_sharpen(int id); + void extension_paper(int id); + void extension_fill_bkg_method(int id); + void extension_text_direction(int id); + void extension_page(int id); + void extension_erase_color(int id); + + bool get_option_value_with_parent(int sn, set_opt_value setv, void* param); // return true if handled + bool set_option_value_with_parent(int sn, void* data, int* err); // return true if handled + int set_option_value(int sn, SANE_Value_Type type, int size, void* data); + + typedef struct _ex_api + { + unsigned int ind; + unsigned int base_ind; + int(scanner::* ex_api)(int, void*, set_opt_value); + bool operator==(const int& id) + { + return ind == id; + } + }EXAPI; + std::vector ex_opts_; + typedef std::vector::iterator EXAPIPOS; + EXAPIPOS find_ex_api(int op_id); +; + EX_OPTION_HANDLER_DECL(multiout); + EX_OPTION_HANDLER_DECL(auto_color_type); + EX_OPTION_HANDLER_DECL(color_mode); + EX_OPTION_HANDLER_DECL(sharpen); // int + EX_OPTION_HANDLER_DECL(paper); + EX_OPTION_HANDLER_DECL(paper_lateral); + EX_OPTION_HANDLER_DECL(auto_paper_size); + EX_OPTION_HANDLER_DECL(auto_paper_crop); + EX_OPTION_HANDLER_DECL(text_direction); + EX_OPTION_HANDLER_DECL(duplex); + EX_OPTION_HANDLER_DECL(fill_background); // bool true - 凸多边形 + EX_OPTION_HANDLER_DECL(discard_blank_page); + EX_OPTION_HANDLER_DECL(discard_blank_receipt); + EX_OPTION_HANDLER_DECL(page_fold); + EX_OPTION_HANDLER_DECL(color_filter); + EX_OPTION_HANDLER_DECL(color_enhance); + + EX_OPTION_HANDLER_DECL(final_compression); // int + EX_OPTION_HANDLER_DECL(final_format); // SANE_FinalImgFormat + EX_OPTION_HANDLER_DECL(serial); // std::string + EX_OPTION_HANDLER_DECL(to_be_scan); // bool + EX_OPTION_HANDLER_DECL(scan_with_hole); // bool + EX_OPTION_HANDLER_DECL(device_code); // std::string + EX_OPTION_HANDLER_DECL(power); // int + EX_OPTION_HANDLER_DECL(hardware_version); // std::string + EX_OPTION_HANDLER_DECL(ip); // std::string + + + template + bool set_cur_and_def_value(T cur, T def, set_opt_value setv, void* param) + { + if (cur == def) + return setv(&cur, value_role(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT), param); + else if (setv(&cur, VAL_ROLE_CURRENT, param)) + return setv(&def, VAL_ROLE_DEFAULT, param); + else + return false; + } + template + void set_value_range(S cur, S def, S l, S u, S s, set_opt_value setv, void* param, T(__stdcall* to_t)(S)) + { + struct + { + int role; + S val; + }vals[5]; + int count = 0; + std::vector sv; + + sv.push_back(cur); + sv.push_back(def); + sv.push_back(l); + sv.push_back(u); + std::sort(sv.begin(), sv.end()); + for (int i = 0; i < sv.size(); ++i) + { + if (i && sv[i] == sv[i - 1]) + continue; + + vals[count].val = sv[i]; + vals[count].role = 0; + if (sv[i] == cur) + vals[count].role |= VAL_ROLE_CURRENT; + if (sv[i] == def) + vals[count].role |= VAL_ROLE_DEFAULT; + if (sv[i] == l) + vals[count].role |= VAL_ROLE_LOWER; + if (sv[i] == u) + vals[count].role |= VAL_ROLE_UPPER; + count++; + } + vals[count].val = s; + vals[count++].role = VAL_ROLE_STEP; + + for (int i = 0; i < count; ++i) + { + T v = to_t(vals[i].val); + if (!setv(&v, (value_role)vals[i].role, param)) + break; + } + } + + static int __stdcall to_int(SANE_Int v); + static float __stdcall to_float(SANE_Fixed v); + +public: + scanner(SCANNERID id); +protected: + ~scanner(); + +public: + static std::string get_scanner_name(SCANNERID id); + static value_type from_sane_type(SANE_Value_Type type); + static value_limit from_sane_constraint(SANE_Constraint_Type type); + + // IRef +public: + COM_API_OVERRIDE(long, add_ref(void)); + COM_API_OVERRIDE(long, release(void)); + + // ISaneInvoker +public: + COM_API_OVERRIDE(int, start(void)); + COM_API_OVERRIDE(int, stop(void)); + COM_API_OVERRIDE(void, set_event_callback(void(*cb)(int ev_type, void* data, unsigned int* len, void* param), void* param)); + COM_API_OVERRIDE(bool, wait_image(DWORD milliseconds = -1)); + COM_API_OVERRIDE(int, get_scanned_images(DWORD milliseconds = 0)); + COM_API_OVERRIDE(IScanImg*, take_first_image(void)); // call 'release' on returned value, plz + COM_API_OVERRIDE(bool, get_first_image_header(SANE_Parameters* header)); + COM_API_OVERRIDE(bool, is_online(void)); + COM_API_OVERRIDE(bool, is_paper_on(void)); + COM_API_OVERRIDE(bool, get_option_info(int sn, value_type* type, value_limit* limit, int* bytes)); + COM_API_OVERRIDE(bool, get_value(int sn, set_opt_value, void* param)); + COM_API_OVERRIDE(int, set_value(int sn, void* val)); + + // SANE options ID ... + SANE_OPTION_ID(is_multiout); + SANE_OPTION_ID(multiout_type); + SANE_OPTION_ID(color_mode); + SANE_OPTION_ID(erase_color); + SANE_OPTION_ID(erase_multiout_red); + SANE_OPTION_ID(erase_paper_red); + SANE_OPTION_ID(is_erase_background); + SANE_OPTION_ID(background_color_range); + SANE_OPTION_ID(sharpen); + SANE_OPTION_ID(erase_morr); + SANE_OPTION_ID(erase_grids); // 除网纹 + SANE_OPTION_ID(error_extend); + SANE_OPTION_ID(is_noise_modify); + SANE_OPTION_ID(noise_threshold); + SANE_OPTION_ID(paper); + SANE_OPTION_ID(is_custom_area); + SANE_OPTION_ID(curstom_area_l); + SANE_OPTION_ID(curstom_area_r); + SANE_OPTION_ID(curstom_area_t); + SANE_OPTION_ID(curstom_area_b); + SANE_OPTION_ID(is_size_check); + SANE_OPTION_ID(page); + SANE_OPTION_ID(blank_page_threshold); // 跳过空白页灵敏度 + SANE_OPTION_ID(resolution); + SANE_OPTION_ID(image_quality); + SANE_OPTION_ID(is_swap); // 交换正反面 + SANE_OPTION_ID(is_split); // 图像拆分 + SANE_OPTION_ID(is_auto_deskew); // 自动纠偏 + SANE_OPTION_ID(is_custom_gamma); + SANE_OPTION_ID(bright); + SANE_OPTION_ID(contrast); + SANE_OPTION_ID(gamma); + SANE_OPTION_ID(is_erase_black_frame); // bool + SANE_OPTION_ID(deep_sample); + SANE_OPTION_ID(threshold); + SANE_OPTION_ID(anti_noise); // 抗噪等级 + SANE_OPTION_ID(margin); + SANE_OPTION_ID(fill_background); + SANE_OPTION_ID(is_anti_permeate); + SANE_OPTION_ID(anti_permeate_level); + SANE_OPTION_ID(is_erase_hole); + SANE_OPTION_ID(search_hole_range); + SANE_OPTION_ID(is_filling_color); // 色彩填充 + SANE_OPTION_ID(is_ultrasonic_check); + SANE_OPTION_ID(is_check_staple); + SANE_OPTION_ID(scan_mode); // 扫描张数 + SANE_OPTION_ID(scan_count); // 扫描数量 + SANE_OPTION_ID(text_direction); + SANE_OPTION_ID(is_rotate_bkg180); + SANE_OPTION_ID(is_check_dogear); + SANE_OPTION_ID(dogear_size); + SANE_OPTION_ID(is_check_skew); + SANE_OPTION_ID(skew_range); + + // SANE-ex option ID: + SANE_OPTION_ID(ex_multiout_type); // int + SANE_OPTION_ID(ex_auto_color_type); // int + SANE_OPTION_ID(ex_color_mode); // int + SANE_OPTION_ID(ex_sharpen); // int + SANE_OPTION_ID(ex_paper); // paper_value + SANE_OPTION_ID(ex_paper_lateral); // bool + SANE_OPTION_ID(ex_auto_paper_size); // bool + SANE_OPTION_ID(ex_is_paper_auto_crop); // bool + SANE_OPTION_ID(ex_text_direction); // float 90, 180, ..., -1 is auto-text-direction + SANE_OPTION_ID(ex_duplex); // bool + SANE_OPTION_ID(ex_fill_background); // bool true - 凸多边形 + SANE_OPTION_ID(ex_discard_blank_page); // bool + SANE_OPTION_ID(ex_discard_blank_receipt); // bool + SANE_OPTION_ID(ex_is_page_fold); // bool + SANE_OPTION_ID(ex_color_filter); // int (filter_value) + SANE_OPTION_ID(ex_color_enhance); // int (enhance_value) + SANE_OPTION_ID(ex_final_compression); // int + SANE_OPTION_ID(ex_final_format); // SANE_FinalImgFormat + SANE_OPTION_ID(ex_serial); // std::string + SANE_OPTION_ID(ex_to_be_scan); // bool + SANE_OPTION_ID(ex_scan_with_hole); // bool + SANE_OPTION_ID(ex_device_code); // std::string + SANE_OPTION_ID(ex_power); // int + SANE_OPTION_ID(ex_hardware_version); // std::string + SANE_OPTION_ID(ex_ip); // std::string + + // ui ... + COM_API_OVERRIDE(void, ui_show_main(void)); + COM_API_OVERRIDE(void, ui_show_setting(bool with_scan)); + COM_API_OVERRIDE(void, ui_show_progress(void)); + COM_API_OVERRIDE(void, ui_hide(void)); + COM_API_OVERRIDE(void, ui_handle_sane_event(int sane_ev, void* data, unsigned int* len)); + COM_API_OVERRIDE(bool, ui_is_ok(void)); + COM_API_OVERRIDE(bool, ui_is_progress_ui_showing(void)); +}; \ No newline at end of file diff --git a/huagaotwain/ui.cpp b/sane/ui.cpp similarity index 100% rename from huagaotwain/ui.cpp rename to sane/ui.cpp diff --git a/huagaotwain/ui.h b/sane/ui.h similarity index 100% rename from huagaotwain/ui.h rename to sane/ui.h diff --git a/sln/hgscanner.sln b/sln/hgscanner.sln index 139bbc3..fec2f9f 100644 --- a/sln/hgscanner.sln +++ b/sln/hgscanner.sln @@ -3,14 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.32106.194 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hgscanner", "..\device\hgscanner.vcxproj", "{9ED4B425-73E0-423E-9712-455E777481B4}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sane", "..\sane\sane.vcxproj", "{6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hgsane", "..\protocol\hgsane.vcxproj", "{6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}" - ProjectSection(ProjectDependencies) = postProject - {9ED4B425-73E0-423E-9712-455E777481B4} = {9ED4B425-73E0-423E-9712-455E777481B4} - EndProjectSection +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scanner", "..\device\scanner.vcxproj", "{9ED4B425-73E0-423E-9712-455E777481B4}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "huagaotwain", "..\huagaotwain\huagaotwain.vcxproj", "{C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "twain", "..\twain\twain.vcxproj", "{C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -20,14 +17,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x64.ActiveCfg = Debug|x64 - {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x64.Build.0 = Debug|x64 - {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x86.ActiveCfg = Debug|Win32 - {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x86.Build.0 = Debug|Win32 - {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x64.ActiveCfg = Release|x64 - {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x64.Build.0 = Release|x64 - {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x86.ActiveCfg = Release|Win32 - {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x86.Build.0 = Release|Win32 {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Debug|x64.ActiveCfg = Debug|x64 {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Debug|x64.Build.0 = Debug|x64 {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Debug|x86.ActiveCfg = Debug|Win32 @@ -36,6 +25,14 @@ Global {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Release|x64.Build.0 = Release|x64 {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Release|x86.ActiveCfg = Release|Win32 {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Release|x86.Build.0 = Release|Win32 + {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x64.ActiveCfg = Debug|x64 + {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x64.Build.0 = Debug|x64 + {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x86.ActiveCfg = Debug|Win32 + {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x86.Build.0 = Debug|Win32 + {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x64.ActiveCfg = Release|x64 + {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x64.Build.0 = Release|x64 + {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x86.ActiveCfg = Release|Win32 + {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x86.Build.0 = Release|Win32 {C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}.Debug|x64.ActiveCfg = Debug|Win32 {C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}.Debug|x86.ActiveCfg = Debug|Win32 {C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}.Debug|x86.Build.0 = Debug|Win32 diff --git a/huagaotwain/dllmain.cpp b/twain/dllmain.cpp similarity index 94% rename from huagaotwain/dllmain.cpp rename to twain/dllmain.cpp index ae98183..2ca3ead 100644 --- a/huagaotwain/dllmain.cpp +++ b/twain/dllmain.cpp @@ -1,5 +1,4 @@ #include "pch.h" -#include "huagaotwain.h" HMODULE me_ = NULL; diff --git a/huagaotwain/huagaotwain.rc b/twain/huagaotwain.rc similarity index 100% rename from huagaotwain/huagaotwain.rc rename to twain/huagaotwain.rc diff --git a/twain/load_sane.cpp b/twain/load_sane.cpp new file mode 100644 index 0000000..8140a3c --- /dev/null +++ b/twain/load_sane.cpp @@ -0,0 +1,176 @@ +#include "pch.h" +#include "load_sane.h" +#include + +namespace load_sane_util +{ + static std::wstring sane_path(L""); + static HMODULE sane_module(NULL); + static int (__stdcall* sane_inst)(SCANNERID, ISaneInvoker**) = NULL; + static int(__stdcall* is_on)(SCANNERID) = NULL; + static int(__stdcall* init)(void*) = NULL; + static int(__stdcall* uninit)(void*) = NULL; + + static std::wstring reg_read(HKEY root, const wchar_t* path, const wchar_t* name) + { + HKEY key = NULL; + + RegOpenKeyW(root, path, &key); + if (!key) + return L""; + + wchar_t* buf = NULL; + DWORD len = 0; + DWORD type = REG_SZ; + std::wstring ret(L""); + + RegQueryValueExW(key, name, NULL, &type, (LPBYTE)buf, &len); + if (len) + { + buf = new wchar_t[len + 4]; + memset(buf, 0, (len + 4) * sizeof(*buf)); + RegQueryValueExW(key, name, NULL, &type, (LPBYTE)buf, &len); + ret = buf; + delete[] buf; + } + RegCloseKey(key); + + return ret; + } + static std::wstring reg_get_app_installing_path(void) + { +#ifdef OEM_HANWANG + std::wstring path(L"SOFTWARE\\HanvonScan"); +#elif defined(OEM_LISICHENG) + std::wstring path(L"SOFTWARE\\LanxumScan"); +#else + std::wstring path(L"SOFTWARE\\HuaGoScan"); +#endif + + return reg_read(HKEY_LOCAL_MACHINE, path.c_str(), L"AppDirectory"); + } + static int load_dll(const wchar_t* path_dll, HMODULE* dll) + { + HMODULE h = LoadLibraryW(path_dll); + int ret = GetLastError(); + + if (!h && ret == ERROR_MOD_NOT_FOUND) + { + std::wstring dir(path_dll); + size_t pos = dir.rfind(L'\\'); + wchar_t path[MAX_PATH] = { 0 }; + + GetCurrentDirectoryW(_countof(path) - 1, path); + if (pos != std::wstring::npos) + dir.erase(pos); + SetCurrentDirectoryW(dir.c_str()); + h = LoadLibraryW(path_dll); + ret = GetLastError(); + SetCurrentDirectoryW(path); + } + + if (dll) + *dll = h; + + return ret; + } + static std::string u2m(const wchar_t* u, int page) + { + char* ansi = NULL; + int len = 0; + std::string mb(""); + + len = WideCharToMultiByte(page, 0, u, lstrlenW(u), NULL, 0, NULL, NULL); + ansi = new char[len + 2]; + len = WideCharToMultiByte(page, 0, u, lstrlenW(u), ansi, len, NULL, NULL); + ansi[len--] = 0; + mb = ansi; + delete[] ansi; + + return mb; + } + static std::wstring m2u(const char* m, int page) + { + wchar_t* unic = NULL; + int len = 0; + std::wstring u(L""); + + len = MultiByteToWideChar(page, 0, m, lstrlenA(m), NULL, 0); + unic = new wchar_t[len + 2]; + len = MultiByteToWideChar(page, 0, m, lstrlenA(m), unic, len); + unic[len--] = 0; + u = unic; + delete[] unic; + + return u; + } + + bool initialize(HMODULE me) + { + bool ret = false; + sane_path = reg_get_app_installing_path(); + if (!sane_path.empty()) + { + sane_path += L"\\sane.dll"; + load_dll(sane_path.c_str(), &sane_module); + if (sane_module) + { + *((FARPROC*)&init) = GetProcAddress(sane_module, "initialize"); + *((FARPROC*)&sane_inst) = GetProcAddress(sane_module, "open_scanner"); + *((FARPROC*)&is_on) = GetProcAddress(sane_module, "is_scanner_online"); + *((FARPROC*)&uninit) = GetProcAddress(sane_module, "uninitialize"); + ret = is_ok(); + if (ret) + ret = init(NULL) == 0; + } + } + + return ret; + } + bool is_ok(void) + { + return sane_inst != NULL && is_on != NULL && init != NULL && uninit != NULL; + } + bool is_online(SCANNERID guid) + { + if (is_on) + return is_on(guid); + else + return false; + } + ISaneInvoker* open(SCANNERID guid, int* err) + { + ISaneInvoker* ret = NULL; + int code = 0; + + if (!err) + err = &code; + + if (sane_inst) + *err = sane_inst(guid, &ret); + + return ret; + } + void uninitialize(void) + { + if (uninit) + uninit(NULL); + + if (sane_module) + { + FreeLibrary(sane_module); + sane_module = NULL; + } + sane_path = L""; + sane_inst = NULL; + } + + std::string utf82ansi(const char* utf8) + { + return u2m(m2u(utf8, CP_UTF8).c_str(), CP_ACP); + } + std::string ansi2utf8(const char* ansi) + { + return u2m(m2u(ansi, CP_ACP).c_str(), CP_UTF8); + } +}; diff --git a/twain/load_sane.h b/twain/load_sane.h new file mode 100644 index 0000000..8f4486a --- /dev/null +++ b/twain/load_sane.h @@ -0,0 +1,19 @@ +#pragma once + +// utility for loading sane component ... + +#include "../sane/s2t_api.h" +#include + +namespace load_sane_util +{ + bool initialize(HMODULE me); + bool is_ok(void); + bool is_online(SCANNERID guid); + ISaneInvoker* open(SCANNERID guid, int* err); + void uninitialize(void); + + std::string utf82ansi(const char* utf8); + std::string ansi2utf8(const char* ansi); +}; + diff --git a/huagaotwain/pch.cpp b/twain/pch.cpp similarity index 100% rename from huagaotwain/pch.cpp rename to twain/pch.cpp diff --git a/huagaotwain/pch.h b/twain/pch.h similarity index 100% rename from huagaotwain/pch.h rename to twain/pch.h diff --git a/huagaotwain/resource.h b/twain/resource.h similarity index 100% rename from huagaotwain/resource.h rename to twain/resource.h diff --git a/huagaotwain/targetver.h b/twain/targetver.h similarity index 100% rename from huagaotwain/targetver.h rename to twain/targetver.h diff --git a/huagaotwain/twain.def b/twain/twain.def similarity index 100% rename from huagaotwain/twain.def rename to twain/twain.def diff --git a/huagaotwain/huagaotwain.vcxproj b/twain/twain.vcxproj similarity index 93% rename from huagaotwain/huagaotwain.vcxproj rename to twain/twain.vcxproj index 67b80f6..3a27b11 100644 --- a/huagaotwain/huagaotwain.vcxproj +++ b/twain/twain.vcxproj @@ -13,7 +13,7 @@ {c3b47ce2-27ce-4509-ab59-3c0f194f0fce} DynamicLibrary - huagaotwain + twain Win32Proj 10.0 @@ -75,7 +75,7 @@ move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" -copy $(TargetPath) $(WinDir)\twain_32\HuaGoScan\$(ProjectName).ds /y +copy $(TargetPath) $(WinDir)\twain_32\HuaGoScan\huagaotwain.ds /y @@ -106,11 +106,10 @@ copy $(TargetPath) $(WinDir)\twain_32\HuaGoScan\$(ProjectName).ds /y - - + + - @@ -153,24 +152,18 @@ copy $(TargetPath) $(WinDir)\twain_32\HuaGoScan\$(ProjectName).ds /y - - + Create Create - - NotUsing - NotUsing - NotUsing NotUsing - diff --git a/huagaotwain/huagaotwain.vcxproj.filters b/twain/twain.vcxproj.filters similarity index 83% rename from huagaotwain/huagaotwain.vcxproj.filters rename to twain/twain.vcxproj.filters index e82d13b..bf07ba3 100644 --- a/huagaotwain/huagaotwain.vcxproj.filters +++ b/twain/twain.vcxproj.filters @@ -11,21 +11,28 @@ {df21031b-938a-4a08-ae64-e869e2586201} + + {89716198-13ed-4593-819e-97f4426c7baa} + + + {6d97172d-832d-4c93-ad0e-92fdf76af26b} + - - - twain - - + + Sources + + + Sources + + + Sources + - - - twain @@ -149,17 +156,30 @@ twain - - - - - - - + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + Resource Files + + + Sources + + \ No newline at end of file diff --git a/twain/twain.vcxproj.user b/twain/twain.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/twain/twain.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/huagaotwain/twain/huagaods.cpp b/twain/twain/huagaods.cpp similarity index 61% rename from huagaotwain/twain/huagaods.cpp rename to twain/twain/huagaods.cpp index 9d8e038..9fe5a0d 100644 --- a/huagaotwain/twain/huagaods.cpp +++ b/twain/twain/huagaods.cpp @@ -18,15 +18,13 @@ #endif // WIN32 using namespace std; -#include "../huagaotwain.h" -#include "../ui.h" - #define enum2str(R) #R using namespace Twpp; using namespace std::placeholders; +extern HMODULE me_; //custom define caps enum enum CapTypeEx : unsigned short { @@ -48,14 +46,15 @@ enum CapTypeEx : unsigned short { CAP_TYPE_EX_DOGEAR_DETECT = 0x8096, CAP_TYPE_EX_BKG_FILLING_METHOD = 0x8097, CAP_TYPE_EX_EDGE_IDENT = 0x8098, - CAP_TYPE_EX_THRESHOLD = 0x8099, - CAP_TYPE_EX_THRESHOLD_1 = 0x8100, + CAP_TYPE_EX_ANTI_NOISE = 0x8099, + CAP_TYPE_EX_THRESHOLD = 0x8100, CAP_TYPE_EX_DETACH_NOISE = 0x8101, CAP_TYPE_EX_DETACH_NOISE_THRESHOLD = 0x8102, CAP_TYPE_EX_SIZE_DETECT = 0x8103, CAP_TYPE_EX_POWER_LEVEL = 0x8104, CAP_TYPE_EX_ENCODE = 0x8105, CAP_TYPE_EX_DARK_SAMPLE = 0x8016, + CAP_TYPE_EX_CROP_MODEL = 0x8106, CAP_TYPE_EX_DOGEAR_DIST = 0x8107, CAP_TYPE_EX_IMAGE_SPLIT = 0x8108, CAP_TYPE_EX_FADE_BKG = 0x8109, @@ -147,6 +146,26 @@ enum CapTypeEx : unsigned short { CAP_TYPE_EX_78, CAP_TYPE_EX_79, CAP_TYPE_EX_80, + CAP_TYPE_EX_81, + CAP_TYPE_EX_82, + CAP_TYPE_EX_83, + CAP_TYPE_EX_84, + CAP_TYPE_EX_85, + CAP_TYPE_EX_86, + CAP_TYPE_EX_87, + CAP_TYPE_EX_88, + CAP_TYPE_EX_89, + CAP_TYPE_EX_90, + CAP_TYPE_EX_91, + CAP_TYPE_EX_92, + CAP_TYPE_EX_93, + CAP_TYPE_EX_94, + CAP_TYPE_EX_95, + CAP_TYPE_EX_96, + CAP_TYPE_EX_97, + CAP_TYPE_EX_98, + CAP_TYPE_EX_99, + CAP_TYPE_EX_100, }; @@ -277,6 +296,24 @@ Result CapSupGetAllReset(Msg msg, Capability& data, std::initializer_list va } } template +Result CapSupGetAllReset(Msg msg, Capability& data, std::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 CapSupGetAllResetEx(Msg msg, Capability& data, std::initializer_list values, T1& currvalue, T2 defaultvalue, UInt32 currindex, UInt32 defaultindex) { switch (msg) { case Msg::Get: @@ -294,6 +331,24 @@ Result CapSupGetAllResetEx(Msg msg, Capability& data, std::initializer_list return { ReturnCode::Failure, ConditionCode::CapBadOperation }; } } +template +Result CapSupGetAllResetEx(Msg msg, Capability& data, std::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 CapSupGetAllReset(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) { @@ -414,6 +469,10 @@ static void copy_type(UInt32& to, int from) { to = from; } +static void copy_type(int& to, UInt32 from) +{ + to = from; +} static void copy_type(Fix32& to, double from) { to = from; @@ -422,28 +481,156 @@ static void copy_type(Fix32& to, float from) { to = from; } +static void copy_type(float& to, Fix32 from) +{ + to = from.toFloat(); +} static void copy_type(Str255& to, std::string from) { - to.setData(sane_invoker::utf82ansi(from.c_str()).c_str()); + to.setData(load_sane_util::utf82ansi(from.c_str()).c_str()); } static void copy_type(std::string& to, Str255 from) { - to = sane_invoker::ansi2utf8(from.data()); + to = load_sane_util::ansi2utf8(from.data()); } static void copy_type(Str64& to, std::string from) { - to.setData(sane_invoker::utf82ansi(from.c_str()).c_str()); + to.setData(load_sane_util::utf82ansi(from.c_str()).c_str()); } static void copy_type(std::string& to, Str64 from) { - to = sane_invoker::ansi2utf8(from.data()); + to = load_sane_util::ansi2utf8(from.data()); } +UINT16 bit_depth_from_sane(int sane) +{ + if (sane == COLOR_BW) + return 1; + else if (sane == COLOR_GRAY) + return 8; + else if (sane == COLOR_RGB) + return 24; + else + return sane; +} +static ImageFileFormat from_sane_image_type(int sane_img_type) +{ + ImageFileFormat fmt = ImageFileFormat::Bmp; + switch (sane_img_type) + { + case SANE_IMAGE_TYPE_PNG: + fmt = ImageFileFormat::Png; + break; + case SANE_IMAGE_TYPE_JPG: + fmt = ImageFileFormat::Jpx; + break; + case SANE_IMAGE_TYPE_TIFF: + fmt = ImageFileFormat::Tiff; + break; + case SANE_IMAGE_TYPE_JFIF: + fmt = ImageFileFormat::Jfif; + break; + case SANE_IMAGE_TYPE_WEBP: + break; + case SANE_IMAGE_TYPE_PDF: + fmt = ImageFileFormat::Pdf; + break; + case SANE_IMAGE_TYPE_GIF: + break; + case SANE_IMAGE_TYPE_SVG: + break; + default: + break; + } + + return fmt; +} + +struct +{ + Filter twain; + int sane; +}g_filter[] = { {Filter::Red, FILTER_RED}, {Filter::Green, FILTER_GREEN}, {Filter::Blue, FILTER_BLUE}, {Filter::None, FILTER_NONE} }; +Filter from_sane_filter(int sane) +{ + for (int i = 0; i < _countof(g_filter); ++i) + { + if (g_filter[i].sane == sane) + return g_filter[i].twain; + } + + return Filter::None; +} +int to_sane_filter(Filter twain) +{ + for (int i = 0; i < _countof(g_filter); ++i) + { + if (g_filter[i].twain == twain) + return g_filter[i].sane; + } + + return FILTER_NONE; +} + +struct +{ + Filter twain; + int sane; +}g_enhance[] = { {Filter::Red, ENHANCE_RED}, {Filter::Green, ENHANCE_GREEN}, {Filter::Blue, ENHANCE_BLUE}, {Filter::None, ENHANCE_NONE} }; +Filter from_sane_enhance(int sane) +{ + for (int i = 0; i < _countof(g_filter); ++i) + { + if (g_filter[i].sane == sane) + return g_filter[i].twain; + } + + return Filter::None; +} +int to_sane_enhance(Filter twain) +{ + for (int i = 0; i < _countof(g_filter); ++i) + { + if (g_filter[i].twain == twain) + return g_filter[i].sane; + } + + return FILTER_NONE; +} + +float trans_range(float val, float min_from, float max_from, float min_to, float max_to) +{ + // transfer val in range [min_from, max_from] to value in range [min_to, max_to] + val -= min_from; + val /= max_from - min_from; + val *= max_to - min_to; + val += min_to; + + return val; +} + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // huagao_ds ... +#define PRODUCT_PID 0x0100 +#define PRODUCT_VID 0x3072 +#define PRODUCT_VENDOR "HUAGO" +#define PRODUCT_FAMILY "HG100" +#define PRODUCT_NAME "HG0100" + +#define TO_STR(a) #a +#define VERSION_MAIN 4 +#define VERSION_SUB 1007 +#define VERSION_BUILD 2022 +#define VERSION_PATCH 6131 +#define TO_VER_STR(vs) TO_STR(v##vs) +#define VERSION_STR(a, b, c, d) TO_VER_STR(a.b.c.d) + static Identity* srcIdent = new Identity( - Version(3, 3, Language::English, Country::China, "v3.3.5.6"), - DataGroup::Image, "HUAGO", "HUAGAO Series", "Huagao scanner series"); + Version(VERSION_MAIN, VERSION_SUB, Language::English, Country::China, VERSION_STR(VERSION_MAIN, VERSION_SUB, VERSION_BUILD, VERSION_PATCH)), + DataGroup::Image, PRODUCT_VENDOR, PRODUCT_FAMILY, PRODUCT_NAME); +static const SCANNERID scanner_guid = MAKE_SCANNER_ID(PRODUCT_PID, PRODUCT_VID); static std::once_flag oc; @@ -489,71 +676,13 @@ void huagao_ds::scan_event(int sane_event, void* data, unsigned int* len, void* const Identity& huagao_ds::defaultIdentity() noexcept { // remember, we return a reference, therefore the identity must not be placed on the stack of this method - if (sane_invoker::is_ok()) - { - DWORD ver = 0; - std::string v(sane_invoker::version(&ver)), - n("HUAGO"), t("Huagao scanner series"), m("HUAGAO Series"); - std::vector devs; - char v32[32] = { 0 }, n32[32] = { 0 }, t32[32] = { 0 }, m32[32] = { 0 }; - - sane_invoker::get_devices(devs); - if (devs.size()) - { - n = devs[0].vendor; - t = devs[0].name; - m = devs[0].product; - } - if (ver == 0) - { - ver = MAKELPARAM(56, 0x303); - v = "v3.3.56"; - } - else - v.insert(0, "v"); - - delete srcIdent; -#define COPY_32(a) strcpy_s(v##32, _countof(v##32), v##.c_str()) - COPY_32(v); - COPY_32(n); - COPY_32(t); - COPY_32(m); - srcIdent = new Twpp::Identity(Twpp::Version((ver >> 24) & 0x0ff, (ver >> 16) & 0x0ff, Language::English, Country::China, v32), - DataGroup::Image, n32, m32, t32); - } - return *srcIdent; } Result huagao_ds::selectIdentity(Twpp::Identity& ident) noexcept { // remember, we return a reference, therefore the identity must not be placed on the stack of this method - if (sane_invoker::is_ok()) - { - DWORD ver = 0; - std::vector devs; - Version twver; - char v32[32] = { 0 }, n32[32] = { 0 }, t32[32] = { 0 }, m32[32] = { 0 }; + ident = *srcIdent; - sane_invoker::get_devices(devs); - if (devs.size()) - { - strcpy(m32, devs[0].type.c_str()); - strcpy(n32, devs[0].product.c_str()); - strcpy(t32, devs[0].name.c_str()); - ident = Identity(twver, DataGroup::Image, n32, m32, t32); - - return success(); - } - // show dialog to select the devices listed in devs here ... - //if (dlg.DoModal() == IDOK) - //{ - // ident = Identity(twver, DataGroup::Image, n32, m32, t32); - // return success(); - //} - //else - { - return { ReturnCode::Failure, ConditionCode::Bummer }; - } - } + return success(); return { ReturnCode::Failure, ConditionCode::NoDs }; } @@ -633,7 +762,7 @@ Result huagao_ds::eventProcess(const Identity&, Event& event) } Twpp::Result huagao_ds::deviceEventGet(const Twpp::Identity& origin, Twpp::DeviceEvent& data) { - // data = DeviceEvent::simple(sane_invoker::take_event(), "HUAGAO"); + // data = DeviceEvent::simple(load_sane_util::take_event(), "HUAGAO"); // return success(); return seqError(); @@ -648,9 +777,9 @@ Result huagao_ds::identityOpenDs(const Identity& id) // // return { ReturnCode::Failure, ConditionCode::CapBadOperation }; //} - if (!sane_invoker::is_ok()) - sane_invoker::initialize(me_); - if (!sane_invoker::is_ok()) + if (!load_sane_util::is_ok()) + load_sane_util::initialize(me_); + if (!load_sane_util::is_ok()) { CloseHandle(singleton_); singleton_ = NULL; @@ -666,21 +795,22 @@ Result huagao_ds::identityOpenDs(const Identity& id) { CloseHandle(singleton_); singleton_ = NULL; - sane_invoker::uninitialize(); + load_sane_util::uninitialize(); return result; } int err = 0; - scanner_.reset(sane_invoker::open_scanner(target.productName().begin(), &err)); + Sleep(100); + scanner_.reset(load_sane_util::open(scanner_guid, &err)); if (!scanner_.get()) { //CloseHandle(singleton_); //singleton_ = NULL; - sane_invoker::uninitialize(); + load_sane_util::uninitialize(); return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(err) }; } - ui_.reset(new twain_ui(local_utility::reg_get_app_installing_path().c_str())); + // ui_.reset(new twain_ui(local_utility::reg_get_app_installing_path().c_str())); scanner_->set_event_callback(&huagao_ds::scan_event, this); init_support_caps(); @@ -688,7 +818,7 @@ Result huagao_ds::identityOpenDs(const Identity& id) } Result huagao_ds::identityCloseDs(const Identity&) { - ui_.reset(); + // ui_.reset(); if (scanner_.get()) { scanner_.reset(); @@ -698,7 +828,7 @@ Result huagao_ds::identityCloseDs(const Identity&) CloseHandle(singleton_); singleton_ = NULL; } - sane_invoker::uninitialize(); + load_sane_util::uninitialize(); return success(); } @@ -749,7 +879,7 @@ Result huagao_ds::setupMemXferGet(const Identity&, SetupMemXfer& data) } Result huagao_ds::userInterfaceDisable(const Identity&, UserInterface& ui) { - ui_->hide_ui(); + scanner_->ui_hide(); return success(); } @@ -758,7 +888,7 @@ Result huagao_ds::userInterfaceEnable(const Identity&, UserInterface& ui) if (!ui.showUi()) { if (m_bIndicator) - ui_->show_main_ui(sane_invoker::get_api()); + scanner_->ui_show_main(); return scanner_->start() == SCANNER_ERR_OK ? success() : seqError(); } @@ -780,13 +910,19 @@ Result huagao_ds::imageInfoGet(const Identity&, ImageInfo& data) if (scanner_->get_first_image_header(&head)) { - data.setBitsPerPixel(head.depth); + if(head.format == SANE_FRAME_RGB) + data.setBitsPerPixel(head.depth * 3); + else + data.setBitsPerPixel(head.depth); data.setHeight(head.lines); - data.setPixelType(head.depth == 24 ? PixelType::Rgb : PixelType::Gray); + data.setPixelType(head.format == SANE_FRAME_RGB ? PixelType::Rgb : PixelType::Gray); data.setPlanar(false); data.setWidth(head.pixels_per_line); - data.setXResolution(scanner_->twain_get_resolution()); - data.setYResolution(scanner_->twain_get_resolution()); + + int res = 200; + GET_SANE_OPT(int, scanner_, resolution, &res, NULL, NULL, NULL, NULL); + data.setXResolution(res); + data.setYResolution(res); data.compression(Compression::None); } @@ -799,11 +935,14 @@ Result huagao_ds::imageLayoutGet(const Identity&, ImageLayout& data) if (!scanner_.get() || scanner_->get_scanned_images() == 0) return seqError(); + int res = 200; + GET_SANE_OPT(int, scanner_, resolution, &res, NULL, NULL, NULL, NULL); + scanner_->get_first_image_header(&head); data.setDocumentNumber(1); data.setFrameNumber(1); data.setPageNumber(1); - data.setFrame(Frame(0, 0, static_cast(head.pixels_per_line) / scanner_->twain_get_resolution(), static_cast(head.lines) / scanner_->twain_get_resolution())); + data.setFrame(Frame(0, 0, static_cast(head.pixels_per_line) / res, static_cast(head.lines) / res)); return success(); } @@ -829,7 +968,7 @@ Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) if (!scanner_.get() || scanner_->get_scanned_images() == 0) return seqError(); - scanned_img *img = scanner_->take_first_image(); + IScanImg *img = scanner_->take_first_image(); unsigned char *src = img->bits() + img->bytes() - img->line_bytes(), *dst = NULL; @@ -843,7 +982,7 @@ Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) dst = (unsigned char*)data.memory().data().data(); for (int i = 0; i < img->height(); ++i, src -= img->line_bytes(), dst += img->line_bytes()) std::copy(src, src + img->line_bytes(), dst); - delete img; + img->release(); return success(); } @@ -852,7 +991,7 @@ Result huagao_ds::imageNativeXferGet(const Identity& id, ImageNativeXfer& data) if (!scanner_.get() || scanner_->get_scanned_images() == 0) return seqError(); - scanned_img* img = scanner_->take_first_image(); + IScanImg* img = scanner_->take_first_image(); if (!img) return seqError(); @@ -860,13 +999,13 @@ Result huagao_ds::imageNativeXferGet(const Identity& id, ImageNativeXfer& data) data.release(); data = ImageNativeXfer(img->bytes()); std::copy(img->bits(), img->bits() + img->bytes(), data.data().data()); - delete img; + img->release(); return { ReturnCode::XferDone, ConditionCode::Success }; } Twpp::Result huagao_ds::pendingXfersStopFeeder(const Identity& origin, PendingXfers& data) { - // sane_invoker::invoke_sane_cancel(); + // load_sane_util::invoke_sane_cancel(); return success(); } @@ -876,7 +1015,7 @@ Twpp::Result huagao_ds::imageFileXferGet(const Twpp::Identity& origin) if (!scanner_.get() || scanner_->get_scanned_images() == 0) return seqError(); - scanned_img *img = scanner_->take_first_image(); + IScanImg *img = scanner_->take_first_image(); Twpp::Result ret = seqError(); FILE* dst = NULL; @@ -892,7 +1031,7 @@ Twpp::Result huagao_ds::imageFileXferGet(const Twpp::Identity& origin) fclose(dst); } - delete img; + img->release(); } return ret; @@ -969,12 +1108,10 @@ Result huagao_ds::capCommon(const Identity&, Msg msg, Capability& data) { Twpp::Result huagao_ds::showTwainUI(Twpp::UserInterface& data, bool bUiOnly) { // display user UI ... (setting UI, can we show my own main window here ?) - LPSANEAPI api = sane_invoker::get_api(); - if (bUiOnly) - ui_->show_setting_ui(api, false); + scanner_->ui_show_setting(false); else - ui_->show_main_ui(api); + scanner_->ui_show_main(); return success(); } @@ -1006,13 +1143,19 @@ void huagao_ds::init_support_caps(void) if (item > 65535 || item < -1 || item == 0) { return badValue(); } - return scanner_->twain_set_scan_count(item) == SCANNER_ERR_OK ? success() : badValue(); + int ret = SCANNER_ERR_OK; + int count = item; + SET_SANE_OPT(ret, scanner_, scan_count, &count); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - Int16 tmp_count = scanner_->twain_get_scan_count(); + int count = -1; + Int16 tmp_count = 0; + GET_SANE_OPT(int, scanner_, scan_count, &count, NULL, NULL, NULL); + tmp_count = count; return oneValGetSet(msg, data, tmp_count, -1); }; - if (ui_->is_ok()) + if (scanner_->ui_is_ok()) { m_query[CapType::UiControllable] = msgSupportGetAll; m_caps[CapType::UiControllable] = std::bind(oneValGet, _1, _2, Bool(true)); @@ -1028,7 +1171,7 @@ void huagao_ds::init_support_caps(void) if(scanner_.get()) data = Capability::createOneValue((Twpp::Bool)scanner_->is_online()); else - data = Capability::createOneValue((Twpp::Bool)(sane_invoker::online_devices() > 0)); + data = Capability::createOneValue((Twpp::Bool)(load_sane_util::is_online(scanner_guid))); return success(); default: @@ -1044,14 +1187,19 @@ void huagao_ds::init_support_caps(void) { int mech = (int)data.currentItem(); if (msg == Msg::Reset) - scanner_->twain_get_final_compression(&mech); - return scanner_->twain_set_final_compression(mech) == SCANNER_ERR_OK ? success() : badValue(); + GET_SANE_OPT(int, scanner_, ex_final_compression, NULL, &mech, NULL, NULL); + + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_final_compression, (int*)&mech); + return ret == SCANNER_ERR_OK ? success() : badValue(); } std::vector values; + int init = 0, now = 0; std::list vals; Compression Now, Init; UInt32 ni = 0, ii = 0; - int init = 0, now = scanner_->twain_get_final_compression(&init, &values); + + GET_SANE_OPT(int, scanner_, ex_final_compression, &now, &init, &values, NULL); Now = (Compression)now; Init = (Compression)init; for (const auto& v : values) @@ -1066,26 +1214,33 @@ void huagao_ds::init_support_caps(void) m_query[CapType::IBitDepth] = msgSupportGetAllSetReset; m_caps[CapType::IBitDepth] = [this](Msg msg, Capability& data) -> Result { - if (Msg::Set == msg) { + int now = 0, init = 0; + std::vector all; + GET_SANE_OPT(int, scanner_, ex_color_mode, &now, &init, &all, NULL); + if (Msg::Set == msg || Msg::Reset == msg) { auto mech = data.currentItem(); int ret = SCANNER_ERR_INVALID_PARAMETER; - if (mech == 1) - ret = scanner_->twain_set_color_mode((int)PixelType::BlackWhite); - else if(mech == 8) - ret = scanner_->twain_set_color_mode((int)PixelType::Gray); - else if(mech == 24) - ret = scanner_->twain_set_color_mode((int)PixelType::Rgb); + if (Msg::Set == msg) + { + if (mech == 1) + init = COLOR_BW; + else if (mech == 8) + init = COLOR_GRAY; + else if (mech == 24) + init = COLOR_RGB; + else + init = mech; + } + SET_SANE_OPT(ret, scanner_, ex_color_mode, &init); return ret == SCANNER_ERR_OK ? success() : badValue(); } - UINT16 twpt = scanner_->twain_get_color_mode(); - if (twpt == (int)PixelType::BlackWhite) - twpt = 1; - else if (twpt == (int)PixelType::Gray) - twpt = 8; - else - twpt = 24; - - return CapSupGetAllReset(msg, data, twpt, 24); + UINT16 Now = bit_depth_from_sane(now), Init = bit_depth_from_sane(init); + std::list vals; + UInt32 ni = std::distance(all.begin(), std::find(all.begin(), all.end(), now)), + ii = std::distance(all.begin(), std::find(all.begin(), all.end(), init)); + for (auto& v : all) + vals.push_back(bit_depth_from_sane(v)); + return cap_get_enum_values(msg, data, vals, Now, Init, ni, ii); }; m_query[CapType::IBitOrder] = msgSupportGetAllSetReset; @@ -1098,12 +1253,12 @@ void huagao_ds::init_support_caps(void) m_caps[CapType::IXResolution] = [this](Msg msg, Capability& data) { if (!scanner_.get()) return seqError(); - std::vector values; - value_limit limit = VAL_LIMIT_NONE; - float init = .0f, now = .0f; + std::vector values; + value_limit limit = VAL_LIMIT_ENUM; + int init = 0, now = 0; + GET_SANE_OPT(int, scanner_, resolution, &now, &init, &values, NULL); switch (msg) { case Msg::Get: - now = scanner_->twain_get_resolution(&init, &values, &limit); if (limit == VAL_LIMIT_RANGE) { data = Capability::createRange(Fix32(values[0]), Fix32(values[1]), Fix32(50.0f), Fix32(now), Fix32(init)); @@ -1117,29 +1272,32 @@ void huagao_ds::init_support_caps(void) for (const auto& v : values) { Fix32 f; - copy_type(f, v); + float vf = v; + copy_type(f, vf); vals.push_back(f); } - copy_type(Now, now); - copy_type(Init, init); + float nowf = now, initf = init; + copy_type(Now, nowf); + copy_type(Init, initf); ni = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), Now)); ii = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), Init)); return cap_get_enum_values(msg, data, vals, Now, Init, ni, ii); } case Msg::GetCurrent: - now = scanner_->twain_get_resolution(); data = Capability::createOneValue(Fix32(now)); return success(); case Msg::GetDefault: - now = scanner_->twain_get_resolution(&init); data = Capability::createOneValue(Fix32(init)); return success(); case Msg::Reset: - now = scanner_->twain_get_resolution(&init); data = Capability::createOneValue(Fix32(init)); case Msg::Set: { auto mech = data.currentItem(); - return scanner_->twain_set_resolution((float)mech) == SCANNER_ERR_OK ? success() : badValue(); + int ret = SCANNER_ERR_OK; + float resl = (float)mech; + int resli = resl; + SET_SANE_OPT(ret, scanner_, resolution, &resli); + return ret == SCANNER_ERR_OK ? success() : badValue(); } default: return capBadOperation(); @@ -1155,6 +1313,32 @@ void huagao_ds::init_support_caps(void) m_query[CapType::IYNativeResolution] = msgSupportGetAll; m_caps[CapType::IYNativeResolution] = m_caps[CapType::IXNativeResolution]; + m_query[CapType::ISupportedSizes] = msgSupportGetAllSetReset; + m_caps[CapType::ISupportedSizes] = [this](Msg msg, Capability& data) { + int now = 0, + init = 0; + std::vector all; + GET_SANE_OPT(int, scanner_, ex_paper, &now, &init, &all, NULL); + if (msg == Msg::Set || msg == Msg::Reset) + { + if(msg == Msg::Set) + init = (int)data.currentItem(); + + SET_SANE_OPT(now, scanner_, ex_paper, &init); + return now == SCANNER_ERR_OK ? success() : badValue(); + } + + std::list vals; + Twpp::PaperSize Now = (PaperSize)now, + Init = (PaperSize)init; + UInt32 ni = std::distance(all.begin(), std::find(all.begin(), all.end(), now)), + ii = std::distance(all.begin(), std::find(all.begin(), all.end(), init)); + for (auto& v : all) + vals.push_back((PaperSize)v); + + return cap_get_enum_values(msg, data, vals, Now, Init, ni, ii); + }; + m_query[CapType::IPhysicalWidth] = msgSupportGetAll; m_caps[CapType::IPhysicalWidth] = [this](Msg msg, Capability& data) -> Result { switch (msg) { @@ -1163,9 +1347,11 @@ void huagao_ds::init_support_caps(void) case Msg::GetDefault: { float init = 10.0f; + int cur = 200; SANE_Parameters param = { 0 }; + GET_SANE_OPT(int, scanner_, resolution, &cur, NULL, NULL, NULL); if (scanner_.get() && scanner_->get_first_image_header(¶m)) - init = param.bytes_per_line / scanner_->twain_get_resolution(); + init = param.bytes_per_line * 1.0f / cur; data = Capability::createOneValue(data.type(), Fix32(init)); return success(); } @@ -1182,9 +1368,11 @@ void huagao_ds::init_support_caps(void) case Msg::GetDefault: { float init = 10.0f; + int cur = 200; SANE_Parameters param = { 0 }; + GET_SANE_OPT(int, scanner_, resolution, &cur, NULL, NULL, NULL); if (scanner_.get() && scanner_->get_first_image_header(¶m)) - init = param.lines / scanner_->twain_get_resolution(); + init = param.lines * 1.0f / cur; data = Capability::createOneValue(data.type(), Fix32(init)); return success(); } @@ -1210,34 +1398,26 @@ void huagao_ds::init_support_caps(void) } return CapSupGetAllReset(msg, data, { XferMech::Native, XferMech::File, XferMech::Memory }, m_capXferMech, XferMech::Native, (int)m_capXferMech, 0); }; - + m_query[CapType::IPixelType] = msgSupportGetAllSetReset; m_caps[CapType::IPixelType] = [this](Msg msg, Capability& data) -> Result { if (!scanner_.get()) return seqError(); - if (Msg::Reset == msg) - { - int init = 0; - scanner_->twain_get_color_mode(&init); - data = Capability::createOneValue((Twpp::PixelType)init); - msg = Msg::Set; - } - if (Msg::Set == msg) { - auto mech = data.currentItem(); - return scanner_->twain_set_color_mode((int)mech) == SCANNER_ERR_OK ? success() : badValue(); - } std::vector values; - value_limit limit = VAL_LIMIT_NONE; int init = 0, now = 0; + + GET_SANE_OPT(int, scanner_, ex_color_mode, &now, &init, &values, NULL); + if (Msg::Reset == msg || Msg::Set == msg) + { + if(Msg::Set == msg) + init = (int)data.currentItem(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_color_mode, &init); + return ret == SCANNER_ERR_OK ? success() : badValue(); + } switch (msg) { case Msg::Get: - now = scanner_->twain_get_color_mode(&init, &values, &limit); - //if (limit == VAL_LIMIT_RANGE) - //{ - // data = Capability::createRange((Twpp::PixelType)(values[0]), (Twpp::PixelType)(values[1]), (Twpp::PixelType)(1), (Twpp::PixelType)(now), (Twpp::PixelType)(init)); - // return success(); - //} - if (limit == VAL_LIMIT_ENUM) + if (1) { std::list vals; UInt32 ni, ii; @@ -1249,11 +1429,9 @@ void huagao_ds::init_support_caps(void) return cap_get_enum_values(msg, data, vals, Now, Init, ni, ii); } case Msg::GetCurrent: - now = scanner_->twain_get_color_mode(); data = Capability::createOneValue((Twpp::PixelType)now); return success(); case Msg::GetDefault: - now = scanner_->twain_get_color_mode(&init); data = Capability::createOneValue((Twpp::PixelType)init); return success(); } @@ -1264,20 +1442,30 @@ void huagao_ds::init_support_caps(void) m_caps[CapType::IAutomaticColorEnabled] = [this](Msg msg, Capability& data)->Result { if (Msg::Set == msg) { auto mech = data.currentItem(); - scanner_->twain_set_color_mode(mech ? TWPT_AUTOMATIC_COLOR : (int)PixelType::Rgb); + int ret = SCANNER_ERR_OK, val = mech ? COLOR_AUTO_MATCH : COLOR_RGB; + SET_SANE_OPT(ret, scanner_, color_mode, &val); + return success(); } - int twpt = scanner_->twain_get_color_mode() == TWPT_AUTOMATIC_COLOR ? 1 : 0; + int cur = 0; + GET_SANE_OPT(int, scanner_, color_mode, &cur, NULL, NULL, NULL); + int twpt = cur == COLOR_AUTO_MATCH ? 1 : 0; return CapSupGetAllReset(msg, data, { FALSE,TRUE }, twpt, false, twpt ? 1 : 0, 0); }; m_query[CapType::IAutomaticColorNonColorPixelType] = msgSupportGetAllSetReset; m_caps[CapType::IAutomaticColorNonColorPixelType] = [this](Msg msg, Capability& data)->Result { if (msg == Msg::Set) { - auto mech = data.currentItem(); - if (scanner_->twain_get_color_mode() == TWPT_AUTOMATIC_COLOR) { + int mech = (int)data.currentItem(); + //int now = 0; + //GET_SANE_OPT(int, scanner_, color_mode, &now, NULL, NULL, NULL); + //if (now == TWPT_AUTOMATIC_COLOR) + { if ((UInt16)mech == 0 || (UInt16)mech == 1) { - if (scanner_->twain_set_auto_color_type((int)mech) == SCANNER_ERR_OK) + int ret = SCANNER_ERR_OK, + val = mech; + SET_SANE_OPT(ret, scanner_, ex_auto_color_type, &val); + if (ret == SCANNER_ERR_OK) { automaticcolortype_ = (UInt16)mech; return success(); @@ -1291,13 +1479,23 @@ void huagao_ds::init_support_caps(void) m_query[CapType::IJpegQuality] = msgSupportGetAllSetReset; m_caps[CapType::IJpegQuality] = [this](Msg msg, Capability& data)->Result { + SANE_FinalImgFormat fif; + fif.img_format = SANE_IMAGE_TYPE_JPG; if (Msg::Set == msg) { auto mech = data.currentItem(); if ((int)mech <= 0 || (int)mech > 100) return badValue(); - return scanner_->twain_set_final_format(SANE_IMAGE_TYPE_JPG, (void*)mech) == SCANNER_ERR_OK ? success() : badValue(); + + int ret = SCANNER_ERR_OK; + fif.detail = (void*)mech; + SET_SANE_OPT(ret, scanner_, ex_final_format, &fif); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - unsigned short q = scanner_->twain_get_jpeg_quality(); + unsigned short q = 80; + fif.detail = (void*)q; + GET_SANE_OPT(SANE_FinalImgFormat, scanner_, ex_final_format, &fif, NULL, NULL, NULL); + if(fif.img_format == SANE_IMAGE_TYPE_JPG) + q = (unsigned short)fif.detail; return CapSupGetAllResetEx(msg, data, q, 80); }; @@ -1306,9 +1504,14 @@ void huagao_ds::init_support_caps(void) CapabilityPrintf(msg, enum2str(CapTypeEx::IOrientation), msg == Msg::Set ? to_string((int)data.currentItem()) : ""); if (Msg::Set == msg) { auto mech = data.currentItem(); - return scanner_->twain_set_paper_lateral(mech == Orientation::Landscape) ? success() : badValue(); + bool lateral = mech == Orientation::Landscape; + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_paper_lateral, &lateral); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - int lateral = scanner_->twain_is_paper_lateral() ? (int)Orientation::Landscape : (int)Orientation::Portrait; + bool is_lateral = false; + GET_SANE_OPT(bool, scanner_, ex_paper_lateral, &is_lateral, NULL, NULL, NULL); + int lateral = is_lateral ? (int)Orientation::Landscape : (int)Orientation::Portrait; return CapSupGetAllReset(msg, data, { Orientation::Portrait, Orientation::Landscape }, lateral, Orientation::Portrait, lateral == 0 ? 0 : 1, 0); }; @@ -1316,12 +1519,15 @@ void huagao_ds::init_support_caps(void) m_caps[CapType::IRotation] = [this](Msg msg, Capability& data) -> Result { if (Msg::Set == msg) { auto res = data.currentItem(); - return scanner_->twain_set_text_direction(res.toFloat()) == SCANNER_ERR_OK ? success() : badValue(); + float angle = res.toFloat(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_text_direction, &angle); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - double init = .0f, now = .0f; - std::list values; - value_limit limit = VAL_LIMIT_NONE; - now = scanner_->twain_get_text_direction(&init, &values, &limit); + float init = .0f, now = .0f; + std::list values; + + GET_SANE_OPT(float, scanner_, ex_text_direction, &now, &init, NULL, &values); Fix32 Init = Fix32(init), Now = Fix32(now); std::list vls; @@ -1358,9 +1564,12 @@ void huagao_ds::init_support_caps(void) m_caps[CapType::DuplexEnabled] = [this](Msg msg, Capability& data) -> Result { if (Msg::Set == msg) { bool mech = data.currentItem(); - return scanner_->twain_set_page_duplex(mech) == SCANNER_ERR_OK ? success() : badValue(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_duplex, &mech); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - BYTE dup = scanner_->twain_is_page_duplex(); + BYTE dup = 1; + GET_SANE_OPT(bool, scanner_, ex_duplex, (bool*)&dup, NULL, NULL, NULL); return CapSupGetAllReset(msg, data, dup, Bool(true)); }; @@ -1376,37 +1585,37 @@ void huagao_ds::init_support_caps(void) m_query[CapType::IImageFileFormat] = msgSupportGetAllSetReset; m_caps[CapType::IImageFileFormat] = [this](Msg msg, Capability& data) -> Result { - CapabilityPrintf(msg, enum2str(CapType::IImageFileFormat), msg == Msg::Set ? to_string((int)data.currentItem()) : ""); - if (Msg::Set == msg) { - auto mech = data.currentItem(); - SANE_ImageType type = SANE_IMAGE_TYPE_BMP; - if (mech == ImageFileFormat::Bmp) - type = SANE_IMAGE_TYPE_BMP; - else if(mech == ImageFileFormat::Tiff) - type = SANE_IMAGE_TYPE_TIFF; - else if(mech == ImageFileFormat::Jfif) - type = SANE_IMAGE_TYPE_JFIF; - else - return badValue(); - return scanner_->twain_set_final_format(type, NULL) == SCANNER_ERR_OK ? success() : badValue(); + SANE_FinalImgFormat now, init; + std::vector all; + GET_SANE_OPT(SANE_FinalImgFormat, scanner_, ex_final_format, &now, &init, &all, NULL); + if (Msg::Set == msg || Msg::Reset == msg) { + if(Msg::Set == msg) + init.img_format = (SANE_ImageType)(int)data.currentItem(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_final_format, &init); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - ImageFileFormat fmt = ImageFileFormat::Bmp; - SANE_ImageType type = scanner_->get_final_format(); - if (type == SANE_IMAGE_TYPE_TIFF) - fmt = ImageFileFormat::Tiff; - else if(type == SANE_IMAGE_TYPE_JFIF) - fmt = ImageFileFormat::Jfif; - return CapSupGetAllReset < ImageFileFormat, ImageFileFormat, CapType::IImageFileFormat>(msg, data, { ImageFileFormat::Bmp, ImageFileFormat::Tiff,ImageFileFormat::Jfif }, - fmt, ImageFileFormat::Bmp, fmt == ImageFileFormat::Bmp ? 0 : (fmt == ImageFileFormat::Tiff ? 1 : 2), 0); + ImageFileFormat Now = (ImageFileFormat)(int)now.img_format, Init = (ImageFileFormat)(int)init.img_format; + std::list vals; + UInt32 i = 0, n = 0; + for (const auto& v : all) + vals.push_back((ImageFileFormat)(int)v.img_format); + i = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), Init)); + n = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), Now)); + + return cap_get_enum_values(msg, data, vals, Now, Init, n, i); }; m_query[CapType::IAutomaticDeskew] = msgSupportGetAllSetReset; m_caps[CapType::IAutomaticDeskew] = [this](Msg msg, Capability& data)->Result { if (Msg::Set == msg) { auto atuodsw = data.currentItem(); - return scanner_->twain_set_auto_descrew((bool)atuodsw) == SCANNER_ERR_OK ? success() : seqError(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, is_auto_deskew, (bool*)&atuodsw); + return ret == SCANNER_ERR_OK ? success() : seqError(); } - BYTE ato = scanner_->twain_is_auto_descrew(); + BYTE ato = 1; + GET_SANE_OPT(bool, scanner_, is_auto_deskew, (bool*)&ato, NULL, NULL, NULL); return CapSupGetAllReset(msg, data, ato, true); }; @@ -1414,16 +1623,24 @@ void huagao_ds::init_support_caps(void) m_caps[CapType::IAutomaticRotate] = [this](Msg msg, Capability& data)->Result { if (Msg::Set == msg) { auto mech = data.currentItem(); - return scanner_->twain_set_text_auto_matic(mech) == SCANNER_ERR_OK ? success() : badValue(); + float direction = mech ? AUTO_MATIC_ROTATE : .0f; + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_text_direction, &direction); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - BYTE am = scanner_->twain_is_text_auto_matic(); + float direction = .0f; + BYTE am = 0; + GET_SANE_OPT(float, scanner_, ex_text_direction, &direction, NULL, NULL, NULL); + am = IS_DOUBLE_EQUAL(direction, AUTO_MATIC_ROTATE); return CapSupGetAllReset(msg, data, am, false); }; m_query[CapType::SerialNumber] = msgSupportGetAll; m_caps[CapType::SerialNumber] = [this](Msg msg, Capability& data)->Result { Str255 str; - scanner_->twain_get_serial_num(str.data()); + std::string v(""); + GET_SANE_OPT(std::string, scanner_, ex_serial, &v, NULL, NULL, NULL); + strcpy(str.data(), v.c_str()); return CapSupGetAll(msg, data, str, str); }; @@ -1442,9 +1659,14 @@ void huagao_ds::init_support_caps(void) CapabilityPrintf(msg, enum2str(CapType::IAutoSize), msg == Msg::Set ? to_string((int)data.currentItem()) : ""); if (Msg::Set == msg) { auto autosize = data.currentItem(); - return scanner_->twain_set_paper_auto_match_size(autosize == AutoSize::Auto) == SCANNER_ERR_OK ? success() : badValue(); + bool match = autosize == AutoSize::Auto; + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_auto_paper_size, &match); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - UInt16 size = scanner_->twain_is_paper_auto_match_size() ? (UInt16)AutoSize::Auto : (UInt16)AutoSize::None; + bool match = true; + GET_SANE_OPT(bool, scanner_, ex_auto_paper_size, &match, NULL, NULL, NULL); + UInt16 size = match ? (UInt16)AutoSize::Auto : (UInt16)AutoSize::None; return CapSupGetAllReset(msg, data, { AutoSize::None, AutoSize::Auto }, size, AutoSize::None, (size == (UInt16)AutoSize::Auto) ? 1 : 0, 0); }; @@ -1452,12 +1674,16 @@ void huagao_ds::init_support_caps(void) m_caps[CapType::IAutomaticBorderDetection] = [this](Msg msg, Capability& data)->Result { if (Msg::Set == msg) { auto autodetectborder = data.currentItem(); - return scanner_->twain_set_erase_black_frame((bool)autodetectborder) == SCANNER_ERR_OK ? success() : badValue(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, is_erase_black_frame, (bool*)&autodetectborder); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - bool val = false; + bool val = false, cur = false; Bool init = false, - erase = scanner_->twain_is_erase_black_frame(&val); + erase = false; + GET_SANE_OPT(bool, scanner_, is_erase_black_frame, &cur, &val, NULL, NULL); init = val; + erase = cur; return CapSupGetAllReset(msg, data, { false,true }, erase, init, erase ? 1 : 0, 0); }; @@ -1465,10 +1691,14 @@ void huagao_ds::init_support_caps(void) m_caps[CapType::IAutoDiscardBlankPages] = [this](Msg msg, Capability& data)->Result { if (Msg::Set == msg) { auto mech = data.currentItem(); - return scanner_->twain_set_page_discarding_blank_page(mech == DiscardBlankPages::Auto, false) == SCANNER_ERR_OK ? success() : badValue(); + bool discard = mech == DiscardBlankPages::Auto; + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_discard_blank_page, &discard); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - DiscardBlankPages autodiscradblank = scanner_->twain_is_page_discarding_blank_page(false) ? - DiscardBlankPages::Auto : DiscardBlankPages::Disabled; + bool discard = false; + GET_SANE_OPT(bool, scanner_, ex_discard_blank_page, &discard, NULL, NULL, NULL); + DiscardBlankPages autodiscradblank = discard ? DiscardBlankPages::Auto : DiscardBlankPages::Disabled; return CapSupGetAllReset(msg, data, autodiscradblank, DiscardBlankPages::Disabled); }; @@ -1476,67 +1706,81 @@ void huagao_ds::init_support_caps(void) m_caps[(CapType)CAP_TYPE_EX_DISCARD_BLANK_RECEIPT] = [this](Msg msg, Capability& data)->Result { if (Msg::Set == msg) { auto mech = data.currentItem(); - return scanner_->twain_set_page_discarding_blank_page(mech == DiscardBlankPages::Auto, true) == SCANNER_ERR_OK ? success() : badValue(); + bool discard = mech == DiscardBlankPages::Auto; + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_discard_blank_receipt, &discard); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - DiscardBlankPages autodiscradblank = scanner_->twain_is_page_discarding_blank_page(true) ? - DiscardBlankPages::Auto : DiscardBlankPages::Disabled; + bool discard = false; + GET_SANE_OPT(bool, scanner_, ex_discard_blank_receipt, &discard, NULL, NULL, NULL); + DiscardBlankPages autodiscradblank = discard ? DiscardBlankPages::Auto : DiscardBlankPages::Disabled; return CapSupGetAllResetEx(msg, data, autodiscradblank, DiscardBlankPages::Disabled); + // return success(); }; m_query[CapType::IFilter] = msgSupportGetAllSetReset; m_caps[CapType::IFilter] = [this](Msg msg, Capability& data)->Result { if (Msg::Set == msg) { auto mech = data.currentItem(); - return scanner_->twain_set_filter((int)mech, false) == SCANNER_ERR_OK ? success() : badValue(); + int ret = SCANNER_ERR_OK, val = to_sane_filter((Filter)mech); + SET_SANE_OPT(ret, scanner_, ex_color_filter, &val); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - BYTE f = (BYTE)scanner_->twain_get_filter(false); - UInt32 ind = 3; - if (f == (BYTE)Filter::Red) - ind = 0; - else if (f == (BYTE)Filter::Green) - ind = 1; - else if (f == (BYTE)Filter::Blue) - ind = 2; - return CapSupGetAllReset(msg, data, { Filter::Red, Filter::Green,Filter::Blue,Filter::None }, f, Filter::None, ind, 3); - }; + int cur = FILTER_NONE, def = FILTER_NONE; + std::vector vals; + GET_SANE_OPT(int, scanner_, ex_color_filter, &cur, &def, &vals, NULL); - m_query[(CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR] = msgSupportGetAllSetReset; - m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR] = [this](Msg msg, Capability& data)->Result { - if (Msg::Set == msg) { - auto mech = data.currentItem(); - return scanner_->twain_set_filter((int)mech, true) == SCANNER_ERR_OK ? success() : badValue(); + std::list vs; + Filter now = Filter::None, init = Filter::None; + UInt32 curInd = 0, defInd = 0, ind = 0; + + for (auto& v : vals) + { + vs.push_back(from_sane_filter(v)); + if (v == cur) + { + curInd = ind; + now = from_sane_filter(v); + } + else if (v == def) + { + defInd = ind; + init = from_sane_filter(v); + } + ind++; } - BYTE f = (BYTE)scanner_->twain_get_filter(true); - UInt32 ind = 3; - if (f == ENHANCE_COLOR_RED) - ind = 0; - else if (f == ENHANCE_COLOR_GREEN) - ind = 1; - else if (f == ENHANCE_COLOR_BLUE) - ind = 2; - return CapSupGetAllResetEx(msg, data, { Filter::Red, Filter::Green,Filter::Blue,Filter::None }, f, Filter::None, ind, 3); + BYTE f = (BYTE)now; + return CapSupGetAllReset(msg, data, vs, f, init, curInd, defInd); }; m_query[CapType::IBrightness] = msgSupportGetAllSetReset; m_caps[CapType::IBrightness] = [this](Msg msg, Capability& data)->Result { - double init = .0f, l = .0f, u = .0f, step = .0f, - now = scanner_->twain_get_bright(&init, &l, &u, &step); + int init = 128, l = 1, u = 255, step = 1, now = 128; + int ret = SCANNER_ERR_OK; + GET_SANE_OPT_RANGE(int, scanner_, bright, &now, &init, &l, &u, &step); + float sf = trans_range(step, l, u, -1000.0f, 1000.0f), + nf = trans_range(now, l, u, -1000.0f, 1000.0f), + initf = trans_range(init, l, u, -1000.0f, 1000.0f); switch (msg) { case Msg::Get: - data = Capability::createRange(Fix32(l), Fix32(u), Fix32(step), Fix32(now), Fix32(init)); + data = Capability::createRange(Fix32(-1000.0f), Fix32(1000.0f), Fix32(sf), Fix32(nf), Fix32(initf)); return success(); case Msg::GetCurrent: - data = Capability::createOneValue(Fix32(now)); + data = Capability::createOneValue(Fix32(nf)); return success(); case Msg::GetDefault: - case Msg::Reset: - data = Capability::createOneValue(Fix32(init)); + data = Capability::createOneValue(Fix32(initf)); return success(); + case Msg::Reset: + data = Capability::createOneValue(Fix32(initf)); case Msg::Set: { auto mech = data.currentItem(); - if (mech > u || mech < -l) + if (mech > 1000.0f || mech < -1000.0f) return badValue(); - return scanner_->twain_set_bright(mech.toFloat()) == SCANNER_ERR_OK ? success() : badValue(); + sf = mech.toFloat(); + now = trans_range(sf, -1000.0f, 1000.0f, l, u) + .5f; + SET_SANE_OPT(ret, scanner_, bright, &now); + return ret == SCANNER_ERR_OK ? success() : badValue(); } default: return capBadOperation(); @@ -1545,24 +1789,68 @@ void huagao_ds::init_support_caps(void) m_query[CapType::IContrast] = msgSupportGetAllSetReset; m_caps[CapType::IContrast] = [this](Msg msg, Capability& data)->Result { - double init = .0f, l = .0f, u = .0f, step = .0f, - now = scanner_->twain_get_contrast(&init, &l, &u, &step); + int init = 4, l = 1, u = 7, step = 1, now = 4; + int ret = SCANNER_ERR_OK; + GET_SANE_OPT_RANGE(int, scanner_, contrast, &now, &init, &l, &u, &step); + float sf = trans_range(step, l, u, -1000.0f, 1000.0f), + nf = trans_range(now, l, u, -1000.0f, 1000.0f), + initf = trans_range(init, l, u, -1000.0f, 1000.0f); switch (msg) { case Msg::Get: - data = Capability::createRange(Fix32(l), Fix32(u), Fix32(step), Fix32(now), Fix32(init)); + data = Capability::createRange(Fix32(-1000.0f), Fix32(1000.0f), Fix32(sf), Fix32(nf), Fix32(initf)); return success(); case Msg::GetCurrent: - data = Capability::createOneValue(Fix32(now)); + data = Capability::createOneValue(Fix32(nf)); return success(); case Msg::GetDefault: - case Msg::Reset: - data = Capability::createOneValue(Fix32(init)); + data = Capability::createOneValue(Fix32(initf)); return success(); + case Msg::Reset: + data = Capability::createOneValue(Fix32(initf)); case Msg::Set: { auto mech = data.currentItem(); - if (mech > u || mech < -l) + if (mech > 1000.0f || mech < -1000.0f) return badValue(); - return scanner_->twain_set_contrast(mech.toFloat()) == SCANNER_ERR_OK ? success() : badValue(); + sf = mech.toFloat(); + now = trans_range(sf, -1000.0f, 1000.0f, l, u) + .5f; + SET_SANE_OPT(ret, scanner_, contrast, &now); + return ret == SCANNER_ERR_OK ? success() : badValue(); + } + default: + return capBadOperation(); + } + }; + + m_query[(CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO] = msgSupportGetAllSetReset; + m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO] = [this](Msg msg, Capability& data)->Result { + float init = .0f, l = .0f, u = .0f, step = .0f, now = .0f; + int ret = SCANNER_ERR_OK; + GET_SANE_OPT_RANGE(float, scanner_, search_hole_range, &now, &init, &l, &u, &step); + init *= 100; init += .5f; + l *= 100; l += .5f; + u *= 100; u += .5f; + step *= 100; step += .5f; + now *= 100; now += .5f; + switch (msg) { + case Msg::Get: + data = Capability::createRange((CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO, UInt32(l), UInt32(u), UInt32(step), UInt32(now), UInt32(init)); + return success(); + case Msg::GetCurrent: + data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO, UInt32(now)); + return success(); + case Msg::GetDefault: + data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO, UInt32(init)); + return success(); + case Msg::Reset: + data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO, UInt32(init)); + case Msg::Set: { + auto mech = data.currentItem(); + if (mech > u || mech < l) + return badValue(); + float v = mech; + v /= 100.0f; + SET_SANE_OPT(ret, scanner_, search_hole_range, &v); + return ret == SCANNER_ERR_OK ? success() : badValue(); } default: return capBadOperation(); @@ -1571,8 +1859,9 @@ void huagao_ds::init_support_caps(void) m_query[CapType::IGamma] = msgSupportGetAllSetReset; m_caps[CapType::IGamma] = [this](Msg msg, Capability& data)->Result { - double init = .0f, l = .0f, u = .0f, step = .0f, - now = scanner_->twain_get_gamma(&init, &l, &u, &step); + float init = .0f, l = .0f, u = .0f, step = .0f, now = .0f; + int ret = SCANNER_ERR_OK; + GET_SANE_OPT_RANGE(float, scanner_, gamma, &now, &init, &l, &u, &step); switch (msg) { case Msg::Get: data = Capability::createRange(Fix32(l), Fix32(u), Fix32(step), Fix32(now), Fix32(init)); @@ -1588,7 +1877,9 @@ void huagao_ds::init_support_caps(void) auto mech = data.currentItem(); if (mech > u || mech < l) return badValue(); - return scanner_->twain_set_gamma(mech.toFloat()) == SCANNER_ERR_OK ? success() : badValue(); + now = mech.toFloat(); + SET_SANE_OPT(ret, scanner_, gamma, &now); + return ret == SCANNER_ERR_OK ? success() : badValue(); } default: return capBadOperation(); @@ -1604,22 +1895,30 @@ void huagao_ds::init_support_caps(void) m_caps[CapType::DoubleFeedDetection] = [this](Msg msg, Capability& data)->Result { if (Msg::Set == msg) { auto atuodsw = data.currentItem(); - return scanner_->twain_set_ultrasonic_check((bool)atuodsw) == SCANNER_ERR_OK ? success() : seqError(); + int ret = SCANNER_ERR_OK; + bool enable = atuodsw == DoubleFeedDetection::Ultrasonic; + SET_SANE_OPT(ret, scanner_, is_ultrasonic_check, &enable); + return ret == SCANNER_ERR_OK ? success() : seqError(); } DoubleFeedDetection init = DoubleFeedDetection::Ultrasonic; - BYTE ato = scanner_->twain_is_ultrasonic_check(); + bool enable = true, def = true; + GET_SANE_OPT(bool, scanner_, is_ultrasonic_check, &enable, &def, NULL, NULL); + BYTE ato = !enable; + init = def ? DoubleFeedDetection::Ultrasonic : DoubleFeedDetection::ByLength; return CapSupGetAllReset(msg, data, ato, init); }; m_query[CapType::IAutomaticCropUsesFrame] = msgSupportGetAll; m_caps[CapType::IAutomaticCropUsesFrame] = [this](Msg msg, Capability& data)->Result { - BYTE crop = scanner_->twain_is_auto_crop(); + bool yes = false; + GET_SANE_OPT(bool, scanner_, ex_is_paper_auto_crop, &yes, NULL, NULL, NULL); + BYTE crop = yes; return CapSupGetAll(msg, data, crop, false); }; m_query[CapType::FeederLoaded] = msgSupportGetAll; m_caps[CapType::FeederLoaded] = [this](Msg msg, Capability& data) -> Result { - Bool paperon = scanner_->twain_is_paper_on(); + Bool paperon = scanner_->is_paper_on(); return CapSupGetAll(msg, data, paperon, paperon); }; @@ -1639,59 +1938,76 @@ void huagao_ds::init_support_caps(void) auto fold = data.currentItem(); if (msg == Msg::Reset) fold = false; - return scanner_->twain_set_page_fold(fold) == SCANNER_ERR_OK ? success() : badValue(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_is_page_fold, &fold); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - BYTE fold = scanner_->twain_is_page_fold(); + bool yes = false; + GET_SANE_OPT(bool, scanner_, ex_is_page_fold, &yes, NULL, NULL, NULL); + BYTE fold = yes; return CapSupGetAllResetEx(msg, data, fold, 0); }; - m_query[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = msgSupportGetAllSetReset; - m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = [this](Msg msg, Capability& data)->Result { - if (Msg::Set == msg) { - auto mech = data.currentItem(); - return scanner_->twain_set_sharpen((int)mech) == SCANNER_ERR_OK ? success() : badValue(); - } - BYTE f = (BYTE)scanner_->twain_get_sharpen(); - return CapSupGetAllResetEx(msg, data, { 0, 1, 2, 3, 4}, f, 0, f, 0); - }; - m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST)] = msgSupportGetAllSetReset; m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST)] = [this](Msg msg, Capability& data)->Result { - if (Msg::Set == msg) { + int now = 10, init = 10, l = 0, u = 100, s = 10; + GET_SANE_OPT_RANGE(int, scanner_, dogear_size, &now, &init, &l, &u, &s); + if (Msg::Set == msg || Msg::Reset == msg) { auto mech = data.currentItem(); if (mech < 10 || mech > 300) return badValue(); - return scanner_->twain_set_dogear_distance(mech) == SCANNER_ERR_OK ? success() : badValue(); + int ret = SCANNER_ERR_OK; + int val = trans_range(mech, 10, 300, l, u) + .5f; + SET_SANE_OPT(ret, scanner_, dogear_size, &val); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - UInt32 init = 50, - now = scanner_->twain_get_dogear_distance(); + UInt32 Now = trans_range(now, l, u, 10, 300) + .5f, + Init = trans_range(init, l, u, 10, 300) + .5f; - return CapSupGetAllResetEx(msg, data, now, init); + return CapSupGetAllResetEx(msg, data, Now, Init); }; - m_query[CapType(CapTypeEx::CAP_TYPE_EX_MULTI_OUT)] = msgSupportGetAllSetReset; - m_caps[CapType(CapTypeEx::CAP_TYPE_EX_MULTI_OUT)] = [this](Msg msg, Capability& data)->Result { - if (Msg::Set == msg || Msg::Reset == msg) { - auto multi = data.currentItem(); - if (msg == Msg::Reset) - multi = false; - multi_out_ = multi; - return success(); + m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_CROP_MODEL)] = msgSupportGetAllSetReset; + m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_CROP_MODEL)] = [this](Msg msg, Capability& data)->Result { + bool cur = false, def = false; + GET_SANE_OPT(bool, scanner_, ex_is_paper_auto_crop, &cur, &def, NULL, NULL); + if (Msg::Set == msg || Msg::Reset == msg) + { + if (Msg::Set == msg) + def = data.currentItem() == 1; + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_is_paper_auto_crop, &def); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - BYTE multi = multi_out_; - return CapSupGetAllResetEx(msg, data, multi, 0); + BYTE crop = cur; + return CapSupGetAll(msg, data, crop, def); }; m_query[(CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE] = msgSupportGetAllSetReset; m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE] = [this](Msg msg, Capability& data)->Result { + int cur = MULTI_OUT_NONE, def = MULTI_OUT_NONE; + std::vector all; + GET_SANE_OPT(int, scanner_, ex_multiout_type, &cur, &def, &all, NULL); if (Msg::Set == msg || Msg::Reset == msg) { auto mech = data.currentItem(); if (msg == Msg::Reset) - mech = -1; - return scanner_->twain_set_multioutput_type((int)mech) == SCANNER_ERR_OK ? success() : badValue(); + mech = def; + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_multiout_type, &mech); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - UInt32 f = (UInt32)scanner_->twain_get_multioutput_type(); - return CapSupGetAllResetEx(msg, data, { (UInt32)-1, 0, 1, 2, 3 }, f, -1, 0, 0); + Int32 now = cur, init = def, ind = 0, curInd = 0, defInd = 0; + std::list vals; + for (auto& v : all) + { + vals.push_back(v); + if (v == cur) + curInd = ind; + else if (v == def) + defInd = ind; + ind++; + } + return CapSupGetAllResetEx(msg, data, vals, now, init, curInd, defInd); }; m_query[CapType(CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN)] = msgSupportGetAllSetReset; @@ -1700,9 +2016,13 @@ void huagao_ds::init_support_caps(void) auto tobe = data.currentItem(); if (msg == Msg::Reset) tobe = false; - return scanner_->twain_set_to_be_scan(tobe) == SCANNER_ERR_OK ? success() : seqError(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_to_be_scan, &tobe); + return ret == SCANNER_ERR_OK ? success() : seqError(); } - BYTE tobe = scanner_->twain_get_to_be_scan(); + bool val = false; + GET_SANE_OPT(bool, scanner_, ex_to_be_scan, &val, NULL, NULL, NULL); + BYTE tobe = val; return CapSupGetAllResetEx(msg, data, tobe, 0); }; @@ -1712,61 +2032,155 @@ void huagao_ds::init_support_caps(void) auto tobe = data.currentItem(); if (msg == Msg::Reset) tobe = false; - return scanner_->twain_set_scan_with_hole(tobe) == SCANNER_ERR_OK ? success() : seqError(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_scan_with_hole, &tobe); + return ret == SCANNER_ERR_OK ? success() : seqError(); } - BYTE tobe = scanner_->twain_get_scan_with_hole(); + bool val = false; + GET_SANE_OPT(bool, scanner_, ex_scan_with_hole, &val, NULL, NULL, NULL); + BYTE tobe = val; return CapSupGetAllResetEx(msg, data, tobe, 0); }; - char code[256] = { 0 }; - unsigned int len = _countof(code); - if (scanner_->twain_get_device_code(code, len) == SCANNER_ERR_OK) - { - m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = msgSupportGetAll; - m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = [this](Msg msg, Capability& data)->Result { - char code[256] = { 0 }; - unsigned int len = _countof(code); - Str255 str; - scanner_->twain_get_device_code(code, len); - str.setData(code, 32); - data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_ENCODE, str); - return success(); - }; - } + m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = msgSupportGetAll; + m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = [this](Msg msg, Capability& data)->Result { + std::string code(""); + GET_SANE_OPT(std::string, scanner_, ex_device_code, &code, NULL, NULL, NULL); + Str255 str; + str.setData(code.c_str(), 32); + data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_ENCODE, str); + return success(); + }; m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_POWER_LEVEL)] = msgSupportGetAllSetReset; m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_POWER_LEVEL)] = [this](Msg msg, Capability& data)->Result { - UInt32 init = 4; + int cur = SANE_POWER_MINUTES_30, def = SANE_POWER_MINUTES_30; + std::vector all; + GET_SANE_OPT(int, scanner_, ex_power, &cur, &def, &all, NULL); if (Msg::Set == msg || Msg::Reset == msg) { if(msg == Msg::Set) - init = data.currentItem(); - scanner_->twain_set_power_level(init); - return success(); + def = data.currentItem(); + + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_power, &def); + return ret == SCANNER_ERR_OK ? success() : badValue(); } - UInt32 level = scanner_->twain_get_power_level(); - return CapSupGetAllResetEx(msg, data, level, init); + UInt32 now = cur, init = def, ind = 0, curInd = 0, defInd = 0; + std::list vals; + for (auto& v : all) + { + vals.push_back(v); + if (v == cur) + curInd = ind; + else if (v == def) + defInd = ind; + ind++; + } + return CapSupGetAllResetEx(msg, data, vals, now, init, curInd, defInd); + }; + + m_query[(CapType)CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD] = msgSupportGetAllSetReset; + m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto convex = data.currentItem(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_fill_background, (bool*)&convex); + return ret == SCANNER_ERR_OK ? success() : badValue(); + } + bool val = false, cur = false; + Bool init = false, + erase = false; + GET_SANE_OPT(bool, scanner_, ex_fill_background, &cur, &val, NULL, NULL); + init = val; + erase = cur; + return CapSupGetAllResetEx(msg, data, { false,true }, erase, init, erase ? 1 : 0, 0); + }; + + m_query[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = msgSupportGetAllSetReset; + m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = [this](Msg msg, Capability& data)->Result { + int cur = MULTI_OUT_NONE, def = MULTI_OUT_NONE; + std::vector all; + GET_SANE_OPT(int, scanner_, ex_sharpen, &cur, &def, &all, NULL); + if (Msg::Set == msg || Msg::Reset == msg) { + auto mech = data.currentItem(); + if (msg == Msg::Reset) + mech = def; + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_sharpen, &mech); + return ret == SCANNER_ERR_OK ? success() : badValue(); + } + Int32 now = cur, init = def, ind = 0, curInd = 0, defInd = 0; + std::list vals; + for (auto& v : all) + { + vals.push_back(v); + if (v == cur) + curInd = ind; + else if (v == def) + defInd = ind; + ind++; + } + return CapSupGetAllResetEx(msg, data, vals, now, init, curInd, defInd); + }; + //SET_EXISTING_EXTENSION(ex_color_enhance, (CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR); + m_query[(CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR] = msgSupportGetAllSetReset; + m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR] = [this](Msg msg, Capability& data)->Result { + int cur = FILTER_NONE, def = FILTER_NONE; + std::vector vals; + GET_SANE_OPT(int, scanner_, ex_color_enhance, &cur, &def, &vals, NULL); + if (Msg::Set == msg || Msg::Reset == msg) { + if(Msg::Set == msg) + def = data.currentItem(); + int ret = SCANNER_ERR_OK; + SET_SANE_OPT(ret, scanner_, ex_color_filter, &def); + return ret == SCANNER_ERR_OK ? success() : badValue(); + } + + std::list vs; + Filter now = from_sane_filter(cur), init = from_sane_filter(def); + UInt32 curInd = 0, defInd = 0, ind = 0; + + for (auto& v : vals) + { + vs.push_back(from_sane_filter(v)); + if (v == cur) + { + curInd = ind; + } + else if (v == def) + { + defInd = ind; + } + ind++; + } + UInt32 val = (UInt32)now; + return CapSupGetAllResetEx(msg, data, vs, val, init, curInd, defInd); }; init_support_caps_ex(); m_query[(CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION] = msgSupportGetAll; m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION] = [this](Msg msg, Capability& data)->Result { + std::string ver(""); + GET_SANE_OPT(std::string, scanner_, ex_hardware_version, &ver, NULL, NULL, NULL); Str255 str; - scanner_->twain_get_hareware_version(str.data()); + strcpy(str.data(), ver.c_str()); data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION, str); - return success(); // CapSupGetAllEx(msg, data, str, str); + return success(); }; m_query[(CapType)CapTypeEx::CAP_TYPE_EX_IP] = msgSupportGetAll; m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_IP] = [this](Msg msg, Capability& data)->Result { + std::string ip(""); + GET_SANE_OPT(std::string, scanner_, ex_ip, &ip, NULL, NULL, NULL); Str255 str; - scanner_->twain_get_ip(str.data()); + strcpy(str.data(), ip.c_str()); data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_IP, str); return success(); // CapSupGetAll(msg, data, str, str); }; #define SET_EXISTING_EXTENSION(scan_ind, cap) \ - op_ind = scanner_->##scan_ind(); \ + op_ind = scanner_->sane_opt_id_##scan_ind();\ if(op_ind != -1) \ { \ m_query[(CapType)cap] = msgSupportGetAllSetReset; \ @@ -1774,29 +2188,32 @@ void huagao_ds::init_support_caps(void) } int op_ind = -1; - SET_EXISTING_EXTENSION(twain_get_paper_ind, CapType::ISupportedSizes); - SET_EXISTING_EXTENSION(twain_get_flip_ind, CapTypeEx::CAP_TYPE_EX_FLIP); - SET_EXISTING_EXTENSION(twain_get_rotate_bkg_ind, CapTypeEx::CAP_TYPE_EX_ROTATE_BKG_180); - SET_EXISTING_EXTENSION(twain_get_fill_black_bkg_ind, CapTypeEx::CAP_TYPE_EX_FILL_BLACK_BKG); - SET_EXISTING_EXTENSION(twain_get_edge_ident_ind, CapTypeEx::CAP_TYPE_EX_EDGE_IDENT); - SET_EXISTING_EXTENSION(twain_get_threshold_ind, CapTypeEx::CAP_TYPE_EX_THRESHOLD); - SET_EXISTING_EXTENSION(twain_get_threshold_ind, CapTypeEx::CAP_TYPE_EX_THRESHOLD_1); - SET_EXISTING_EXTENSION(twain_bkg_filling_method_ind, CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD); - SET_EXISTING_EXTENSION(twain_fill_hole_ind, CapTypeEx::CAP_TYPE_EX_FILL_HOLE); - SET_EXISTING_EXTENSION(twain_fill_hole_ratio_ind, CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO); - SET_EXISTING_EXTENSION(twain_detach_noise_ind, CapTypeEx::CAP_TYPE_EX_DETACH_NOISE); - SET_EXISTING_EXTENSION(twain_detach_noise_threshold_ind, CapTypeEx::CAP_TYPE_EX_DETACH_NOISE_THRESHOLD); - SET_EXISTING_EXTENSION(twain_rid_red_ind, CapTypeEx::CAP_TYPE_EX_RID_RED); - SET_EXISTING_EXTENSION(twain_rid_red_hsv_ind, CapTypeEx::CAP_TYPE_EX_RID_RED_HSV); - SET_EXISTING_EXTENSION(twain_screw_detect_ind, CapTypeEx::CAP_TYPE_EX_SCREW_DETECT); - SET_EXISTING_EXTENSION(twain_screw_detect_level_ind, CapTypeEx::CAP_TYPE_EX_SCREW_DETECT_LEVEL); - SET_EXISTING_EXTENSION(twain_staple_detect_ind, CapTypeEx::CAP_TYPE_EX_STAPLE_DETECT); - SET_EXISTING_EXTENSION(twain_dogear_detect_ind, CapTypeEx::CAP_TYPE_EX_DOGEAR_DETECT); - SET_EXISTING_EXTENSION(twain_dark_sample_ind, CapTypeEx::CAP_TYPE_EX_DARK_SAMPLE); - SET_EXISTING_EXTENSION(twain_image_split_ind, CapTypeEx::CAP_TYPE_EX_IMAGE_SPLIT); - SET_EXISTING_EXTENSION(twain_fade_bkground_ind, CapTypeEx::CAP_TYPE_EX_FADE_BKG); - SET_EXISTING_EXTENSION(twain_fade_bkground_val_ind, CapTypeEx::CAP_TYPE_EX_FADE_BKG_VALUE); - SET_EXISTING_EXTENSION(twain_size_detect_ind, CapTypeEx::CAP_TYPE_EX_SIZE_DETECT); + // SET_EXISTING_EXTENSION(paper, CapType::ISupportedSizes); + SET_EXISTING_EXTENSION(is_swap, CapTypeEx::CAP_TYPE_EX_FLIP); + SET_EXISTING_EXTENSION(is_rotate_bkg180, CapTypeEx::CAP_TYPE_EX_ROTATE_BKG_180); + SET_EXISTING_EXTENSION(is_filling_color, CapTypeEx::CAP_TYPE_EX_FILL_BLACK_BKG); + SET_EXISTING_EXTENSION(margin, CapTypeEx::CAP_TYPE_EX_EDGE_IDENT); + SET_EXISTING_EXTENSION(anti_noise, CapTypeEx::CAP_TYPE_EX_ANTI_NOISE); + SET_EXISTING_EXTENSION(threshold, CapTypeEx::CAP_TYPE_EX_THRESHOLD); + SET_EXISTING_EXTENSION(is_erase_hole, CapTypeEx::CAP_TYPE_EX_FILL_HOLE); + //SET_EXISTING_EXTENSION(ex_fill_background, CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD); + //SET_EXISTING_EXTENSION(ex_sharpen, (CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN); + //SET_EXISTING_EXTENSION(ex_color_enhance, (CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR); + //SET_EXISTING_EXTENSION(search_hole_range, CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO); + SET_EXISTING_EXTENSION(is_noise_modify, CapTypeEx::CAP_TYPE_EX_DETACH_NOISE); + SET_EXISTING_EXTENSION(noise_threshold, CapTypeEx::CAP_TYPE_EX_DETACH_NOISE_THRESHOLD); + SET_EXISTING_EXTENSION(erase_multiout_red, CapTypeEx::CAP_TYPE_EX_RID_RED); + SET_EXISTING_EXTENSION(erase_paper_red, CapTypeEx::CAP_TYPE_EX_RID_RED_HSV); + SET_EXISTING_EXTENSION(is_check_skew, CapTypeEx::CAP_TYPE_EX_SCREW_DETECT); + SET_EXISTING_EXTENSION(skew_range, CapTypeEx::CAP_TYPE_EX_SCREW_DETECT_LEVEL); + SET_EXISTING_EXTENSION(is_check_staple, CapTypeEx::CAP_TYPE_EX_STAPLE_DETECT); + SET_EXISTING_EXTENSION(is_check_dogear, CapTypeEx::CAP_TYPE_EX_DOGEAR_DETECT); + SET_EXISTING_EXTENSION(deep_sample, CapTypeEx::CAP_TYPE_EX_DARK_SAMPLE); + SET_EXISTING_EXTENSION(is_split, CapTypeEx::CAP_TYPE_EX_IMAGE_SPLIT); + SET_EXISTING_EXTENSION(is_erase_background, CapTypeEx::CAP_TYPE_EX_FADE_BKG); + SET_EXISTING_EXTENSION(background_color_range, CapTypeEx::CAP_TYPE_EX_FADE_BKG_VALUE); + SET_EXISTING_EXTENSION(is_size_check, CapTypeEx::CAP_TYPE_EX_SIZE_DETECT); + SET_EXISTING_EXTENSION(is_multiout, CapTypeEx::CAP_TYPE_EX_MULTI_OUT); } void huagao_ds::init_support_caps_ex(void) { @@ -1805,17 +2222,21 @@ void huagao_ds::init_support_caps_ex(void) m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \ if (!scanner_.get()) \ return seqError(); \ - if(msg == Msg::Set) { \ - ctype item; \ - copy_type(item, data.currentItem()); \ - return scanner_->set_value(sn, item) == SCANNER_ERR_OK ? success() : badValue(); \ - } \ std::list org; \ ctype now, init; \ std::list vals; \ ttype Now, Init; \ UInt32 ni, ii; \ - scanner_->get_value(sn, org, now, init); \ + sane_opts::get_opts op(&now, &init, NULL, &org); \ + scanner_->get_value(sn, sane_opts::set_opt_value, &op);\ + if(msg == Msg::Set || msg == Msg::Reset) { \ + ctype item; \ + if(msg == Msg::Reset) \ + item = init; \ + else \ + copy_type(item, data.currentItem()); \ + return scanner_->set_value(sn, &item) == SCANNER_ERR_OK ? success() : badValue(); \ + } \ ni = std::distance(org.begin(), std::find(org.begin(), org.end(), now)); \ ii = std::distance(org.begin(), std::find(org.begin(), org.end(), init)); \ copy_type(Now, now); \ @@ -1832,13 +2253,16 @@ void huagao_ds::init_support_caps_ex(void) m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \ if (!scanner_.get()) \ return seqError(); \ - if(msg == Msg::Set) { \ - ctype item = (ctype)data.currentItem(); \ - return scanner_->set_value(sn, item) == SCANNER_ERR_OK ? success() : badValue(); \ - } \ ctype now, init, lower, upper, step; \ ttype Now, Init, Lower, Upper, Step; \ - scanner_->get_value(sn, now, init, &lower, &upper, &step); \ + sane_opts::get_opts op(&now, &init, NULL, NULL, &lower, &upper, &step); \ + scanner_->get_value(sn, sane_opts::set_opt_value, &op); \ + if(msg == Msg::Set || msg == Msg::Reset) { \ + ctype item = (ctype)data.currentItem(); \ + if(msg == Msg::Reset) \ + item = init; \ + return scanner_->set_value(sn, &item) == SCANNER_ERR_OK ? success() : badValue(); \ + } \ copy_type(Now, now); \ copy_type(Init, init); \ copy_type(Lower, lower); \ @@ -1853,11 +2277,11 @@ void huagao_ds::init_support_caps_ex(void) return seqError(); \ if(msg == Msg::Set) { \ auto item = data.currentItem(); \ - return scanner_->set_value(sn, (bool)item) == SCANNER_ERR_OK ? success() : badValue(); \ + return scanner_->set_value(sn, (bool*)&item) == SCANNER_ERR_OK ? success() : badValue(); \ } \ bool init = false, now = false; \ - std::list vals; \ - scanner_->get_value(sn, vals, now, init); \ + sane_opts::get_opts op(&now, &init, NULL, NULL); \ + scanner_->get_value(sn, sane_opts::set_opt_value, &op); \ BYTE v = now; \ return CapSupGetAllResetEx(msg, data, v, init); \ }; @@ -1867,64 +2291,85 @@ void huagao_ds::init_support_caps_ex(void) m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \ if (!scanner_.get()) \ return seqError(); \ - if(msg == Msg::Set) { \ - ctype item = (ctype)data.currentItem(); \ - return scanner_->set_value(sn, item) == SCANNER_ERR_OK ? success() : badValue(); \ - } \ ctype now, init; \ ttype Now, Init; \ - scanner_->get_value(sn, now, init); \ + sane_opts::get_opts op(&now, &init); \ + scanner_->get_value(sn, sane_opts::set_opt_value, &op); \ + if(msg == Msg::Set || msg == Msg::Reset) { \ + ctype item; \ + copy_type(item, data.currentItem()); \ + if(msg == Msg::Reset) \ + item = init; \ + return scanner_->set_value(sn, &item) == SCANNER_ERR_OK ? success() : badValue(); \ + } \ copy_type(Now, now); \ copy_type(Init, init); \ return cap_get_one_value(msg, data, Now, Init, NULL, NULL, NULL); \ }; #define ADD_CAP(sn) \ -{ \ - std::string data_type(""); \ - value_limit vl = VAL_LIMIT_NONE; \ - if(!scanner_->get_value_info(sn, data_type, vl)) \ - return; \ - if(data_type == "bool") \ { \ - SET_BOOL(sn, CAP_TYPE_EX_##sn); \ - } \ - else if(data_type == "int") \ - { \ - if(vl == VAL_LIMIT_RANGE) \ - { SET_CAP_RANGE(sn, int, UInt32, CAP_TYPE_EX_##sn); } \ - else \ - { SET_CAP(sn, int, UInt32, CAP_TYPE_EX_##sn); } \ - } \ - else if(data_type == "float") \ - { \ - if(vl == VAL_LIMIT_RANGE) \ - { SET_CAP_RANGE(sn, float, Fix32, CAP_TYPE_EX_##sn); } \ - else \ - { SET_CAP(sn, float, Fix32, CAP_TYPE_EX_##sn); } \ - } \ - else if(data_type == "string") \ - { \ - if(vl == VAL_LIMIT_ENUM) \ - { SET_CAP_ENUM(sn, std::string, Twpp::Str64, CAP_TYPE_EX_##sn); } \ - } \ - else if(data_type == "button") \ - { \ - m_query[(CapType)CAP_TYPE_EX_##sn] = MsgSupport::Set | MsgSupport::Reset; \ - m_caps[(CapType)CAP_TYPE_EX_##sn] = [this](Msg msg, Capability& data) -> Result { \ - if (!scanner_.get()) \ - return seqError(); \ - if(msg == Msg::Set) { \ - scanner_->set_value(sn, false); \ - return success(); \ - } \ - return enmGet(msg, data, true); \ - }; \ - } \ -} + value_limit vl = VAL_LIMIT_NONE; \ + value_type type = VAL_TYPE_NONE; \ + int bytes = 0; \ + if(!scanner_->get_option_info(sn, &type, &vl, &bytes)) \ + return; \ + if(type == VAL_TYPE_BOOL) \ + { \ + SET_BOOL(sn, CAP_TYPE_EX_##sn); \ + } \ + else if(type == VAL_TYPE_INT) \ + { \ + if(vl == VAL_LIMIT_RANGE) \ + { SET_CAP_RANGE(sn, int, Int32, CAP_TYPE_EX_##sn); } \ + else if(vl == VAL_LIMIT_ENUM) \ + { SET_CAP_ENUM(sn, int, Int32, CAP_TYPE_EX_##sn); } \ + else \ + { SET_CAP(sn, int, Int32, CAP_TYPE_EX_##sn); } \ + } \ + else if(type == VAL_TYPE_FLOAT) \ + { \ + if(vl == VAL_LIMIT_RANGE) \ + { SET_CAP_RANGE(sn, float, Fix32, CAP_TYPE_EX_##sn); } \ + else if(vl == VAL_LIMIT_ENUM) \ + { SET_CAP_ENUM(sn, float, Fix32, CAP_TYPE_EX_##sn); } \ + else \ + { SET_CAP(sn, float, Fix32, CAP_TYPE_EX_##sn); } \ + } \ + else if(type == VAL_TYPE_STR) \ + { \ + if(vl == VAL_LIMIT_ENUM) \ + { SET_CAP_ENUM(sn, std::string, Twpp::Str64, CAP_TYPE_EX_##sn); } \ + else \ + { \ + m_query[(CapType)CAP_TYPE_EX_##sn] = MsgSupport::Get; \ + m_caps[(CapType)CAP_TYPE_EX_##sn] = [this](Msg msg, Capability& data) -> Result { \ + std::string val(""); \ + sane_opts::get_opts op(&val, NULL, NULL, NULL, NULL); \ + scanner_->get_value(sn, sane_opts::set_opt_value, &op); \ + Str255 str; \ + str.setData(val.c_str()); \ + data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_##sn, str); \ + return success(); \ + }; \ + } \ + } \ + else if(type == VAL_TYPE_BUTTON) \ + { \ + m_query[(CapType)CAP_TYPE_EX_##sn] = MsgSupport::Set | MsgSupport::Reset; \ + m_caps[(CapType)CAP_TYPE_EX_##sn] = [this](Msg msg, Capability& data) -> Result { \ + if (!scanner_.get()) \ + return seqError(); \ + if(msg == Msg::Set || msg == Msg::Reset) { \ + scanner_->set_value(sn, NULL); \ + return success(); \ + } \ + return enmGet(msg, data, true); \ + }; \ + } \ + } // setting items ... - ADD_CAP(1); ADD_CAP(2); ADD_CAP(3); @@ -1995,28 +2440,23 @@ void huagao_ds::init_support_caps_ex(void) ADD_CAP(68); ADD_CAP(69); ADD_CAP(70); - ADD_CAP(71); - ADD_CAP(72); - ADD_CAP(73); - ADD_CAP(74); - ADD_CAP(75); - ADD_CAP(76); - ADD_CAP(77); - ADD_CAP(78); - ADD_CAP(79); - ADD_CAP(80); } void huagao_ds::on_scan_event(int sane_event, void* data, unsigned int* len) { - if (ui_.get()) + if (scanner_.get()) { - ui_->handle_sane_event(sane_event, data, len); + scanner_->ui_handle_sane_event(sane_event, data, len); if (sane_event == SANE_EVENT_SCAN_FINISHED) { - if (ui_->is_progress_ui_showing()) - ui_->hide_ui(); - else if (!scanner_->twain_get_to_be_scan()) - ui_->hide_ui(); + if (scanner_->ui_is_progress_ui_showing()) + scanner_->ui_hide(); + else //if (!scanner_->twain_get_to_be_scan()) + { + bool now = false; + GET_SANE_OPT(bool, scanner_, ex_to_be_scan, &now, NULL, NULL, NULL); + if(!now) + scanner_->ui_hide(); + } } } } diff --git a/huagaotwain/twain/huagaods.hpp b/twain/twain/huagaods.hpp similarity index 97% rename from huagaotwain/twain/huagaods.hpp rename to twain/twain/huagaods.hpp index 8ae8354..5ae5443 100644 --- a/huagaotwain/twain/huagaods.hpp +++ b/twain/twain/huagaods.hpp @@ -8,7 +8,7 @@ #include #include #include "twpp.hpp" -#include "../huagaotwain.h" +#include "../load_sane.h" namespace std { @@ -26,11 +26,10 @@ class twain_ui; class huagao_ds : public Twpp::SourceFromThis { std::unordered_map> m_caps; std::unordered_map m_query; - std::unique_ptr scanner_; + std::unique_ptr scanner_; Twpp::SetupFileXfer m_fileXfer; Twpp::XferMech m_capXferMech = Twpp::XferMech::Native; std::unique_ptr memoryinfo; - std::unique_ptr ui_; bool m_memoryfalg = true; bool m_bFeederEnabled = true; bool m_bAutoFeed = true; diff --git a/huagaotwain/twain/twain_2.4.h b/twain/twain/twain_2.4.h similarity index 100% rename from huagaotwain/twain/twain_2.4.h rename to twain/twain/twain_2.4.h diff --git a/huagaotwain/twain/twpp.hpp b/twain/twain/twpp.hpp similarity index 100% rename from huagaotwain/twain/twpp.hpp rename to twain/twain/twpp.hpp diff --git a/huagaotwain/twain/twpp/application.hpp b/twain/twain/twpp/application.hpp similarity index 100% rename from huagaotwain/twain/twpp/application.hpp rename to twain/twain/twpp/application.hpp diff --git a/huagaotwain/twain/twpp/audio.hpp b/twain/twain/twpp/audio.hpp similarity index 100% rename from huagaotwain/twain/twpp/audio.hpp rename to twain/twain/twpp/audio.hpp diff --git a/huagaotwain/twain/twpp/capability.hpp b/twain/twain/twpp/capability.hpp similarity index 98% rename from huagaotwain/twain/twpp/capability.hpp rename to twain/twain/twpp/capability.hpp index 06a4b33..6c96bb2 100644 --- a/huagaotwain/twain/twpp/capability.hpp +++ b/twain/twain/twpp/capability.hpp @@ -1466,6 +1466,19 @@ public: return std::move(ret); } + template + static Capability createEnumeration(CapType cap, std::list values, UInt32 currIndex = 0, UInt32 defIndex = 0){ + Capability ret = createEnumeration(cap, static_cast(values.size()), currIndex, defIndex); + auto enm = ret.enumeration(); + + UInt32 i = 0; + for (const auto& val : values){ + enm[i] = val; + i++; + } + + return std::move(ret); + } /// Creates capability holding Enumeration container. /// \tparam type ID of the internal data type. @@ -1502,6 +1515,10 @@ public: static Capability createEnumeration(CapType cap, std::initializer_list values, UInt32 currIndex = 0, UInt32 defIndex = 0){ return createEnumeration::twty, T>(cap, values, currIndex, defIndex); } + template + static Capability createEnumeration(CapType cap, std::list values, UInt32 currIndex = 0, UInt32 defIndex = 0){ + return createEnumeration::twty, T>(cap, values, currIndex, defIndex); + } /// Creates capability holding Enumeration container. /// \tparam cap Capability type. Data types are set accordingly. @@ -1524,6 +1541,10 @@ public: static Capability createEnumeration(std::initializer_list::DataType> values, UInt32 currIndex = 0, UInt32 defIndex = 0){ return createEnumeration::twty, typename Detail::Cap::DataType>(cap, values, currIndex, defIndex); } + template + static Capability createEnumeration(std::list::DataType> values, UInt32 currIndex = 0, UInt32 defIndex = 0){ + return createEnumeration::twty, typename Detail::Cap::DataType>(cap, values, currIndex, defIndex); + } /// Creates capability holding Range container. diff --git a/huagaotwain/twain/twpp/cie.hpp b/twain/twain/twpp/cie.hpp similarity index 100% rename from huagaotwain/twain/twpp/cie.hpp rename to twain/twain/twpp/cie.hpp diff --git a/huagaotwain/twain/twpp/curveresponse.hpp b/twain/twain/twpp/curveresponse.hpp similarity index 100% rename from huagaotwain/twain/twpp/curveresponse.hpp rename to twain/twain/twpp/curveresponse.hpp diff --git a/huagaotwain/twain/twpp/customdata.hpp b/twain/twain/twpp/customdata.hpp similarity index 100% rename from huagaotwain/twain/twpp/customdata.hpp rename to twain/twain/twpp/customdata.hpp diff --git a/huagaotwain/twain/twpp/datasource.hpp b/twain/twain/twpp/datasource.hpp similarity index 100% rename from huagaotwain/twain/twpp/datasource.hpp rename to twain/twain/twpp/datasource.hpp diff --git a/huagaotwain/twain/twpp/deviceevent.hpp b/twain/twain/twpp/deviceevent.hpp similarity index 100% rename from huagaotwain/twain/twpp/deviceevent.hpp rename to twain/twain/twpp/deviceevent.hpp diff --git a/huagaotwain/twain/twpp/element8.hpp b/twain/twain/twpp/element8.hpp similarity index 100% rename from huagaotwain/twain/twpp/element8.hpp rename to twain/twain/twpp/element8.hpp diff --git a/huagaotwain/twain/twpp/enums.hpp b/twain/twain/twpp/enums.hpp similarity index 100% rename from huagaotwain/twain/twpp/enums.hpp rename to twain/twain/twpp/enums.hpp diff --git a/huagaotwain/twain/twpp/env.hpp b/twain/twain/twpp/env.hpp similarity index 100% rename from huagaotwain/twain/twpp/env.hpp rename to twain/twain/twpp/env.hpp diff --git a/huagaotwain/twain/twpp/event.hpp b/twain/twain/twpp/event.hpp similarity index 100% rename from huagaotwain/twain/twpp/event.hpp rename to twain/twain/twpp/event.hpp diff --git a/huagaotwain/twain/twpp/exception.hpp b/twain/twain/twpp/exception.hpp similarity index 100% rename from huagaotwain/twain/twpp/exception.hpp rename to twain/twain/twpp/exception.hpp diff --git a/huagaotwain/twain/twpp/extimageinfo.hpp b/twain/twain/twpp/extimageinfo.hpp similarity index 100% rename from huagaotwain/twain/twpp/extimageinfo.hpp rename to twain/twain/twpp/extimageinfo.hpp diff --git a/huagaotwain/twain/twpp/filesystem.hpp b/twain/twain/twpp/filesystem.hpp similarity index 100% rename from huagaotwain/twain/twpp/filesystem.hpp rename to twain/twain/twpp/filesystem.hpp diff --git a/huagaotwain/twain/twpp/fix32.hpp b/twain/twain/twpp/fix32.hpp similarity index 100% rename from huagaotwain/twain/twpp/fix32.hpp rename to twain/twain/twpp/fix32.hpp diff --git a/huagaotwain/twain/twpp/frame.hpp b/twain/twain/twpp/frame.hpp similarity index 100% rename from huagaotwain/twain/twpp/frame.hpp rename to twain/twain/twpp/frame.hpp diff --git a/huagaotwain/twain/twpp/identity.hpp b/twain/twain/twpp/identity.hpp similarity index 100% rename from huagaotwain/twain/twpp/identity.hpp rename to twain/twain/twpp/identity.hpp diff --git a/huagaotwain/twain/twpp/imageinfo.hpp b/twain/twain/twpp/imageinfo.hpp similarity index 100% rename from huagaotwain/twain/twpp/imageinfo.hpp rename to twain/twain/twpp/imageinfo.hpp diff --git a/huagaotwain/twain/twpp/imagelayout.hpp b/twain/twain/twpp/imagelayout.hpp similarity index 100% rename from huagaotwain/twain/twpp/imagelayout.hpp rename to twain/twain/twpp/imagelayout.hpp diff --git a/huagaotwain/twain/twpp/imagememxfer.hpp b/twain/twain/twpp/imagememxfer.hpp similarity index 100% rename from huagaotwain/twain/twpp/imagememxfer.hpp rename to twain/twain/twpp/imagememxfer.hpp diff --git a/huagaotwain/twain/twpp/imagenativexfer.hpp b/twain/twain/twpp/imagenativexfer.hpp similarity index 100% rename from huagaotwain/twain/twpp/imagenativexfer.hpp rename to twain/twain/twpp/imagenativexfer.hpp diff --git a/huagaotwain/twain/twpp/internal.hpp b/twain/twain/twpp/internal.hpp similarity index 100% rename from huagaotwain/twain/twpp/internal.hpp rename to twain/twain/twpp/internal.hpp diff --git a/huagaotwain/twain/twpp/jpegcompression.hpp b/twain/twain/twpp/jpegcompression.hpp similarity index 100% rename from huagaotwain/twain/twpp/jpegcompression.hpp rename to twain/twain/twpp/jpegcompression.hpp diff --git a/huagaotwain/twain/twpp/memory.hpp b/twain/twain/twpp/memory.hpp similarity index 100% rename from huagaotwain/twain/twpp/memory.hpp rename to twain/twain/twpp/memory.hpp diff --git a/huagaotwain/twain/twpp/memoryops.hpp b/twain/twain/twpp/memoryops.hpp similarity index 100% rename from huagaotwain/twain/twpp/memoryops.hpp rename to twain/twain/twpp/memoryops.hpp diff --git a/huagaotwain/twain/twpp/palette8.hpp b/twain/twain/twpp/palette8.hpp similarity index 100% rename from huagaotwain/twain/twpp/palette8.hpp rename to twain/twain/twpp/palette8.hpp diff --git a/huagaotwain/twain/twpp/passthrough.hpp b/twain/twain/twpp/passthrough.hpp similarity index 100% rename from huagaotwain/twain/twpp/passthrough.hpp rename to twain/twain/twpp/passthrough.hpp diff --git a/huagaotwain/twain/twpp/pendingxfers.hpp b/twain/twain/twpp/pendingxfers.hpp similarity index 100% rename from huagaotwain/twain/twpp/pendingxfers.hpp rename to twain/twain/twpp/pendingxfers.hpp diff --git a/huagaotwain/twain/twpp/setupfilexfer.hpp b/twain/twain/twpp/setupfilexfer.hpp similarity index 100% rename from huagaotwain/twain/twpp/setupfilexfer.hpp rename to twain/twain/twpp/setupfilexfer.hpp diff --git a/huagaotwain/twain/twpp/setupmemxfer.hpp b/twain/twain/twpp/setupmemxfer.hpp similarity index 100% rename from huagaotwain/twain/twpp/setupmemxfer.hpp rename to twain/twain/twpp/setupmemxfer.hpp diff --git a/huagaotwain/twain/twpp/status.hpp b/twain/twain/twpp/status.hpp similarity index 100% rename from huagaotwain/twain/twpp/status.hpp rename to twain/twain/twpp/status.hpp diff --git a/huagaotwain/twain/twpp/strings.hpp b/twain/twain/twpp/strings.hpp similarity index 100% rename from huagaotwain/twain/twpp/strings.hpp rename to twain/twain/twpp/strings.hpp diff --git a/huagaotwain/twain/twpp/twglue.hpp b/twain/twain/twpp/twglue.hpp similarity index 100% rename from huagaotwain/twain/twpp/twglue.hpp rename to twain/twain/twpp/twglue.hpp diff --git a/huagaotwain/twain/twpp/types.hpp b/twain/twain/twpp/types.hpp similarity index 100% rename from huagaotwain/twain/twpp/types.hpp rename to twain/twain/twpp/types.hpp diff --git a/huagaotwain/twain/twpp/typesops.hpp b/twain/twain/twpp/typesops.hpp similarity index 100% rename from huagaotwain/twain/twpp/typesops.hpp rename to twain/twain/twpp/typesops.hpp diff --git a/huagaotwain/twain/twpp/userinterface.hpp b/twain/twain/twpp/userinterface.hpp similarity index 100% rename from huagaotwain/twain/twpp/userinterface.hpp rename to twain/twain/twpp/userinterface.hpp diff --git a/huagaotwain/twain/twpp/utils.hpp b/twain/twain/twpp/utils.hpp similarity index 100% rename from huagaotwain/twain/twpp/utils.hpp rename to twain/twain/twpp/utils.hpp