#include "dialog_scan.h" #include "ui_dialog_scan.h" #include #include #include #include #include "base/HGTime.h" #include "base/HGUtility.h" #include "imgproc/HGImgProc.h" #include "imgproc/HGOCR.h" #include "HGUIGlobal.h" Dialog_Scan::Dialog_Scan(class MainWindow *mainWnd) : QDialog(nullptr) , ui(new Ui::Dialog_Scan) , m_mainWnd(mainWnd) , m_devHandle(nullptr) , m_scanning(false) , m_dpi(200) , m_scanFileName("") , m_scanImgFmtWriter(nullptr) , m_ocrMsgPump(nullptr) , m_ocrThread(nullptr) { 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))); 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); } Dialog_Scan::~Dialog_Scan() { if (NULL != m_devHandle) { StopScan(); sane_close(m_devHandle); m_devHandle = NULL; m_devName.clear(); } sane_exit(); delete ui; } 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; } } void Dialog_Scan::StopScan() { if (m_scanning) { assert(NULL != m_devHandle); sane_cancel(m_devHandle); m_scanning = false; m_dpi = 200; ui->comboBox->setEnabled(true); ui->pushButtonScan->setEnabled(true); } } 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: { SANE_Device* sane_dev = (SANE_Device*)data; emit p->deviceArrive(sane_dev->name); } break; case SANE_EVENT_DEVICE_LEFT: { SANE_Device* sane_dev = (SANE_Device*)data; emit p->deviceRemove(sane_dev->name); } break; 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; } 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; } } 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) { 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; } } } void Dialog_Scan::on_keyPress(unsigned int buttonId) { assert(NULL != m_devHandle); StartScan(buttonId); } void Dialog_Scan::on_scanWorking() { // TODO 显示扫描进度窗口 } void Dialog_Scan::on_scanInfo(QString info, bool error) { // TODO 更新扫描信息到进度窗口 } void Dialog_Scan::on_scanImage(unsigned int count) { // TODO 更新扫描数量到进度窗口 } 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) { 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; } } void Dialog_Scan::on_pushButtonScan_clicked() { assert(!m_scanning); StartScan(0); }