#include "hg_scanner.h" #include "../wrapper/hg_log.h" #include "sane/sane_option_definitions.h" #if defined(WIN32) || defined(_WIN64) #include "scanner_manager.h" #include #endif static int ui_default_callback(scanner_handle, int, void*, unsigned int*, void*) { return 0; } static std::string bmp_821(unsigned char* bits/*bits data*/, int w, int h, int* lbytes, bool line_align_4, int threashold) { static unsigned int g_bmp8_pallete[] = { 0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0, 0x00c0dcc0, 0x00a6caf0, 0x00402000, 0x00602000, 0x00802000, 0x00a02000, 0x00c02000, 0x00e02000 , 0x00004000, 0x00204000, 0x00404000, 0x00604000, 0x00804000, 0x00a04000, 0x00c04000, 0x00e04000, 0x00006000, 0x00206000, 0x00406000, 0x00606000, 0x00806000, 0x00a06000, 0x00c06000, 0x00e06000 , 0x00008000, 0x00208000, 0x00408000, 0x00608000, 0x00808000, 0x00a08000, 0x00c08000, 0x00e08000, 0x0000a000, 0x0020a000, 0x0040a000, 0x0060a000, 0x0080a000, 0x00a0a000, 0x00c0a000, 0x00e0a000 , 0x0000c000, 0x0020c000, 0x0040c000, 0x0060c000, 0x0080c000, 0x00a0c000, 0x00c0c000, 0x00e0c000, 0x0000e000, 0x0020e000, 0x0040e000, 0x0060e000, 0x0080e000, 0x00a0e000, 0x00c0e000, 0x00e0e000 , 0x00000040, 0x00200040, 0x00400040, 0x00600040, 0x00800040, 0x00a00040, 0x00c00040, 0x00e00040, 0x00002040, 0x00202040, 0x00402040, 0x00602040, 0x00802040, 0x00a02040, 0x00c02040, 0x00e02040 , 0x00004040, 0x00204040, 0x00404040, 0x00604040, 0x00804040, 0x00a04040, 0x00c04040, 0x00e04040, 0x00006040, 0x00206040, 0x00406040, 0x00606040, 0x00806040, 0x00a06040, 0x00c06040, 0x00e06040 , 0x00008040, 0x00208040, 0x00408040, 0x00608040, 0x00808040, 0x00a08040, 0x00c08040, 0x00e08040, 0x0000a040, 0x0020a040, 0x0040a040, 0x0060a040, 0x0080a040, 0x00a0a040, 0x00c0a040, 0x00e0a040 , 0x0000c040, 0x0020c040, 0x0040c040, 0x0060c040, 0x0080c040, 0x00a0c040, 0x00c0c040, 0x00e0c040, 0x0000e040, 0x0020e040, 0x0040e040, 0x0060e040, 0x0080e040, 0x00a0e040, 0x00c0e040, 0x00e0e040 , 0x00000080, 0x00200080, 0x00400080, 0x00600080, 0x00800080, 0x00a00080, 0x00c00080, 0x00e00080, 0x00002080, 0x00202080, 0x00402080, 0x00602080, 0x00802080, 0x00a02080, 0x00c02080, 0x00e02080 , 0x00004080, 0x00204080, 0x00404080, 0x00604080, 0x00804080, 0x00a04080, 0x00c04080, 0x00e04080, 0x00006080, 0x00206080, 0x00406080, 0x00606080, 0x00806080, 0x00a06080, 0x00c06080, 0x00e06080 , 0x00008080, 0x00208080, 0x00408080, 0x00608080, 0x00808080, 0x00a08080, 0x00c08080, 0x00e08080, 0x0000a080, 0x0020a080, 0x0040a080, 0x0060a080, 0x0080a080, 0x00a0a080, 0x00c0a080, 0x00e0a080 , 0x0000c080, 0x0020c080, 0x0040c080, 0x0060c080, 0x0080c080, 0x00a0c080, 0x00c0c080, 0x00e0c080, 0x0000e080, 0x0020e080, 0x0040e080, 0x0060e080, 0x0080e080, 0x00a0e080, 0x00c0e080, 0x00e0e080 , 0x000000c0, 0x002000c0, 0x004000c0, 0x006000c0, 0x008000c0, 0x00a000c0, 0x00c000c0, 0x00e000c0, 0x000020c0, 0x002020c0, 0x004020c0, 0x006020c0, 0x008020c0, 0x00a020c0, 0x00c020c0, 0x00e020c0 , 0x000040c0, 0x002040c0, 0x004040c0, 0x006040c0, 0x008040c0, 0x00a040c0, 0x00c040c0, 0x00e040c0, 0x000060c0, 0x002060c0, 0x004060c0, 0x006060c0, 0x008060c0, 0x00a060c0, 0x00c060c0, 0x00e060c0 , 0x000080c0, 0x002080c0, 0x004080c0, 0x006080c0, 0x008080c0, 0x00a080c0, 0x00c080c0, 0x00e080c0, 0x0000a0c0, 0x0020a0c0, 0x0040a0c0, 0x0060a0c0, 0x0080a0c0, 0x00a0a0c0, 0x00c0a0c0, 0x00e0a0c0 , 0x0000c0c0, 0x0020c0c0, 0x0040c0c0, 0x0060c0c0, 0x0080c0c0, 0x00a0c0c0, 0x00fffbf0, 0x00a0a0a4, 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00, 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff }; int l = (w + 31) / 32 * 4, size = l * h, line_bytes = (w + 3) / 4 * 4; std::string f(""); unsigned char* data = nullptr; unsigned int* pallete = g_bmp8_pallete; if (!line_align_4) { l = (w + 7) / 8; size = l * h; } if (lbytes && *lbytes) line_bytes = *lbytes; f.resize(size); data = (unsigned char*)&f[0]; for (int i = 0; i < h; ++i) { unsigned char v = 0, *dst = data; for (int j = 0; j < w; ++j) { v <<= 1; unsigned char pixel = ((pallete[bits[j]] & 0x0ff) + ((pallete[bits[j]] >> 8) & 0x0ff) + ((pallete[bits[j]] >> 16) & 0x0ff)) / 3; if (pixel >= threashold) v |= 1; if ((j + 1) % 8 == 0) { *dst++ = v; v = 0; } } if (w % 8) { v <<= 8 - (w % 8); *dst++ = v; } data += l; bits += line_bytes; } if (lbytes) *lbytes = l; return f; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // hg_scanner hg_scanner::hg_scanner(ScannerSerial serial , const char* dev_name, usb_io* io) : name_(dev_name ? dev_name : ""), io_(io), status_(SCANNER_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),is_quality_(-1),is_color_fill(false),is_multiout(false),save_multiout(OPTION_VALUE_DLSC_CS_HD_HB) , final_img_index_(0), custom_area_(false),save_sizecheck(false), bw_threshold_(128), custom_gamma_(false), double_paper_handle_(0) { final_path_ = hg_log::ini_get("paths", "final_img"); if(final_path_.empty()) final_path_ = hg_log::local_data_path() + PATH_SEPARATOR + "imgs"; if (hg_log::create_folder(final_path_.c_str())) { VLOG_MINI_1(LOG_LEVEL_WARNING, "temporary image folder: %s\n", final_path_.c_str()); final_path_ += PATH_SEPARATOR; } else { VLOG_MINI_1(LOG_LEVEL_WARNING, "create temporary image folder failed: %s\n", final_path_.c_str()); final_path_ = ""; } 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; VLOG_MINI_2(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_ == SCANNER_ERR_OK; } wait_usb_.set_debug_info("USB"); wait_img_.set_debug_info("Image"); wait_usb_result_.set_debug_info("start"); 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); VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "%s(%s) destroyed.\n", name_.c_str(), hg_log::format_ptr(this).c_str()); } std::string hg_scanner::temporary_file(char* tail, char* head) { std::string path("/tmp/"); char buf[128]; FILE* src = NULL; unsigned int ind = 1; if (!head || *head == 0) head = (char*)"scan"; if (!tail) tail = (char*)""; #if defined(WIN32) || defined(_WIN64) char me[MAX_PATH] = { 0 }, * n = NULL; GetModuleFileNameA(NULL, me, _countof(me) - 1); n = strrchr(me, '\\'); if (n++ == NULL) n = me; *n = 0; path = me; path += "img_tmp\\"; mkdir(path.c_str()); #endif srand(time(NULL)); sprintf(buf, "%s%s", head, tail); while ((src = fopen((path + buf).c_str(), "rb"))) { fclose(src); sprintf(buf, "%s(%u)%s", head, ind++, tail); } return path + buf; } int hg_scanner::save_2_tempory_file(std::shared_ptr> data, std::string* path_file, unsigned int index) { char head[40] = { 0 }; std::string file(""); FILE* dst = nullptr; int ret = SCANNER_ERR_OK; sprintf(head, "usb_%05u", index); if(!path_file || path_file->empty()) file = hg_scanner::temporary_file((char*)".jpg", (char*)head); dst = fopen(file.c_str(), "wb"); if (dst) { size_t wrote = fwrite(data->data(), 1, data->size(), dst); if (wrote == data->size()) { if (path_file) *path_file = file; VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "--->Wrote %u bytes to file '%s'\n", wrote, file.c_str()); } else { ret = SCANNER_ERR_WRITE_FILE_FAILED; VLOG_MINI_3(LOG_LEVEL_FATAL, "Failed in writting file(%u/%u) '%s'\n", wrote, data->size(), file.c_str()); } fclose(dst); } else { ret = SCANNER_ERR_CREATE_FILE_FAILED; VLOG_MINI_1(LOG_LEVEL_FATAL, "Failed in creating file '%s'\n", file.c_str()); } return ret; } void hg_scanner::set_setting_map(int sn, const char* title) { std::string val(title); int empty = 0; while (empty < val.length() && val[empty] == ' ') empty++; val.erase(0, empty); //VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "title: '%s', val: '%s'\n", title, val.c_str()); if (val == OPTION_TITLE_HFMRSZ) setting_map_[sn] = &hg_scanner::setting_restore; else if (val == OPTION_TITLE_BZ) setting_map_[sn] = &hg_scanner::setting_help; else if (val == OPTION_TITLE_YSMS) setting_map_[sn] = &hg_scanner::setting_color_mode; else if (val == OPTION_TITLE_DLSC) setting_map_[sn] = &hg_scanner::setting_multi_out; else if (val == OPTION_TITLE_DLSCLX) setting_map_[sn] = &hg_scanner::setting_multi_out_type; else if (val == OPTION_TITLE_HDHHBTX_CS) setting_map_[sn] = &hg_scanner::setting_rid_color; else if (val == OPTION_TITLE_24WCSTX_DLSCCH) setting_map_[sn] = &hg_scanner::setting_rid_multi_red; else if (val == OPTION_TITLE_24WCSTX_DTKCH) setting_map_[sn] = &hg_scanner::setting_rid_answer_red; else if (val == OPTION_TITLE_BJYC) setting_map_[sn] = &hg_scanner::setting_erase_background; else if (val == OPTION_TITLE_BJSCFDFW) setting_map_[sn] = &hg_scanner::setting_erase_background_range; else if (val == OPTION_TITLE_HBTXZDYH) setting_map_[sn] = &hg_scanner::setting_noise_optimize; else if (val == OPTION_TITLE_ZDYHCC) setting_map_[sn] = &hg_scanner::setting_noise_optimize_range; else if (val == OPTION_TITLE_ZZCC) setting_map_[sn] = &hg_scanner::setting_paper; else if (val == OPTION_TITLE_CCJC) setting_map_[sn] = &hg_scanner::setting_paper_check; else if (val == OPTION_TITLE_ZDYSMQY) setting_map_[sn] = &hg_scanner::setting_is_custom_area; else if (val == OPTION_TITLE_SMQYZCmm) setting_map_[sn] = &hg_scanner::setting_custom_area_left; else if (val == OPTION_TITLE_SMQYYCmm) setting_map_[sn] = &hg_scanner::setting_custom_area_right; else if (val == OPTION_TITLE_SMQYSCmm) setting_map_[sn] = &hg_scanner::setting_custom_area_top; else if (val == OPTION_TITLE_SMQYXCmm) setting_map_[sn] = &hg_scanner::setting_custom_area_bottom; else if (val == OPTION_TITLE_SMYM) setting_map_[sn] = &hg_scanner::setting_page; else if (val == OPTION_TITLE_TGKBYLMD) setting_map_[sn] = &hg_scanner::setting_page_omit_empty; else if (val == OPTION_TITLE_FBL) setting_map_[sn] = &hg_scanner::setting_resolution; else if (val == OPTION_TITLE_HZ) setting_map_[sn] = &hg_scanner::setting_img_quality; else if (val == OPTION_TITLE_JHZFM) setting_map_[sn] = &hg_scanner::setting_exchagnge; else if (val == OPTION_TITLE_TXCF) setting_map_[sn] = &hg_scanner::setting_split_image; else if (val == OPTION_TITLE_ZDJP) setting_map_[sn] = &hg_scanner::setting_automatic_skew; else if (val == OPTION_TITLE_CKYC) setting_map_[sn] = &hg_scanner::setting_rid_hole; else if (val == OPTION_TITLE_CKSSFWZFMBL) setting_map_[sn] = &hg_scanner::setting_rid_hoe_range; else if (val == OPTION_TITLE_QYSDQX) setting_map_[sn] = &hg_scanner::setting_is_custom_gamma; else if (val == OPTION_TITLE_LDZ) setting_map_[sn] = &hg_scanner::setting_bright; else if (val == OPTION_TITLE_DBD) setting_map_[sn] = &hg_scanner::setting_contrast; else if (val == OPTION_TITLE_GMZ) setting_map_[sn] = &hg_scanner::setting_gamma; else if (val == OPTION_TITLE_RHYMH) setting_map_[sn] = &hg_scanner::setting_sharpen; else if (val == OPTION_TITLE_SSYZ) setting_map_[sn] = &hg_scanner::setting_dark_sample; else if (val == OPTION_TITLE_XCHK) setting_map_[sn] = &hg_scanner::setting_erase_black_frame; else if (val == OPTION_TITLE_YZ) setting_map_[sn] = &hg_scanner::setting_threshold; else if (val == OPTION_TITLE_BJKZDJ) setting_map_[sn] = &hg_scanner::setting_anti_noise; else if (val == OPTION_TITLE_BYSJ) setting_map_[sn] = &hg_scanner::setting_margin; else if (val == OPTION_TITLE_BJTCFS) setting_map_[sn] = &hg_scanner::setting_filling_background; else if (val == OPTION_TITLE_FZST) setting_map_[sn] = &hg_scanner::setting_is_permeate; else if (val == OPTION_TITLE_FZSTDJ) setting_map_[sn] = &hg_scanner::setting_is_permeate_lv; else if (val == OPTION_TITLE_QCMW) setting_map_[sn] = &hg_scanner::setting_remove_morr; else if (val == OPTION_TITLE_CWKS) setting_map_[sn] = &hg_scanner::setting_error_extention; else if (val == OPTION_TITLE_CWW) setting_map_[sn] = &hg_scanner::setting_remove_texture; else if (val == OPTION_TITLE_CSBJC) setting_map_[sn] = &hg_scanner::setting_ultrasonic_check; else if (val == OPTION_TITLE_SZTPCL) setting_map_[sn] = &hg_scanner::setting_go_on_when_double_checked; else if (val == OPTION_TITLE_ZDJC) setting_map_[sn] = &hg_scanner::setting_staple_check; else if (val == OPTION_TITLE_SMZS) { setting_map_[sn] = &hg_scanner::setting_scan_mode; id_scan_mode_ = sn; } else if (val == OPTION_TITLE_SMSL) { setting_map_[sn] = &hg_scanner::setting_scan_count; id_scan_count_ = sn; } else if (val == OPTION_TITLE_WGFX) setting_map_[sn] = &hg_scanner::setting_text_direction; else if (val == OPTION_TITLE_BMXZ180) setting_map_[sn] = &hg_scanner::setting_rotate_bkg_180; else if (val == OPTION_TITLE_ZJJC) setting_map_[sn] = &hg_scanner::setting_fractate_check; else if (val == OPTION_TITLE_ZJDX) setting_map_[sn] = &hg_scanner::setting_fractate_check_level; else if (val == OPTION_TITLE_WXJC) setting_map_[sn] = &hg_scanner::setting_skew_check; else if (val == OPTION_TITLE_WXRRD) setting_map_[sn] = &hg_scanner::setting_skew_check_level; else if (val == OPTION_TITLE_SCTC) setting_map_[sn] = &hg_scanner::setting_color_fill; else if(val == OPTION_TITLE_HBTXYZ) setting_map_[sn] = &hg_scanner::setting_black_white_threshold; } 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_) { LOG_INFO(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); usb_img_index_ = 0; 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); //VLOG_MINI_3(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("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 = SCANNER_ERR_OK; return sn; } bool hg_scanner::get_default_value(void* buf, json* jsn) { std::string type(""); 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 tiny_buffer; if (imgs_.Size() == 0) { if (wait_usb_.is_waiting()) break; this_thread::sleep_for(chrono::milliseconds(30)); continue; } tiny_buffer = imgs_.Take(); if(tiny_buffer->swap()) image_process(tiny_buffer); else { VLOG_MINI_1(LOG_LEVEL_FATAL, "Reload USB data '%s' failed!\n", tiny_buffer->file().c_str()); } } } void hg_scanner::working_begin(void*) { final_img_index_ = 0; notify_ui_working_status(STATU_DESC_SCAN_WORKING, SANE_EVENT_WORKING, SCANNER_ERR_OK); VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "[%s] scanning ...\n", hg_log::current_time().c_str()); } void hg_scanner::working_done(void*) { imgs_.Clear(); if(user_cancel_) final_imgs_.clear(); switch (status_) { case SCANNER_ERR_OK: notify_ui_working_status(STATU_DESC_SCAN_STOPPED, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_BUSY: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_PC_BUSY, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_STOPPED: notify_ui_working_status(STATU_DESC_SCAN_STOPPED, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_COVER_OPENNED: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_COVER_OPENNED, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_NO_PAPER: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_NO_PAPER, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_FEEDING_PAPER: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_FEEDING_PAPER, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_NOT_FOUND: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_NOT_FOUND, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_SLEEPING: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_SLEEPING, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_COUNT_MODE: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_COUNT_MODE, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_DOUBLE_FEEDING: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_DOUBLE_FEEDING, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_PAPER_JAMMED: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_PAPER_JAMMED, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_STAPLE_ON: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_STAPLE_ON, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_PAPER_SKEW: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_PAPER_SKEW, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_SIZE_CHECK: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_SIZE_CHECK, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_DOGEAR: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_DOGEAR, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_NO_IMAGE: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_NO_IMAGE, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_SCANN_ERROR: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_SCANN_ERROR, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_DEVICE_PC_BUSY: notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_PC_BUSY, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_INSUFFICIENT_MEMORY: notify_ui_working_status(STATU_DESC_SCANNER_ERR_INSUFFICIENT_MEMORY, SANE_EVENT_SCAN_FINISHED, status_); break; case SCANNER_ERR_TIMEOUT: notify_ui_working_status(STATU_DESC_SCANNER_ERR_TIMEOUT, 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; } if (test_1_paper_) { LOG_INFO(LOG_LEVEL_DEBUG_INFO, "scanning mode: finished testing ONE paper, restore to normal scanning.\n"); } else { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "[%s] scanned %d picture(s) and finished with error %s.\n", hg_log::current_time().c_str(), final_img_index_, hg_scanner_err_name(status_)); } 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 = 210; paper_size_mm_.cy = 297; } } int hg_scanner::set_color_change(void) { // if (/* condition */) // { // /* code */ // } return SCANNER_ERR_OK; } int hg_scanner::invoke_setting_xxx(int(hg_scanner::*func)(int, void*), void* data) { int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT; auto it = setting_map_.begin(); while (it != setting_map_.end()) { if (it->second == func) { ret = (this->*it->second)(it->first, data); break; } ++it; } return ret; } int hg_scanner::setting_restore(int sn, 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 SCANNER_ERR_CONFIGURATION_CHANGED; } int hg_scanner::setting_help(int sn, void* data) { int ret = SCANNER_ERR_OK; std::string helpfile = helpfile_; std::string com = "xdg-open ";//注意空格保留 printf("helpfile = %s\r\n",helpfile.c_str()); #if defined(WIN32) || defined(_WIN64) com = ""; helpfile.insert(0, hg_log::get_scanner_path()); FILE* src = fopen(helpfile.c_str(), "rb"); if (src) fclose(src); else #else if (access(helpfile.c_str(),F_OK) == -1) #endif { VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"App_Help_pdf path is:%s system is:%d\r\n",helpfile.c_str()); ret = SCANNER_ERR_OPEN_FILE_FAILED; return ret ; } com += helpfile; system(com.c_str()); VLOG_MINI_1(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(int sn, void* data) { std::string str((char*)data); int old = image_prc_param_.bits.color_mode, sub = SCANNER_ERR_OK, val = 0, ret = SCANNER_ERR_OK; bool exact = check_range(sn, 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 == SCANNER_ERR_NOT_EXACT) { image_prc_param_.bits.color_mode = old; str = color_mode_string(image_prc_param_.bits.color_mode); ret = SCANNER_ERR_NOT_EXACT; } else if (sub) { ret = sub; image_prc_param_.bits.color_mode = old; } else if (!exact) { ret = SCANNER_ERR_NOT_EXACT; } is_auto_matic_color = image_prc_param_.bits.color_mode == COLOR_MODE_AUTO_MATCH ? true :false; // 等于COLOR_MODE_AUTO_MATCH 的时候颜色模式需要变为2 彩色模式图像参数和硬件参数都如此 VLOG_MINI_4(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_err_name(ret),str.c_str()); if(ret == SCANNER_ERR_NOT_EXACT) strcpy((char*)data, str.c_str()); return ret; } int hg_scanner::setting_multi_out(int sn, void*data) { is_multiout = *((bool*)data); int val = image_prc_param_.bits.color_mode; VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "image_prc_param_.bits.multi_out %d ", image_prc_param_.bits.multi_out); if (is_multiout) { if (image_prc_param_.bits.multi_out == MULTI_GRAY_AND_BW) val = COLOR_MODE_256_GRAY; else val = COLOR_MODE_24_BITS; } on_color_mode_changed(val); return SCANNER_ERR_OK; } int hg_scanner::setting_multi_out_type(int sn, void*data) { int ret = SCANNER_ERR_OK; std::string str((char*)data); bool exact = check_range(sn, str); int color; image_prc_param_.bits.multi_out = match_best_multi_out(str,NULL); save_multiout = str; VLOG_MINI_3(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_err_name(ret)); if (image_prc_param_.bits.multi_out == MULTI_GRAY_AND_BW) color = COLOR_MODE_256_GRAY; else color = COLOR_MODE_24_BITS; on_color_mode_changed(color); return ret; } int hg_scanner::setting_rid_color(int sn, void* data) { std::string str((char*)data); int ret = SCANNER_ERR_OK, color = -1, old = image_prc_param_.bits.rid_color; bool exact = check_range(sn, str); image_prc_param_.bits.rid_color = match_best_rid_color(str, NULL); on_color_mode_changed(color); if (!exact) { ret = SCANNER_ERR_NOT_EXACT; strcpy((char*)data, str.c_str()); } return ret; } int hg_scanner::setting_rid_multi_red(int sn, void* data) { image_prc_param_.bits.rid_red = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_rid_answer_red(int sn, void* data) { image_prc_param_.bits.rid_answer_red = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_erase_background(int sn, void* data) { image_prc_param_.bits.erase_bakground = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_erase_background_range(int sn, void* data) { int ret = SCANNER_ERR_OK; erase_bkg_range_ = *((int*)data); if (!check_range(sn, erase_bkg_range_)) { ret = SCANNER_ERR_NOT_EXACT; *((int*)data) = erase_bkg_range_; } return ret; } int hg_scanner::setting_noise_optimize(int sn, void* data) { image_prc_param_.bits.noise_optimize = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_noise_optimize_range(int sn, void* data) { int ret = SCANNER_ERR_OK; noise_range_ = *((int*)data); if (!check_range(sn, noise_range_)) { ret = SCANNER_ERR_NOT_EXACT; *((int*)data) = noise_range_; } return ret; } int hg_scanner::setting_paper(int sn, void* data) { std::string paper((char*)data); bool exact = check_range(sn, paper); int ret = SCANNER_ERR_OK, sub = SCANNER_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 == SCANNER_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 = SCANNER_ERR_NOT_EXACT; if (save_sizecheck) { //setting_paper_check(0,(void*)&save_sizecheck); invoke_setting_xxx(&hg_scanner::setting_paper_check, &save_sizecheck); } VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Change paper from %s to %s = %s\n", paper_string(old).c_str(), (char*)data, hg_scanner_err_name(ret)); if(ret == SCANNER_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(int sn, void* data) { bool use = *((bool*)data); int ret = on_paper_check_changed(use); VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "Change paper size-checking %s = %s\n", *((bool*)data) ? "enabled" : "disabled", hg_scanner_err_name(ret)); *((bool*)data) = use; save_sizecheck = use; return ret; } int hg_scanner::setting_page(int sn, void* data) { std::string val((char*)data); bool exact = check_range(sn, val); int ret = exact ? SCANNER_ERR_OK : SCANNER_ERR_NOT_EXACT; VLOG_MINI_3(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_err_name(ret)); 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(int sn, void* data) { int ret = SCANNER_ERR_OK; omit_empty_level_ = *((int*)data); if (!check_range(sn, omit_empty_level_)) { ret = SCANNER_ERR_NOT_EXACT; *((int*)data) = omit_empty_level_; } return ret; } int hg_scanner::setting_resolution(int sn, void* data) { int ret = SCANNER_ERR_OK, old = resolution_, sub = SCANNER_ERR_OK; resolution_ = *((int*)data); if (!check_range(sn, resolution_)) ret = SCANNER_ERR_NOT_EXACT; sub = on_resolution_changed(resolution_); if (sub == SCANNER_ERR_NOT_EXACT) ret = sub; else if (sub) ret = sub; VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Change resolution from %d to %d = %s\n", old, *((int*)data), hg_scanner_err_name(ret)); *((int*)data) = resolution_; return ret; } int hg_scanner::setting_exchagnge(int sn, void* data) { image_prc_param_.bits.exchange = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_split_image(int sn, void* data) { image_prc_param_.bits.split = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_automatic_skew(int sn, void* data) { // automatic_skew_detection_ = *((bool*)data); image_prc_param_.bits.automatic_skew = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_rid_hole(int sn, void* data) { image_prc_param_.bits.rid_hole = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_rid_hoe_range(int sn, void* data) { int ret = SCANNER_ERR_OK; rid_hole_range_ = *((double*)data); if (!check_range(sn, rid_hole_range_)) { ret = SCANNER_ERR_NOT_EXACT; *((int*)data) = rid_hole_range_; } rid_hole_range_*=100; VLOG_MINI_1(LOG_LEVEL_WARNING, "rid_hole_range_ = %f\r\n", rid_hole_range_); return ret; } int hg_scanner::setting_bright(int sn, void* data) { int ret = SCANNER_ERR_OK; bright_ = *((int*)data); if (!check_range(sn, bright_)) { ret = SCANNER_ERR_NOT_EXACT; *((int*)data) = bright_; } return ret; } int hg_scanner::setting_contrast(int sn, void* data) { int ret = SCANNER_ERR_OK; contrast_ = *((int*)data); if (!check_range(sn, contrast_)) { ret = SCANNER_ERR_NOT_EXACT; *((int*)data) = contrast_; } return ret; } int hg_scanner::setting_gamma(int sn, void* data) { int ret = SCANNER_ERR_OK; gamma_ = *((double*)data); if (!check_range(sn, gamma_)) { ret = SCANNER_ERR_NOT_EXACT; *((double*)data) = gamma_; } return ret; } int hg_scanner::setting_sharpen(int sn, void* data) { std::string str((char*)data); int ret = SCANNER_ERR_OK; bool exact = check_range(sn, str); VLOG_MINI_2(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 = SCANNER_ERR_NOT_EXACT; } VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%d\n", ret); return ret; } int hg_scanner::setting_dark_sample(int sn, void* data) { image_prc_param_.bits.dark_sample = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_erase_black_frame(int sn, void* data) { image_prc_param_.bits.erase_black_frame = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_threshold(int sn, void* data) { int ret = SCANNER_ERR_OK; threshold_ = *((int*)data); if (!check_range(sn, threshold_)) { ret = SCANNER_ERR_NOT_EXACT; *((int*)data) = threshold_; } return ret; } int hg_scanner::setting_anti_noise(int sn, void* data) { int ret = SCANNER_ERR_OK; anti_noise_ = *((int*)data); if (!check_range(sn, anti_noise_)) { ret = SCANNER_ERR_NOT_EXACT; *((int*)data) = anti_noise_; } return ret; } int hg_scanner::setting_margin(int sn, void* data) { int ret = SCANNER_ERR_OK; margin_ = *((int*)data); if (!check_range(sn, margin_)) { ret = SCANNER_ERR_NOT_EXACT; *((int*)data) = margin_; } return ret; } int hg_scanner::setting_filling_background(int sn, void* data) { std::string str((char*)data); bool exact = check_range(sn, str); int ret = exact ? SCANNER_ERR_OK : SCANNER_ERR_NOT_EXACT; image_prc_param_.bits.fill_background = match_best_fill_background(str, NULL); if (!exact) { strcpy((char*)data, str.c_str()); ret = SCANNER_ERR_NOT_EXACT; } return ret; } int hg_scanner::setting_is_permeate(int sn, void* data) { image_prc_param_.bits.is_permeate = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_is_permeate_lv(int sn, void* data) { int ret = SCANNER_ERR_OK; std::string str((char*)data); bool exact = check_range(sn, str); VLOG_MINI_2(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 = SCANNER_ERR_NOT_EXACT; } VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%d\n", ret); return ret; } int hg_scanner::setting_remove_morr(int sn, void* data) { image_prc_param_.bits.remove_morr = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_error_extention(int sn, void* data) { image_prc_param_.bits.error_extention = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_remove_texture(int sn, void* data) { image_prc_param_.bits.remove_txtture = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_ultrasonic_check(int sn, void* data) { bool use = *((bool*)data); int ret = on_ultrasonic_check_changed(use); if (ret) *((bool*)data) = use; return ret; } int hg_scanner::setting_go_on_when_double_checked(int sn, void* data) { bool ok = true; std::string val((char*)data); double_paper_handle_ = double_paper_flag_from_option_value(val, &ok); if(ok) return SCANNER_ERR_OK; else { strcpy((char*)data, val.c_str()); return SCANNER_ERR_NOT_EXACT; } } int hg_scanner::setting_staple_check(int sn, 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(int sn, void* data) { std::string str((char*)data); bool exact = check_range(sn, str); int ret = exact ? SCANNER_ERR_OK : SCANNER_ERR_NOT_EXACT; if (strcmp(str.c_str(), OPTION_VALUE_SMZS_LXSM) == 0) { scan_count_ = -1; } else { char key[20]; sprintf(key, "%d", id_scan_count_); setting_jsn_.at(key).at("cur").get_to(scan_count_); } VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "set scanning pages to %d\n", scan_count_); return ret; } int hg_scanner::setting_scan_count(int sn, void* data) { int ret = SCANNER_ERR_OK; std::string val(""); if (id_scan_mode_ != -1) { char key[20]; sprintf(key, "%d", id_scan_mode_); setting_jsn_.at(key).at("cur").get_to(val); } if (val == OPTION_VALUE_SMZS_LXSM) { scan_count_ = -1; } else { scan_count_ = *((int*)data); } VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "set scanning pages to %d\n", scan_count_); return ret; } int hg_scanner::setting_text_direction(int sn, void* data) { std::string str((char*)data); bool exact = check_range(sn, str); int ret = exact ? SCANNER_ERR_OK : SCANNER_ERR_NOT_EXACT; VLOG_MINI_3(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_err_name(ret)); 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(int sn, void* data) { image_prc_param_.bits.rotate_back_180 = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_fractate_check(int sn, void* data) { image_prc_param_.bits.fractate_check = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_fractate_check_level(int sn, void* data) { int ret = SCANNER_ERR_OK; fractate_level_ = *((int*)data); if (!check_range(sn, fractate_level_)) { ret = SCANNER_ERR_NOT_EXACT; *((int*)data) = fractate_level_; } return ret; } int hg_scanner::setting_skew_check(int sn, 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(int sn, void* data) { int level = *((int*)data); bool exact = check_range(sn, level); int ret = exact ? SCANNER_ERR_OK : SCANNER_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(int sn, void* data) { custom_gamma_ = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_custom_gamma_data(int sn, void* data) { SANE_Gamma* gamma = (SANE_Gamma*)data; memcpy(custom_gamma_val_, gamma, sizeof(*custom_gamma_val_)); return SCANNER_ERR_OK; } int hg_scanner::setting_is_custom_area(int sn, void* data) { custom_area_ = *((bool*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_custom_area_left(int sn, void* data) { SANE_Fixed* v = (SANE_Fixed*)data; custom_area_lt_x_ = *((double*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_custom_area_top(int sn, void* data) { SANE_Fixed* v = (SANE_Fixed*)data; custom_area_lt_y_ = *((double*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_custom_area_right(int sn, void* data) { SANE_Fixed* v = (SANE_Fixed*)data; custom_area_br_x_ = *((double*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_custom_area_bottom(int sn, void* data) { SANE_Fixed* v = (SANE_Fixed*)data; custom_area_br_y_ = *((double*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_img_quality(int sn, void *data) { std::string str((char*)data); bool exact = check_range(sn, str); int ret = exact ? SCANNER_ERR_OK : SCANNER_ERR_NOT_EXACT; VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Change quality from '%s' to '%s' = %s\n", is_img_quality(is_quality_).c_str() , (char*)data, hg_scanner_err_name(ret)); is_quality_ = match_best_img_quality(str,NULL); return SCANNER_ERR_OK; } int hg_scanner::setting_color_fill(int sn, void*data) { is_color_fill = *((bool *)data); return SCANNER_ERR_OK; } int hg_scanner::setting_black_white_threshold(int sn, void* data) { bw_threshold_ = (unsigned char)(*(SANE_Int*)data); return SCANNER_ERR_OK; } int hg_scanner::setting_feedmode(int sn, void* data) { feedmode_ = *((int *)data); return SCANNER_ERR_OK; } int hg_scanner::on_color_mode_changed(int& color_mode) { int ret = SCANNER_ERR_OK; if ((((color_mode == COLOR_MODE_24_BITS || color_mode == COLOR_MODE_AUTO_MATCH) && !is_color_type_) || ((color_mode != COLOR_MODE_24_BITS && color_mode != COLOR_MODE_AUTO_MATCH) && is_color_type_)) && color_mode != -1) { is_color_type_ ^= 1; } if (image_prc_param_.bits.rid_color != RID_COLOR_NONE &&(image_prc_param_.bits.color_mode == COLOR_MODE_256_GRAY || image_prc_param_.bits.color_mode == COLOR_MODE_BLACK_WHITE) ) { is_color_type_ = 1; } if(image_prc_param_.bits.rid_color != RID_COLOR_NONE && (image_prc_param_.bits.color_mode == COLOR_MODE_256_GRAY || image_prc_param_.bits.color_mode == COLOR_MODE_BLACK_WHITE) && color_mode == -1) { is_color_type_ = 1; } else if (image_prc_param_.bits.rid_color == RID_COLOR_NONE && (image_prc_param_.bits.color_mode == COLOR_MODE_256_GRAY || image_prc_param_.bits.color_mode == COLOR_MODE_BLACK_WHITE) && color_mode == -1) { is_color_type_ = 0; } if (is_multiout) { is_color_type_ = 1; // if (/* condition */) // { // /* code */ // } } return SCANNER_ERR_OK; } int hg_scanner::on_paper_changed(int& paper) { return SCANNER_ERR_OK; } int hg_scanner::on_paper_check_changed(bool& check) { return SCANNER_ERR_OK; } int hg_scanner::on_resolution_changed(int& dpi) { return SCANNER_ERR_OK; } int hg_scanner::on_ultrasonic_check_changed(bool& check) { return SCANNER_ERR_OK; } int hg_scanner::on_staple_check_changed(bool& check) { return SCANNER_ERR_OK; } int hg_scanner::on_skew_check_changed(bool& check) { return SCANNER_ERR_OK; } int hg_scanner::on_skew_check_level_changed(int& check) { return SCANNER_ERR_OK; } int hg_scanner::on_set_feedmode(int feedmode) { return SCANNER_ERR_OK; } int hg_scanner::on_get_feedmode(int &feedmode) { return SCANNER_ERR_OK; } void hg_scanner::on_device_reconnected(void) { std::lock_guard lock(io_lock_); VLOG_MINI_2(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 SCANNER_ERR_OK; } int hg_scanner::on_scanner_closing(bool force) { return SCANNER_ERR_OK; } void hg_scanner::thread_handle_usb_read(void) { } void hg_scanner::adjust_color(hg_imgproc::HIMGPRC handle) { int tableLength = 0; // ZERO length perform color-adjust only unsigned char buffer1[256 * 3]; if (custom_gamma_) { if (img_conf_.pixtype == COLOR_MODE_BLACK_WHITE || img_conf_.pixtype == COLOR_MODE_256_GRAY) { tableLength = 256; memcpy(buffer1, custom_gamma_val_->table, tableLength); } else { // convert R[256] + G[256] + B[256] to BGR[256] ... tableLength = 256 * 3; for (int i = 0; i < 256; ++i) { buffer1[i * 3 + 0] = custom_gamma_val_->table[256 * 2 + i]; buffer1[i * 3 + 1] = custom_gamma_val_->table[256 * 1 + i]; buffer1[i * 3 + 2] = custom_gamma_val_->table[256 * 0 + i]; } } } hg_imgproc::adjust_color(handle, buffer1, tableLength); } hg_imgproc::HIMGPRC hg_scanner::get_image_process_object(int model) { hg_imgproc::IMGPRCPARAM param; hg_imgproc::HIMGPRC handle = nullptr; float bright = img_conf_.brightness, contrast = img_conf_.contrast; bzero(¶m, sizeof(param)); param.bits = 8; param.black_white = img_conf_.pixtype == COLOR_MODE_BLACK_WHITE; param.channels = img_conf_.pixtype == COLOR_MODE_24_BITS ? 3 : 1; param.color_mode = img_conf_.pixtype; param.double_side = img_conf_.is_duplex; param.dpi = img_conf_.resolution_dst; img_conf_.brightness = (float)bright_; img_conf_.contrast = (float)contrast_; handle = hg_imgproc::init(&img_conf_, ¶m, model); img_conf_.brightness = bright; img_conf_.contrast = contrast; return handle; } SANE_Image_Statu hg_scanner::last_usb_image_statu(int err) { SANE_Image_Statu statu = SANE_Image_Statu_OK; if (!is_continue_when_double_paper(double_paper_handle_) && is_save_img_when_double_paper(double_paper_handle_)) { if (err == SCANNER_ERR_DEVICE_DOUBLE_FEEDING) statu = SANE_Image_Statu_Double; else if (err == SCANNER_ERR_DEVICE_PAPER_JAMMED) statu = SANE_Image_Statu_Jammed; } return statu; } 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); #ifdef MAPPING_FUNCTION_IN_BASE setting_jsn_.at(key).at("title").get_to(val); set_setting_map(sn, val.c_str()); #endif 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; VLOG_MINI_1(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_err_name(err), &e, NULL); } int hg_scanner::try_third_app_handle_start(bool& handled) { int ret = SCANNER_ERR_OK; handled = !async_io_; if (handled) { while (wait_usb_result_.try_wait()) std::this_thread::sleep_for(std::chrono::milliseconds(3)); if (!wait_img_.is_waiting() || !wait_usb_.is_waiting() || final_imgs_.size()) { while (final_imgs_.size() == 0) { if (wait_img_.is_waiting() && wait_usb_.is_waiting()) break; std::this_thread::sleep_for(std::chrono::milliseconds(3)); } if (final_imgs_.size() == 0) { final_img_index_ = 0; if (user_cancel_) handled = false; else ret = SCANNER_ERR_DEVICE_NO_PAPER; } } else if (final_img_index_) { final_img_index_ = 0; if (user_cancel_) handled = false; else ret = SCANNER_ERR_DEVICE_NO_PAPER; } else handled = false; } return ret; } int hg_scanner::try_third_app_after_start(int err) { if (!async_io_) { while (wait_img_.is_waiting() && !wait_usb_.is_waiting()) std::this_thread::sleep_for(std::chrono::milliseconds(10)); if (wait_img_.is_waiting() && wait_usb_.is_waiting()) err = status_; } return err; } std::shared_ptr hg_scanner::aquire_memory(int size, bool from_usb) { std::string lead(from_usb ? "usb" : "imgp"), ext(from_usb ? "jpg" : "dat"); unsigned int ind = from_usb ? usb_img_index_ : final_img_index_; std::shared_ptr mem(new tiny_buffer(size, final_path_.c_str(), lead.c_str(), ext.c_str(), ind)); if (!mem->data(0, (unsigned int*)&size)) { mem.reset(); LOG_INFO(LOG_LEVEL_FATAL, "Can't aquire enough memory, working must be stopped!\n"); notify_ui_working_status(STATU_DESC_SCANNER_ERR_INSUFFICIENT_MEMORY, SANE_EVENT_ERROR, SCANNER_ERR_INSUFFICIENT_MEMORY); stop(); } return mem; } 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 == SCANNER_ERR_INSUFFICIENT_MEMORY) { user_cancel_ = true; status_ = SCANNER_ERR_INSUFFICIENT_MEMORY; ret = false; } else if (ret == SCANNER_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) { VLOG_MINI_1(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) { VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "waited for memory need(%u)\n", need_bytes); } else { VLOG_MINI_1(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, int bits) { if (channels == 3) header->format = SANE_FRAME_RGB; else header->format = SANE_FRAME_GRAY; header->depth = bits >= 8 ? 8 : bits; // 此处指每一个颜色分量的位深,我们的扫描仪固定为“8” header->last_frame = SANE_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 = SCANNER_ERR_OK; usb_img_index_++; VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "USB read one picture with %u bytes\n", data->size()); if (!data->swap()) { ret = SCANNER_ERR_OPEN_FILE_FAILED; } else { imgs_.Put(data); if (wait_img_.is_waiting()) wait_img_.notify(); } unsigned int bytes = data->size(); int type = io_->get_pid() & 0x0ff; if(type != 0x39 || (usb_img_index_ & 1)) ui_ev_cb_((scanner_handle)this, SANE_EVENT_USB_DATA_RECEIVED, NULL, &bytes, NULL); return ret; } int hg_scanner::save_final_image(hg_imgproc::LPIMGHEAD head, void* buf) { std::string bw(""); final_img_index_++; bool is_1bit = false; if (image_prc_param_.bits.multi_out == MULTI_OUT_ALL && is_multiout) { if(final_img_index_%3 == 0) is_1bit = true; } else if ((image_prc_param_.bits.multi_out == MULTI_GRAY_AND_BW||image_prc_param_.bits.multi_out == MULTI_COLOR_AND_BW) && is_multiout) { if(final_img_index_%2 == 0) is_1bit = true; } if (img_conf_.pixtype == 0 || (is_1bit && is_multiout)) { int old = head->line_bytes; bw = bmp_821((unsigned char*)buf, head->width, head->height, &head->line_bytes, async_io_, bw_threshold_); buf = &bw[0]; head->channels = head->bits = 1; head->total_bytes = head->line_bytes * head->height; VLOG_MINI_5(LOG_LEVEL_DEBUG_INFO, "convert to 1-bit bmp(%d * %d), total = %u, len = %u , black_white_image_threshold_ =%d\n", head->width, head->height, head->total_bytes, bw.length(), bw_threshold_); } if (async_io_) { SANE_Image img; ZERO_STRUCT(&img); copy_to_sane_image_header(&img.header, head->width, head->height, head->line_bytes, head->channels, head->bits); img.data = (unsigned char*)buf; img.bytes = head->total_bytes; img.flag.statu = head->statu; if (img.flag.statu) { VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "some error with final image: %s\n", hg_scanner_image_statu_name(img.flag.statu)); } return ui_ev_cb_((scanner_handle)this, SANE_EVENT_IMAGE_OK, &img, &final_img_index_, NULL); } if (final_imgs_.put(head->width, head->height, head->bits, head->channels, head->line_bytes, buf, head->total_bytes , final_path_.c_str(), "final", "dat", final_img_index_)) return SCANNER_ERR_OK; else return SCANNER_ERR_INSUFFICIENT_MEMORY; } int hg_scanner::is_running(void) { if (!scan_life_) return THREAD_RUNNING_IDLE; int run = THREAD_RUNNING_IDLE; if (!wait_usb_.is_waiting()) run |= THREAD_RUNNING_USB; if (!wait_img_.is_waiting()) run |= THREAD_RUNNING_IMAGE; return run; } int hg_scanner::reset_io(usb_io* io) { online_ = false; if (!io) return SCANNER_ERR_INVALID_PARAMETER; { std::lock_guard lock(io_lock_); usb_io* old = io_; io->add_ref(); io_ = io; status_ = io_->last_error(); online_ = status_ == SCANNER_ERR_OK; if (old) old->release(); } on_device_reconnected(); return SCANNER_ERR_OK; } int hg_scanner::io_disconnected(void) { std::lock_guard lock(io_lock_); online_ = false; io_->on_disconnected(); return SCANNER_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 == SCANNER_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_) { LOG_INFO(LOG_LEVEL_WARNING, "close scanner: USB thread or Image thread is still running.\n"); io_->close(); io_->release(); io_ = NULL; } status_ = SCANNER_ERR_NOT_OPEN; } return ret; } int hg_scanner::set_setting(int setting_no, void* data, int len) { bool hit = setting_map_.count(setting_no) > 0; int ret = SCANNER_ERR_OUT_OF_RANGE; char sn[20]; if (hit) { ret = (this->*setting_map_[setting_no])(setting_no, data); sprintf(sn, "%d", setting_no); } else { VLOG_MINI_1(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 == SCANNER_ERR_OK || ret == SCANNER_ERR_NOT_EXACT || ret == SCANNER_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, "\350\256\276\347\275\256 \""); name += "\" \345\200\274\344\270\272\""; name += type + "\" \346\210\220\345\212\237\343\200\202"; 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("\350\256\276\347\275\256\351\241\271") + sn; name.insert(0, "\350\256\276\347\275\256 \""); name += std::string("\" \345\200\274\345\244\261\350\264\245: ") + hg_scanner_err_name(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 SCANNER_ERR_INVALID_PARAMETER; if (setting_no == 0) { int count = 0; setting_jsn_.at("option_count").get_to(count); *len = count; return SCANNER_ERR_OK; } if (setting_count_ <= setting_no || setting_no < 0) return SCANNER_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)) VLOG_MINI_2(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 == SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT || name == SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT) { is_area_x = true; add = 20; } else if (name == SANE_STD_OPT_NAME_CUSTOM_AREA_TOP || name == SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM) { is_area_y = true; add = 20; } //else if (/* condition */) { /* code */ } if (*len <= text.length() + add) { *len = text.length() + 8 + add; return SCANNER_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 SCANNER_ERR_OK; } std::string hg_scanner::name(void) { return name_; } int hg_scanner::status(void) { if (!wait_usb_.is_waiting() || !wait_img_.is_waiting()) return SCANNER_ERR_DEVICE_BUSY; else 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 = SCANNER_ERR_OK; IMH imh; bzero(&imh, sizeof(imh)); bzero(ii, sizeof(*ii)); 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 = SCANNER_ERR_NO_DATA; else { if (!final_imgs_.front(&imh)) ret = SCANNER_ERR_NO_DATA; else copy_to_sane_image_header(ii, imh.width, imh.height, imh.line_bytes, imh.channels, imh.bits); } if (ret == SCANNER_ERR_NO_DATA /*&& final_img_index_ == 0*/) { if (status_ != SCANNER_ERR_OK && status_ != SCANNER_ERR_DEVICE_BUSY) ret = SCANNER_ERR_NO_DATA; else { ii->depth = image_prc_param_.bits.color_mode == COLOR_MODE_BLACK_WHITE ? 1 : 8; ii->last_frame = SANE_TRUE; ii->format = image_prc_param_.bits.color_mode == COLOR_MODE_24_BITS || image_prc_param_.bits.color_mode == COLOR_MODE_AUTO_MATCH ? SANE_FRAME_RGB : SANE_FRAME_GRAY; SIZE paper = paper_size(image_prc_param_.bits.paper); ii->pixels_per_line = paper.cx * 1.0f / 25.4 * resolution_ + .5f; ii->lines = paper.cy * 1.0f / 25.4 * resolution_ + .5f; ii->bytes_per_line = ii->format == SANE_FRAME_RGB ? ii->pixels_per_line * 3 : ii->pixels_per_line; if (ii->bytes_per_line > ii->pixels_per_line) imh.bits = 24; else imh.bits = 8; ret = SCANNER_ERR_OK; } } VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "Get image info(%d * %d * %d) = %s\n", ii->pixels_per_line, ii->lines, imh.bits, hg_scanner_err_name(ret)); return ret; } int hg_scanner::read_image_data(unsigned char* buf, int* len) { if (!len) return SCANNER_ERR_INVALID_PARAMETER; if (!buf) { IMH imh; final_imgs_.front(&imh); *len = imh.bytes; return SCANNER_ERR_INSUFFICIENT_MEMORY; } if (final_imgs_.size() > 0) { int fetch = *len; bool over = false; final_imgs_.fetch_front(buf, len, &over); return over ? SCANNER_ERR_NO_DATA : SCANNER_ERR_OK; } else { *len = 0; return SCANNER_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) { int ret = invoke_setting_xxx(&hg_scanner::setting_restore, data); if (ret == SCANNER_ERR_OK) ret = SCANNER_ERR_CONFIGURATION_CHANGED; return ret; } 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 == SCANNER_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 = SCANNER_ERR_OK; else ret = SCANNER_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_GET_FINAL_IMAGE_FORMAT) { SANE_FinalImgFormat* fmt = (SANE_FinalImgFormat*)data; if (!fmt) { *len = sizeof(SANE_FinalImgFormat); return SCANNER_ERR_INSUFFICIENT_MEMORY; } if (img_type_ == ".bmp") fmt->img_format = SANE_IMAGE_TYPE_BMP; else if (img_type_ == ".jpg") fmt->img_format = SANE_IMAGE_TYPE_JPG; else if (img_type_ == ".png") fmt->img_format = SANE_IMAGE_TYPE_PNG; else if (img_type_ == ".gif") fmt->img_format = SANE_IMAGE_TYPE_GIF; else fmt->img_format = SANE_IMAGE_TYPE_BMP; return SCANNER_ERR_OK; } 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_GET_FINAL_COMPRESSION) { *(int*)data = SANE_COMPRESSION_NONE; return SCANNER_ERR_OK; } else if (code == IO_CTRL_CODE_SET_FINAL_COMPRESSION) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } 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 SCANNER_ERR_INSUFFICIENT_MEMORY; } if (data) strcpy((char*)data, fw.c_str()); return SCANNER_ERR_OK; } else if(code == IO_CTRL_CODE_GET_SERIAL) { std::string ser = get_serial_num(); if (*len < ser.size()) { *len = ser.size(); return SCANNER_ERR_INSUFFICIENT_MEMORY; } if(data) strcpy((char*)data, ser.c_str()); return SCANNER_ERR_OK; } else if (code == IO_CTRL_CODE_GET_HARDWARE_VERSION) { std::string ip = get_ip(); if (*len < ip.size()) { *len = ip.size(); return SCANNER_ERR_INSUFFICIENT_MEMORY; } if(data) strcpy((char*)data, ip.c_str()); return SCANNER_ERR_OK; } 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 = SCANNER_ERR_OK; if (*len < sizeof(int *)) { *len = sizeof(int *); return SCANNER_ERR_INSUFFICIENT_MEMORY; } ret = get_sleep_time(val); if (ret == SCANNER_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_)); if (len) *len = image_prc_param_.bits.color_mode; return SCANNER_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 SCANNER_ERR_OK; } else if(code == IO_CTRL_CODE_DISPLAY_APP_HELP) { //setting_help(data); return SCANNER_ERR_OK; } else if (code == IO_CTRL_CODE_GET_IMAGE_QUEUE_COUNT) { *len = final_imgs_.size(); return wait_img_.is_waiting() && wait_usb_.is_waiting() ? SCANNER_ERR_NO_DATA : SCANNER_ERR_OK; } else if (code == IO_CTRL_CODE_GET_PAPER_SIZE) { std::string name((char*)data); int paper = match_best_paper(name, NULL); SIZE size = paper_size(paper); *len = (size.cx & 0x0ffff) | ((size.cy & 0x0ffff) << 16); } else if (code == IO_CTRL_CODE_CONVERT_IMAGE_FORMAT) { SANE_ImageFormatConvert *conv = (SANE_ImageFormatConvert*)data; void* threshold = conv->dst.fmt.compress.detail; int ret = SCANNER_ERR_OK; conv->dst.fmt.compress.detail = (void*)bw_threshold_; ret = hg_imgproc::convert_image_file(conv); conv->dst.fmt.compress.detail = threshold; return ret; } else if (code == IO_CTRL_CODE_FREE_MEMORY) { free_memory(data); return SCANNER_ERR_OK; } else if(code == IO_CTRL_CODE_GET_LOG_FILE && len && *len == LOG_FILE_DRIVER) { string save_path = hg_log::temporary_path() + "/device.log"; int ret = get_device_log(save_path); if (ret != SCANNER_ERR_OK) { return ret; } FILE* src = fopen(save_path.c_str(), "rb"); if (src) { ret = SCANNER_ERR_OK; fclose(src); } else { ret = SCANNER_ERR_WRITE_FILE_FAILED; } return ret; } return SCANNER_ERR_DEVICE_NOT_SUPPORT; } std::string hg_scanner::get_firmware_version(void) { return BRAND_DEVICE_NOT_SUPPORT; } std::string hg_scanner::get_serial_num(void) { return BRAND_DEVICE_NOT_SUPPORT; } std::string hg_scanner::get_ip(void) { return BRAND_DEVICE_NOT_SUPPORT; } int hg_scanner::get_roller_num(void) { return -2; } int hg_scanner::get_device_log(string &log) { return -2; } int hg_scanner::clear_roller_num(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_history_count(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } ////////////////////////////////////////////////////////////////////////////////////////////////////// int hg_scanner::set_leaflet_scan(void) { return SCANNER_ERR_NO_DATA; } int hg_scanner::get_abuot_info(void) { return SCANNER_ERR_NO_DATA; } int hg_scanner::restore_default_setting(void) { return SCANNER_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 SCANNER_ERR_INVALID_PARAMETER; case SANE_IMAGE_TYPE_WEBP: return SCANNER_ERR_INVALID_PARAMETER; case SANE_IMAGE_TYPE_PDF: return SCANNER_ERR_INVALID_PARAMETER; case SANE_IMAGE_TYPE_GIF: return SCANNER_ERR_INVALID_PARAMETER; case SANE_IMAGE_TYPE_SVG: return SCANNER_ERR_INVALID_PARAMETER; default: img_type_ = ".bmp"; break; } return SCANNER_ERR_OK; } int hg_scanner::get_compression_format(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_compression_format(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_auto_color_type(void) { is_auto_matic_color = true; return SCANNER_ERR_OK; } int hg_scanner::get_device_code(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_sleep_time(int& getsleepime) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_sleep_time(int sleeptime) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::notify_sleep() { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_dogear_distance(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_dogear_distance(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_scanner_paperon(SANE_Bool* paperon) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_scan_when_paper_on(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_scan_when_paper_on(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_scan_with_hole(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::set_scan_with_hole(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int hg_scanner::get_scan_is_sleep(void) { return SCANNER_ERR_DEVICE_NOT_SUPPORT; }