731 lines
17 KiB
C++
731 lines
17 KiB
C++
#include "hg_scanner.h"
|
||
|
||
|
||
#include "scanner_manager.h"
|
||
#include <sane_opt_json/device_opt.h>
|
||
#include <imgprc/imgprc_mgr.h>
|
||
#include <lang/app_language.h>
|
||
#include "./scanner/scanner_handler.h"
|
||
#include "user-opt/user.h"
|
||
#include <base/paper.h>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
|
||
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// hg_scanner
|
||
static std::string device_opt_json[] = {
|
||
"{\"tx-prog\":{\"cat\":\"none\",\"group\":\"\\u9ad8\\u7ea7\\u8bbe\\u7f6e\",\"title\":\"\\u6587\\u4ef6\\u4f20\\u8f93\\u8fdb\\u5ea6\",\"desc\":\"\\u4f20\\u8f93\\u6587\\u4ef6\\u5b8c\\u6210\\u767e\\u5206\\u6bd4\",\"type\":\"float\",\"ui-pos\":0,\"auth\":0,\"visible\":1,\"size\":8,\"ownread\":true,\"cur\":0.000000,\"default\":0.000000},\"dump-path\":{\"cat\":\"base\",\"group\":\"\\u9ad8\\u7ea7\\u8bbe\\u7f6e\",\"title\":\"\\u6d4b\\u8bd5\\u56fe\\u50cf\\u4fdd\\u5b58\\u8def\\u5f84 \",\"desc\":\"\\u6d4b\\u8bd5\\u65f6\\u4e2d\\u95f4\\u56fe\\u50cf\\u7684\\u4fdd\\u5b58\\u8def\\u5f84\",\"type\":\"string\",\"ui-pos\":20,\"auth\":0,\"enabled\":false,\"size\":256,\"ownread\":true,\"cur\":\"\",\"default\":\"\",\"depend\":\"dump-img==true\"}}"
|
||
};
|
||
|
||
hg_scanner::hg_scanner(ONLNSCANNER* dev, imgproc_mgr* imgproc, hguser* user, std::vector<sane_opt_provider*>* constopts)
|
||
: dev_(*dev), status_(SCANNER_ERR_OPENED_BY_OTHER_PROCESS)
|
||
, msg_(from_default_language("\350\256\276\345\244\207\345\267\262\347\273\217\350\242\253\350\277\233\347\250\213 '%s' \345\215\240\347\224\250"))
|
||
, raw_imgs_("img-usb"), final_imgs_("img-final")
|
||
{
|
||
raw_imgs_.enable_wait_log(false);
|
||
final_imgs_.enable_wait_log(false);
|
||
|
||
singleton_ = hg_scanner::create_device_singleton(dev_.vid, dev_.pid, dev_.addr);
|
||
if (!singleton_->is_first())
|
||
{
|
||
std::string pre(singleton_->read());
|
||
size_t pos = msg_.find("%s");
|
||
|
||
if (pos == std::string::npos)
|
||
msg_ += ": " + pre;
|
||
else
|
||
msg_.replace(pos, 2, pre);
|
||
singleton_->release();
|
||
}
|
||
else
|
||
{
|
||
set_where(dev->display_name.c_str());
|
||
user_ = user;
|
||
init();
|
||
if (status() == SCANNER_ERR_OK)
|
||
{
|
||
//imgproc_ = imgproc;
|
||
//imgproc_->add_ref();
|
||
//dev_opts_->add(imgproc_);
|
||
|
||
if (constopts)
|
||
{
|
||
for(auto& v: *constopts)
|
||
dev_opts_->add(v);
|
||
}
|
||
std::string alg(dev_opts_->get_option_value(nullptr, SANE_ACTION_GET_ENTIRE_JSON));
|
||
gb_json *root = new gb_json(), *child = nullptr;
|
||
if (root->attach_text(&alg[0]))
|
||
{
|
||
alg = "";
|
||
child = root->first_child();
|
||
while (child)
|
||
{
|
||
child->get_value("cat", alg);
|
||
if (alg == "imgp")
|
||
{
|
||
int pos = 0;
|
||
if (child->get_value("pos", pos))
|
||
{
|
||
img_prc_name_[pos] = child->key();
|
||
}
|
||
}
|
||
child->release();
|
||
child = root->next_child();
|
||
}
|
||
}
|
||
root->release();
|
||
|
||
#ifdef USE_SAFE_THREAD
|
||
auto tf = [this](void) -> void
|
||
{
|
||
thread_image_processor();
|
||
};
|
||
imgpr_thread_.start(tf, 0, "hg_scanner::thread_image_processor");
|
||
#else
|
||
imgpr_thread_.reset(new std::thread(&hg_scanner::thread_image_processor, this));
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
hg_scanner::~hg_scanner()
|
||
{
|
||
close();
|
||
}
|
||
|
||
shared_memory* hg_scanner::create_device_singleton(int vid, int pid, int addr)
|
||
{
|
||
unsigned long long key = vid;
|
||
key <<= 16;
|
||
key |= pid;
|
||
key <<= 16;
|
||
key |= addr;
|
||
|
||
return new shared_memory(key);
|
||
}
|
||
image_holder_ptr hg_scanner::make_finished_image_holder(int err)
|
||
{
|
||
PACKIMAGE over;
|
||
image_holder_ptr ihp = nullptr;
|
||
|
||
memset(&over, 0, sizeof(over));
|
||
over.info_size = err;
|
||
ihp = new image_holder(&over);
|
||
|
||
return ihp;
|
||
}
|
||
bool hg_scanner::is_finished_image_holder(image_holder_ptr ptr, int* err)
|
||
{
|
||
PACKIMAGE over;
|
||
bool finish = false;
|
||
|
||
memset(&over, 0, sizeof(over));
|
||
over.info_size = ptr->get_info()->info_size;
|
||
finish = memcmp(&over, ptr->get_info(), sizeof(over)) == 0;
|
||
if (finish && err)
|
||
*err = over.info_size;
|
||
|
||
return finish;
|
||
}
|
||
|
||
void hg_scanner::init(void)
|
||
{
|
||
std::string opts("");
|
||
int ret = SCANNER_ERR_OK;
|
||
|
||
auto on_status = [this](uint32_t statu) ->void
|
||
{
|
||
//status_ = statu;
|
||
};
|
||
auto on_image_received = [this](LPPACKIMAGE pimg, uint64_t size) ->data_holder_ptr
|
||
{
|
||
data_holder_ptr pdh = nullptr;
|
||
|
||
if (pimg == IMG_RECEIVER_PAPER_CNT)
|
||
{
|
||
|
||
}
|
||
else if (pimg == IMG_RECEIVER_FINISHED)
|
||
{
|
||
image_holder_ptr ihp = hg_scanner::make_finished_image_holder(size);
|
||
|
||
raw_imgs_.save(ihp, true);
|
||
utils::to_log(LOG_LEVEL_DEBUG, "Scan finished with error: %s\n", scanner_error_name(size).c_str());
|
||
}
|
||
else
|
||
{
|
||
auto over = [this](uint64_t total, uint64_t cur_size, uint32_t err, void* user) -> int
|
||
{
|
||
image_holder_ptr pimg = (image_holder_ptr)user;
|
||
|
||
tx_prg_ = cur_size;
|
||
tx_prg_ /= total;
|
||
|
||
if (total != cur_size || total == FINAL_NOTIFY)
|
||
return 0;
|
||
|
||
pimg->add_ref();
|
||
raw_imgs_.save(pimg, true);
|
||
|
||
return 0;
|
||
};
|
||
|
||
image_holder_ptr ihp = new image_holder(pimg);
|
||
|
||
ihp->set_progress_notify(over, ihp);
|
||
pdh = dynamic_cast<data_holder_ptr>(ihp);
|
||
}
|
||
|
||
return pdh;
|
||
};
|
||
|
||
auto privilege = [this](int priv) -> bool
|
||
{
|
||
return user_->has_privilege(priv);
|
||
};
|
||
auto privilege_empty = [this](int priv) -> bool
|
||
{
|
||
return true;
|
||
};
|
||
auto logmsg = [&](const char* msg) -> void
|
||
{
|
||
utils::to_log(LOG_LEVEL_DEBUG, msg);
|
||
};
|
||
|
||
scanner_ = new scanner_handler();
|
||
scanner_->set_image_receiver(on_image_received);
|
||
scanner_->set_status_notifyer(on_status);
|
||
ret = scanner_->open_usb_scanner(dev_.dev);
|
||
img_prc_name_[0] = "raw";
|
||
img_prc_name_[10] = "rebuild";
|
||
|
||
if (ret == SCANNER_ERR_OK)
|
||
{
|
||
std::string pc("");
|
||
for (auto& v : device_opt_json)
|
||
pc += v;
|
||
ret = scanner_->option_get_all(opts);
|
||
if (ret != SCANNER_ERR_OK)
|
||
{
|
||
int times = 0, err = ret;
|
||
do
|
||
{
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||
ret = scanner_->option_get_all(opts);
|
||
} while (ret != SCANNER_ERR_OK && times++ < 20);
|
||
utils::to_log(LOG_LEVEL_WARNING, "Failed to get options from device with err %d. wait %d times(%ums) and result = %d\n"
|
||
, err, times, times * 5, ret);
|
||
}
|
||
if (ret == SCANNER_ERR_OK)
|
||
{
|
||
// merge two JSON texts ...
|
||
size_t pos = pc.rfind('}');
|
||
if (pos != std::string::npos)
|
||
{
|
||
pc[pos] = ',';
|
||
pos = opts.find("{");
|
||
if (pos++ != std::string::npos)
|
||
{
|
||
opts.erase(0, pos);
|
||
opts.insert(0, pc);
|
||
}
|
||
}
|
||
}
|
||
|
||
set_opt_json_text(&opts[0]);
|
||
if(user_)
|
||
dev_opts_ = new device_option(false, privilege, logmsg);
|
||
else
|
||
dev_opts_ = new device_option(false, privilege_empty, logmsg);
|
||
dev_opts_->add(this);
|
||
|
||
pc = dev_opts_->get_option_value(SANE_STD_OPT_NAME_DEVICE_MODEL, SANE_ACTION_GET_VALUE);
|
||
if (pc.length())
|
||
{
|
||
opts = dev_opts_->get_option_value(SANE_STD_OPT_NAME_DEVICE_SERIAL_NO, SANE_ACTION_GET_VALUE);
|
||
if (opts.length())
|
||
pc += " - " + opts;
|
||
set_where(pc.c_str());
|
||
}
|
||
|
||
status_ = SCANNER_ERR_OK;
|
||
msg_ = "OK";
|
||
}
|
||
else
|
||
{
|
||
status_ = ret;
|
||
}
|
||
}
|
||
void hg_scanner::thread_image_processor(void)
|
||
{
|
||
imgproc_mgr * processor = imgproc_;
|
||
image_holder* raw = nullptr;
|
||
|
||
//processor->add_ref();
|
||
while (raw_imgs_.take(raw, true))
|
||
{
|
||
int err = 0;
|
||
if (hg_scanner::is_finished_image_holder(raw, &err))
|
||
{
|
||
status_ = err;
|
||
if (scan_over_notify_)
|
||
scan_over_notify_(status_);
|
||
utils::to_log(LOG_LEVEL_DEBUG, "Finished scanning %d picture(s) in %ums.\n", final_cnt_, scan_time_.elapse_ms());
|
||
}
|
||
else
|
||
{
|
||
process_image(raw);
|
||
}
|
||
|
||
raw->release();
|
||
}
|
||
//processor->release();
|
||
}
|
||
void hg_scanner::process_image(image_holder_ptr img)
|
||
{
|
||
bool addref = true;
|
||
int stage = img->get_info()->prc_stage;
|
||
|
||
if (!dump_path_.empty())
|
||
{
|
||
char alg[128] = { 0 };
|
||
|
||
if (img_prc_name_.count(stage))
|
||
sprintf(alg, "%s", img_prc_name_[stage].c_str());
|
||
else
|
||
sprintf(alg, "%s", "Unk");
|
||
img->save_2_file(dump_path_.c_str(), stage, alg);
|
||
}
|
||
else
|
||
{
|
||
std::string alg(img_prc_name_.count(stage) ? img_prc_name_[stage] : std::to_string(stage));
|
||
if(alg == SANE_OPT_NAME(OUT_FORMAT))
|
||
utils::to_log(LOG_LEVEL_ALL, "Image-Process '%s' of picture '%04d-%d%d%d' is %ums, total = %ums.\n", alg.c_str()
|
||
, (int)img->get_info()->pos.paper_ind, (int)img->get_info()->pos.paper_side, (int)img->get_info()->pos.split_ind, (int)img->get_info()->pos.multiout_ind
|
||
, img->get_info()->prc_time, (int)img->get_info()->life);
|
||
else
|
||
utils::to_log(LOG_LEVEL_ALL, "Image-Process '%s' of picture '%04d-%d%d%d' is %ums.\n", alg.c_str()
|
||
, (int)img->get_info()->pos.paper_ind, (int)img->get_info()->pos.paper_side, (int)img->get_info()->pos.split_ind, (int)img->get_info()->pos.multiout_ind, img->get_info()->prc_time);
|
||
}
|
||
|
||
if (img->get_info()->format != IMG_FMT_BMP)
|
||
{
|
||
// decode ...
|
||
#ifdef TEST_HGSCANNER
|
||
#else
|
||
cv::ImreadModes mode = img->get_info()->channels == 1 ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR;
|
||
std::vector<uchar> buf(img->data_length());
|
||
|
||
memcpy(buf.data(), img->data(), img->data_length());
|
||
cv::Mat mat(cv::imdecode(buf, mode));
|
||
|
||
PACKIMAGE head(*img->get_info());
|
||
image_holder *ptr = nullptr;
|
||
uint32_t size = mat.total() * mat.channels();
|
||
|
||
head.data_size = size;
|
||
head.format = IMG_FMT_BMP;
|
||
ptr = new image_holder(&head);
|
||
ptr->put_data(mat.ptr(), &size);
|
||
img = ptr;
|
||
addref = false;
|
||
#endif
|
||
}
|
||
|
||
if(addref)
|
||
img->add_ref();
|
||
final_cnt_++;
|
||
final_imgs_.save(img, true);
|
||
}
|
||
image_holder_ptr hg_scanner::wait_image(void)
|
||
{
|
||
image_holder_ptr ptr = nullptr;
|
||
|
||
if (final_imgs_.size() == 0)
|
||
{
|
||
while (status_ == SCANNER_ERR_DEVICE_BUSY)
|
||
{
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(3));
|
||
if (final_imgs_.size())
|
||
break;
|
||
}
|
||
}
|
||
if (final_imgs_.size())
|
||
ptr = final_imgs_.front();
|
||
|
||
return ptr;
|
||
}
|
||
|
||
char* hg_scanner::get_value(const char* name, void* value, size_t* size, int* err)
|
||
{
|
||
char* ret = nullptr;
|
||
|
||
if (strcmp(name, "tx-prog") == 0)
|
||
{
|
||
ret = (char*)malloc(sizeof(double));
|
||
|
||
*(double*)ret = tx_prg_;
|
||
if (size)
|
||
*size = sizeof(double);
|
||
if (err)
|
||
*err = status_;
|
||
}
|
||
else if (strcmp(name, SANE_OPT_NAME(DUMP_IMG_PATH)) == 0)
|
||
{
|
||
ret = (char*)malloc(dump_path_.length() + 1);
|
||
strcpy(ret, dump_path_.c_str());
|
||
if (size)
|
||
*size = dump_path_.length();
|
||
if (err)
|
||
*err = SCANNER_ERR_OK;
|
||
}
|
||
else if (scanner_)
|
||
{
|
||
uint32_t len = 0;
|
||
int result = 0;
|
||
size_t l = 0;
|
||
|
||
if (!size)
|
||
size = &l;
|
||
dev_opts_->get_option_value_type(name, size);
|
||
len = *size;
|
||
ret = (char*)malloc(len);
|
||
result = scanner_->option_value_get(name, ret, &len);
|
||
*size = len;
|
||
if (result)
|
||
{
|
||
free(ret);
|
||
ret = nullptr;
|
||
}
|
||
if (err)
|
||
*err = result;
|
||
}
|
||
else if (err)
|
||
*err = SCANNER_ERR_NOT_OPEN;
|
||
|
||
return ret;
|
||
}
|
||
int hg_scanner::set_value(const char* name, void* val)
|
||
{
|
||
int type = DATA_TYPE_BOOL,
|
||
val_size = 0,
|
||
ret = SCANNER_ERR_OK;
|
||
size_t size = 0;
|
||
std::string t(dev_opts_->get_option_value_type(name, &size));
|
||
uint16_t after = 0;
|
||
|
||
if (strcmp(SANE_OPT_NAME(RESOLUTION), name) == 0)
|
||
dpi_ = *(int*)val;
|
||
|
||
if (strcmp(name, SANE_OPT_NAME(DUMP_IMG)) == 0)
|
||
{
|
||
if (*(bool*)val && dump_path_.empty())
|
||
{
|
||
dump_path_ = utils::get_local_data_path() + PATH_SEPARATOR + "imgs";
|
||
utils::create_folder(dump_path_.c_str());
|
||
dump_path_ += std::string(PATH_SEPARATOR);
|
||
}
|
||
}
|
||
else if (strcmp(name, SANE_OPT_NAME(DUMP_IMG_PATH)) == 0)
|
||
{
|
||
dump_path_ = (char*)val;
|
||
|
||
return ret;
|
||
}
|
||
|
||
val_size = size;
|
||
if (t == JSON_SANE_TYPE_BOOL)
|
||
{
|
||
type = DATA_TYPE_BOOL;
|
||
}
|
||
else if (t == JSON_SANE_TYPE_INT)
|
||
{
|
||
type = DATA_TYPE_INT4;
|
||
}
|
||
else if (t == JSON_SANE_TYPE_FIXED)
|
||
{
|
||
type = DATA_TYPE_FLOAT;
|
||
}
|
||
else if (t == JSON_SANE_TYPE_STRING)
|
||
{
|
||
type = DATA_TYPE_STRING;
|
||
val_size = strlen((char*)val);
|
||
}
|
||
ret = scanner_->option_value_set(name, type, val, size, val_size, &after);
|
||
if (ret == SCANNER_ERR_OK)
|
||
ret = after;
|
||
if (ret == SCANNER_ERR_RELOAD_OPT_PARAM ||
|
||
ret == SCANNER_ERR_CONFIGURATION_CHANGED)
|
||
{
|
||
// re-set json text
|
||
int e = scanner_->option_get_all(t);
|
||
if (e == SCANNER_ERR_OK)
|
||
set_opt_json_text(&t[0]);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
int hg_scanner::start(std::string* devcfg, std::function<void(int)> over_cb)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
|
||
cancelled_ = false;
|
||
clear_images();
|
||
if (scanner_)
|
||
{
|
||
scan_over_notify_ = over_cb;
|
||
ret = scanner_->scan_start(devcfg);
|
||
if (ret == SCANNER_ERR_OK)
|
||
{
|
||
scan_time_.reset();
|
||
status_ = SCANNER_ERR_DEVICE_BUSY;
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
int hg_scanner::stop(void)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
|
||
cancelled_ = true;
|
||
if (scanner_)
|
||
ret = scanner_->scan_stop();
|
||
|
||
return ret;
|
||
}
|
||
int hg_scanner::close(void)
|
||
{
|
||
int ret = SCANNER_ERR_OK;
|
||
|
||
if (scanner_)
|
||
{
|
||
ret = scanner_->close();
|
||
if (ret)
|
||
return ret;
|
||
scanner_->release();
|
||
scanner_ = nullptr;
|
||
}
|
||
|
||
if (dev_opts_)
|
||
{
|
||
dev_opts_->clear();
|
||
dev_opts_->release();
|
||
dev_opts_ = nullptr;
|
||
}
|
||
|
||
if (singleton_)
|
||
{
|
||
singleton_->release();
|
||
singleton_ = nullptr;
|
||
}
|
||
|
||
// wait image thread ...
|
||
raw_imgs_.trigger();
|
||
#ifndef USE_SAFE_THREAD
|
||
if (imgpr_thread_.get() && imgpr_thread_->joinable())
|
||
imgpr_thread_->join();
|
||
#endif
|
||
|
||
if (imgproc_)
|
||
{
|
||
imgproc_->release();
|
||
imgproc_ = nullptr;
|
||
}
|
||
user_ = nullptr;
|
||
|
||
return ret;
|
||
}
|
||
int hg_scanner::re_connect(void)
|
||
{
|
||
return SCANNER_ERR_OK;
|
||
}
|
||
int hg_scanner::get_image_info(SANE_Parameters* pii)
|
||
{
|
||
image_holder_ptr ptr = wait_image();
|
||
|
||
if (ptr)
|
||
{
|
||
pii->bytes_per_line = (ptr->get_info()->bpp * ptr->get_info()->width * ptr->get_info()->channels + 7) / 8; // no 4-bytes align
|
||
pii->depth = ptr->get_info()->bpp; // <20>˴<EFBFBD>ָÿһ<C3BF><D2BB><EFBFBD><EFBFBD>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EEA3AC><EFBFBD>ǵ<EFBFBD>ɨ<EFBFBD><C9A8><EFBFBD>ǹ̶<C7B9>Ϊ<EFBFBD><CEAA>8<EFBFBD><38>
|
||
pii->last_frame = SANE_TRUE; // һ<><D2BB>ͼƬ<CDBC><C6AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0BBA5><EFBFBD>룬<EFBFBD><EBA3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊtrue<75><65><EFBFBD><EFBFBD>ɫͼ<C9AB><CDBC>RGBʱҲֻ<D2B2><D6BB>һ<EFBFBD><D2BB>֡<EFBFBD><D6A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҲΪtrue
|
||
if (ptr->get_info()->format == IMG_FMT_JPEG)
|
||
pii->format = (SANE_Frame)SANE_FRAME_JPEG;
|
||
else if (ptr->get_info()->format == IMG_FMT_PNG)
|
||
pii->format = (SANE_Frame)SANE_FRAME_PNG;
|
||
else
|
||
pii->format = ptr->get_info()->channels == 3 ? SANE_FRAME_RGB : SANE_FRAME_GRAY;
|
||
pii->lines = ptr->get_info()->height;
|
||
pii->pixels_per_line = ptr->get_info()->width;
|
||
}
|
||
else
|
||
{
|
||
// default ...
|
||
double *w = (double*)get_value(SANE_OPT_NAME(PAPER_W), nullptr, nullptr),
|
||
*h = (double*)get_value(SANE_OPT_NAME(PAPER_H), nullptr, nullptr);
|
||
int res = dpi_;
|
||
SIZE size(paper::size("A3"));
|
||
|
||
if (w)
|
||
{
|
||
size.cx = *w;
|
||
free(w);
|
||
}
|
||
if (h)
|
||
{
|
||
size.cy = *h;
|
||
free(h);
|
||
}
|
||
pii->pixels_per_line = utils::mm_2_pixel(size.cx, res);
|
||
pii->lines = utils::mm_2_pixel(size.cy, res);
|
||
pii->bytes_per_line = pii->pixels_per_line * 3; // no 4-bytes align
|
||
pii->depth = 8; // <20>˴<EFBFBD>ָÿһ<C3BF><D2BB><EFBFBD><EFBFBD>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EEA3AC><EFBFBD>ǵ<EFBFBD>ɨ<EFBFBD><C9A8><EFBFBD>ǹ̶<C7B9>Ϊ<EFBFBD><CEAA>8<EFBFBD><38>
|
||
pii->last_frame = SANE_TRUE; // һ<><D2BB>ͼƬ<CDBC><C6AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0BBA5><EFBFBD>룬<EFBFBD><EBA3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊtrue<75><65><EFBFBD><EFBFBD>ɫͼ<C9AB><CDBC>RGBʱҲֻ<D2B2><D6BB>һ<EFBFBD><D2BB>֡<EFBFBD><D6A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҲΪtrue
|
||
pii->format = SANE_FRAME_RGB;
|
||
}
|
||
|
||
return SCANNER_ERR_OK;
|
||
}
|
||
int hg_scanner::read_image_data(uint8_t* buf, size_t* len)
|
||
{
|
||
int ret = SCANNER_ERR_INVALID_PARAMETER;
|
||
|
||
if (len)
|
||
{
|
||
image_holder_ptr ptr = wait_image();
|
||
size_t bufl = *len;
|
||
|
||
*len = 0;
|
||
ret = SCANNER_ERR_NO_DATA;
|
||
if (ptr)
|
||
{
|
||
if (cur_img_pos_ == 0)
|
||
cur_img_pos_ = ptr->get_info()->info_size;
|
||
|
||
if (buf)
|
||
{
|
||
if (bufl >= ptr->data_length() - cur_img_pos_)
|
||
{
|
||
*len = ptr->data_length() - cur_img_pos_;
|
||
memcpy(buf, ptr->data() + cur_img_pos_, *len);
|
||
cur_img_pos_ = 0;
|
||
final_imgs_.pop_front();
|
||
ptr->release();
|
||
}
|
||
else
|
||
{
|
||
memcpy(buf, ptr->data() + cur_img_pos_, bufl);
|
||
*len = bufl;
|
||
cur_img_pos_ += *len;
|
||
ret = SCANNER_ERR_OK;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
*len = ptr->get_info()->data_size;
|
||
ret = SCANNER_ERR_INSUFFICIENT_MEMORY;
|
||
}
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
int hg_scanner::get_resolution(void)
|
||
{
|
||
return dpi_;
|
||
}
|
||
void hg_scanner::clear_images(void)
|
||
{
|
||
image_holder_ptr img = nullptr;
|
||
while (final_imgs_.take(img))
|
||
img->release();
|
||
cur_img_pos_ = 0;
|
||
final_cnt_ = 0;
|
||
}
|
||
int hg_scanner::status(EP0REPLYSTATUS* ds, bool en_dev_log)
|
||
{
|
||
if (ds)
|
||
scanner_->get_scanner_status(ds, en_dev_log);
|
||
|
||
return status_;
|
||
}
|
||
std::string hg_scanner::status_message(void)
|
||
{
|
||
return msg_;
|
||
}
|
||
bool hg_scanner::is_online(void)
|
||
{
|
||
return online_;
|
||
}
|
||
|
||
char* hg_scanner::get_option_value(const char* name, void* value, size_t* size, int* err)
|
||
{
|
||
std::string val(dev_opts_->get_option_value(name, SANE_ACTION_GET_VALUE, (int*)size, value));
|
||
char* ret = nullptr;
|
||
|
||
if (val.empty())
|
||
{
|
||
if (err)
|
||
*err = SCANNER_ERR_DEVICE_NOT_FOUND;
|
||
}
|
||
else
|
||
{
|
||
ret = (char*)malloc(val.length() + 1);
|
||
memcpy(ret, val.c_str(), val.length());
|
||
ret[val.length()] = 0;
|
||
if (err)
|
||
*err = SCANNER_ERR_OK;
|
||
if (size)
|
||
*size = val.length();
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
device_option* hg_scanner::get_device_opt(void)
|
||
{
|
||
dev_opts_->add_ref();
|
||
|
||
return dev_opts_;
|
||
}
|
||
int hg_scanner::get_peer_config(LPPEERCFG cfg)
|
||
{
|
||
return scanner_->get_peer_config(cfg);
|
||
}
|
||
int hg_scanner::file_transfer(const char* local, const char* remote, bool to_remote)
|
||
{
|
||
auto prog = [this](uint64_t total, uint64_t txed, uint32_t err, void* user) -> int
|
||
{
|
||
double now = txed;
|
||
now /= total;
|
||
|
||
tx_prg_ = now;
|
||
status_ = err;
|
||
if (err)
|
||
utils::to_log(LOG_LEVEL_WARNING, "File transfer error: %s (at %llu/%llu)\n", scanner_error_name(err).c_str(), txed, total);
|
||
else if (txed >= total)
|
||
utils::to_log(LOG_LEVEL_DEBUG, "File transfer finished(%llu/%llu) with error %d\n", txed, total, scanner_error_name(err).c_str());
|
||
|
||
|
||
return 0;
|
||
};
|
||
|
||
tx_prg_ = .0f;
|
||
|
||
return scanner_->file_transfer(local, remote, to_remote, prog);
|
||
}
|
||
|