code_app/app/scanner/config.cpp

627 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "config.h"
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <sstream>
#include <iomanip>
#include <QDir>
#include <fcntl.h>
#include <sys/stat.h>
#include <QLatin1String>
#include <qtextcodec.h>
#include <string.h>
#include <QCoreApplication>
#include "base/HGUtility.h"
struct
{
const char* name;
const char* title;
}g_opts[] = { {SANE_STD_OPT_NAME_RESTORE , OPTION_TITLE_HFMRSZ}
, {SANE_STD_OPT_NAME_HELP , OPTION_TITLE_BZ}
, {SANE_STD_OPT_NAME_IS_MULTI_OUT , OPTION_TITLE_DLSC}
, {SANE_STD_OPT_NAME_MULTI_OUT_TYPE , OPTION_TITLE_DLSCLX}
, {SANE_STD_OPT_NAME_COLOR_MODE , OPTION_TITLE_YSMS}
, {SANE_STD_OPT_NAME_BINARY_THRESHOLD , OPTION_TITLE_HBTXYZ}
, {SANE_STD_OPT_NAME_REVERSE_01 , OPTION_TITLE_HBTXFSSC}
, {SANE_STD_OPT_NAME_FILTER , OPTION_TITLE_HDHHBTX_CSYZQ}
, {SANE_STD_OPT_NAME_RID_MULTIOUT_RED , OPTION_TITLE_24WCSTX_DLSCCH}
, {SANE_STD_OPT_NAME_RID_ANSWER_SHEET_RED , OPTION_TITLE_24WCSTX_DTKCH}
, {SANE_STD_OPT_NAME_ERASE_BACKGROUND , OPTION_TITLE_BJYC}
, {SANE_STD_OPT_NAME_BKG_COLOR_RANGE , OPTION_TITLE_BJSCFDFW}
, {SANE_STD_OPT_NAME_SHARPEN , OPTION_TITLE_RHYMH}
, {SANE_STD_OPT_NAME_RID_MORR , OPTION_TITLE_QCMW}
, {SANE_STD_OPT_NAME_RID_GRID , OPTION_TITLE_CWW}
, {SANE_STD_OPT_NAME_ERROR_EXTENSION , OPTION_TITLE_CWKS}
, {SANE_STD_OPT_NAME_NOISE_OPTIMIZE , OPTION_TITLE_HBTXZDYH}
, {SANE_STD_OPT_NAME_NOISE_SIZE , OPTION_TITLE_ZDYHCC}
, {SANE_STD_OPT_NAME_PAPER , OPTION_TITLE_ZZCC}
, {SANE_STD_OPT_NAME_CUSTOM_AREA , OPTION_TITLE_ZDYSMQY}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT , OPTION_TITLE_SMQYZCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT , OPTION_TITLE_SMQYYCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_TOP , OPTION_TITLE_SMQYSCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM , OPTION_TITLE_SMQYXCmm}
, {SANE_STD_OPT_NAME_SIZE_CHECK , OPTION_TITLE_CCJC}
, {SANE_STD_OPT_NAME_PAGE , OPTION_TITLE_SMYM}
, {SANE_STD_OPT_NAME_DISCARD_BLANK_SENS , OPTION_TITLE_TGKBYLMD}
, {SANE_STD_OPT_NAME_RESOLUTION , OPTION_TITLE_FBL}
, {SANE_STD_OPT_NAME_TIME_TO_SLEEP , OPTION_TITLE_XMSJ}
, {SANE_STD_OPT_NAME_IMAGE_QUALITY , OPTION_TITLE_HZ}
, {SANE_STD_OPT_NAME_EXCHANGE ,OPTION_TITLE_JHZFM}
, {SANE_STD_OPT_NAME_SPLIT ,OPTION_TITLE_TXCF }
, {SANE_STD_OPT_NAME_ANTI_SKEW , OPTION_TITLE_ZDJP}
, {SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA , OPTION_TITLE_QYSDQX}
, {SANE_STD_OPT_NAME_GAMMA , OPTION_TITLE_JMZ}
, {SANE_STD_OPT_NAME_BRIGHTNESS , OPTION_TITLE_LDZ}
, {SANE_STD_OPT_NAME_CONTRAST , OPTION_TITLE_DBD}
, {SANE_STD_OPT_NAME_IS_PHOTO_MODE , OPTION_TITLE_ZPMS}
, {SANE_STD_OPT_NAME_ERASE_BLACK_FRAME , OPTION_TITLE_XCHK}
, {SANE_STD_OPT_NAME_DARK_SAMPLE , OPTION_TITLE_SSYZ}
, {SANE_STD_OPT_NAME_THRESHOLD , OPTION_TITLE_YZ}
, {SANE_STD_OPT_NAME_ANTI_NOISE_LEVEL , OPTION_TITLE_BJKZDJ}
, {SANE_STD_OPT_NAME_MARGIN , OPTION_TITLE_BYSJ}
, {SANE_STD_OPT_NAME_FILL_BKG_MODE , OPTION_TITLE_BJTCFS}
, {SANE_STD_OPT_NAME_IS_ANTI_PERMEATE , OPTION_TITLE_FZST}
, {SANE_STD_OPT_NAME_ANTI_PERMEATE_LEVEL , OPTION_TITLE_FZSTDJ}
, {SANE_STD_OPT_NAME_RID_HOLE_L , OPTION_TITLE_CKYCZC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_L , OPTION_TITLE_ZCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_R , OPTION_TITLE_CKYCYC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_R , OPTION_TITLE_YCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_T , OPTION_TITLE_CKYCSC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_T , OPTION_TITLE_SCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_B , OPTION_TITLE_CKYCXC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_B , OPTION_TITLE_XCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_IS_FILL_COLOR , OPTION_TITLE_SCTC}
, {SANE_STD_OPT_NAME_IS_ULTROSONIC_CHECK , OPTION_TITLE_CSBJC}
, {SANE_STD_OPT_NAME_DOUBLE_FEED_HANDLE , OPTION_TITLE_SZTPCL}
, {SANE_STD_OPT_NAME_IS_CHECK_STAPLE , OPTION_TITLE_ZDJC}
, {SANE_STD_OPT_NAME_SCAN_MODE , OPTION_TITLE_SMZS}
, {SANE_STD_OPT_NAME_SCAN_COUNT , OPTION_TITLE_SMSL}
, {SANE_STD_OPT_NAME_TEXT_DIRECTION , OPTION_TITLE_WGFX}
, {SANE_STD_OPT_NAME_IS_ROTATE_BKG_180 , OPTION_TITLE_BMXZ180}
, {SANE_STD_OPT_NAME_IS_CHECK_DOG_EAR , OPTION_TITLE_ZJJC}
, {SANE_STD_OPT_NAME_DOG_EAR_SIZE , OPTION_TITLE_ZJDX}
, {SANE_STD_OPT_NAME_IS_CHECK_ASKEW , OPTION_TITLE_WXJC}
, {SANE_STD_OPT_NAME_ASKEW_RANGE , OPTION_TITLE_WXRRD}
, {SANE_STD_OPT_NAME_FEED_STRENGTH , OPTION_TITLE_FZQD}
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , OPTION_TITLE_ZDFZQD}
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , OPTION_TITLE_JZSBL}
, {SANE_STD_OPT_NAME_WAIT_TO_SCAN , OPTION_TITLE_DZSM}
},
g_discard[] = { {SANE_STD_OPT_NAME_REVERSE_01 , "\351\273\221\347\231\275\345\233\276\345\203\217\345\217\215\350\211\262\350\276\223\345\207\272\357\274\210\346\255\243\345\270\270\351\242\234\350\211\262\344\270\272\357\274\2320-\351\273\221\350\211\262\357\274\2331-\347\231\275\350\211\262\357\274\211"} // 黑白图像反色输出正常颜色为0-黑色1-白色)
, {SANE_STD_OPT_NAME_FILTER , "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262"} // 灰度或黑白图像 - 除色
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , "\350\207\252\345\212\250\346\220\223\347\272\270\345\274\272\345\272\246"} // 自动搓纸强度
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , "\346\220\223\347\272\270\351\230\210\345\200\274"} // " 搓纸阈值"
};
config::config() : ini_(NULL), file_(""), schem_jsn_(NULL)
{
}
config::~config()
{
if(ini_)
delete ini_;
if(schem_jsn_)
delete schem_jsn_;
}
QString config::get_scanner_config_file(void)
{
QString file(get_val("scanner", "schemes"));
if(file.length() == 0)
{
HGChar logpath[512] = {0};
HGBase_GetConfigPath(logpath, 512);
file = strcat(logpath, "scanner.schm");
ini_->setValue("schemes", file);
}
if(file[0] != '/')
{
std::string path(file_.toStdString());
path.erase(path.rfind('/') + 1);
path += file.toStdString();
file = QString::fromStdString(path);
}
return file;
}
void config::reload_schemes(void)
{
if(schem_jsn_)
{
delete schem_jsn_;
schem_jsn_ = NULL;
}
std::string jsntxt(""), org(config::read_mini_file(get_scanner_config_file()));
gb::base64 base64;
if(org.empty())
return;
jsntxt = base64.decode(org.c_str(), org.length());
schem_jsn_ = new gb::json();
if(!schem_jsn_->attach_text(&jsntxt[0]))
{
delete schem_jsn_;
schem_jsn_ = NULL;
}
}
QString config::self_path(void)
{
QString qexePath = QCoreApplication::applicationDirPath();
return qexePath;
}
std::string config::read_mini_file(QString file)
{
std::string f(file.toStdString()),
ret("");
FILE* src = fopen(f.c_str(), "rb");
if(src)
{
long l = 0;
char *buf = NULL;
fseek(src, 0, SEEK_END);
l = ftell(src);
fseek(src, 0, SEEK_SET);
buf = (char*)malloc(l + 4);
memset(buf, 0, l + 4);
fread(buf, 1, l, src);
fclose(src);
ret = buf;
free(buf);
}
return ret;
}
std::string config::device_to_config_dev_name(QString& dev_name)
{
std::string name(dev_name.toStdString());
size_t pos = name.find(" - ");
if(pos != std::string::npos)
{
pos = name.find(" - ", pos + 3); // the first is ' - PID' 2022-10-11
if(pos != std::string::npos)
name.erase(pos);
}
return name;
}
int config::save_2_file(QString file, const void* buf, size_t l)
{
FILE* dst = fopen(file.toStdString().c_str(), "wb");
if(!dst)
return errno;
fwrite(buf, 1, l, dst);
fclose(dst);
return 0;
}
int config::find_config(QString dev_name, std::vector<DEVCFG>& cfgs)
{
std::string name(config::device_to_config_dev_name(dev_name));
int ind = -1;
for(size_t i = 0; i < cfgs.size(); ++i)
{
if(cfgs[i].name == name)
{
ind = i;
break;
}
}
return ind;
}
bool config::is_accessible_file(const std::string& path_file)
{
size_t pos = path_file.rfind('.');
if(pos++ == std::string::npos)
return false;
std::string ext(path_file.substr(pos));
config::to_lower(ext);
return (ext == "png" ||
ext == "jpg" ||
ext == "jpeg" ||
ext == "bmp" ||
ext == "tif" ||
ext == "pdf" ||
ext == "png");
}
void config::to_lower(std::string& str)
{
for(size_t i = 0; i < str.length(); ++i)
{
if(str[i] >= 'A' && str[i] <= 'Z')
str[i] -= 'A' - 'a';
}
}
bool config::load_custom_gamma(const char* file, SANE_Gamma* gamma)
{
bool ret = false;
FILE* src = fopen(file, "rb");
if(src)
{
long l = 0;
SANE_Gamma tmp = {0};
fseek(src, 0, SEEK_END);
l = ftell(src);
fseek(src, 0, SEEK_SET);
if(l == sizeof(SANE_Gamma) &&
fread(&tmp, l, 1, src) == 1)
{
if( tmp.pt_count >= 0 && tmp.pt_count <= sizeof (tmp.keypoint) / sizeof(tmp.keypoint[0]) &&
tmp.pt_count_r >= 0 && tmp.pt_count_r <= sizeof (tmp.keypoint_r) / sizeof(tmp.keypoint_r[0]) &&
tmp.pt_count_g >= 0 && tmp.pt_count_g <= sizeof (tmp.keypoint_g) / sizeof(tmp.keypoint_g[0]) &&
tmp.pt_count_b >= 0 && tmp.pt_count_b <= sizeof (tmp.keypoint_b) / sizeof(tmp.keypoint_b[0]))
{
memcpy(gamma, &tmp, l);
ret = true;
}
}
fclose(src);
}
return ret;
}
int config::load(QString file)
{
if(ini_)
delete ini_;
ini_ = NULL;
if(file.length() == 0)
file = "scanner.conf";
file_ = file;
if(file_[0] != '/')
{
HGChar logpath[512] = {0};
HGBase_GetConfigPath(logpath, sizeof(logpath) / sizeof(logpath[0]) - 1);
file_ = logpath;
file_ += file;
}
ini_ = new QSettings(file_, QSettings::IniFormat);
ini_->setIniCodec(QTextCodec::codecForName("UTF-8"));
reload_schemes();
return 0;
}
QString config::get_val(QString sec_name, QString key, QString def_val)
{
if(!ini_)
return def_val;
QVariant qv = ini_->value(sec_name + "/" + key);
char buf[128];
if(qv.isNull())
return def_val;
if(qv.type() == QVariant::Type::Int)
{
sprintf(buf, "%d", qv.toInt());
return QString::fromStdString(buf);
}
else if(qv.type() == QVariant::Type::UInt)
{
sprintf(buf, "%u", qv.toInt());
return QString::fromStdString(buf);
}
else if(qv.type() == QVariant::Type::Double)
{
sprintf(buf, "%f", qv.toFloat());
return QString::fromStdString(buf);
}
else
return qv.toString();
}
QString config::get_file(void)
{
return file_;
}
void config::load_all_scanner_configs(std::vector<DEVCFG>& cfgs)
{
#if 0
_opt_scheme opt1;
opt1.name = "aaa";
_opt_scheme opt2;
opt2.name = "bbb";
DEVCFG d1;
d1.name = "d1";
d1.schemes.push_back(opt1);
d1.schemes.push_back(opt2);
cfgs.push_back(d1);
_opt_scheme opt3;
opt3.name = "ccc";
_opt_scheme opt4;
opt4.name = "ddd";
DEVCFG d2;
d2.name = "d2";
d2.schemes.push_back(opt1);
d2.schemes.push_back(opt2);
cfgs.push_back(d2);
#endif
if(!schem_jsn_)
return;
std::vector<std::string> devs;
std::string cont(""), name("");
if(schem_jsn_->first_child(cont, &name))
{
do
{
if(!name.empty())
devs.push_back(name);
}while(schem_jsn_->next_child(cont, &name));
}
for(size_t i = 0; i < devs.size(); ++i)
{
DEVCFG cfg;
load_scanner_configs(QString::fromStdString(devs[i]), &cfg);
cfgs.push_back(cfg);
}
}
void config::transferTitle2Name(std::string& name)
{
int size = sizeof(g_opts) / sizeof(g_opts[0]);
for (size_t i = 0; i < size; i++)
{
if (strcmp(name.c_str(), g_opts[i].title) == 0)
{
name = g_opts[i].name;
}
}
}
std::string config::transferName2Title(std::string& name)
{
int size = sizeof(g_opts) / sizeof(g_opts[0]);
for (size_t i = 0; i < size; i++)
{
if (strcmp(name.c_str(), g_opts[i].name) == 0)
{
name = g_opts[i].title;
}
}
return name;
}
void config::load_scanner_configs(QString dev_name, DEVCFG* cfg)
{
std::string name(config::device_to_config_dev_name(dev_name)), cont("");
OPTSCHEME scheme;
OPTVAL val;
cfg->name = name;
cfg->cur_scheme = -1;
if(!schem_jsn_)
return;
gb::json *child = NULL;
schem_jsn_->get_value(name.c_str(), child);
if(!child)
return;
if(child->first_child(cont))
{
gb::json *cur = new gb::json();
if(cur->attach_text(&cont[0]))
{
if(!cur->get_value("cur_sel", cfg->cur_scheme))
cfg->cur_scheme = -1;
}
delete cur;
while(child->next_child(cont))
{
if(cont.empty())
continue;
gb::json jsn, *son = NULL;
if(!jsn.attach_text(&cont[0]))
continue;
jsn.get_value("scheme", scheme.name);
jsn.get_value("opts", son);
if(!son)
continue;
scheme.opts.clear();
if(son->first_child(cont))
{
do
{
if(cont.empty())
continue;
gb::json item;
if(!item.attach_text(&cont[0]))
continue;
if(item.get_value("name", val.name) && item.get_value("value", val.val))
{
transferTitle2Name(val.name); // chinese title to english name
item.get_value("extra", val.extra);
scheme.opts.push_back(val);
}
}while(son->next_child(cont));
}
delete son;
if(scheme.opts.size())
cfg->schemes.push_back(scheme);
}
}
delete child;
}
int config::save_scanner_configs(const DEVCFG* cfg)
{
if(!schem_jsn_)
schem_jsn_ = new gb::json();
gb::json *child = NULL, *scheme = NULL, *val = NULL;
std::string text("");
schem_jsn_->get_value(cfg->name.c_str(), child);
if(child)
schem_jsn_->remove(cfg->name.c_str());
if(child)
child->clear();
else {
child = new gb::json();
}
child->create_empty(true);
scheme = new gb::json();
scheme->set_value("cur_sel", cfg->cur_scheme);
scheme->set_value("version", cfg->appVersionNum);
child->set_value(NULL, scheme);
delete scheme;
for(size_t i = 0; i < cfg->schemes.size(); ++i)
{
if(cfg->schemes[i].opts.empty())
continue;
scheme = new gb::json();
scheme->create_empty();
scheme->set_value("scheme", cfg->schemes[i].name);
gb::json *opt = new gb::json();
opt->create_empty(true);
for(size_t j = 0; j < cfg->schemes[i].opts.size(); ++j)
{
val = new gb::json();
std::string jsonName = cfg->schemes[i].opts[j].name;
transferTitle2Name(jsonName);
val->set_value("name", jsonName);
// val->set_value("type", cfg->schemes[i].opts[j].type);
val->set_value("extra", cfg->schemes[i].opts[j].extra);
val->set_value("value", cfg->schemes[i].opts[j].val);
text = val->to_string(false);
opt->set_value(NULL, val);
text = opt->to_string(false);
delete val;
}
printf("scheme %d: %s\n", i + 1, text.c_str());
scheme->set_value("opts", opt);
text = scheme->to_string(false);
printf("all: %s\n", text.c_str());
delete opt;
child->set_value(NULL, scheme);
text = child->to_string(false);
delete scheme;
}
schem_jsn_->set_value(cfg->name.c_str(), child);
delete child;
text = schem_jsn_->to_string(false);
// save as base64
gb::base64 base64;
std::string ec(base64.encode(text.c_str(), text.length()));
return save_2_file(get_scanner_config_file(), ec.c_str(), ec.length());
}