回调方式取图

This commit is contained in:
gb 2022-06-18 08:54:01 +08:00
parent 712d49809b
commit 79f8208ea4
6 changed files with 360 additions and 119 deletions

View File

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

View File

@ -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<std::mutex> lock(que_lock_);
return queue_.size();
}
bool safe_img_queue::save(scanned_img* img)
{
std::lock_guard<std::mutex> lock(que_lock_);
queue_.push_back(img);
return true;
}
bool safe_img_queue::get_header(SANE_Parameters* header)
{
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> lock(que_lock_);
for (size_t i = 0; i < queue_.size(); ++i)
queue_[i]->release();
queue_.clear();
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "s2t_api.h"
#include <vector>
#include <mutex>
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<scanned_img*> 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);

View File

@ -6,6 +6,7 @@
#include "../../code_device/hgsane/sane_hg_mdw.h"
#include "sane_option_trans.h"
#include <chrono>
#include <mutex>
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<SCNINST> 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<std::mutex> lock(cb_lock_);
std::vector<SCNINST>::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<std::mutex> lock(cb_lock_);
std::vector<SCNINST>::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<std::mutex> lock(cb_lock_);
std::vector<SCNINST>::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<IScanImg*>(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;

View File

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

View File

@ -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<Int16>(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<Bool>, _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<CapType::Indicators>();
m_bIndicator = show;
return success();
}
return CapSupGetAllReset<bool, Bool, CapType::Indicators>(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<Bool, Bool, CapType::FeederLoaded>(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<CapType::Indicators>();
m_bIndicator = show;
return success();
}
return CapSupGetAllReset<bool, Bool, CapType::Indicators>(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();
}
}
}