code_app/app/scantool/dialog_scan.cpp

684 lines
21 KiB
C++
Raw Normal View History

2024-04-23 09:44:22 +00:00
#include "dialog_scan.h"
#include "ui_dialog_scan.h"
#include <QCloseEvent>
2024-04-26 04:11:10 +00:00
#include <QMessageBox>
#include <QDateTime>
#include <QFileInfo>
#include "base/HGTime.h"
#include "base/HGUtility.h"
#include "imgproc/HGImgProc.h"
#include "imgproc/HGOCR.h"
#include "HGUIGlobal.h"
2024-04-23 09:44:22 +00:00
2024-04-24 06:57:44 +00:00
Dialog_Scan::Dialog_Scan(class MainWindow *mainWnd)
2024-04-24 07:08:43 +00:00
: QDialog(nullptr)
2024-04-23 09:44:22 +00:00
, ui(new Ui::Dialog_Scan)
2024-04-24 06:57:44 +00:00
, m_mainWnd(mainWnd)
, m_devHandle(nullptr)
2024-04-26 04:11:10 +00:00
, m_scanning(false)
, m_dpi(200)
, m_scanFileName("")
, m_scanImgFmtWriter(nullptr)
, m_ocrMsgPump(nullptr)
, m_ocrThread(nullptr)
2024-04-23 09:44:22 +00:00
{
ui->setupUi(this);
setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint);
connect(this, SIGNAL(deviceArrive(QString)), this, SLOT(on_deviceArrive(QString)));
connect(this, SIGNAL(deviceRemove(QString)), this, SLOT(on_deviceRemove(QString)));
2024-04-26 04:11:10 +00:00
connect(this, SIGNAL(keyPress(unsigned int)), this, SLOT(on_keyPress(unsigned int)));
connect(this, SIGNAL(scanWorking()), this, SLOT(on_scanWorking()));
connect(this, SIGNAL(scanInfo(QString, bool)), this, SLOT(on_scanInfo(QString, bool)));
connect(this, SIGNAL(scanImage(unsigned int)), this, SLOT(on_scanImage(unsigned int)));
connect(this, SIGNAL(scanFinish()), this, SLOT(on_scanFinish()));
SANE_Int version_code = 0;
sane_init_ex(&version_code, sane_ex_callback, this);
2024-04-23 09:44:22 +00:00
}
Dialog_Scan::~Dialog_Scan()
{
if (NULL != m_devHandle)
{
2024-04-26 04:11:10 +00:00
StopScan();
sane_close(m_devHandle);
m_devHandle = NULL;
m_devName.clear();
}
sane_exit();
2024-04-23 09:44:22 +00:00
delete ui;
}
2024-04-26 05:15:43 +00:00
void Dialog_Scan::StartScan(unsigned int buttonId)
{
if (nullptr == m_devHandle)
{
QMessageBox::information(this, tr("Tips"), tr("Device is offline"));
return;
}
if (m_scanning)
{
return;
}
std::string deviceType = m_devName.toStdString();
char v[256] = {0};
SANE_Status status = sane_control_option(m_devHandle, (SANE_Int)0x886D, SANE_ACTION_GET_VALUE, v, NULL);
if (SANE_STATUS_GOOD == status)
{
deviceType = v;
}
ScanParam scanParam;
if (!m_mainWnd->GetScanParam(deviceType, buttonId, scanParam))
{
QMessageBox::information(this, tr("Tips"), tr("No key scanning configuration found"));
return;
}
// 1.恢复默认
SANE_Int num_dev_options = 0;
sane_control_option(m_devHandle, 0, SANE_ACTION_GET_VALUE, &num_dev_options, NULL);
for (int i = 1; i < num_dev_options; ++i)
{
const SANE_Option_Descriptor* desp = sane_get_option_descriptor(m_devHandle, i);
if (NULL == desp)
continue;
const char* name = desp->name;
while (' ' == *name)
++name;
if (0 == strcmp(SANE_STD_OPT_NAME_RESTORE, name) && SANE_TYPE_BUTTON == desp->type)
{
sane_control_option(m_devHandle, i, SANE_ACTION_SET_VALUE, NULL, NULL);
break;
}
}
// 2.设置新的属性
for (int i = 0; i < (int)scanParam.deviceConfigs.size(); ++i)
{
for (int j = 1; j < num_dev_options; ++j)
{
const SANE_Option_Descriptor* desp = sane_get_option_descriptor(m_devHandle, j);
if (NULL == desp)
continue;
const char* name = desp->name;
while (' ' == *name)
++name;
if (0 == strcmp(scanParam.deviceConfigs[i].name.c_str(), name))
{
if (SANE_TYPE_STRING == desp->type)
{
sane_control_option(m_devHandle, j, SANE_ACTION_SET_VALUE, (void*)scanParam.deviceConfigs[i].stringValue.c_str(), NULL);
}
else if (SANE_TYPE_INT == desp->type)
{
SANE_Int value = scanParam.deviceConfigs[i].intValue;
sane_control_option(m_devHandle, j, SANE_ACTION_SET_VALUE, &value, NULL);
}
else if (SANE_TYPE_FIXED == desp->type)
{
SANE_Fixed value = SANE_FIX(scanParam.deviceConfigs[i].doubleValue);
sane_control_option(m_devHandle, j, SANE_ACTION_SET_VALUE, &value, NULL);
}
else if (SANE_TYPE_BOOL == desp->type)
{
SANE_Bool value = (SANE_Bool)scanParam.deviceConfigs[i].boolValue;
sane_control_option(m_devHandle, j, SANE_ACTION_SET_VALUE, &value, NULL);
}
break;
}
}
}
// 3. 获取DPI
for (int i = 1; i < num_dev_options; ++i)
{
const SANE_Option_Descriptor* desp = sane_get_option_descriptor(m_devHandle, i);
if (nullptr == desp)
continue;
if (SANE_TYPE_INT == desp->type)
{
SANE_Int value = 0;
sane_control_option(m_devHandle, i, SANE_ACTION_GET_VALUE, &value, nullptr);
if (0 == strcmp(desp->name, SANE_STD_OPT_NAME_RESOLUTION))
{
m_dpi = (HGUInt)value;
}
}
}
// 4.保存配置
assert(m_scanFileName.isEmpty());
assert(nullptr == m_scanImgFmtWriter);
m_aquireIntoSaveParam = scanParam.saveParam;
m_aquireIntoInBlank = true;
m_aquireIntoBatchStartIndex = 0;
m_aquireIntoPageIndex = 0;
m_aquireIntoMultiPageCount = 0;
QDateTime dateTime = QDateTime::currentDateTime();
if (m_aquireIntoSaveParam.m_isUseSubfolderByTime)
{
m_aquireIntoSaveParam.m_savePath = getStdFileName(m_aquireIntoSaveParam.m_savePath + dateTime.toString("yyyy-MM-dd") + "/");
}
if (m_aquireIntoSaveParam.m_isOcr)
{
HGBase_CreateMsgPump(&m_ocrMsgPump);
HGBase_OpenThread(ocrThreadFunc, this, &m_ocrThread);
}
m_scanning = true;
ui->comboBox->setEnabled(false);
ui->pushButtonScan->setEnabled(false);
status = sane_start(m_devHandle);
if (SANE_STATUS_GOOD != status)
{
if (NULL != m_ocrMsgPump)
{
HGBase_ExitMsgPump(m_ocrMsgPump);
HGBase_CloseThread(m_ocrThread);
m_ocrThread = NULL;
HGBase_DestroyMsgPump(m_ocrMsgPump);
m_ocrMsgPump = NULL;
}
m_scanning = false;
m_dpi = 200;
ui->comboBox->setEnabled(true);
ui->pushButtonScan->setEnabled(true);
return;
}
}
2024-04-26 04:11:10 +00:00
void Dialog_Scan::StopScan()
{
if (m_scanning)
{
assert(NULL != m_devHandle);
sane_cancel(m_devHandle);
m_scanning = false;
m_dpi = 200;
2024-04-26 05:15:43 +00:00
ui->comboBox->setEnabled(true);
ui->pushButtonScan->setEnabled(true);
2024-04-26 04:11:10 +00:00
}
}
void Dialog_Scan::SaveImage(HGImage image)
{
if (m_aquireIntoSaveParam.m_isSaveAsMultiPage)
{
if (nullptr == m_scanImgFmtWriter)
{
assert(m_scanFileName.isEmpty());
HGBase_CreateDir(getStdString(m_aquireIntoSaveParam.m_savePath).c_str());
QString scanFileName;
while (1)
{
scanFileName = m_aquireIntoSaveParam.m_savePath + m_aquireIntoSaveParam.m_fileNamePrefix + QString("%1.%2")
.arg(m_aquireIntoSaveParam.m_fileNameStartIndex, m_aquireIntoSaveParam.m_fileNameDigits, 10, QLatin1Char('0'))
.arg(m_aquireIntoSaveParam.m_fileNameExt);
QFileInfo fileInfo(scanFileName);
if (fileInfo.isFile())
{
++m_aquireIntoSaveParam.m_fileNameStartIndex;
}
else
{
break;
}
}
HGUInt fmtType = 0;
if (nullptr != m_ocrMsgPump)
{
fmtType = HGIMGFMT_TYPE_TIFF;
}
HGImgFmt_OpenImageWriter(getStdString(getStdFileName(scanFileName)).c_str(), fmtType, &m_scanImgFmtWriter);
if (nullptr != m_scanImgFmtWriter)
{
m_scanFileName = scanFileName;
}
}
if (nullptr != m_scanImgFmtWriter)
{
HGImgFmtSaveInfo saveInfo;
saveInfo.jpegQuality = (HGUInt)m_aquireIntoSaveParam.m_jpegQuality;
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_NONE;
saveInfo.tiffJpegQuality = (HGUInt)m_aquireIntoSaveParam.m_tiffQuality;
HGImageInfo imgInfo;
HGBase_GetImageInfo(image, &imgInfo);
if (HGBASE_IMGTYPE_BINARY == imgInfo.type)
{
if (1 == m_aquireIntoSaveParam.m_tiffCompressionBW)
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_LZW;
else if (2 == m_aquireIntoSaveParam.m_tiffCompressionBW)
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_CCITTFAX4;
}
else
{
if (1 == m_aquireIntoSaveParam.m_tiffCompression)
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_LZW;
else if (2 == m_aquireIntoSaveParam.m_tiffCompression)
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_JPEG;
}
if (nullptr != m_ocrMsgPump)
{
saveInfo.jpegQuality = 100;
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_NONE;
saveInfo.tiffJpegQuality = 100;
}
if (HGBASE_ERR_OK == HGImgFmt_SaveImageToWriter(m_scanImgFmtWriter, image, &saveInfo))
{
++m_aquireIntoMultiPageCount;
if (1 == m_aquireIntoSaveParam.m_multiPagesType && m_aquireIntoMultiPageCount == m_aquireIntoSaveParam.m_customMultiPages)
{
HGImgFmt_CloseImageWriter(m_scanImgFmtWriter);
m_scanImgFmtWriter = nullptr;
if (nullptr != m_ocrMsgPump)
{
QString *filePath = new QString(m_scanFileName);
HGMsg msg;
msg.id = 1;
msg.data = filePath;
if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_ocrMsgPump, &msg))
{
delete filePath;
}
}
m_scanFileName.clear();
++m_aquireIntoSaveParam.m_fileNameStartIndex;
m_aquireIntoMultiPageCount = 0;
}
}
}
}
else
{
assert(nullptr == m_scanImgFmtWriter);
QString savePath = m_aquireIntoSaveParam.m_savePath;
if (m_aquireIntoSaveParam.m_isUseSubfolderByBlankPages)
{
HGBool isBlank = HGFALSE;
HGImgProc_ImageBlankCheck(image, nullptr, &isBlank);
if (isBlank)
{
m_aquireIntoInBlank = true;
}
else
{
if (m_aquireIntoInBlank)
{
++m_aquireIntoBatchStartIndex;
}
m_aquireIntoInBlank = false;
}
char batchDir[20];
sprintf(batchDir, "batch%d", m_aquireIntoBatchStartIndex);
savePath = getStdFileName(savePath + batchDir + "/");
}
if (m_aquireIntoSaveParam.m_isUseSubfolderByColor)
{
QString colorModeName;
HGImageInfo imgInfo;
HGBase_GetImageInfo(image, &imgInfo);
if (HGBASE_IMGTYPE_BINARY == imgInfo.type)
colorModeName = tr("binary");
else if (HGBASE_IMGTYPE_GRAY == imgInfo.type)
colorModeName = tr("gray");
else
colorModeName = tr("rgb");
savePath = getStdFileName(savePath + colorModeName + "/");
}
HGBase_CreateDir(getStdString(savePath).c_str());
while (1)
{
m_scanFileName = savePath + m_aquireIntoSaveParam.m_fileNamePrefix + QString("%1.%2")
.arg(m_aquireIntoSaveParam.m_fileNameStartIndex, m_aquireIntoSaveParam.m_fileNameDigits, 10, QLatin1Char('0'))
.arg(m_aquireIntoSaveParam.m_fileNameExt);
QFileInfo fileInfo(m_scanFileName);
if (fileInfo.isFile())
{
++m_aquireIntoSaveParam.m_fileNameStartIndex;
}
else
{
break;
}
}
HGImgFmtSaveInfo saveInfo;
saveInfo.jpegQuality = (HGUInt)m_aquireIntoSaveParam.m_jpegQuality;
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_NONE;
saveInfo.tiffJpegQuality = (HGUInt)m_aquireIntoSaveParam.m_tiffQuality;
HGImageInfo imgInfo;
HGBase_GetImageInfo(image, &imgInfo);
if (HGBASE_IMGTYPE_BINARY == imgInfo.type)
{
if (1 == m_aquireIntoSaveParam.m_tiffCompressionBW)
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_LZW;
else if (2 == m_aquireIntoSaveParam.m_tiffCompressionBW)
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_CCITTFAX4;
}
else
{
if (1 == m_aquireIntoSaveParam.m_tiffCompression)
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_LZW;
else if (2 == m_aquireIntoSaveParam.m_tiffCompression)
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_JPEG;
}
HGUInt fmtType = 0;
if (nullptr != m_ocrMsgPump)
{
fmtType = HGIMGFMT_TYPE_TIFF;
saveInfo.jpegQuality = 100;
saveInfo.tiffCompression = HGIMGFMT_TIFFCOMP_NONE;
saveInfo.tiffJpegQuality = 100;
}
if (HGBASE_ERR_OK == HGImgFmt_SaveImage(image, fmtType, &saveInfo, getStdString(m_scanFileName).c_str()))
{
if (nullptr != m_ocrMsgPump)
{
QString *filePath = new QString(m_scanFileName);
HGMsg msg;
msg.id = 1;
msg.data = filePath;
if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_ocrMsgPump, &msg))
{
delete filePath;
}
}
++m_aquireIntoSaveParam.m_fileNameStartIndex;
}
m_scanFileName.clear();
}
}
int Dialog_Scan::sane_ex_callback(SANE_Handle hdev, int code, void* data, unsigned int* len, void* param)
{
(void)hdev;
(void)len;
Dialog_Scan* p = (Dialog_Scan*)param;
switch (code)
{
case SANE_EVENT_DEVICE_ARRIVED:
2024-04-26 04:11:10 +00:00
{
SANE_Device* sane_dev = (SANE_Device*)data;
emit p->deviceArrive(sane_dev->name);
}
break;
case SANE_EVENT_DEVICE_LEFT:
2024-04-26 04:11:10 +00:00
{
SANE_Device* sane_dev = (SANE_Device*)data;
emit p->deviceRemove(sane_dev->name);
}
break;
2024-04-26 04:11:10 +00:00
case SANE_EVENT_WORKING:
{
emit p->scanWorking();
emit p->scanInfo((const char*)data, false);
}
break;
case SANE_EVENT_SCAN_FINISHED:
{
emit p->scanInfo((const char*)data, (0 != *len));
emit p->scanFinish();
}
break;
case SANE_EVENT_STATUS:
{
emit p->scanInfo((const char*)data, false);
}
break;
case SANE_EVENT_ERROR:
{
emit p->scanInfo((const char*)data, (0 != *len));
}
break;
case SANE_EVENT_IMAGE_OK:
{
++p->m_aquireIntoPageIndex;
emit p->scanImage(p->m_aquireIntoPageIndex);
if ((1 == p->m_aquireIntoSaveParam.m_fileNameOddEventType && 1 != p->m_aquireIntoPageIndex % 2)
|| (2 == p->m_aquireIntoSaveParam.m_fileNameOddEventType && 0 != p->m_aquireIntoPageIndex % 2))
{
// 跳过
}
else
{
SANE_Image* sane_img = (SANE_Image*)data;
HGUInt imgType = 0;
if (sane_img->header.format == SANE_FRAME_GRAY)
{
if (1 == sane_img->header.depth)
imgType = HGBASE_IMGTYPE_BINARY;
else if (8 == sane_img->header.depth)
imgType = HGBASE_IMGTYPE_GRAY;
}
else if (sane_img->header.format == SANE_FRAME_RGB)
imgType = HGBASE_IMGTYPE_RGB;
HGByte* data = sane_img->data;
HGImageInfo imgInfo = { (HGUInt)sane_img->header.pixels_per_line, (HGUInt)sane_img->header.lines,
imgType, (HGUInt)sane_img->header.bytes_per_line, HGBASE_IMGORIGIN_TOP };
HGImage img = NULL;
HGBase_CreateImageFromData(data, &imgInfo, NULL, 0, HGBASE_IMGORIGIN_TOP, &img);
if (NULL != img)
{
HGBase_SetImageDpi(img, p->m_dpi, p->m_dpi);
p->SaveImage(img);
HGBase_DestroyImage(img);
}
}
}
break;
}
return 0;
}
2024-04-26 04:11:10 +00:00
void Dialog_Scan::ocrThreadFunc(HGThread thread, HGPointer param)
{
Dialog_Scan *p = (Dialog_Scan*)param;
HGBase_RunMsgPump(p->m_ocrMsgPump, ocrMsgPumpFunc, param);
}
void Dialog_Scan::ocrMsgPumpFunc(HGMsgPump msgPump, const HGMsg *msg, HGPointer param)
{
Dialog_Scan *p = (Dialog_Scan*)param;
if (msg->id == 1)
{
QString *filePath = (QString *)msg->data;
HGOCRMgr ocrMgr = NULL;
HGImgProc_CreateOCRMgr(HGIMGPROC_OCRALGO_DEFAULT, &ocrMgr);
if (NULL != ocrMgr)
{
HGImgFmtReader reader = NULL;
HGImgFmt_OpenImageReader(filePath->toLocal8Bit().toStdString().c_str(), 0, &reader);
if (NULL != reader)
{
HGUInt count = 0;
HGImgFmt_GetImagePageCount(reader, &count);
for (HGUInt i = 0; i < count; ++i)
{
HGImage image = NULL;
HGImgFmt_LoadImageFromReader(reader, i, NULL, 0, 0, &image);
if (NULL != image)
{
HGImgProc_AddToImageOCRList(ocrMgr, image);
HGBase_DestroyImage(image);
}
}
HGImgFmt_CloseImageReader(reader);
}
//HGBase_DeleteFile(filePath->toLocal8Bit().toStdString().c_str());
HGImgProc_ImageListOCRToFile(ocrMgr, 0, filePath->toLocal8Bit().toStdString().c_str(), NULL, NULL);
HGImgProc_DestroyOCRMgr(ocrMgr);
}
delete filePath;
}
}
2024-04-23 09:44:22 +00:00
void Dialog_Scan::closeEvent(QCloseEvent *e)
{
hide(); // 隐藏主窗口
e->ignore(); //忽略关闭事件,这样才不会关闭程序
}
void Dialog_Scan::on_deviceArrive(QString devName)
{
ui->comboBox->addItem(devName);
if (nullptr == m_devHandle)
{
SANE_Status status = sane_open(devName.toStdString().c_str(), &m_devHandle);
if (SANE_STATUS_GOOD == status)
{
m_devName = devName;
}
}
}
void Dialog_Scan::on_deviceRemove(QString devName)
{
if (devName == m_devName)
{
2024-04-26 04:11:10 +00:00
StopScan();
sane_close(m_devHandle);
m_devHandle = NULL;
m_devName.clear();
}
for (int i = 0; i < ui->comboBox->count(); ++i)
{
if (ui->comboBox->itemText(i) == devName)
{
ui->comboBox->removeItem(i);
break;
}
}
}
2024-04-26 05:15:43 +00:00
void Dialog_Scan::on_keyPress(unsigned int buttonId)
2024-04-26 04:11:10 +00:00
{
assert(NULL != m_devHandle);
2024-04-26 05:15:43 +00:00
StartScan(buttonId);
2024-04-26 04:11:10 +00:00
}
void Dialog_Scan::on_scanWorking()
{
// TODO 显示扫描进度窗口
}
void Dialog_Scan::on_scanInfo(QString info, bool error)
{
// TODO 更新扫描信息到进度窗口
}
void Dialog_Scan::on_scanImage(unsigned int count)
{
2024-04-26 05:15:43 +00:00
// TODO 更新扫描数量到进度窗口
2024-04-26 04:11:10 +00:00
}
void Dialog_Scan::on_scanFinish()
{
if (nullptr != m_scanImgFmtWriter)
{
HGImgFmt_CloseImageWriter(m_scanImgFmtWriter);
m_scanImgFmtWriter = nullptr;
if (nullptr != m_ocrMsgPump)
{
QString *filePath = new QString(m_scanFileName);
HGMsg msg;
msg.id = 1;
msg.data = filePath;
if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_ocrMsgPump, &msg))
{
delete filePath;
}
}
m_scanFileName.clear();
++m_aquireIntoSaveParam.m_fileNameStartIndex;
m_aquireIntoMultiPageCount = 0;
}
if (NULL != m_ocrMsgPump)
{
HGBase_ExitMsgPump(m_ocrMsgPump);
HGBase_CloseThread(m_ocrThread);
m_ocrThread = NULL;
HGBase_DestroyMsgPump(m_ocrMsgPump);
m_ocrMsgPump = NULL;
}
// TODO 隐藏扫描进度窗口
StopScan();
}
void Dialog_Scan::on_comboBox_currentIndexChanged(const QString &arg1)
{
if (NULL != m_devHandle)
{
2024-04-26 04:11:10 +00:00
StopScan();
sane_close(m_devHandle);
m_devHandle = NULL;
m_devName.clear();
}
SANE_Status status = sane_open(arg1.toStdString().c_str(), &m_devHandle);
if (SANE_STATUS_GOOD == status)
{
m_devName = arg1;
}
}
2024-04-26 05:15:43 +00:00
void Dialog_Scan::on_pushButtonScan_clicked()
{
assert(!m_scanning);
StartScan(0);
}