#include "imgprc_mgr.h" #include #include #include "../../../sdk/include/huagao/hgscanner_error.h" #include #include #include #include static std::string device_opt_json[] = { "{\"dumpimg\":{\"cat\":\"base\",\"group\":\"debug\",\"title\":\"\\u8f93\\u51fa\\u7b97\\u6cd5\\u4e2d\\u95f4\\u56fe\\u50cf\",\"desc\":\"\\u6bcf\\u4e2a\\u7b97\\u6cd5\\u6267\\u884c\\u540e\\uff0c\\u8f93\\u51fa\\u4e2d\\u95f4\\u7684\\u4e34\\u65f6\\u56fe\\u50cf\",\"type\":\"bool\",\"pos\":10,\"size\":4,\"cur\":false,\"default\":false},\"dump-path\":{\"cat\":\"base\",\"group\":\"debug\",\"title\":\"\\u4e2d\\u95f4\\u56fe\\u50cf\\u8f93\\u51fa\\u8def\\u5f84\",\"desc\":\"\\u6bcf\\u4e2a\\u7b97\\u6cd5\\u6267\\u884c\\u540e\\uff0c\\u8f93\\u51fa\\u4e2d\\u95f4\\u4e34\\u65f6\\u56fe\\u50cf\\u7684\\u5b58\\u653e\\u8def\\u5f84\",\"type\":\"string\",\"pos\":10,\"size\":260,\"cur\":\"\",\"default\":\"\",\"depend\":\"dumpimg==true\"}}" }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // imgproc_mgr imgproc_mgr::imgproc_mgr(device_option* devopts , bool dumpimg , const char* dumpath) : opts_(devopts), dump_path_(dumpath ? dumpath : "") , dumpf_(dumpimg ? &imgproc_mgr::dump_real : &imgproc_mgr::dump_empty) , dumpusbf_(dumpimg ? &imgproc_mgr::dump_usb_img_real : &imgproc_mgr::dump_usb_img_empty) { std::string text(""); gb_json *jsn = new gb_json(); for (auto& v : device_opt_json) text += v; if (jsn->attach_text(&text[0])) { gb_json* child = nullptr; jsn->get_value(SANE_STD_OPT_NAME_DUMP_IMG, child); if (child) { child->set_value("cur", dumpimg); child->set_value("default", dumpimg); child->release(); } jsn->get_value(SANE_STD_OPT_NAME_DUMP_IMG_PATH, child); if (child) { child->set_value("cur", dump_path_.c_str()); child->set_value("default", dump_path_.c_str()); child->release(); } text = jsn->to_string(); } jsn->release(); set_opt_json_text(&text[0]); if (opts_) opts_->add_ref(); else opts_ = new device_option(); } imgproc_mgr::~imgproc_mgr() { clear(); opts_->release(); } std::vector imgproc_mgr::decode_before_simple(uint8_t* data, size_t bytes, HGIMGINFO* info) { std::vector simple; DECDAT in; in.info = *info; in.img.reset(new std::vector(bytes)); memcpy(in.img->data(), data, bytes); simple.push_back(in); return std::move(simple); } std::vector imgproc_mgr::decode_before_g200dsp(uint8_t* data, size_t bytes, HGIMGINFO* info) { // pid == 0x100 || pid == 0x200 std::vector g200dsp; DECDAT f, b; int line = 1024, off_f = 0, off_b = 0; f.info = *info; f.info.paper_side = PAPER_SIDE_FRONT; f.img.reset(new std::vector(bytes)); b.info = *info; b.info.paper_side = PAPER_SIDE_BACK; b.img.reset(new std::vector(bytes)); for (int i = 0; i < bytes / line; ++i) { if (data[line - 1] == 0) { // this is back memcpy(b.img->data() + off_b, data, line - 1); off_b += line - 1; } else if (data[line - 1] == 0x0ff) { // this is front memcpy(f.img->data() + off_f, data, line - 1); off_f += line - 1; } data += line; } f.img->resize(off_f); b.img->resize(off_b); g200dsp.push_back(b); g200dsp.push_back(f); return std::move(g200dsp); } void imgproc_mgr::dump_real(const std::vector& img, const char* after, int pos) { std::string root(dump_path_ + PATH_SEPARATOR); std::vector existing; for (auto& v : img) { char name[128] = { 0 }; int ind = 0; sprintf(name, "%04x-%d-%d-%04x-%s", v.info.paper_ind, v.info.paper_side, v.info.split_ind, pos, after); while(std::find(existing.begin(), existing.end(), name) != existing.end()) sprintf(name, "%04x-%d-%d-%04x-%s(%d)", v.info.paper_ind, v.info.paper_side, v.info.split_ind, pos, after, ++ind); existing.push_back(name); cv::imwrite((root + name + ".jpg").c_str(), v.img); } } void imgproc_mgr::dump_empty(const std::vector& img, const char* after, int pos) {} std::string imgproc_mgr::dump_usb_img_real(uint8_t* data, size_t bytes, HGIMGINFO* info, const char* tail) { std::string root(dump_path_ + PATH_SEPARATOR); char name[128] = { 0 }; const char *tail_leader = ""; FILE *dst = nullptr; int ind = 0; if (tail && *tail) tail_leader = "-"; else tail = ""; sprintf(name, "%04x-usb%s%s", info->paper_ind, tail_leader, tail); { // check repeat ... dst = fopen((root + name + ".jpg").c_str(), "rb"); while (dst) { fclose(dst); sprintf(name, "%04x-usb%s%s(%d)", info->paper_ind, tail_leader, tail, ++ind); dst = fopen((root + name + ".jpg").c_str(), "rb"); } } dst = fopen((root + name + ".jpg").c_str(), "wb"); if (dst) { fwrite(data, 1, bytes, dst); fclose(dst); utils::to_log(LOG_LEVEL_DEBUG, "Temporary file '%s' OK.\n", (root + name + ".jpg").c_str()); } else { utils::to_log(LOG_LEVEL_DEBUG, "Temporary file '%s' failed with err: %d\n", (root + name + ".jpg").c_str(), errno); } return std::move(root + name + ".jpg"); } std::string imgproc_mgr::dump_usb_img_empty(uint8_t* data, size_t bytes, HGIMGINFO* info, const char* tail) { return ""; } int imgproc_mgr::decode(HGIMGINFO* info, uint8_t* data, size_t bytes, std::vector& result) { std::vector tmp(info->paper_side == PAPER_SIDE_DSP ? imgproc_mgr::decode_before_g200dsp(data, bytes, info) : imgproc_mgr::decode_before_simple(data, bytes, info)); int ret = SCANNER_ERR_OK; (this->*dumpusbf_)(data, bytes, info, nullptr); for (auto& v : tmp) { PROCIMGINFO pii; try { cv::ImreadModes rmc = info->channels > 1 ? cv::IMREAD_COLOR : cv::IMREAD_GRAYSCALE; if (v.img->at(0) == 0x89 && v.img->at(1) == 'P' && v.img->at(2) == 'N' && v.img->at(2) == 'G') rmc = cv::IMREAD_GRAYSCALE; memset(&pii.info, 0, sizeof(pii.info)); pii.info = v.info; pii.img = cv::imdecode(*v.img, rmc); if (pii.img.empty()) { std::string f(dump_usb_img_real((uint8_t*)&(*v.img)[0], v.img->size(), info, "error")); utils::to_log(LOG_LEVEL_WARNING, "Warning: decode failure, source content save to file '%s'\n", f.c_str()); } else { if (info->paper_side == PAPER_SIDE_LEFT || info->paper_side == PAPER_SIDE_RIGHT) { PROCIMGINFO front(pii); front.info.paper_side = PAPER_SIDE_FRONT; if (info->paper_side == PAPER_SIDE_LEFT) { front.img = pii.img(cv::Rect(0, 0, pii.img.cols / 2, pii.img.rows)); pii.img = pii.img(cv::Rect(pii.img.cols / 2, 0, pii.img.cols / 2, pii.img.rows)); } else { front.img = pii.img(cv::Rect(pii.img.cols / 2, 0, pii.img.cols / 2, pii.img.rows)); pii.img = pii.img(cv::Rect(0, 0, pii.img.cols / 2, pii.img.rows)); } result.push_back(front); pii.info.paper_side = PAPER_SIDE_BACK; } else if (info->paper_side == PAPER_SIDE_TOP || info->paper_side == PAPER_SIDE_BOTTOM) { PROCIMGINFO front(pii); front.info.paper_side = PAPER_SIDE_FRONT; if (info->paper_side == PAPER_SIDE_TOP) { front.img = pii.img(cv::Rect(0, 0, pii.img.cols, pii.img.rows / 2)); pii.img = pii.img(cv::Rect(0, pii.img.rows / 2, pii.img.cols, pii.img.rows / 2)); } else { front.img = pii.img(cv::Rect(0, pii.img.rows / 2, pii.img.cols, pii.img.rows / 2)); pii.img = pii.img(cv::Rect(0, 0, pii.img.cols, pii.img.rows / 2)); } result.push_back(front); pii.info.paper_side = PAPER_SIDE_BACK; } result.push_back(pii); } } catch (const std::exception& e) { utils::to_log(LOG_LEVEL_FATAL, "FATAL: exception occurs when decode image %d-%d failed with reason '%s'!\n", info->paper_ind, pii.info.paper_side, e.what()); std::string f(dump_usb_img_real((uint8_t*)&(*v.img)[0], v.img->size(), info, "decode")); utils::to_log(LOG_LEVEL_WARNING, "FATAL: decode image %d-%d failed, source content save to file '%s'\n", info->paper_ind, pii.info.paper_side, f.c_str()); //throw(e); // continue the error handling ret = SCANNER_ERR_THROW_EXCEPTION; break; // fatal occurs, stop } catch (...) { utils::to_log(LOG_LEVEL_FATAL, "FATAL: exception occurs when decode image %d-%d failed\n", info->paper_ind, pii.info.paper_side); std::string f(dump_usb_img_real((uint8_t*)&(*v.img)[0], v.img->size(), info, "decode")); utils::to_log(LOG_LEVEL_WARNING, "FATAL: decode image %d-%d failed, source content save to file '%s'\n", info->paper_ind, pii.info.paper_side, f.c_str()); ret = SCANNER_ERR_THROW_EXCEPTION; break; // fatal occurs, stop } } tmp.clear(); char errbuf[40] = { 0 }; utils::to_log(LOG_LEVEL_DEBUG, "Decode %u bytes to %u picture(s) = %s\n", bytes, result.size(), hg_scanner_err_name(ret, errbuf)); (this->*dumpf_)(result, "decode", 10); return ret; } bool imgproc_mgr::sort_processor_by_pos(image_processor* l, image_processor* r) { return l->get_position() < r->get_position(); } int imgproc_mgr::set_value(const char* name, void* val) { int ret = SCANNER_ERR_OK; if (strcmp(name, SANE_STD_OPT_NAME_DUMP_IMG) == 0) { if (*(bool*)val) { dumpf_ = &imgproc_mgr::dump_real; dumpusbf_ = &imgproc_mgr::dump_usb_img_real; } else { dumpf_ = &imgproc_mgr::dump_empty; dumpusbf_ = &imgproc_mgr::dump_usb_img_empty; } } else if (strcmp(name, SANE_STD_OPT_NAME_DUMP_IMG_PATH) == 0) dump_path_ = (char*)val; else ret = SCANNER_ERR_DEVICE_NOT_SUPPORT; return ret; } int imgproc_mgr::load_processor(const char* path) { int ret = SCANNER_ERR_OK; #define ADD_IMG_PROCESSOR(cls) \ { \ cls *obj = new cls(); \ opts_->add(obj); \ obj->release(); \ } ADD_IMG_PROCESSOR(hole_filler); ADD_IMG_PROCESSOR(multi_outer); std::sort(processors_.begin(), processors_.end(), &imgproc_mgr::sort_processor_by_pos); return ret; } int imgproc_mgr::clear(void) { for (auto& v : processors_) v->release(); processors_.clear(); return 0; } int imgproc_mgr::process(HGIMGINFO* info, uint8_t* data, size_t bytes, std::vector& out) { std::vector mid[2], in, *src = &in, * dst = &mid[0]; int ret = decode(info, data, bytes, in), sn = 0; if (ret == SCANNER_ERR_OK) { for (auto& v : processors_) { if (v->is_enable()) { try { if (v->is_in_another_module()) { // use LPPROCIIM function ... } else ret = v->process(*src, *dst); (this->*dumpf_)(*dst, v->from(), v->get_position()); if (ret) break; src = dst; sn ^= 1; dst = &mid[sn]; } catch (const std::exception& e) { ret = SCANNER_ERR_THROW_EXCEPTION; utils::to_log(LOG_LEVEL_DEBUG, "FATAL: image %d process '%s' throws exception: %s!\n", info->paper_ind, v->from(), e.what()); std::string f(dump_usb_img_real(data, bytes, info, v->from())); utils::to_log(LOG_LEVEL_WARNING, "FATAL: process image %d failed on '%s', source content save to file '%s'\n", info->paper_ind, v->from(), f.c_str()); break; } catch (...) { ret = SCANNER_ERR_THROW_EXCEPTION; utils::to_log(LOG_LEVEL_DEBUG, "FATAL: image process '%s' throws unknown exception!\n", v->from()); std::string f(dump_usb_img_real(data, bytes, info, v->from())); utils::to_log(LOG_LEVEL_WARNING, "FATAL: process image %d failed on '%s', source content save to file '%s'\n", info->paper_ind, v->from(), f.c_str()); break; } } } } out = *src; return ret; }