code_device/sdk/imgprc/imgprc_mgr.cpp

374 lines
11 KiB
C++

#include "imgprc_mgr.h"
#include <json/gb_json.h>
#include <sane_opt_json/device_opt.h>
#include "../../../sdk/include/huagao/hgscanner_error.h"
#include <ImageMatQueue.h>
#include <huagaoxxx_warraper_ex.h>
#include <imgproc-pak/fill_hole.h>
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::DECDAT> imgproc_mgr::decode_before_simple(uint8_t* data, size_t bytes, HGIMGINFO* info)
{
std::vector<DECDAT> simple;
DECDAT in;
in.info = *info;
in.img.reset(new std::vector<char>(bytes));
memcpy(in.img->data(), data, bytes);
simple.push_back(in);
return std::move(simple);
}
std::vector<imgproc_mgr::DECDAT> imgproc_mgr::decode_before_g200dsp(uint8_t* data, size_t bytes, HGIMGINFO* info)
{
// pid == 0x100 || pid == 0x200
std::vector<DECDAT> 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<char>(bytes));
b.info = *info;
b.info.paper_side = PAPER_SIDE_BACK;
b.img.reset(new std::vector<char>(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<PROCIMGINFO>& img, const char* after, int pos)
{
std::string root(dump_path_ + PATH_SEPARATOR);
std::vector<std::string> 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<PROCIMGINFO>& 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<PROCIMGINFO>& result)
{
std::vector<DECDAT> 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;
hole_filler* holer = new hole_filler();
opts_->add(holer);
holer->release();
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<PROCIMGINFO>& out)
{
std::vector<PROCIMGINFO> 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
{
ret = v->process(*src, *dst);
(this->*dumpf_)(*dst, v->from().c_str(), 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().c_str(), e.what());
std::string f(dump_usb_img_real(data, bytes, info, v->from().c_str()));
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().c_str(), 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().c_str());
std::string f(dump_usb_img_real(data, bytes, info, v->from().c_str()));
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().c_str(), f.c_str());
break;
}
}
}
}
out = *src;
return ret;
}