#include "hg_scanner.h" #include "../../sdk/hginclude/hg_log.h" #ifdef WIN32 #include "scanner_manager.h" #endif static int ui_default_callback(scanner_handle, int, void*, unsigned int*, void*) { return 0; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // hg_scanner hg_scanner::hg_scanner(ScannerSerial serial , const char* dev_name, usb_io* io) : name_(dev_name ? dev_name : ""), io_(io), status_(HG_ERR_NOT_START) , scan_count_(-1), run_(true), paper_size_(TwSS::A4), erase_bkg_range_(10) , noise_range_(30), omit_empty_level_(50), resolution_(200), rid_hole_range_(.1f) , bright_(128), contrast_(4), gamma_(1.0f), threshold_(40), anti_noise_(8), margin_(5) , fractate_level_(50), ui_ev_cb_(ui_default_callback), scan_life_(NULL) , notify_setting_result_(false), user_cancel_(false), cb_mem_(true), test_1_paper_(false) , setting_count_(0),img_type_(""), online_(false) { custom_gamma_val_ = new SANE_Gamma; memset(custom_gamma_val_, 0, sizeof(SANE_Gamma)); paper_size_mm_.cx = 210; paper_size_mm_.cy = 297; custom_gamma_val_->pt_count_r = custom_gamma_val_->pt_count_g = custom_gamma_val_->pt_count_b = 0; for (int i = 0; i < ARRAY_SIZE(custom_gamma_val_->table); ++i) custom_gamma_val_->table[i] = i & 0x0ff; HG_VLOG_MINI_2(HG_LOG_LEVEL_DEBUG_INFO, "%s(%s) constructed\n", name_.c_str(), hg_log::format_ptr(this).c_str()); image_prc_param_.value = 0; if (io_) { io_->add_ref(); status_ = io_->last_error(); online_ = status_ == HG_ERR_OK; } wait_usb_.set_debug_info("USB"); wait_img_.set_debug_info("Image"); thread_usb_read_.reset(new std::thread(&hg_scanner::thread_handle_usb, this)); thread_img_handle_.reset(new std::thread(&hg_scanner::thread_image_handle, this)); } hg_scanner::~hg_scanner() { close(true); if (thread_usb_read_.get() && thread_usb_read_->joinable()) thread_usb_read_->join(); if (thread_img_handle_.get() && thread_img_handle_->joinable()) thread_img_handle_->join(); delete custom_gamma_val_; name_.insert(0, "\350\256\276\345\244\207 “"); name_ += "”\345\267\262\347\273\217\345\205\263\351\227\255\343\200\202"; notify_ui_working_status(name_.c_str(), SANE_EVENT_SCANNER_CLOSED); HG_VLOG_MINI_2(HG_LOG_LEVEL_DEBUG_INFO, "%s(%s) destroyed.\n", name_.c_str(), hg_log::format_ptr(this).c_str()); } std::string hg_scanner::strerr(hg_err err) { RETURN_IF(err, HG_ERR_OK); RETURN_IF(err, HG_ERR_INVALID_PARAMETER); RETURN_IF(err, HG_ERR_INSUFFICIENT_MEMORY); RETURN_IF(err, HG_ERR_ACCESS_DENIED); RETURN_IF(err, HG_ERR_IO_PENDING); RETURN_IF(err, HG_ERR_NOT_EXACT); RETURN_IF(err, HG_ERR_CONFIGURATION_CHANGED); RETURN_IF(err, HG_ERR_NOT_OPEN); RETURN_IF(err, HG_ERR_NOT_START); RETURN_IF(err, HG_ERR_NO_DATA); RETURN_IF(err, HG_ERR_HAS_DATA_YET); RETURN_IF(err, HG_ERR_OUT_OF_RANGE); RETURN_IF(err, HG_ERR_IO); RETURN_IF(err, HG_ERR_TIMEOUT); RETURN_IF(err, HG_ERR_CREATE_FILE_FAILED); RETURN_IF(err, HG_ERR_WRITE_FILE_FAILED); RETURN_IF(err, HG_ERR_OPENED_BY_OTHER_PROCESS); // 2:USB错误 RETURN_IF(err, HG_ERR_USB_INIT_FAILED); RETURN_IF(err, HG_ERR_USB_REGISTER_PNP_FAILED); RETURN_IF(err, HG_ERR_USB_CLAIM_INTERFACE_FAILED); // 3:硬件错误 RETURN_IF(err, HG_ERR_DEVICE_NOT_FOUND); RETURN_IF(err, HG_ERR_DEVICE_NOT_SUPPORT); RETURN_IF(err, HG_ERR_DEVICE_BUSY); RETURN_IF(err, HG_ERR_DEVICE_STOPPED); RETURN_IF(err, HG_ERR_DEVICE_COVER_OPENNED); RETURN_IF(err, HG_ERR_DEVICE_NO_PAPER); RETURN_IF(err, HG_ERR_DEVICE_FEEDING_PAPER); RETURN_IF(err, HG_ERR_DEVICE_DOUBLE_FEEDING); RETURN_IF(err, HG_ERR_DEVICE_PAPER_JAMMED); RETURN_IF(err, HG_ERR_DEVICE_STAPLE_ON); RETURN_IF(err, HG_ERR_DEVICE_PAPER_SKEW); RETURN_IF(err, HG_ERR_DEVICE_SIZE_CHECK); RETURN_IF(err, HG_ERR_DEVICE_DOGEAR); RETURN_IF(err, HG_ERR_DEVICE_NO_IMAGE); RETURN_IF(err, HG_ERR_DEVICE_SCANN_ERROR); char unk[80]; sprintf(unk, "\346\234\252\347\237\245\351\224\231\350\257\257\357\274\2320x%x", err); return unk; } std::string hg_scanner::error_description(hg_err err) { RETURN_DESC_IF(err, HG_ERR_OK); RETURN_DESC_IF(err, HG_ERR_INVALID_PARAMETER); RETURN_DESC_IF(err, HG_ERR_INSUFFICIENT_MEMORY); RETURN_DESC_IF(err, HG_ERR_ACCESS_DENIED); RETURN_DESC_IF(err, HG_ERR_IO_PENDING); RETURN_DESC_IF(err, HG_ERR_NOT_EXACT); RETURN_DESC_IF(err, HG_ERR_CONFIGURATION_CHANGED); RETURN_DESC_IF(err, HG_ERR_NOT_OPEN); RETURN_DESC_IF(err, HG_ERR_NOT_START); RETURN_DESC_IF(err, HG_ERR_NO_DATA); RETURN_DESC_IF(err, HG_ERR_HAS_DATA_YET); RETURN_DESC_IF(err, HG_ERR_OUT_OF_RANGE); RETURN_DESC_IF(err, HG_ERR_IO); RETURN_DESC_IF(err, HG_ERR_TIMEOUT); RETURN_DESC_IF(err, HG_ERR_CREATE_FILE_FAILED); RETURN_DESC_IF(err, HG_ERR_WRITE_FILE_FAILED); RETURN_DESC_IF(err, HG_ERR_OPENED_BY_OTHER_PROCESS); // 2:USB错误 RETURN_DESC_IF(err, HG_ERR_USB_INIT_FAILED); RETURN_DESC_IF(err, HG_ERR_USB_REGISTER_PNP_FAILED); RETURN_DESC_IF(err, HG_ERR_USB_CLAIM_INTERFACE_FAILED); // 3:硬件错误 RETURN_DESC_IF(err, HG_ERR_DEVICE_NOT_FOUND); RETURN_DESC_IF(err, HG_ERR_DEVICE_NOT_SUPPORT); RETURN_DESC_IF(err, HG_ERR_DEVICE_BUSY); RETURN_DESC_IF(err, HG_ERR_DEVICE_STOPPED); RETURN_DESC_IF(err, HG_ERR_DEVICE_COVER_OPENNED); RETURN_DESC_IF(err, HG_ERR_DEVICE_NO_PAPER); RETURN_DESC_IF(err, HG_ERR_DEVICE_FEEDING_PAPER); RETURN_DESC_IF(err, HG_ERR_DEVICE_DOUBLE_FEEDING); RETURN_DESC_IF(err, HG_ERR_DEVICE_PAPER_JAMMED); RETURN_DESC_IF(err, HG_ERR_DEVICE_STAPLE_ON); RETURN_DESC_IF(err, HG_ERR_DEVICE_PAPER_SKEW); RETURN_DESC_IF(err, HG_ERR_DEVICE_SIZE_CHECK); RETURN_DESC_IF(err, HG_ERR_DEVICE_DOGEAR); RETURN_DESC_IF(err, HG_ERR_DEVICE_NO_IMAGE); RETURN_DESC_IF(err, HG_ERR_DEVICE_SCANN_ERROR); char unk[80]; sprintf(unk, "\346\234\252\347\237\245\351\224\231\350\257\257\357\274\2320x%x", err); return unk; } std::string hg_scanner::temporary_file(char* tail, char* head) { char buf[128]; FILE* src = NULL; if (!head || *head == 0) head = (char*)"scan"; if (!tail) tail = (char*)""; srand(time(NULL)); sprintf(buf, "/tmp/%s_%04x%s", head, rand(), tail); while ((src = fopen(buf, "rb"))) { fclose(src); sprintf(buf, "/tmp/%s_%04x%s", head, rand(), tail); } return buf; } int hg_scanner::save_2_tempory_file(std::shared_ptr> data, std::string* path_file) { std::string file(hg_scanner::temporary_file((char*)".jpg")); FILE* dst = fopen(file.c_str(), "wb+"); int ret = HG_ERR_OK; if (dst) { ENOSPC; EROFS; strerror(errno); size_t wrote = fwrite(data->data(), 1, data->size(), dst); if (wrote == data->size()) { if (path_file) *path_file = file; HG_VLOG_MINI_2(HG_LOG_LEVEL_DEBUG_INFO, "--->Wrote %u bytes to file '%s'\n", wrote, file.c_str()); } else { ret = HG_ERR_WRITE_FILE_FAILED; HG_VLOG_MINI_3(HG_LOG_LEVEL_FATAL, "Failed in writting file(%u/%u) '%s'\n", wrote, data->size(), file.c_str()); } fclose(dst); } else { ret = HG_ERR_CREATE_FILE_FAILED; HG_VLOG_MINI_1(HG_LOG_LEVEL_FATAL, "Failed in creating file '%s'\n", file.c_str()); } return ret; } void hg_scanner::init_setting_map(int* setting_map, int count) { for (int i = 0; i < count; ++i) setting_map[i] = -1; } void hg_scanner::thread_handle_usb(void) { while (run_) { wait_usb_.wait(); if (!run_) break; if (scan_life_) { std::this_thread::sleep_for(std::chrono::milliseconds(3000)); if (scan_life_) { HG_LOG(HG_LOG_LEVEL_FATAL, "image process is still running!\n"); continue; } } scan_life_ = new do_when_born_and_dead(this, &hg_scanner::working_begin, &hg_scanner::working_done, NULL); thread_handle_usb_read(); if (scan_life_->release() == 0) scan_life_ = NULL; } } void hg_scanner::thread_image_handle(void) { while (run_) { wait_img_.wait(); if (!run_) break; scan_life_->add_ref(); thread_handle_image_process(); if (scan_life_->release() == 0) scan_life_ = NULL; } } void hg_scanner::get_range(int setting_no, std::vector& range, std::string& def_val, bool& is_range/*range or list*/) { char sn[20]; std::string type(""); sprintf(sn, "%d", setting_no); range.clear(); if (setting_jsn_.at(sn).contains("range")) { setting_jsn_.at(sn).at("type").get_to(type); is_range = !setting_jsn_.at(sn).at("range").is_array(); if (is_range) { if (type == "int") { int l = 0, u = 0; setting_jsn_.at(sn).at("range").at("min").get_to(l); setting_jsn_.at(sn).at("range").at("max").get_to(u); char str[20]; sprintf(str, "%d", l); range.push_back(str); sprintf(str, "%d", u); range.push_back(str); } else { double l = .0f, u = .0f; setting_jsn_.at(sn).at("range").at("min").get_to(l); setting_jsn_.at(sn).at("range").at("max").get_to(u); char str[40]; sprintf(str, "%f", l); range.push_back(str); sprintf(str, "%f", u); range.push_back(str); } } else { char str[40]; for (int i = 0; i < setting_jsn_.at(sn).at("range").size(); ++i) { if (type == "int") { int v = 0; setting_jsn_.at(sn).at("range").at(i).get_to(v); sprintf(str, "%d", v); range.push_back(str); } else if(type == "float") { double v = 0; setting_jsn_.at(sn).at("range").at(i).get_to(v); sprintf(str, "%f", v); range.push_back(str); } else { std::string v(""); setting_jsn_.at(sn).at("range").at(i).get_to(v); range.push_back(v); } } } } if (type == "int") { int v = 0; setting_jsn_.at(sn).at("default").get_to(v); sprintf(sn, "%d", v); def_val = sn; } else if (type == "float") { double v = 0; setting_jsn_.at(sn).at("default").get_to(v); sprintf(sn, "%f", v); def_val = sn; } else if(type == "string") setting_jsn_.at(sn).at("default").get_to(def_val); HG_VLOG_MINI_3(HG_LOG_LEVEL_DEBUG_INFO, "setting %d has %d range(s) and default value is '%s'\n", setting_no, range.size(), def_val.c_str()); } bool hg_scanner::check_range(int setting_no, bool& val) { std::vector range; std::string init(""), in(val ? "true" : "false"); bool is_range = false;; get_range(setting_no, range, init, is_range); if (range.size() == 0) return true; for (int i = 0; i < range.size(); ++i) { if (in == range[i]) return true; } val = init == "true" ? true : false; return false; } bool hg_scanner::check_range(int setting_no, int& val) { std::vector range; std::string init(""); bool is_range = false;; get_range(setting_no, range, init, is_range); if (range.size() == 0) return true; if (is_range && range.size() == 2) { if (val >= atoi(range[0].c_str()) && val <= atoi(range[1].c_str())) return true; if(val < atoi(range[0].c_str())) val = atoi(range[0].c_str()); else val = atoi(range[1].c_str()); return false; } else if (!is_range) { for (int i = 0; i < range.size(); ++i) { if (atoi(range[i].c_str()) == val) return true; } } val = atoi(init.c_str()); return false; } bool hg_scanner::check_range(int setting_no, double& val) { std::vector range; std::string init(""); bool is_range = false;; get_range(setting_no, range, init, is_range); if (range.size() == 0) return true; if (is_range && range.size() == 2) { if (val >= atof(range[0].c_str()) && val <= atof(range[1].c_str())) return true; if (val < atof(range[0].c_str())) val = atof(range[0].c_str()); else val = atof(range[1].c_str()); return false; } else if (!is_range) { for (int i = 0; i < range.size(); ++i) { if (fabs(atof(range[i].c_str()) - val) < .000001) return true; } } val = atof(init.c_str()); return false; } bool hg_scanner::check_range(int setting_no, std::string& val) { std::vector range; std::string init(""), in(val); bool is_range = false;; get_range(setting_no, range, init, is_range); if (range.size() == 0) return true; for (int i = 0; i < range.size(); ++i) { if (in == range[i]) return true; } val = init; return false; } int hg_scanner::restore(int setting_no) { char key[20]; int sn = setting_no; std::string val(""); sprintf(key, "%d", setting_no); setting_jsn_.at(key).at("name").get_to(val); if (val == KNOWN_OPT_NAME_CUSTOM_GAMMA) { custom_gamma_val_->pt_count_r = custom_gamma_val_->pt_count_g = custom_gamma_val_->pt_count_b = 0; for (int i = 0; i < ARRAY_SIZE(custom_gamma_val_->table); ++i) custom_gamma_val_->table[i] = i & 0x0ff; return HG_ERR_OK; } setting_jsn_.at(key).at("type").get_to(val); if (val == "string") { val = ""; setting_jsn_.at(key).at("default").get_to(val); char* buf = NULL; int size = 0; setting_jsn_.at(key).at("size").get_to(size); buf = (char*)malloc(size + 4); bzero(buf, size + 4); strcpy(buf, val.c_str()); sn = set_setting(sn, buf, val.length()); free(buf); } else if (val == "int") { int v = 0; setting_jsn_.at(key).at("default").get_to(v); sn = set_setting(sn, (char*)&v, sizeof(v)); } else if (val == "float") { double v = .0f; setting_jsn_.at(key).at("default").get_to(v); sn = set_setting(sn, (char*)&v, sizeof(v)); } else if (val == "bool") { bool v = false; setting_jsn_.at(key).at("default").get_to(v); sn = set_setting(sn, (char*)&v, sizeof(v)); } else sn = HG_ERR_OK; return sn; } bool hg_scanner::get_default_value(void* buf, json* jsn) { std::string type(""); jsn->at("name").get_to(type); if (type == KNOWN_OPT_NAME_CUSTOM_GAMMA) { SANE_Int* gma = (SANE_Int*)buf; for (size_t i = 0; i < sizeof(custom_gamma_val_); ++i) gma[i] = i & 0x0ff; return true; } jsn->at("type").get_to(type); if (type == "bool") { bool v = false; jsn->at("default").get_to(v); *((SANE_Bool*)buf) = v; } else if (type == "int") { int v = 0; jsn->at("default").get_to(v); *((SANE_Int*)buf) = v; } else if (type == "float") { double v = 0; jsn->at("default").get_to(v); *((SANE_Fixed*)buf) = SANE_FIX(v); } else if (type == "string") { type = ""; jsn->at("default").get_to(type); strcpy((char*)buf, type.c_str()); } else return false; return true; } bool hg_scanner::is_to_file(void) { return resolution_ > 200 || paper_size_ == TwSS::USStatement || paper_size_ == TwSS::MaxSize || paper_size_ == TwSS::Trigeminy; } void hg_scanner::thread_handle_image_process(void) { while (run_ && !user_cancel_) { std::shared_ptr> buffer; if (imgs_.Size() == 0 && paths_.Size() == 0) { if (wait_usb_.is_waiting()) break; this_thread::sleep_for(chrono::milliseconds(30)); continue; } if (is_to_file()) { std::string file(paths_.Take()); FILE* src = fopen(file.c_str(), "rb+"); if (src) { unsigned length = 0; fseek(src, 0, SEEK_END); length = ftell(src); fseek(src, 0, SEEK_SET); buffer.reset(new std::vector); buffer->resize(length); fread(buffer->data(), 1, length, src); fclose(src); remove(file.c_str()); } else { HG_VLOG_MINI_1(HG_LOG_LEVEL_FATAL, "FATAL: open tempory image file '%s' failed.\n", file.c_str()); } } else { buffer = imgs_.Take(); } image_process(buffer); } } void hg_scanner::working_begin(void*) { final_img_index_ = 0; notify_ui_working_status(STATU_DESC_SCAN_WORKING, SANE_EVENT_WORKING, HG_ERR_OK); } void hg_scanner::working_done(void*) { imgs_.Clear(); while (paths_.Size()) { remove(paths_.Take().c_str()); } switch (status_) { case HG_ERR_OK: notify_ui_working_status(STATU_DESC_SCAN_STOPPED, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_BUSY: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_PC_BUSY, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_STOPPED: notify_ui_working_status(STATU_DESC_SCAN_STOPPED, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_COVER_OPENNED: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_COVER_OPENNED, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_NO_PAPER: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_NO_PAPER, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_FEEDING_PAPER: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_FEEDING_PAPER, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_NOT_FOUND: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_NOT_FOUND, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_SLEEPING: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_SLEEPING, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_COUNT_MODE: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_COUNT_MODE, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_DOUBLE_FEEDING: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_DOUBLE_FEEDING, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_PAPER_JAMMED: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_PAPER_JAMMED, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_STAPLE_ON: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_STAPLE_ON, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_PAPER_SKEW: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_PAPER_SKEW, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_SIZE_CHECK: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_SIZE_CHECK, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_DOGEAR: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_DOGEAR, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_NO_IMAGE: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_NO_IMAGE, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_SCANN_ERROR: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_SCANN_ERROR, SANE_EVENT_SCAN_FINISHED, status_); break; case HG_ERR_DEVICE_PC_BUSY: notify_ui_working_status(STATU_DESC_HG_ERR_DEVICE_PC_BUSY, SANE_EVENT_SCAN_FINISHED, status_); break; default: notify_ui_working_status(user_cancel_ ? STATU_DESC_SCAN_CANCELED : STATU_DESC_SCAN_STOPPED, SANE_EVENT_SCAN_FINISHED, status_); break; } //notify_ui_working_status(STATU_DESC_SCAN_STOPPED, SANE_EVENT_SCAN_FINISHED, status_); if (test_1_paper_) { HG_LOG(HG_LOG_LEVEL_DEBUG_INFO, "scanning mode: finished testing ONE paper, restore to normal scanning.\n"); } else { HG_VLOG_MINI_2(HG_LOG_LEVEL_DEBUG_INFO, "scanned %d picture(s) and finished with error %s.\n", final_img_index_, hg_scanner::strerr((hg_err)status_).c_str()); } test_1_paper_ = false; } void hg_scanner::reset_custom_area_range(int paper) { if (paper == PAPER_A3) { paper_size_mm_.cx = 297; paper_size_mm_.cy = 420; } else if (paper == PAPER_A4) { paper_size_mm_.cx = 210; paper_size_mm_.cy = 297; } else if (paper == PAPER_A4_LATERAL) { paper_size_mm_.cx = 297; paper_size_mm_.cy = 210; } else if (paper == PAPER_A5) { paper_size_mm_.cx = 148; paper_size_mm_.cy = 210; } else if (paper == PAPER_A5_LATERAL) { paper_size_mm_.cx = 210; paper_size_mm_.cy = 148; } else if (paper == PAPER_A6) { paper_size_mm_.cx = 105; paper_size_mm_.cy = 148; } else if (paper == PAPER_A6_LATERAL) { paper_size_mm_.cx = 148; paper_size_mm_.cy = 105; } else if (paper == PAPER_B4) { paper_size_mm_.cx = 250; paper_size_mm_.cy = 353; } else if (paper == PAPER_B5) { paper_size_mm_.cx = 176; paper_size_mm_.cy = 250; } else if (paper == PAPER_B6) { paper_size_mm_.cx = 125; paper_size_mm_.cy = 176; } else if (paper == PAPER_B5_LATERAL) { paper_size_mm_.cx = 250; paper_size_mm_.cy = 176; } else if (paper == PAPER_B6_LATERAL) { paper_size_mm_.cx = 176; paper_size_mm_.cy = 125; } else { paper_size_mm_.cx = 2338; paper_size_mm_.cy = 3307; } } int hg_scanner::setting_restore(void* data) { // restore ... int count = 0; setting_jsn_.at("option_count").get_to(count); notify_setting_result_ = false; for (int i = 1; i < count; ++i) restore(i); notify_setting_result_ = true; return HG_ERR_CONFIGURATION_CHANGED; } int hg_scanner::setting_help(void* data) { int ret = HG_ERR_OK; if (name_ == "华高扫描仪—G100") //保留 { /* code */ } std::string helpfile = helpfile_; std::string com = "xdg-open ";//注意空格保留 #ifdef WIN32 FILE* src = fopen(helpfile.c_str(), "rb"); if (src) fclose(src); else #else if (access(helpfile.c_str(),F_OK) == -1) #endif { HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO,"App_Help_pdf path is:%s\r\n",hg_scanner::strerr((hg_err)ret).c_str()); ret = HG_ERR_OPEN_FILE_FAILED; return ret ; } com += helpfile; system(com.c_str()); HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO,"App_Help_pdf path is:%s system is:%d\r\n",helpfile.c_str()); return ret; } int hg_scanner::setting_color_mode(void* data) { std::string str((char*)data); int old = image_prc_param_.bits.color_mode, sub = HG_ERR_OK, val = 0, ret = HG_ERR_OK; bool exact = check_range(setting_map_[HG_BASE_SETTING_INDEX_COLOR_MODE], str); val = image_prc_param_.bits.color_mode = match_best_color_mode(str, NULL); sub = on_color_mode_changed(val); image_prc_param_.bits.color_mode = val; if (sub == HG_ERR_NOT_EXACT) { image_prc_param_.bits.color_mode = old; str = color_mode_string(image_prc_param_.bits.color_mode); ret = HG_ERR_NOT_EXACT; } else if (sub) { ret = sub; image_prc_param_.bits.color_mode = old; } else if (!exact) { ret = HG_ERR_NOT_EXACT; } is_auto_matic_color = image_prc_param_.bits.color_mode == COLOR_MODE_AUTO_MATCH ? true :false; // 等于COLOR_MODE_AUTO_MATCH 的时候颜色模式需要变为2 彩色模式图像参数和硬件参数都如此 HG_VLOG_MINI_4(HG_LOG_LEVEL_DEBUG_INFO, "Change color mode from %s to %s = %s color is =%s\n", color_mode_string(old).c_str(), (char*)data, hg_scanner::strerr((hg_err)ret).c_str(),str.c_str()); if(ret == HG_ERR_NOT_EXACT) strcpy((char*)data, str.c_str()); return ret; } int hg_scanner::setting_multi_out(void *data) { int ret = HG_ERR_OK; if(image_prc_param_.bits.color_mode != 2) { ret = HG_ERR_INVALID_PARAMETER; return ret; } std::string str((char*)data); bool exact = check_range(setting_map_[HG_BASE_SETTING_MULTI_OUT], str); image_prc_param_.bits.multi_out = match_best_multi_out(str,NULL); HG_VLOG_MINI_3(HG_LOG_LEVEL_DEBUG_INFO, "set multi_out type from %s to %s = %s\n", multi_out_string(image_prc_param_.bits.multi_out).c_str(), (char*)data, hg_scanner::strerr((hg_err)ret).c_str()); return ret; } int hg_scanner::setting_rid_color(void* data) { std::string str((char*)data); int ret = HG_ERR_OK, color = -1, old = image_prc_param_.bits.rid_color; bool exact = check_range(setting_map_[HG_BASE_SETTING_INDEX_ERASE_COLOR], str); image_prc_param_.bits.rid_color = match_best_rid_color(str, NULL); on_color_mode_changed(color); if (!exact) { ret = HG_ERR_NOT_EXACT; strcpy((char*)data, str.c_str()); } return ret; } int hg_scanner::setting_rid_multi_red(void* data) { image_prc_param_.bits.rid_red = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_rid_answer_red(void* data) { image_prc_param_.bits.rid_answer_red = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_erase_background(void* data) { image_prc_param_.bits.erase_bakground = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_erase_background_range(void* data) { int ret = HG_ERR_OK; erase_bkg_range_ = *((int*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_ERASE_BACKGROUND_RANGE], erase_bkg_range_)) { ret = HG_ERR_NOT_EXACT; *((int*)data) = erase_bkg_range_; } return ret; } int hg_scanner::setting_noise_optimize(void* data) { image_prc_param_.bits.noise_optimize = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_noise_optimize_range(void* data) { int ret = HG_ERR_OK; noise_range_ = *((int*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_NOISE_OPTIMIZE_SIZE], noise_range_)) { ret = HG_ERR_NOT_EXACT; *((int*)data) = noise_range_; } return ret; } int hg_scanner::setting_paper(void* data) { std::string paper((char*)data); bool exact = check_range(setting_map_[HG_BASE_SETTING_INDEX_PAPER], paper); int ret = HG_ERR_OK, sub = HG_ERR_OK, val = 0, old = image_prc_param_.bits.paper; val = image_prc_param_.bits.paper = match_best_paper(paper, NULL); sub = on_paper_changed(val); image_prc_param_.bits.paper = val; if (sub == HG_ERR_NOT_EXACT) { ret = sub; paper = paper_string(image_prc_param_.bits.paper); } else if (sub) { ret = sub; image_prc_param_.bits.paper = old; } else if (!exact) ret = HG_ERR_NOT_EXACT; HG_VLOG_MINI_3(HG_LOG_LEVEL_DEBUG_INFO, "Change paper from %s to %s = %s\n", paper_string(old).c_str(), (char*)data, hg_scanner::strerr((hg_err)ret).c_str()); if(ret == HG_ERR_NOT_EXACT) strcpy((char*)data, paper.c_str()); if(old != image_prc_param_.bits.paper) reset_custom_area_range(image_prc_param_.bits.paper); return ret; } int hg_scanner::setting_paper_check(void* data) { bool use = *((bool*)data); int ret = on_paper_check_changed(use); HG_VLOG_MINI_2(HG_LOG_LEVEL_DEBUG_INFO, "Change paper size-checking %s = %s\n", *((bool*)data) ? "enabled" : "disabled", hg_scanner::strerr((hg_err)ret).c_str()); *((bool*)data) = use; return ret; } int hg_scanner::setting_page(void* data) { std::string val((char*)data); bool exact = check_range(setting_map_[HG_BASE_SETTING_INDEX_PAGE], val); int ret = exact ? HG_ERR_OK : HG_ERR_NOT_EXACT; HG_VLOG_MINI_3(HG_LOG_LEVEL_DEBUG_INFO, "Change page from %s to %s = %s\n", page_string(image_prc_param_.bits.page).c_str(), (char*)data, hg_scanner::strerr((hg_err)ret).c_str()); image_prc_param_.bits.page = match_best_page(val, NULL); if (!exact) strcpy((char*)data, val.c_str()); return ret; } int hg_scanner::setting_page_omit_empty(void* data) { int ret = HG_ERR_OK; omit_empty_level_ = *((int*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_PAGE_OMIT_EMPTY_LEVEL], omit_empty_level_)) { ret = HG_ERR_NOT_EXACT; *((int*)data) = omit_empty_level_; } return ret; } int hg_scanner::setting_resolution(void* data) { int ret = HG_ERR_OK, old = resolution_, sub = HG_ERR_OK; resolution_ = *((int*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_RESOLUTION], resolution_)) ret = HG_ERR_NOT_EXACT; sub = on_resolution_changed(resolution_); if (sub == HG_ERR_NOT_EXACT) ret = sub; else if (sub) ret = sub; HG_VLOG_MINI_3(HG_LOG_LEVEL_DEBUG_INFO, "Change resolution from %d to %d = %s\n", old, *((int*)data), hg_scanner::strerr((hg_err)ret).c_str()); *((int*)data) = resolution_; return ret; } int hg_scanner::setting_exchagnge(void* data) { image_prc_param_.bits.exchange = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_split_image(void* data) { image_prc_param_.bits.split = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_automatic_skew(void* data) { // automatic_skew_detection_ = *((bool*)data); image_prc_param_.bits.automatic_skew = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_rid_hole(void* data) { image_prc_param_.bits.rid_hole = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_rid_hoe_range(void* data) { int ret = HG_ERR_OK; rid_hole_range_ = *((double*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_RID_HOLE_RANGE], rid_hole_range_)) { ret = HG_ERR_NOT_EXACT; *((int*)data) = rid_hole_range_; } rid_hole_range_*=100; HG_VLOG_MINI_1(HG_LOG_LEVEL_WARNING, "rid_hole_range_ = %f\r\n", rid_hole_range_); return ret; } int hg_scanner::setting_bright(void* data) { int ret = HG_ERR_OK; bright_ = *((int*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_BRIGHT], bright_)) { ret = HG_ERR_NOT_EXACT; *((int*)data) = bright_; } return ret; } int hg_scanner::setting_contrast(void* data) { int ret = HG_ERR_OK; contrast_ = *((int*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_CONTRAST], contrast_)) { ret = HG_ERR_NOT_EXACT; *((int*)data) = contrast_; } return ret; } int hg_scanner::setting_gamma(void* data) { int ret = HG_ERR_OK; gamma_ = *((double*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_GAMMA], gamma_)) { ret = HG_ERR_NOT_EXACT; *((double*)data) = gamma_; } return ret; } int hg_scanner::setting_sharpen(void* data) { std::string str((char*)data); int ret = HG_ERR_OK; bool exact = check_range(setting_map_[HG_BASE_SETTING_INDEX_SHARPEN], str); HG_VLOG_MINI_2(HG_LOG_LEVEL_DEBUG_INFO, "Change sharpen from %s to %s = ", sharpen_string(image_prc_param_.bits.sharpen).c_str(), (char*)data); image_prc_param_.bits.sharpen = match_best_sharpen(str, NULL); if (!exact) { strcpy((char*)data, str.c_str()); ret = HG_ERR_NOT_EXACT; } HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "%d\n", ret); return ret; } int hg_scanner::setting_dark_sample(void* data) { image_prc_param_.bits.dark_sample = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_erase_black_frame(void* data) { image_prc_param_.bits.erase_black_frame = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_threshold(void* data) { int ret = HG_ERR_OK; threshold_ = *((int*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_THRESHOLD], threshold_)) { ret = HG_ERR_NOT_EXACT; *((int*)data) = threshold_; } return ret; } int hg_scanner::setting_anti_noise(void* data) { int ret = HG_ERR_OK; anti_noise_ = *((int*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_ANTI_NOISE_LEVEL], anti_noise_)) { ret = HG_ERR_NOT_EXACT; *((int*)data) = anti_noise_; } return ret; } int hg_scanner::setting_margin(void* data) { int ret = HG_ERR_OK; margin_ = *((int*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_MARGIN], margin_)) { ret = HG_ERR_NOT_EXACT; *((int*)data) = margin_; } return ret; } int hg_scanner::setting_filling_background(void* data) { std::string str((char*)data); bool exact = check_range(setting_map_[HG_BASE_SETTING_INDEX_FILL_BACKGROUND], str); int ret = exact ? HG_ERR_OK : HG_ERR_NOT_EXACT; image_prc_param_.bits.fill_background = match_best_fill_background(str, NULL); if (!exact) { strcpy((char*)data, str.c_str()); ret = HG_ERR_NOT_EXACT; } return ret; } int hg_scanner::setting_is_permeate(void* data) { image_prc_param_.bits.is_permeate = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_is_permeate_lv(void* data) { int ret = HG_ERR_OK; std::string str((char*)data); bool exact = check_range(setting_map_[HG_BASE_SETTING_INDEX_PERMEATE_LV], str); HG_VLOG_MINI_2(HG_LOG_LEVEL_DEBUG_INFO, "Change is_permeate_lv from %s to %s = ", is_permaeate_string(image_prc_param_.bits.is_permeate_lv_).c_str(), (char*)data); image_prc_param_.bits.is_permeate_lv_ = match_best_permaeate_lv(str, NULL); if (!exact) { strcpy((char*)data, str.c_str()); ret = HG_ERR_NOT_EXACT; } HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "%d\n", ret); return ret; } int hg_scanner::setting_remove_morr(void* data) { image_prc_param_.bits.remove_morr = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_error_extention(void* data) { image_prc_param_.bits.error_extention = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_remove_texture(void* data) { image_prc_param_.bits.remove_txtture = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_ultrasonic_check(void* data) { bool use = *((bool*)data); int ret = on_ultrasonic_check_changed(use); if (ret) *((bool*)data) = use; return ret; } int hg_scanner::setting_staple_check(void* data) { bool use = *((bool*)data); int ret = on_staple_check_changed(use); if (ret) *((bool*)data) = use; return ret; } int hg_scanner::setting_scan_mode(void* data) { std::string str((char*)data); bool exact = check_range(setting_map_[HG_BASE_SETTING_INDEX_SCAN_MODE], str); int ret = exact ? HG_ERR_OK : HG_ERR_NOT_EXACT; if (strcmp(str.c_str(), HUAGAO_SETTING_STR_SCAN_MODE_CONTINUOUS) == 0) { scan_count_ = -1; } else { char key[20]; sprintf(key, "%d", setting_map_[HG_BASE_SETTING_INDEX_SCAN_COUNT]); setting_jsn_.at(key).at("cur").get_to(scan_count_); } HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "set scanning pages to %d\n", scan_count_); return ret; } int hg_scanner::setting_scan_count(void* data) { int ret = HG_ERR_OK; char key[20]; std::string val(""); sprintf(key, "%d", setting_map_[HG_BASE_SETTING_INDEX_SCAN_MODE]); setting_jsn_.at(key).at("cur").get_to(val); if (val == HUAGAO_SETTING_STR_SCAN_MODE_CONTINUOUS) { scan_count_ = -1; } else { scan_count_ = *((int*)data); } HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "set scanning pages to %d\n", scan_count_); return ret; } int hg_scanner::setting_text_direction(void* data) { std::string str((char*)data); bool exact = check_range(setting_map_[HG_BASE_SETTING_INDEX_TEXT_DIRECTION], str); int ret = exact ? HG_ERR_OK : HG_ERR_NOT_EXACT; HG_VLOG_MINI_3(HG_LOG_LEVEL_DEBUG_INFO, "Change text direction from '%s' to '%s' = %s\n", text_direction_string(image_prc_param_.bits.text_direction).c_str() , (char*)data, hg_scanner::strerr((hg_err)ret).c_str()); image_prc_param_.bits.text_direction = match_best_text_direction(str, NULL); if (!exact) strcpy((char*)data, str.c_str()); return ret; } int hg_scanner::setting_rotate_bkg_180(void* data) { image_prc_param_.bits.rotate_back_180 = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_fractate_check(void* data) { image_prc_param_.bits.fractate_check = *((bool*)data); return HG_ERR_OK; } int hg_scanner::setting_fractate_check_level(void* data) { int ret = HG_ERR_OK; fractate_level_ = *((int*)data); if (!check_range(setting_map_[HG_BASE_SETTING_INDEX_FRACTATE_CHECK_LEVEL], fractate_level_)) { ret = HG_ERR_NOT_EXACT; *((int*)data) = fractate_level_; } return ret; } int hg_scanner::setting_skew_check(void* data) { bool use = *((bool*)data); int ret = on_skew_check_changed(use); if (ret) *((bool*)data) = use; return ret; } int hg_scanner::setting_skew_check_level(void* data) { int level = *((int*)data); bool exact = check_range(setting_map_[HG_BASE_SETTING_INDEX_SKEW_CHECK_LEVEL], level); int ret = exact ? HG_ERR_OK : HG_ERR_NOT_EXACT, sub = on_skew_check_level_changed(level); if (sub) { ret = sub; } if (ret) *((int*)data) = level; return ret; } int hg_scanner::setting_is_custom_gamma(void* data) { SANE_Bool* v = (SANE_Bool*)data; custom_gamma_ = *v == SANE_TRUE; return HG_ERR_OK; } int hg_scanner::setting_custom_gamma_data(void* data) { SANE_Gamma* gamma = (SANE_Gamma*)data; memcpy(custom_gamma_val_, gamma, sizeof(*custom_gamma_val_)); return HG_ERR_OK; } int hg_scanner::setting_is_custom_area(void* data) { SANE_Bool* v = (SANE_Bool*)data; custom_area_ = *v == SANE_TRUE; return HG_ERR_OK; } int hg_scanner::setting_custom_area_left(void* data) { SANE_Fixed* v = (SANE_Fixed*)data; custom_area_lt_x_ = *((double*)data); return HG_ERR_OK; } int hg_scanner::setting_custom_area_top(void* data) { SANE_Fixed* v = (SANE_Fixed*)data; custom_area_lt_y_ = *((double*)data); return HG_ERR_OK; } int hg_scanner::setting_custom_area_right(void* data) { SANE_Fixed* v = (SANE_Fixed*)data; custom_area_br_x_ = *((double*)data); return HG_ERR_OK; } int hg_scanner::setting_custom_area_bottom(void* data) { SANE_Fixed* v = (SANE_Fixed*)data; custom_area_br_y_ = *((double*)data); return HG_ERR_OK; } int hg_scanner::on_color_mode_changed(int& color_mode) { return HG_ERR_OK; } int hg_scanner::on_paper_changed(int& paper) { return HG_ERR_OK; } int hg_scanner::on_paper_check_changed(bool& check) { return HG_ERR_OK; } int hg_scanner::on_resolution_changed(int& dpi) { return HG_ERR_OK; } int hg_scanner::on_ultrasonic_check_changed(bool& check) { return HG_ERR_OK; } int hg_scanner::on_staple_check_changed(bool& check) { return HG_ERR_OK; } int hg_scanner::on_skew_check_changed(bool& check) { return HG_ERR_OK; } int hg_scanner::on_skew_check_level_changed(int& check) { return HG_ERR_OK; } void hg_scanner::on_device_reconnected(void) { std::lock_guard lock(io_lock_); HG_VLOG_MINI_2(HG_LOG_LEVEL_DEBUG_INFO, "%04x:%04x reconnected.\n", io_->get_vid(), io_->get_pid()); } int hg_scanner::set_setting_value(int setting_no, void* data, int len) { return HG_ERR_OK; } int hg_scanner::on_scanner_closing(bool force) { return HG_ERR_OK; } void hg_scanner::thread_handle_usb_read(void) { } void hg_scanner::init_settings(const char* json_setting_text) { setting_jsn_ = jsonconfig::load_json_from_text(json_setting_text); int count = 0; notify_setting_result_ = false; setting_jsn_.at("option_count").get_to(count); for (int sn = 1; sn < count; ++sn) { char key[20]; std::string val(""); sprintf(key, "%d", sn); setting_jsn_.at(key).at("name").get_to(val); if (val == KNOWN_OPT_NAME_CUSTOM_GAMMA) continue; setting_jsn_.at(key).at("type").get_to(val); if (val == "string") { val = ""; setting_jsn_.at(key).at("default").get_to(val); char* buf = NULL; int size = 0; setting_jsn_.at(key).at("size").get_to(size); buf = (char*)malloc(size + 4); bzero(buf, size + 4); strcpy(buf, val.c_str()); set_setting(sn, buf, val.length()); free(buf); } else if (val == "int") { int v = 0; setting_jsn_.at(key).at("default").get_to(v); set_setting(sn, (char*)&v, sizeof(v)); } else if (val == "float") { double v = .0f; setting_jsn_.at(key).at("default").get_to(v); set_setting(sn, (char*)&v, sizeof(v)); } else if (val == "bool") { bool v = false; setting_jsn_.at(key).at("default").get_to(v); set_setting(sn, (char*)&v, sizeof(v)); } } setting_count_ = count; notify_setting_result_ = true; } int hg_scanner::on_scann_error(int err) { status_ = err; HG_VLOG_MINI_1(HG_LOG_LEVEL_FATAL, "[xxx]Device status: 0x%x\n", err); unsigned int e = err; return ui_ev_cb_((scanner_handle)this, SANE_EVENT_ERROR, (void*)hg_scanner::strerr((hg_err)err).c_str(), &e, NULL); } int hg_scanner::notify_ui_working_status(const char* msg, int ev, int status) { unsigned int s = status; return ui_ev_cb_((scanner_handle)this, ev, (void*)msg, &s, NULL); } bool hg_scanner::waiting_for_memory_enough(unsigned need_bytes) { return true; // disable the memory control - added on 2022-03-22 bool ret = true; if(cb_mem_) { int ret = ui_ev_cb_((scanner_handle)this, SANE_EVENT_IS_MEMORY_ENOUGH, NULL, &need_bytes, NULL); if (ret == HG_ERR_INSUFFICIENT_MEMORY) { user_cancel_ = true; status_ = HG_ERR_INSUFFICIENT_MEMORY; ret = false; } else if (ret == HG_ERR_NOT_ANY_MORE) cb_mem_ = false; } else { need_bytes *= 4; void* buf = malloc(need_bytes); bool first = true; while (!buf && !user_cancel_) { if (first) { HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "Memory is too small for aquiring image(%u bytes), wait for ENOUGH ...\n", need_bytes); notify_ui_working_status(STATU_DESC_WAIT_FOR_MEM); first = false; } std::this_thread::sleep_for(std::chrono::milliseconds(30)); buf = malloc(need_bytes); } if (!first) { if (buf) { HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "waited for memory need(%u)\n", need_bytes); } else { HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "canceled by user while waiting for memory need(%u)\n", need_bytes); } } ret = (!user_cancel_) && (buf != NULL); if (buf) free(buf); } return ret; } void hg_scanner::copy_to_sane_image_header(SANE_Parameters* header, int w, int h, int line_bytes, int channels) { if (channels == 3) header->format = SANE_FRAME_RGB; else header->format = SANE_FRAME_GRAY; header->depth = 8; // 此处指每一个颜色分量的位深,我们的扫描仪固定为“8” header->last_frame = true; // 一幅图片如果各个分量相互分离,则最后一个分量的时候设置为true。彩色图像RGB时也只有一“帧”,所以也为true header->pixels_per_line = w; header->lines = h; header->bytes_per_line = line_bytes; } int hg_scanner::save_usb_data(std::shared_ptr> data) { int ret = HG_ERR_OK; HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "USB read one picture with %u bytes\n", data->size()); if (is_to_file()) { std::string file(""); ret = hg_scanner::save_2_tempory_file(data, &file); if (ret == HG_ERR_OK) paths_.Put(file); } else { imgs_.Put(data); #ifdef SAVE_TO_FILE hg_scanner::save_2_tempory_file(data, NULL); #endif } if (wait_img_.is_waiting()) wait_img_.notify(); return ret; } int hg_scanner::save_final_image(hg_imgproc::LPIMGHEAD head, void* buf) { final_img_index_++; if (async_io_) { SANE_Image img; copy_to_sane_image_header(&img.header, head->width, head->height, head->line_bytes, head->channels); img.data = (unsigned char*)buf; img.bytes = head->total_bytes; return ui_ev_cb_((scanner_handle)this, SANE_EVENT_IMAGE_OK, &img, &final_img_index_, NULL); } final_imgs_.put(head->width, head->height, head->bits, head->channels, head->line_bytes, buf, head->total_bytes); return HG_ERR_OK; } int hg_scanner::reset_io(usb_io* io) { online_ = false; if (!io) return HG_ERR_INVALID_PARAMETER; { std::lock_guard lock(io_lock_); usb_io* old = io_; io->add_ref(); io_ = io; status_ = io_->last_error(); online_ = status_ == HG_ERR_OK; if (old) old->release(); } on_device_reconnected(); return HG_ERR_OK; } int hg_scanner::io_disconnected(void) { std::lock_guard lock(io_lock_); online_ = false; io_->on_disconnected(); return HG_ERR_OK; } void hg_scanner::set_ui_callback(sane_callback cb, bool enable_async_io) { ui_ev_cb_ = cb ? cb : ui_default_callback; async_io_ = enable_async_io; } int hg_scanner::get_pid(void) { std::lock_guard lock(io_lock_); return io_->get_pid(); } int hg_scanner::get_vid(void) { std::lock_guard lock(io_lock_); return io_->get_vid(); } int hg_scanner::close(bool force) { int ret = on_scanner_closing(force); online_ = false; if (ret == HG_ERR_OK) { run_ = false; wait_usb_.notify(); wait_img_.notify(); if(!scan_life_) { std::lock_guard lock(io_lock_); if (io_) { io_->close(); io_->release(); io_ = NULL; } } else if (io_) { HG_LOG(HG_LOG_LEVEL_WARNING, "close scanner: USB thread or Image thread is still running.\n"); io_->close(); io_->release(); io_ = NULL; } status_ = HG_ERR_NOT_OPEN; } return ret; } int hg_scanner::set_setting(int setting_no, void* data, int len) { // NOTE: the array of 'func' must be ONE to ONE of the HG_BASE_SETTING_INDEX_xxx int(hg_scanner:: * func[])(void*) = { &hg_scanner::setting_restore , &hg_scanner::setting_help , &hg_scanner::setting_color_mode , &hg_scanner::setting_multi_out , &hg_scanner::setting_rid_color , &hg_scanner::setting_rid_multi_red , &hg_scanner::setting_rid_answer_red , &hg_scanner::setting_erase_background , &hg_scanner::setting_erase_background_range , &hg_scanner::setting_noise_optimize , &hg_scanner::setting_noise_optimize_range , &hg_scanner::setting_paper , &hg_scanner::setting_paper_check , &hg_scanner::setting_is_custom_area , &hg_scanner::setting_custom_area_left , &hg_scanner::setting_custom_area_right , &hg_scanner::setting_custom_area_top , &hg_scanner::setting_custom_area_bottom , &hg_scanner::setting_page , &hg_scanner::setting_page_omit_empty , &hg_scanner::setting_resolution , &hg_scanner::setting_exchagnge , &hg_scanner::setting_split_image , &hg_scanner::setting_automatic_skew , &hg_scanner::setting_rid_hole , &hg_scanner::setting_rid_hoe_range , &hg_scanner::setting_is_custom_gamma // 2022-05-05 , &hg_scanner::setting_bright , &hg_scanner::setting_contrast , &hg_scanner::setting_gamma , &hg_scanner::setting_custom_gamma_data , &hg_scanner::setting_sharpen , &hg_scanner::setting_dark_sample , &hg_scanner::setting_erase_black_frame , &hg_scanner::setting_threshold , &hg_scanner::setting_anti_noise , &hg_scanner::setting_margin , &hg_scanner::setting_filling_background , &hg_scanner::setting_is_permeate , &hg_scanner::setting_is_permeate_lv , &hg_scanner::setting_remove_morr , &hg_scanner::setting_error_extention , &hg_scanner::setting_remove_texture , &hg_scanner::setting_ultrasonic_check , &hg_scanner::setting_staple_check , &hg_scanner::setting_scan_mode , &hg_scanner::setting_scan_count , &hg_scanner::setting_text_direction , &hg_scanner::setting_rotate_bkg_180 , &hg_scanner::setting_fractate_check , &hg_scanner::setting_fractate_check_level , &hg_scanner::setting_skew_check , &hg_scanner::setting_skew_check_level }; bool hit = false; int ret = HG_ERR_OUT_OF_RANGE; char sn[20]; sprintf(sn, "%d", setting_no); for (size_t i = 0; i < ARRAY_SIZE(func); ++i) { if (setting_map_[i] == setting_no) { ret = (this->*func[i])(data); hit = true; break; } } if (!hit) { HG_VLOG_MINI_1(HG_LOG_LEVEL_WARNING, "Setting %d is not found in base setting functions.\n", setting_no); ret = set_setting_value(setting_no, data, len); } if (ret == HG_ERR_OK || ret == HG_ERR_NOT_EXACT || ret == HG_ERR_CONFIGURATION_CHANGED) { std::string type(""), name(""); setting_jsn_.at(sn).at("type").get_to(type); setting_jsn_.at(sn).at("title").get_to(name); if (type == "string") { setting_jsn_.at(sn).at("cur") = (char*)data; type = (char*)data; } else if (type == "int") { setting_jsn_.at(sn).at("cur") = *((int*)data); sprintf(sn, "%d", *((int*)data)); type = sn; } else if (type == "float") { setting_jsn_.at(sn).at("cur") = *((double*)data); sprintf(sn, "%f", *((double*)data)); type = sn; } else if (type == "bool") { setting_jsn_.at(sn).at("cur") = *((bool*)data); type = *((bool*)data) ? "true" : "false"; } if (notify_setting_result_) { name.insert(0, "设置 “"); name += "” 值为“"; name += type + "” 成功。"; notify_ui_working_status(name.c_str()); } } else if (notify_setting_result_) { std::string name(""); if (setting_jsn_.contains(sn)) { setting_jsn_.at(sn).at("title").get_to(name); } else name = std::string("设置项") + sn; name.insert(0, "设置 “"); name += "” 值失败: " + hg_scanner::strerr((hg_err)ret); notify_ui_working_status(name.c_str()); } return ret; } int hg_scanner::get_setting(int setting_no, char* json_txt_buf, int* len) { if (!len) return HG_ERR_INVALID_PARAMETER; if (setting_no == 0) { int count = 0; setting_jsn_.at("option_count").get_to(count); *len = count; return HG_ERR_OK; } if (setting_count_ <= setting_no || setting_no < 0) return HG_ERR_OUT_OF_RANGE; char sn[20]; std::string text(""), name(""), tag(""); int add = 0; bool is_gamma = false, is_area_x = false, is_area_y = false; sprintf(sn, "%d", setting_no); if (!setting_jsn_.contains(sn)) HG_VLOG_MINI_2(HG_LOG_LEVEL_FATAL, "!!!option(%d - %s) is not found.\n", setting_no, sn); text = setting_jsn_.at(sn).dump(); setting_jsn_.at(sn).at("name").get_to(name); if (name == KNOWN_OPT_NAME_CUSTOM_GAMMA) { is_gamma = true; add = 4 * sizeof(custom_gamma_val_); } else if (name == KNOWN_OPT_NAME_CUSTOM_AREA_LEFT || name == KNOWN_OPT_NAME_CUSTOM_AREA_RIGHT) { is_area_x = true; add = 20; } else if (name == KNOWN_OPT_NAME_CUSTOM_AREA_TOP || name == KNOWN_OPT_NAME_CUSTOM_AREA_BOTTOM) { is_area_y = true; add = 20; } if (*len <= text.length() + add) { *len = text.length() + 8 + add; return HG_ERR_INSUFFICIENT_MEMORY; } if (is_gamma) { name = ""; add = 3 * 256; sprintf(sn, "[%u", custom_gamma_val_->table[0]); name += sn; for (int i = 1; i < add; ++i) { sprintf(sn, ",%u", custom_gamma_val_->table[i]); name += sn; } name += "]"; tag = "\"cur\":"; } else if (is_area_x) { sprintf(sn, "%u.0", paper_size_mm_.cx); name = sn; tag = "\"max\":"; } else if (is_area_y) { sprintf(sn, "%u.0", paper_size_mm_.cy); name = sn; tag = "\"max\":"; } if (!tag.empty()) { size_t pos = text.find(tag), end = pos; if (pos != std::string::npos) { pos += tag.length(); end = pos; while (end < text.length()) { if (text[end] == ',' || text[end] == '}' || text[end] == ']' || text[end] == '\r' || text[end] == '\n') break; end++; } if (end > pos) text.replace(pos, end - pos, name); else text.insert(end, name); } } strcpy(json_txt_buf, text.c_str()); *len = text.length(); return HG_ERR_OK; } std::string hg_scanner::name(void) { return name_; } int hg_scanner::status(void) { return status_; } bool hg_scanner::is_online(void) { return online_; } int hg_scanner::start(void) { user_cancel_ = false; return status_; } int hg_scanner::get_image_info(SANE_Parameters* ii) { int ret = HG_ERR_OK; IMH imh; bzero(&imh, sizeof(imh)); while ((!wait_img_.is_waiting() || !wait_usb_.is_waiting()) && final_imgs_.Size() <= 0) this_thread::sleep_for(chrono::milliseconds(10)); if (final_imgs_.Size() <= 0) ret = HG_ERR_NO_DATA; else { if (!final_imgs_.front(&imh)) ret = HG_ERR_NO_DATA; else copy_to_sane_image_header(ii, imh.width, imh.height, imh.line_bytes, imh.channels); } HG_VLOG_MINI_4(HG_LOG_LEVEL_DEBUG_INFO, "Get image info(%d * %d * %d) = %s\n", ii->pixels_per_line, ii->lines, imh.bits, hg_scanner::strerr((hg_err)ret).c_str()); return ret; } int hg_scanner::read_image_data(unsigned char* buf, int* len) { if (!len) return HG_ERR_INVALID_PARAMETER; if (!buf) { IMH imh; final_imgs_.front(&imh); *len = imh.bytes; return HG_ERR_INSUFFICIENT_MEMORY; } if (final_imgs_.Size() > 0) { int fetch = *len; bool over = false; final_imgs_.fetch_front(buf, len, &over); return over ? HG_ERR_NO_DATA : HG_ERR_OK; } else return HG_ERR_NO_DATA; } int hg_scanner::stop(void) { user_cancel_ = true; return status_; } int hg_scanner::reset(void) { return status_; } int hg_scanner::device_io_control(unsigned long code, void* data, unsigned* len) { if (code == IO_CTRL_CODE_RESTORE_SETTINGS) { setting_restore(data); return HG_ERR_CONFIGURATION_CHANGED; } else if (code == IO_CTRL_CODE_GET_DEFAULT_VALUE) { char* jsn_txt = NULL; int size = 0; json jsn; int ret = get_setting(*len, jsn_txt, &size); if (ret == HG_ERR_INSUFFICIENT_MEMORY) { jsn_txt = (char*)malloc(size + 4); bzero(jsn_txt, size + 4); get_setting(*len, jsn_txt, &size); jsn = jsonconfig::load_json_from_text(jsn_txt); free(jsn_txt); if (get_default_value(data, &jsn)) ret = HG_ERR_OK; else ret = HG_ERR_DATA_DAMAGED; } return ret; } else if (code == IO_CTRL_CODE_CLEAR_ROLLER_COUNT) { int count = get_roller_num(); if (len) *len = count; return clear_roller_num(); } else if (code == IO_CTRL_CODE_SET_FINAL_IMAGE_FORMAT) { SANE_FinalImgFormat* fmt = (SANE_FinalImgFormat*)data; return set_final_image_format(fmt); } else if(code == IO_CTRL_CODE_TEST_SINGLE) { return set_leaflet_scan(); } else if (code == IO_CTRL_CODE_SET_AUTO_COLOR_TYPE) { return set_auto_color_type(); } else if(code == IO_CTRL_CODE_GET_HARDWARE_VERSION) { std::string fw = get_firmware_version(); if (*len < fw.size()) { *len = fw.size(); return HG_ERR_INSUFFICIENT_MEMORY; } char* buf = strcpy((char*)data, fw.c_str()); if (buf) { return HG_ERR_OK; } return HG_ERR_DATA_DAMAGED; } else if(code == IO_CTRL_CODE_GET_SERIAL) { std::string ser = get_serial_num(); if (*len < ser.size()) { *len = ser.size(); return HG_ERR_INSUFFICIENT_MEMORY; } char* buf = strcpy((char*)data, ser.c_str()); if (buf) { return HG_ERR_OK; } return HG_ERR_DATA_DAMAGED; } else if (code == IO_CTRL_CODE_GET_HARDWARE_VERSION) { std::string ip = get_ip(); if (*len < ip.size()) { *len = ip.size(); return HG_ERR_INSUFFICIENT_MEMORY; } char* buf = strcpy((char*)data, ip.c_str()); if (buf) { return HG_ERR_OK; } return HG_ERR_DATA_DAMAGED; } else if (code == IO_CTRL_CODE_GET_PAPER_ON) { return get_scanner_paperon((SANE_Bool*)data); } else if(code == IO_CTRL_CODE_GET_POWER_LEVEL) { int val = 0, ret = HG_ERR_OK; if (*len < sizeof(int *)) { *len = sizeof(int *); return HG_ERR_INSUFFICIENT_MEMORY; } ret = get_sleep_time(val); if (ret == HG_ERR_OK) { *((int *)data) = val; } return ret; } else if(code == IO_CTRL_CODE_SET_POWER_LEVEL) { int val = *((int*)data); int sleeptime = 0; switch (val) { case SANE_POWER_NONE: sleeptime = 0; break; case SANE_POWER_MINUTES_5: sleeptime = 300; break; case SANE_POWER_MINUTES_10: sleeptime = 600; break; case SANE_POWER_MINUTES_20: sleeptime = 1200; break; case SANE_POWER_MINUTES_30: sleeptime = 1800; break; case SANE_POWER_MINUTES_60: sleeptime = 3600; break; case SANE_POWER_MINUTES_120: sleeptime = 7200; break; case SANE_POWER_MINUTES_240: sleeptime = 14400; break; default: sleeptime = 0; break; } return set_sleep_time(sleeptime); } else if (code == IO_CTRL_CODE_GET_CUSTOM_GAMMA) { SANE_Gamma* v = (SANE_Gamma*)data; memcpy(v, custom_gamma_val_, sizeof(*custom_gamma_val_)); return HG_ERR_OK; } else if (code == IO_CTRL_CODE_SET_CUSTOM_GAMMA) { SANE_Gamma* v = (SANE_Gamma*)data; memcpy(custom_gamma_val_, v, sizeof(*custom_gamma_val_)); return HG_ERR_OK; } return HG_ERR_DEVICE_NOT_SUPPORT; } std::string hg_scanner::get_firmware_version(void) { return ""; } std::string hg_scanner::get_serial_num(void) { return ""; } std::string hg_scanner::get_ip(void) { return ""; } int hg_scanner::get_roller_num(void) { return -1; } int hg_scanner::clear_roller_num(void) { return HG_ERR_DEVICE_NOT_SUPPORT; } ////////////////////////////////////////////////////////////////////////////////////////////////////// int hg_scanner::set_leaflet_scan(void) { return HG_ERR_NO_DATA; } int hg_scanner::get_abuot_info(void) { return HG_ERR_NO_DATA; } int hg_scanner::restore_default_setting(void) { return HG_ERR_NO_DATA; } int hg_scanner::set_final_image_format(SANE_FinalImgFormat* fmt) { switch (fmt->img_format) { case SANE_IMAGE_TYPE_BMP: img_type_ = ".bmp"; break; case SANE_IMAGE_TYPE_PNG: img_type_ = ".png"; break; case SANE_IMAGE_TYPE_JPG: img_type_ = ".jpg"; break; case SANE_IMAGE_TYPE_TIFF: return HG_ERR_INVALID_PARAMETER; case SANE_IMAGE_TYPE_WEBP: return HG_ERR_INVALID_PARAMETER; case SANE_IMAGE_TYPE_PDF: return HG_ERR_INVALID_PARAMETER; case SANE_IMAGE_TYPE_GIF: return HG_ERR_INVALID_PARAMETER; case SANE_IMAGE_TYPE_SVG: return HG_ERR_INVALID_PARAMETER; default: img_type_ = ""; break; } return HG_ERR_OK; } int hg_scanner::get_compression_format(void) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_compression_format(void) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_auto_color_type(void) { is_auto_matic_color = true; return HG_ERR_OK; } int hg_scanner::get_device_code(void) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_sleep_time(int& getsleepime) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_sleep_time(int sleeptime) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_dogear_distance(void) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_dogear_distance(void) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_scanner_paperon(SANE_Bool* paperon) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_scan_when_paper_on(void) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_scan_when_paper_on(void) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_scan_with_hole(void) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_scan_with_hole(void) { return HG_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_scan_is_sleep(void) { return HG_ERR_DEVICE_NOT_SUPPORT; }