diff --git a/sane/s2t_api.h b/sane/s2t_api.h index 2836c25..d1d84df 100644 --- a/sane/s2t_api.h +++ b/sane/s2t_api.h @@ -254,13 +254,14 @@ __declspec(novtable) struct ISaneInvoker : public IRef 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(bool, ui_show_main(HWND parent)); + COM_API_DECLARE(bool, ui_show_setting(HWND parent, bool with_scan)); + COM_API_DECLARE(bool, ui_show_progress(HWND parent)); 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)); + + // twain + COM_API_DECLARE(void, twain_set_transfer(twain_xfer xfer)); }; struct delete_scanner diff --git a/sane/scanned_img.cpp b/sane/scanned_img.cpp index d4aac54..3f2db92 100644 --- a/sane/scanned_img.cpp +++ b/sane/scanned_img.cpp @@ -246,20 +246,20 @@ unsigned char* mapping_buf::buffer(unsigned long long off, unsigned int* bytes) bool mapping_buf::save(const void* data, size_t* bytes, unsigned long long off) { unsigned int len = *bytes, total = 0; - unsigned char* buf = buffer(off, &len); + unsigned char* buf = buffer(off, &len); bool ret = false; const char* src = (const char*)data; while (buf) { - if (len > *bytes - total) + if (len >= *bytes - total) { memcpy(buf, src, *bytes - total); total = *bytes; ret = true; break; } - memcpy(buf, data, len); + memcpy(buf, src, len); total += len; off += len; src += len; @@ -398,50 +398,48 @@ scanned_img::scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi ok = total + h.length() + dif == data_->bytes(); } } - - if (ok) - { - if (fmt_.img_format == SANE_IMAGE_TYPE_BMP && channel() == 3 && - xfer != TWAIN_XFER_Memory) - { - // swap RGB - unsigned long long off = 0; - unsigned int line = line_bytes(), len = line; - for (int i = 0; i < height(); ++i) - { - int l = head_.bytes_per_line, cur = 0; - - off = i * line + h.length(); - while (l > 0) - { - len = l; - dst = data_->buffer(off + cur, &len); - if (!dst) - break; - if (len > l) - len = l; - len /= 3; - for (int pos = 0; pos < len; ++pos) - { - unsigned char uc = dst[pos * 3 + 0]; - dst[pos * 3 + 0] = dst[pos * 3 + 2]; - dst[pos * 3 + 2] = uc; - } - l -= len * 3; - cur += len * 3; - } - if (!dst) - break; - } - } - data_->unmap(); - } + do_result(ok, xfer); +} +scanned_img::scanned_img(SANE_Parameters head, void* data, unsigned int len, int dpi, const wchar_t* tmp_file + , twain_xfer xfer, SANE_FinalImgFormat* fmt) : head_(head), dpi_(dpi), header_size_(0) +{ + if (fmt) + fmt_ = *fmt; else { - delete data_; - data_ = NULL; - header_size_ = 0; + fmt_.img_format = SANE_IMAGE_TYPE_BMP; + fmt_.detail = 0; } + + size_t bytes = line_bytes() * head.lines; + std::string h(file_header(fmt_.img_format, dpi, xfer)); + unsigned char* dst = NULL, *src = (unsigned char*)data; + bool ok = false; + + header_size_ = h.length(); + data_ = new mapping_buf(); + bytes += header_size_; + dst = data_->allocate(tmp_file, bytes); + bytes = h.length(); + if (dst && data_->save(h.c_str(), &bytes, 0)) + { + unsigned long long off = bytes, line_l = line_bytes(); + unsigned int buf_len = line_bytes(), row = 0; + if (xfer == TWAIN_XFER_Memory) + line_l *= -1; + else + off = data_->bytes() - line_l; + for (; row < head.lines; ++row) + { + bytes = head.bytes_per_line; + if (!data_->save(src, &bytes, off)) + break; + off -= line_l; + src += head.bytes_per_line; + } + ok = row == head.lines; + } + do_result(ok, xfer); } scanned_img::~scanned_img() { @@ -481,6 +479,59 @@ std::string scanned_img::file_header(SANE_ImageType type, float resolution, twai return h; } +void scanned_img::do_result(bool ok, twain_xfer xfer) +{ + if (ok) + { + if (fmt_.img_format == SANE_IMAGE_TYPE_BMP + && channel() == 3 + && xfer != TWAIN_XFER_Memory) + { + // swap RGB + swap_rgb(); + } + data_->unmap(); + } + else + { + delete data_; + data_ = NULL; + header_size_ = 0; + } +} +void scanned_img::swap_rgb(void) +{ + unsigned long long off = 0; + unsigned int line = line_bytes(), len = line; + unsigned char* dst = NULL; + + for (int i = 0; i < height(); ++i) + { + int l = head_.bytes_per_line, cur = 0; + + off = i * line + header_size_; + while (l > 0) + { + len = l; + dst = data_->buffer(off + cur, &len); + if (!dst) + break; + if (len > l) + len = l; + len /= 3; + for (int pos = 0; pos < len; ++pos) + { + unsigned char uc = dst[pos * 3 + 0]; + dst[pos * 3 + 0] = dst[pos * 3 + 2]; + dst[pos * 3 + 2] = uc; + } + l -= len * 3; + cur += len * 3; + } + if (!dst) + break; + } +} // IRef COM_API_IMPLEMENT(scanned_img, long, add_ref(void)) @@ -557,3 +608,70 @@ COM_API_IMPLEMENT(scanned_img, void, copy_header(SANE_Parameters* head)) { *head = head_; } + + + + + + + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class safe_img_queue +safe_img_queue::safe_img_queue() +{} +safe_img_queue::~safe_img_queue() +{ + clear(); +} + +size_t safe_img_queue::count(void) +{ + std::lock_guard lock(que_lock_); + + return queue_.size(); +} +bool safe_img_queue::save(scanned_img* img) +{ + std::lock_guard lock(que_lock_); + + queue_.push_back(img); + + return true; +} +bool safe_img_queue::get_header(SANE_Parameters* header) +{ + std::lock_guard lock(que_lock_); + bool ok = false; + + if (queue_.size()) + { + queue_[0]->copy_header(header); + ok = true; + } + + return ok; +} +scanned_img* safe_img_queue::take(void) +{ + std::lock_guard lock(que_lock_); + scanned_img* img = NULL; + + if (queue_.size()) + { + img = queue_[0]; + queue_.erase(queue_.begin()); + } + + return img; +} +void safe_img_queue::clear() +{ + std::lock_guard lock(que_lock_); + + for (size_t i = 0; i < queue_.size(); ++i) + queue_[i]->release(); + queue_.clear(); +} + diff --git a/sane/scanned_img.h b/sane/scanned_img.h index b0c4e8a..d2c3efc 100644 --- a/sane/scanned_img.h +++ b/sane/scanned_img.h @@ -1,6 +1,7 @@ #pragma once #include "s2t_api.h" - +#include +#include class refer : public IRef { @@ -59,10 +60,14 @@ class scanned_img : public IScanImg, virtual public refer SANE_FinalImgFormat fmt_; std::string file_header(SANE_ImageType type, float resolution, twain_xfer xfer); + void do_result(bool ok, twain_xfer xfer); + void swap_rgb(void); public: scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi, const wchar_t* tmp_file , twain_xfer xfer = TWAIN_XFER_Native, SANE_FinalImgFormat *fmt = NULL); + scanned_img(SANE_Parameters head, void* data, unsigned int len, int dpi, const wchar_t* tmp_file + , twain_xfer xfer = TWAIN_XFER_Native, SANE_FinalImgFormat *fmt = NULL); protected: @@ -90,6 +95,23 @@ public: COM_API_OVERRIDE(void, copy_header(SANE_Parameters* head)); }; +class safe_img_queue +{ + std::mutex que_lock_; + std::vector queue_; + +public: + safe_img_queue(); + ~safe_img_queue(); + +public: + size_t count(void); + bool save(scanned_img* img); + bool get_header(SANE_Parameters* header); + scanned_img* take(void); + void clear(); +}; + namespace local_trans { std::string u2a(const wchar_t* unic, UINT cp = CP_ACP); diff --git a/sane/scanner.cpp b/sane/scanner.cpp index f51db72..7fd5623 100644 --- a/sane/scanner.cpp +++ b/sane/scanner.cpp @@ -6,6 +6,7 @@ #include "../../code_device/hgsane/sane_hg_mdw.h" #include "sane_option_trans.h" #include +#include static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt); @@ -18,10 +19,74 @@ static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt); } + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// callback +namespace callback +{ + static std::mutex cb_lock_; + typedef struct _scanner_inst + { + SANE_Handle dev; + scanner* invoker; + + bool operator==(const SANE_Handle& h) + { + return dev == h; + } + bool operator==(const scanner* obj) + { + return invoker == obj; + } + }SCNINST; + std::vector g_scanner_instances; + + int sane_event_callback( // 注册回调的对象,需要保证该回调是多线程安全的 + SANE_Handle hdev // 产生事件的设备句柄 + , int code // 回调事件代码 + , void* data // 回调事件数据,根据事件代码有所不同,参照具体事件定义 + , unsigned int* len // 数据长度(字节),或者event_data的缓冲区长度,详细请看相应的事件代码 + , void* param // 用户自定义数据,与调用sane_init_ex传入时的保持一致 + ) // 返回值依不同的事件代码而定,通常为“0” + { + std::lock_guard lock(cb_lock_); + std::vector::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), hdev); + + if (it != g_scanner_instances.end()) + return it->invoker->handle_event(code, data, len); + else + return 0; + } + void reg_callback(SANE_Handle dev, scanner* invoker) + { + std::lock_guard lock(cb_lock_); + std::vector::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), dev); + if (it == g_scanner_instances.end()) + { + SCNINST inst; + + inst.dev = dev; + inst.invoker = invoker; + g_scanner_instances.push_back(inst); + } + else + it->invoker = invoker; + } + void unreg_callback(scanner* invoker) + { + std::lock_guard lock(cb_lock_); + std::vector::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), invoker); + if (it != g_scanner_instances.end()) + g_scanner_instances.erase(it); + } +} + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // class scanner scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START) - , dpi_(200), tmp_path_(L""), img_ind_(0) + , dpi_(200), tmp_path_(L""), img_ind_(0), cb_invoker_(NULL), cb_param_(NULL), working_(false) { tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str()); tmp_path_ += L"imgs"; @@ -31,7 +96,9 @@ scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BAS err_ = open(); } scanner::~scanner() -{} +{ + callback::unreg_callback(this); +} std::string scanner::get_scanner_name(SCANNERID id) { @@ -113,6 +180,7 @@ int scanner::open(void) ret = hg_sane_middleware::instance()->open_device(name.c_str(), &handle_); if (ret == SANE_STATUS_GOOD) { + callback::reg_callback(handle_, this); ret = init_options_id(); } @@ -1372,6 +1440,7 @@ COM_API_IMPLEMENT(scanner, int, start(void)) unsigned int l = sizeof(img_fmt_); if (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_IMAGE_FORMAT, &img_fmt_, &l)) img_fmt_.img_format = SANE_IMAGE_TYPE_BMP; + working_ = true; } prev_start_result_ = ret; @@ -1379,10 +1448,13 @@ COM_API_IMPLEMENT(scanner, int, start(void)) } COM_API_IMPLEMENT(scanner, int, stop(void)) { + working_ = false; 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)) { + cb_invoker_ = cb; + cb_param_ = param; } COM_API_IMPLEMENT(scanner, bool, wait_image(DWORD milliseconds)) { @@ -1392,24 +1464,18 @@ COM_API_IMPLEMENT(scanner, bool, wait_image(DWORD milliseconds)) } COM_API_IMPLEMENT(scanner, int, get_scanned_images(DWORD milliseconds)) { - unsigned int count = 0; + size_t count = images_.count(); - hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_IMAGE_QUEUE_COUNT, NULL, &count); - if (count == 0 && milliseconds) + while (count == 0 && milliseconds && working_) { - while (count == 0) + Sleep(10); + count = images_.count(); + if (milliseconds != -1) { - Sleep(10); - if (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_IMAGE_QUEUE_COUNT, NULL, &count) - != SCANNER_ERR_OK) + if (milliseconds <= 10) break; - if (milliseconds != -1) - { - if (milliseconds <= 10) - break; - milliseconds -= 10; - } + milliseconds -= 10; } } @@ -1417,22 +1483,13 @@ COM_API_IMPLEMENT(scanner, int, get_scanned_images(DWORD milliseconds)) } COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(twain_xfer xfer)) { - scanned_img* img = NULL; - SANE_Parameters head; - - if (hg_sane_middleware::instance()->get_image_parameters(handle_, &head) == SANE_STATUS_GOOD) - { - wchar_t name[40] = { 0 }; - - swprintf_s(name, _countof(name) - 1, L"img_%05u.bmp", ++img_ind_); - img = new scanned_img(head, handle_, dpi_, (tmp_path_ + name).c_str(), xfer, &img_fmt_); - } + scanned_img* img = images_.take(); 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; + return images_.get_header(header); } COM_API_IMPLEMENT(scanner, bool, is_online(void)) { @@ -1712,29 +1769,62 @@ SANE_OPTION_ID_IMPLEMENT(ex_power) SANE_OPTION_ID_IMPLEMENT(ex_hardware_version) SANE_OPTION_ID_IMPLEMENT(ex_ip) +COM_API_IMPLEMENT(scanner, void, twain_set_transfer(twain_xfer xfer)) +{ + xfer_ = xfer; +} + // ui ... -COM_API_IMPLEMENT(scanner, void, ui_show_main(void)) +COM_API_IMPLEMENT(scanner, bool, ui_show_main(HWND parent)) { + return false; } -COM_API_IMPLEMENT(scanner, void, ui_show_setting(bool with_scan)) +COM_API_IMPLEMENT(scanner, bool, ui_show_setting(HWND parent, bool with_scan)) { + return false; } -COM_API_IMPLEMENT(scanner, void, ui_show_progress(void)) +COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent)) { + return false; } 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; + return true; } -COM_API_IMPLEMENT(scanner, bool, ui_is_progress_ui_showing(void)) + + + + +int scanner::handle_event(int ev_code, void* data, unsigned int* len) { - return false; + if (ev_code == SANE_EVENT_IMAGE_OK) + { + SANE_Image* simg = (SANE_Image*)data; + scanned_img* img = NULL; + wchar_t name[40] = { 0 }; + + swprintf_s(name, _countof(name) - 1, L"img_%05u.bmp", ++img_ind_); + img = new scanned_img(simg->header, simg->data, simg->bytes, dpi_, (tmp_path_ + name).c_str(), xfer_, &img_fmt_); + if (img->bytes() >= simg->bytes) + { + images_.save(img); + } + else + { + img->release(); + } + } + else if (ev_code == SANE_EVENT_SCAN_FINISHED) + { + working_ = false; + //if (cb_invoker_) // calling this when UI exited + // cb_invoker_(ev_code, data, len, cb_param_); + } + + return 0; } @@ -1744,6 +1834,14 @@ COM_API_IMPLEMENT(scanner, bool, ui_is_progress_ui_showing(void)) + + + + + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // exports #ifdef EXPORT_SANE_API @@ -1753,6 +1851,7 @@ __declspec(dllimport) #endif int __stdcall initialize(void* reserve) { + hg_sane_middleware::set_callback(callback::sane_event_callback, NULL); hg_sane_middleware::instance(); return SANE_STATUS_GOOD; @@ -1791,6 +1890,7 @@ __declspec(dllimport) #endif int __stdcall uninitialize(void* reserve) { + hg_sane_middleware::set_callback(NULL, NULL); hg_sane_middleware::clear(); return 0; diff --git a/sane/scanner.h b/sane/scanner.h index d8c945e..73f5c13 100644 --- a/sane/scanner.h +++ b/sane/scanner.h @@ -26,11 +26,16 @@ class scanner : public ISaneInvoker, virtual public refer SANE_Handle handle_; SCANNERID id_; int err_; + void(*cb_invoker_)(int ev_type, void* data, unsigned int* len, void* param); + void* cb_param_; int ex_id_; int prev_start_result_; int dpi_; unsigned int img_ind_; std::wstring tmp_path_; + twain_xfer xfer_; + safe_img_queue images_; + volatile bool working_; SANE_FinalImgFormat img_fmt_; int open(void); @@ -264,11 +269,16 @@ public: 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(bool, ui_show_main(HWND parent)); + COM_API_OVERRIDE(bool, ui_show_setting(HWND parent, bool with_scan)); + COM_API_OVERRIDE(bool, ui_show_progress(HWND parent)); 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)); + + // twain + COM_API_OVERRIDE(void, twain_set_transfer(twain_xfer xfer)); + + // methods: +public: + int handle_event(int ev_code, void* data, unsigned int* len); }; \ No newline at end of file diff --git a/twain/twain/huagaods.cpp b/twain/twain/huagaods.cpp index 9737857..932b16f 100644 --- a/twain/twain/huagaods.cpp +++ b/twain/twain/huagaods.cpp @@ -837,8 +837,11 @@ Result huagao_ds::userInterfaceEnable(const Identity&, UserInterface& ui) { if (!ui.showUi()) { - if (m_bIndicator) - scanner_->ui_show_main(); + if (m_bIndicator && !scanner_->ui_show_progress((HWND)ui.parent().raw())) + return seqError(); + + scanner_->twain_set_transfer((twain_xfer)m_capXferMech); + return scanner_->start() == SCANNER_ERR_OK ? success() : seqError(); } @@ -1127,12 +1130,7 @@ 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 ?) - if (bUiOnly) - scanner_->ui_show_setting(false); - else - scanner_->ui_show_main(); - - return success(); + return scanner_->ui_show_setting((HWND)data.parent().raw(), !bUiOnly) ? success() : seqError(); } void huagao_ds::init_support_caps(void) { @@ -1178,10 +1176,21 @@ void huagao_ds::init_support_caps(void) return oneValGetSet(msg, data, tmp_count, -1); }; - if (scanner_->ui_is_ok()) + m_bIndicator = scanner_->ui_is_ok(); + if (m_bIndicator) { m_query[CapType::UiControllable] = msgSupportGetAll; m_caps[CapType::UiControllable] = std::bind(oneValGet, _1, _2, Bool(true)); + + m_query[CapType::Indicators] = msgSupportGetAllSetReset; + m_caps[CapType::Indicators] = [this](Msg msg, Capability& data) -> Result { + if (Msg::Set == msg) { + auto show = data.currentItem(); + m_bIndicator = show; + return success(); + } + return CapSupGetAllReset(msg, data, { FALSE,TRUE }, m_bIndicator, TRUE, m_bIndicator ? 1 : 0, 1); + }; } m_query[CapType::DeviceOnline] = msgSupportGetAll; @@ -1945,16 +1954,6 @@ void huagao_ds::init_support_caps(void) return CapSupGetAll(msg, data, paperon, paperon); }; - m_query[CapType::Indicators] = msgSupportGetAllSetReset; - m_caps[CapType::Indicators] = [this](Msg msg, Capability& data) -> Result { - if (Msg::Set == msg) { - auto show = data.currentItem(); - m_bIndicator = show; - return success(); - } - return CapSupGetAllReset(msg, data, { FALSE,TRUE }, m_bIndicator, TRUE, m_bIndicator ? 1 : 0, 1); - }; - m_query[CapType(CapTypeEx::CAP_TYPE_EX_FOLD)] = msgSupportGetAllSetReset; m_caps[CapType(CapTypeEx::CAP_TYPE_EX_FOLD)] = [this](Msg msg, Capability& data)->Result { if (Msg::Set == msg || Msg::Reset == msg) { @@ -2470,18 +2469,9 @@ void huagao_ds::on_scan_event(int sane_event, void* data, unsigned int* len) { if (scanner_.get()) { - scanner_->ui_handle_sane_event(sane_event, data, len); if (sane_event == SANE_EVENT_SCAN_FINISHED) { - 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(); - } + notifyCloseOk(); } } }