Files
TZShot/src/viewmodel/ocr_view_model.cpp
T

135 lines
4.3 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 "ocr_view_model.h"
#include "ocr/ocr_engine.h"
#include <QtConcurrent/QtConcurrentRun>
#include <QClipboard>
#include <QGuiApplication>
#include <QDebug>
#include <QDesktopServices>
#include <QDir>
#include <QFileInfo>
#include <QUrl>
// ── 构造 ─────────────────────────────────────────────────
OcrViewModel::OcrViewModel(QObject *parent)
: QObject(parent)
{
connect(&m_watcher, &QFutureWatcher<QString>::finished,
this, &OcrViewModel::onRecognitionFinished);
}
// ── recognize ────────────────────────────────────────────
void OcrViewModel::recognize(const QImage &image)
{
if (m_isRecognizing) {
qWarning() << "[OcrViewModel] 正在识别中,忽略重复请求";
return;
}
if (image.isNull()) {
emit recognizeFailed("输入图像为空");
return;
}
m_isRecognizing = true;
emit isRecognizingChanged();
// 在子线程中执行同步识别;OcrEngine 在 lambda 内部构造/销毁(线程安全)
QImage imgCopy = image; // 拷贝,避免主线程释放
QFuture<QString> future = QtConcurrent::run([imgCopy]() -> QString {
OcrEngine engine;
if (!engine.isReady())
return QString("__ERROR__:") + engine.lastError();
QString result = engine.recognize(imgCopy);
if (result.isEmpty() && !engine.lastError().isEmpty())
return QString("__ERROR__:") + engine.lastError();
return result;
});
m_watcher.setFuture(future);
}
// ── onRecognitionFinished ─────────────────────────────────
void OcrViewModel::onRecognitionFinished()
{
m_isRecognizing = false;
emit isRecognizingChanged();
QString result = m_watcher.result();
if (result.startsWith("__ERROR__:")) {
QString err = result.mid(10);
qWarning() << "[OcrViewModel] 识别失败:" << err;
emit recognizeFailed(err);
return;
}
m_resultText = result;
emit resultTextChanged();
emit resultReady(result);
}
// ── copyResultToClipboard ─────────────────────────────────
void OcrViewModel::copyResultToClipboard()
{
if (m_resultText.isEmpty()) return;
QClipboard *cb = QGuiApplication::clipboard();
if (cb) {
cb->setText(m_resultText, QClipboard::Clipboard);
#ifdef Q_OS_LINUX
cb->setText(m_resultText, QClipboard::Selection);
#endif
}
}
QString OcrViewModel::runSelfCheck()
{
const QStringList available = OcrEngine::availableTessdataDirs();
const QStringList candidates = OcrEngine::tessdataSearchCandidates();
QString report;
if (!available.isEmpty()) {
report += tr("OCR 环境检查:通过\n");
report += tr("可用 tessdata:\n");
for (const QString &dir : available) {
report += QStringLiteral(" - %1\n").arg(QDir::toNativeSeparators(dir));
}
} else {
report += tr("OCR 环境检查:未通过(缺少 chi_sim/eng 语言包)\n");
report += tr("建议把以下文件放到目录中:\n");
report += QStringLiteral(" - chi_sim.traineddata\n");
report += QStringLiteral(" - eng.traineddata\n");
report += tr("候选 tessdata 目录:\n");
for (const QString &dir : candidates) {
report += QStringLiteral(" - %1\n").arg(QDir::toNativeSeparators(dir));
}
}
OcrEngine engine;
if (engine.isReady()) {
report += tr("引擎初始化:成功");
} else {
report += tr("引擎初始化:失败\n");
report += tr("错误信息:%1").arg(engine.lastError());
}
m_selfCheckText = report.trimmed();
emit selfCheckTextChanged();
return m_selfCheckText;
}
bool OcrViewModel::openTessdataFolder()
{
QString dirPath = OcrEngine::suggestedTessdataDir();
if (dirPath.isEmpty()) {
return false;
}
QDir dir(dirPath);
if (!dir.exists()) {
if (!QDir().mkpath(dirPath)) {
return false;
}
}
return QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(dirPath).absoluteFilePath()));
}