重构TWAIN架构

This commit is contained in:
gb 2022-06-15 11:04:40 +08:00
parent 948063dd41
commit 12ba0f8979
77 changed files with 4159 additions and 1797 deletions

View File

@ -1,4 +1,4 @@
LIBRARY hgscanner
LIBRARY scanner
EXPORTS
hg_scanner_initialize
hg_scanner_uninitialize

View File

@ -22,7 +22,7 @@
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{9ed4b425-73e0-423e-9712-455e777481b4}</ProjectGuid>
<RootNamespace>hgscanner</RootNamespace>
<RootNamespace>scanner</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

View File

@ -1,446 +0,0 @@
#pragma once
#include "huagao/hgscanner_error.h"
#include <string>
#include <vector>
#include <algorithm>
#include <mutex>
#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<unsigned char> 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<scanned_img*> 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<SANEOPTION> 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<std::string>& values, std::string& now, std::string& init);
bool get_value(int sn, std::list<float>& values, float& now, float& init);
bool get_value(int sn, std::list<bool>& 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<float>* 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<int>* 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<int>* values = NULL);
int twain_set_text_direction(double degree);
double twain_get_text_direction(double* init = NULL, std::list<double>* 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<SANEDEV> 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<SANEDEV>& 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<SANEDEV>& devs);
static scanner* open_scanner(const char* name, int* err);
static int online_devices(void);
};

View File

@ -1,630 +0,0 @@
#include "sane_option_trans.h"
#include <Windows.h>
#include "./twain/twain_2.4.h"
namespace sane_trans
{
bool get_value_list(const SANE_Option_Descriptor* desc, std::list<std::string>* 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<double>* 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;
}
}

View File

@ -1,230 +0,0 @@
// utilities for transfroming options between TWAIN and sane ...
//
// Date: 2022-04-14
//
#pragma once
#include "sane/sane_ex.h"
#include <list>
#include <string>
#include <math.h>
#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<std::string>* values);
bool get_value_list(const SANE_Option_Descriptor* desc, std::list<double>* 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);
}

View File

@ -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

View File

@ -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);
}

12
sane/huagaotwain.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "huagao/hgscanner_error.h"
#include <string>
#include <vector>
#include <algorithm>
#include <mutex>
#include "sane_option_trans.h"
#include "s2t_api.h"

393
sane/s2t_api.h Normal file
View File

@ -0,0 +1,393 @@
#pragma once
//
// For: interface definition for SANE to TWAIN
//
// Date: 2022-06-08
//
#include <Windows.h>
#include <sane/sane_ex.h>
#include <huagao/hgscanner_error.h>
#include <string>
#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 <vector>
#include <list>
namespace sane_opts
{
template<class T>
class get_opts
{
public:
T* init_;
T* cur_;
T* lower_;
T* upper_;
T* step_;
std::vector<T>* vvs_;
std::list<T>* lvs_;
public:
get_opts(T* cur = NULL, T* init = NULL, std::vector<T>* vs = NULL, std::list<T>* 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<class T>
bool __stdcall set_opt_value(void* val, value_role role, void* param)
{
get_opts<T>* v = (get_opts<T>*)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<type> op(cur, init, vec, lst); \
object->get_value(ind, sane_opts::set_opt_value<type>, &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<type> op(cur, init, NULL, NULL, low, up, step); \
object->get_value(ind, sane_opts::set_opt_value<type>, &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);

6
sane/sane.def Normal file
View File

@ -0,0 +1,6 @@
LIBRARY sane
EXPORTS
initialize
open_scanner
is_scanner_online
uninitialize

View File

@ -22,9 +22,9 @@
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{6eec8a02-7f98-4422-8ed6-2434d43bd1e1}</ProjectGuid>
<RootNamespace>hgsane</RootNamespace>
<RootNamespace>sane</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>hgsane</ProjectName>
<ProjectName>sane</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -103,7 +103,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>BACKEND_NAME=hgsane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>BACKEND_NAME=sane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
@ -128,7 +128,7 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>BACKEND_NAME=hgsane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>BACKEND_NAME=sane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
@ -197,6 +197,9 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$
<ClCompile Include="..\..\code_device\hgsane\main.c" />
<ClCompile Include="..\..\code_device\hgsane\sane_hg_mdw.cpp" />
<ClCompile Include="..\..\code_device\hgsane\sane_option.cpp" />
<ClCompile Include="sane_option_trans.cpp" />
<ClCompile Include="scanned_img.cpp" />
<ClCompile Include="scanner.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\code_device\hgsane\cJSON.h" />
@ -211,6 +214,10 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$
<ClInclude Include="..\..\sdk\include\sane\sanei_debug.h" />
<ClInclude Include="..\..\sdk\include\sane\sane_ex.h" />
<ClInclude Include="..\..\sdk\include\sane\sane_option_definitions.h" />
<ClInclude Include="s2t_api.h" />
<ClInclude Include="sane_option_trans.h" />
<ClInclude Include="scanned_img.h" />
<ClInclude Include="scanner.h" />
</ItemGroup>
<ItemGroup>
<None Include="sane.def" />

View File

@ -13,6 +13,9 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="sane2twain">
<UniqueIdentifier>{8ae15a45-410d-4611-b852-f82b64bb1fcc}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\code_device\hgsane\cJSON.c">
@ -30,6 +33,15 @@
<ClCompile Include="..\..\code_device\hgsane\sane_option.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="sane_option_trans.cpp">
<Filter>sane2twain</Filter>
</ClCompile>
<ClCompile Include="scanned_img.cpp">
<Filter>sane2twain</Filter>
</ClCompile>
<ClCompile Include="scanner.cpp">
<Filter>sane2twain</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\code_device\hgsane\cJSON.h">
@ -68,6 +80,18 @@
<ClInclude Include="..\..\sdk\include\sane\sane_option_definitions.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="s2t_api.h">
<Filter>sane2twain</Filter>
</ClInclude>
<ClInclude Include="sane_option_trans.h">
<Filter>sane2twain</Filter>
</ClInclude>
<ClInclude Include="scanned_img.h">
<Filter>sane2twain</Filter>
</ClInclude>
<ClInclude Include="scanner.h">
<Filter>sane2twain</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="sane.def">

4
sane/sane.vcxproj.user Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

294
sane/sane_option_trans.cpp Normal file
View File

@ -0,0 +1,294 @@
#include "sane_option_trans.h"
#include <Windows.h>
#include <sane/sane_option_definitions.h>
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<int> support_image_types(void)
{
std::vector<int> it;
it.push_back(SANE_IMAGE_TYPE_BMP);
it.push_back(SANE_IMAGE_TYPE_TIFF);
it.push_back(SANE_IMAGE_TYPE_JFIF);
return it;
}
}

41
sane/sane_option_trans.h Normal file
View File

@ -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<int> support_image_types(void);
}

143
sane/scanned_img.cpp Normal file
View File

@ -0,0 +1,143 @@
#include "scanned_img.h"
#include <Windows.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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_;
}

51
sane/scanned_img.h Normal file
View File

@ -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));
};

1767
sane/scanner.cpp Normal file

File diff suppressed because it is too large Load Diff

270
sane/scanner.h Normal file
View File

@ -0,0 +1,270 @@
#pragma once
#include "scanned_img.h"
#include <vector>
#include <algorithm>
#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<EXAPI> ex_opts_;
typedef std::vector<EXAPI>::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<class T>
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<class S, class T>
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<S> 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));
};

View File

@ -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

View File

@ -1,5 +1,4 @@
#include "pch.h"
#include "huagaotwain.h"
HMODULE me_ = NULL;

176
twain/load_sane.cpp Normal file
View File

@ -0,0 +1,176 @@
#include "pch.h"
#include "load_sane.h"
#include <string>
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);
}
};

19
twain/load_sane.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
// utility for loading sane component ...
#include "../sane/s2t_api.h"
#include <string>
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);
};

View File

@ -13,7 +13,7 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{c3b47ce2-27ce-4509-ab59-3c0f194f0fce}</ProjectGuid>
<Keyword>DynamicLibrary</Keyword>
<RootNamespace>huagaotwain</RootNamespace>
<RootNamespace>twain</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
@ -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</Command>
copy $(TargetPath) $(WinDir)\twain_32\HuaGoScan\huagaotwain.ds /y</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -106,11 +106,10 @@ copy $(TargetPath) $(WinDir)\twain_32\HuaGoScan\$(ProjectName).ds /y</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\sdk\hginclude\huagao_ui.h" />
<ClInclude Include="huagaotwain.h" />
<ClInclude Include="..\sane\s2t_api.h" />
<ClInclude Include="load_sane.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="sane_option_trans.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="twain\huagaods.hpp" />
<ClInclude Include="twain\twain_2.4.h" />
@ -153,24 +152,18 @@ copy $(TargetPath) $(WinDir)\twain_32\HuaGoScan\$(ProjectName).ds /y</Command>
<ClInclude Include="twain\twpp\typesops.hpp" />
<ClInclude Include="twain\twpp\userinterface.hpp" />
<ClInclude Include="twain\twpp\utils.hpp" />
<ClInclude Include="ui.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="huagaotwain.cpp" />
<ClCompile Include="load_sane.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="sane_option_trans.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="twain\huagaods.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="ui.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="twain.def" />

View File

@ -11,21 +11,28 @@
<Filter Include="twain\twpp">
<UniqueIdentifier>{df21031b-938a-4a08-ae64-e869e2586201}</UniqueIdentifier>
</Filter>
<Filter Include="Headers">
<UniqueIdentifier>{89716198-13ed-4593-819e-97f4426c7baa}</UniqueIdentifier>
</Filter>
<Filter Include="Sources">
<UniqueIdentifier>{6d97172d-832d-4c93-ad0e-92fdf76af26b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="huagaotwain.cpp" />
<ClCompile Include="pch.cpp" />
<ClCompile Include="twain\huagaods.cpp">
<Filter>twain</Filter>
</ClCompile>
<ClCompile Include="sane_option_trans.cpp" />
<ClCompile Include="ui.cpp" />
<ClCompile Include="dllmain.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="load_sane.cpp">
<Filter>Sources</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="huagaotwain.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="twain\twain_2.4.h">
<Filter>twain</Filter>
</ClInclude>
@ -149,17 +156,30 @@
<ClInclude Include="twain\twpp.hpp">
<Filter>twain</Filter>
</ClInclude>
<ClInclude Include="sane_option_trans.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="..\..\sdk\hginclude\huagao_ui.h" />
<ClInclude Include="ui.h" />
</ItemGroup>
<ItemGroup>
<None Include="twain.def" />
<ClInclude Include="pch.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="..\sane\s2t_api.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="load_sane.h">
<Filter>Headers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="huagaotwain.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="twain.def">
<Filter>Sources</Filter>
</None>
</ItemGroup>
</Project>

4
twain/twain.vcxproj.user Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
#include <queue>
#include <string>
#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<huagao_ds> {
std::unordered_map<Twpp::CapType, std::function<Twpp::Result(Twpp::Msg msg, Twpp::Capability& data)>> m_caps;
std::unordered_map<Twpp::CapType, Twpp::MsgSupport> m_query;
std::unique_ptr <scanner, delete_scanner> scanner_;
std::unique_ptr <ISaneInvoker, delete_scanner> scanner_;
Twpp::SetupFileXfer m_fileXfer;
Twpp::XferMech m_capXferMech = Twpp::XferMech::Native;
std::unique_ptr<std::thread> memoryinfo;
std::unique_ptr<twain_ui> ui_;
bool m_memoryfalg = true;
bool m_bFeederEnabled = true;
bool m_bAutoFeed = true;

View File

@ -1466,6 +1466,19 @@ public:
return std::move(ret);
}
template<Type type, typename DataType>
static Capability createEnumeration(CapType cap, std::list<DataType> values, UInt32 currIndex = 0, UInt32 defIndex = 0){
Capability ret = createEnumeration<type, DataType>(cap, static_cast<UInt32>(values.size()), currIndex, defIndex);
auto enm = ret.enumeration<type, DataType>();
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<T> values, UInt32 currIndex = 0, UInt32 defIndex = 0){
return createEnumeration<Detail::Tytw<T>::twty, T>(cap, values, currIndex, defIndex);
}
template<typename T>
static Capability createEnumeration(CapType cap, std::list<T> values, UInt32 currIndex = 0, UInt32 defIndex = 0){
return createEnumeration<Detail::Tytw<T>::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<typename Detail::Cap<cap>::DataType> values, UInt32 currIndex = 0, UInt32 defIndex = 0){
return createEnumeration<Detail::Cap<cap>::twty, typename Detail::Cap<cap>::DataType>(cap, values, currIndex, defIndex);
}
template<CapType cap>
static Capability createEnumeration(std::list<typename Detail::Cap<cap>::DataType> values, UInt32 currIndex = 0, UInt32 defIndex = 0){
return createEnumeration<Detail::Cap<cap>::twty, typename Detail::Cap<cap>::DataType>(cap, values, currIndex, defIndex);
}
/// Creates capability holding Range container.