From 9af54b3d732288244948b4ce63007a05971dc584 Mon Sep 17 00:00:00 2001 From: Raul Sampedro Date: Fri, 27 Jan 2023 20:19:50 +0100 Subject: [PATCH] fix #702 add OCR with tesseract --- data/graphics.qrc | 2 + data/img/material/black/ocr.svg | 8 ++++ data/img/material/white/ocr.svg | 8 ++++ src/config/generalconf.cpp | 27 +++++++++++ src/config/generalconf.h | 3 ++ src/core/capturerequest.h | 1 + src/core/flameshot.cpp | 24 ++++++++++ src/tools/CMakeLists.txt | 1 + src/tools/capturetool.h | 1 + src/tools/ocr/ocrtool.cpp | 55 +++++++++++++++++++++++ src/tools/ocr/ocrtool.h | 27 +++++++++++ src/tools/toolfactory.cpp | 2 + src/utils/confighandler.cpp | 2 + src/utils/confighandler.h | 1 + src/widgets/capture/capturetoolbutton.cpp | 3 +- 15 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 data/img/material/black/ocr.svg create mode 100644 data/img/material/white/ocr.svg create mode 100644 src/tools/ocr/ocrtool.cpp create mode 100644 src/tools/ocr/ocrtool.h diff --git a/data/graphics.qrc b/data/graphics.qrc index fd1d93d139..a2c17dfa86 100644 --- a/data/graphics.qrc +++ b/data/graphics.qrc @@ -96,8 +96,10 @@ img/material/white/move_up.svg img/material/white/delete.svg img/material/black/apps.svg + img/material/black/ocr.svg img/material/black/image.svg img/material/white/apps.svg + img/material/white/ocr.svg img/material/white/image.svg diff --git a/data/img/material/black/ocr.svg b/data/img/material/black/ocr.svg new file mode 100644 index 0000000000..fc08c6f5f1 --- /dev/null +++ b/data/img/material/black/ocr.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/data/img/material/white/ocr.svg b/data/img/material/white/ocr.svg new file mode 100644 index 0000000000..44d5e3e471 --- /dev/null +++ b/data/img/material/white/ocr.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/config/generalconf.cpp b/src/config/generalconf.cpp index fa67969133..3beb2ab3ef 100644 --- a/src/config/generalconf.cpp +++ b/src/config/generalconf.cpp @@ -56,6 +56,7 @@ GeneralConf::GeneralConf(QWidget* parent) initAntialiasingPinZoom(); initUploadHistoryMax(); initUndoLimit(); + initTesseractPath(); initUploadClientSecret(); initPredefinedColorPaletteLarge(); initShowSelectionGeometry(); @@ -545,6 +546,32 @@ void GeneralConf::initUploadHistoryMax() vboxLayout->addWidget(m_uploadHistoryMax); } +void GeneralConf::initTesseractPath() +{ + auto* box = new QGroupBox(tr("Tesseract path (for OCR)")); + box->setFlat(true); + m_layout->addWidget(box); + + auto* vboxLayout = new QVBoxLayout(); + box->setLayout(vboxLayout); + + m_tesseractPath = new QLineEdit(this); + QString foreground = this->palette().windowText().color().name(); + m_tesseractPath->setStyleSheet( + QStringLiteral("color: %1").arg(foreground)); + m_tesseractPath->setText(ConfigHandler().tesseractBinPath()); + connect(m_tesseractPath, + SIGNAL(editingFinished()), + this, + SLOT(tesseractPathEdited())); + vboxLayout->addWidget(m_tesseractPath); +} + +void GeneralConf::tesseractPathEdited() +{ + ConfigHandler().setTesseractBinPath(m_tesseractPath->text()); +} + void GeneralConf::initUploadClientSecret() { auto* box = new QGroupBox(tr("Imgur Application Client ID")); diff --git a/src/config/generalconf.h b/src/config/generalconf.h index 29bbfffe62..a41c8975f5 100644 --- a/src/config/generalconf.h +++ b/src/config/generalconf.h @@ -52,6 +52,7 @@ private slots: void exportFileConfiguration(); void resetConfiguration(); void togglePathFixed(); + void tesseractPathEdited(); void uploadClientKeyEdited(); void useJpgForClipboardChanged(bool checked); void setSaveAsFileExtension(QString extension); @@ -87,6 +88,7 @@ private slots: void initUploadWithoutConfirmation(); void initUseJpgForClipboard(); void initUploadHistoryMax(); + void initTesseractPath(); void initUploadClientSecret(); void initSaveLastRegion(); void initShowSelectionGeometry(); @@ -118,6 +120,7 @@ private slots: QPushButton* m_resetButton; QCheckBox* m_saveAfterCopy; QLineEdit* m_savePath; + QLineEdit* m_tesseractPath; QLineEdit* m_uploadClientKey; QPushButton* m_changeSaveButton; QCheckBox* m_screenshotPathFixedCheck; diff --git a/src/core/capturerequest.h b/src/core/capturerequest.h index ac8f885cec..3afb1d82cc 100644 --- a/src/core/capturerequest.h +++ b/src/core/capturerequest.h @@ -27,6 +27,7 @@ class CaptureRequest PIN = 16, UPLOAD = 32, ACCEPT_ON_SELECT = 64, + OCR = 128, }; CaptureRequest(CaptureMode mode, diff --git a/src/core/flameshot.cpp b/src/core/flameshot.cpp index ca7d5fb2a9..665f288ec2 100644 --- a/src/core/flameshot.cpp +++ b/src/core/flameshot.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -349,6 +350,29 @@ void Flameshot::exportCapture(QPixmap capture, << selection.x() << "+" << selection.y() << "\n"; } + if (tasks & CR::OCR) { + QProcess *tesseractProcess = new QProcess(); + + tesseractProcess->setProcessChannelMode(QProcess::MergedChannels); + tesseractProcess->start(ConfigHandler().tesseractBinPath(), QStringList() << "stdin" << "stdout"); + + capture.save(tesseractProcess, "PNG"); + tesseractProcess->closeWriteChannel(); + + AbstractLogger::info() << QObject::tr("Running OCR with tesseract"); + + if(!tesseractProcess->waitForFinished()){ + QMessageBox messageBox; + QString errorMessage = tr("Error running tesseract OCR from ") + ConfigHandler().tesseractBinPath() + "\n" + tesseractProcess->errorString(); + messageBox.critical(0, tr("Error"), errorMessage); + messageBox.setFixedSize(500,200); + }else{ + QString stdout = tesseractProcess->readAllStandardOutput(); + FlameshotDaemon::copyToClipboard(stdout); + } + + } + if (tasks & CR::PRINT_RAW) { QByteArray byteArray; QBuffer buffer(&byteArray); diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index d2a629242b..b2d3e61492 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -41,6 +41,7 @@ target_sources( target_sources(flameshot PRIVATE rectangle/rectangletool.h rectangle/rectangletool.cpp) target_sources(flameshot PRIVATE redo/redotool.h redo/redotool.cpp) target_sources(flameshot PRIVATE save/savetool.h save/savetool.cpp) +target_sources(flameshot PRIVATE ocr/ocrtool.h ocr/ocrtool.cpp) target_sources(flameshot PRIVATE accept/accepttool.h accept/accepttool.cpp) target_sources(flameshot PRIVATE invert/inverttool.h invert/inverttool.cpp) target_sources(flameshot PRIVATE selection/selectiontool.h selection/selectiontool.cpp) diff --git a/src/tools/capturetool.h b/src/tools/capturetool.h index e9fc669fe8..b8a251e0c2 100644 --- a/src/tools/capturetool.h +++ b/src/tools/capturetool.h @@ -48,6 +48,7 @@ class CaptureTool : public QObject TYPE_SIZEDECREASE = 21, TYPE_INVERT = 22, TYPE_ACCEPT = 23, + TYPE_OCR = 24, }; Q_ENUM(Type); diff --git a/src/tools/ocr/ocrtool.cpp b/src/tools/ocr/ocrtool.cpp new file mode 100644 index 0000000000..ab3af60d52 --- /dev/null +++ b/src/tools/ocr/ocrtool.cpp @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors + +#include "ocrtool.h" +#include "src/utils/screenshotsaver.h" +#include +#include +#include +#if defined(Q_OS_MACOS) +#include "src/widgets/capture/capturewidget.h" +#include +#endif + +OcrTool::OcrTool(QObject* parent) + : AbstractActionTool(parent) +{} + +bool OcrTool::closeOnButtonPressed() const +{ + return true; +} + +QIcon OcrTool::icon(const QColor& background, bool inEditor) const +{ + Q_UNUSED(inEditor) + return QIcon(iconPath(background) + "ocr.svg"); +} + +QString OcrTool::name() const +{ + return tr("OCR"); +} + +CaptureTool::Type OcrTool::type() const +{ + return CaptureTool::TYPE_OCR; +} + +QString OcrTool::description() const +{ + return tr("OCR the capture"); +} + +CaptureTool* OcrTool::copy(QObject* parent) +{ + return new OcrTool(parent); +} + +void OcrTool::pressed(CaptureContext& context) +{ + emit requestAction(REQ_CLEAR_SELECTION); + emit requestAction(REQ_CAPTURE_DONE_OK); + context.request.addTask(CaptureRequest::OCR); + emit requestAction(REQ_CLOSE_GUI); +} diff --git a/src/tools/ocr/ocrtool.h b/src/tools/ocr/ocrtool.h new file mode 100644 index 0000000000..eba087589f --- /dev/null +++ b/src/tools/ocr/ocrtool.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors + +#pragma once + +#include "abstractactiontool.h" + +class OcrTool : public AbstractActionTool +{ + Q_OBJECT +public: + explicit OcrTool(QObject* parent = nullptr); + + bool closeOnButtonPressed() const override; + + QIcon icon(const QColor& background, bool inEditor) const override; + QString name() const override; + QString description() const override; + + CaptureTool* copy(QObject* parent = nullptr) override; + +protected: + CaptureTool::Type type() const override; + +public slots: + void pressed(CaptureContext& context) override; +}; diff --git a/src/tools/toolfactory.cpp b/src/tools/toolfactory.cpp index 98ed0ab3d7..f9d2a13cf8 100644 --- a/src/tools/toolfactory.cpp +++ b/src/tools/toolfactory.cpp @@ -14,6 +14,7 @@ #include "line/linetool.h" #include "marker/markertool.h" #include "move/movetool.h" +#include "ocr/ocrtool.h" #include "pencil/penciltool.h" #include "pin/pintool.h" #include "pixelate/pixelatetool.h" @@ -61,6 +62,7 @@ CaptureTool* ToolFactory::CreateTool(CaptureTool::Type t, QObject* parent) if_TYPE_return_TOOL(TYPE_SIZEINCREASE, SizeIncreaseTool); if_TYPE_return_TOOL(TYPE_SIZEDECREASE, SizeDecreaseTool); if_TYPE_return_TOOL(TYPE_INVERT, InvertTool); + if_TYPE_return_TOOL(TYPE_OCR, OcrTool); if_TYPE_return_TOOL(TYPE_ACCEPT, AcceptTool); default: return nullptr; diff --git a/src/utils/confighandler.cpp b/src/utils/confighandler.cpp index b77b964e17..af92e36478 100644 --- a/src/utils/confighandler.cpp +++ b/src/utils/confighandler.cpp @@ -123,6 +123,7 @@ static QMap> // drawFontSize, remember to update ConfigHandler::toolSize OPTION("copyOnDoubleClick" ,Bool ( false )), OPTION("uploadClientSecret" ,String ( "313baf0c7b4d3ff" )), + OPTION("tesseractBinPath" ,String ( "tesseract" )), OPTION("showSelectionGeometry" , BoundedInt (0,5,4)), OPTION("showSelectionGeometryHideTime", LowerBoundedInt (0, 3000)) }; @@ -142,6 +143,7 @@ static QMap> recognizedShortcuts = { SHORTCUT("TYPE_SAVE" , "Ctrl+S" ), SHORTCUT("TYPE_ACCEPT" , "Return" ), SHORTCUT("TYPE_EXIT" , "Ctrl+Q" ), + SHORTCUT("TYPE_OCR" , ), SHORTCUT("TYPE_IMAGEUPLOADER" , ), #if !defined(Q_OS_MACOS) SHORTCUT("TYPE_OPEN_APP" , "Ctrl+O" ), diff --git a/src/utils/confighandler.h b/src/utils/confighandler.h index e8f4775441..ae396b69f2 100644 --- a/src/utils/confighandler.h +++ b/src/utils/confighandler.h @@ -124,6 +124,7 @@ class ConfigHandler : public QObject CONFIG_GETTER_SETTER(squareMagnifier, setSquareMagnifier, bool) CONFIG_GETTER_SETTER(copyOnDoubleClick, setCopyOnDoubleClick, bool) CONFIG_GETTER_SETTER(uploadClientSecret, setUploadClientSecret, QString) + CONFIG_GETTER_SETTER(tesseractBinPath, setTesseractBinPath, QString) CONFIG_GETTER_SETTER(saveLastRegion, setSaveLastRegion, bool) CONFIG_GETTER_SETTER(showSelectionGeometry, setShowSelectionGeometry, int) // SPECIAL CASES diff --git a/src/widgets/capture/capturetoolbutton.cpp b/src/widgets/capture/capturetoolbutton.cpp index bc51eb7272..11518f7744 100644 --- a/src/widgets/capture/capturetoolbutton.cpp +++ b/src/widgets/capture/capturetoolbutton.cpp @@ -157,6 +157,7 @@ static std::map buttonTypeOrder { CaptureTool::TYPE_SIZEINCREASE, 22 }, { CaptureTool::TYPE_SIZEDECREASE, 23 }, + { CaptureTool::TYPE_OCR, 24 }, }; int CaptureToolButton::getPriorityByButton(CaptureTool::Type b) @@ -175,7 +176,7 @@ QList CaptureToolButton::iterableButtonTypes = { CaptureTool::TYPE_MOVESELECTION, CaptureTool::TYPE_UNDO, CaptureTool::TYPE_REDO, CaptureTool::TYPE_COPY, CaptureTool::TYPE_SAVE, CaptureTool::TYPE_EXIT, - CaptureTool::TYPE_IMAGEUPLOADER, + CaptureTool::TYPE_IMAGEUPLOADER, CaptureTool::TYPE_OCR, #if !defined(Q_OS_MACOS) CaptureTool::TYPE_OPEN_APP, #endif