community/spectacle: link against tesseract-ocr

This commit is contained in:
Bart Ribbers 2026-04-14 14:48:12 +02:00
parent 35134c0bdd
commit fdba3f501b
3 changed files with 652 additions and 37 deletions

View File

@ -1,35 +0,0 @@
From 0cfb57d7e37a80cfc07443a4cb8f9b1e5f8bf280 Mon Sep 17 00:00:00 2001
From: Bart Ribbers <bribbers@disroot.org>
Date: Mon, 13 Apr 2026 21:13:13 +0200
Subject: [PATCH] Revert "Fix tesseract not being found on Fedora"
This reverts commit 89538f014de81ce15f70a3e8b1125648ef5d37ef.
---
src/TesseractRuntimeLoader.cpp | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/src/TesseractRuntimeLoader.cpp b/src/TesseractRuntimeLoader.cpp
index 57276fbc..528d220a 100644
--- a/src/TesseractRuntimeLoader.cpp
+++ b/src/TesseractRuntimeLoader.cpp
@@ -50,10 +50,6 @@ bool TesseractRuntimeLoader::loadLocked()
{
const auto candidates = candidateLibraryNames();
for (const QString &candidate : candidates) {
- // From https://doc.qt.io/qt-6/qlibrary.html :
- // QLibrary tries the name with different platform-specific file prefixes,
- // like "lib" on Unix and Mac, and suffixes, like ".so" on Unix,
- // ".dylib" on the Mac, or ".dll" on Windows.
m_library.setFileName(candidate);
m_library.setLoadHints(QLibrary::ExportExternalSymbolsHint | QLibrary::PreventUnloadHint);
@@ -185,5 +181,5 @@ bool TesseractRuntimeLoader::validateLoadedVersion()
QStringList TesseractRuntimeLoader::candidateLibraryNames() const
{
- return {QStringLiteral("tesseract")};
+ return {QStringLiteral("libtesseract.so.5"), QStringLiteral("libtesseract.so.4"), QStringLiteral("libtesseract.so")};
}
--
2.53.0

View File

@ -0,0 +1,643 @@
From 2aa789096b0f81ec0f46f6f2542c33b8c3c6154b Mon Sep 17 00:00:00 2001
From: Nicolas Fella <nicolas.fella@gmx.de>
Date: Mon, 13 Apr 2026 22:00:56 +0200
Subject: [PATCH] Properly link against tesseract
Dynamically loading it at runtime only complicates things, for no apparent benefit
---
CMakeLists.txt | 3 +
src/CMakeLists.txt | 2 +-
src/OcrManager.cpp | 103 +++++++-----------
src/OcrManager.h | 9 +-
src/TesseractRuntimeLoader.cpp | 189 ---------------------------------
src/TesseractRuntimeLoader.h | 76 -------------
6 files changed, 44 insertions(+), 338 deletions(-)
delete mode 100644 src/TesseractRuntimeLoader.cpp
delete mode 100644 src/TesseractRuntimeLoader.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e79b6ab7b..cac222370 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -92,6 +92,7 @@ find_package(PlasmaWaylandProtocols REQUIRED)
find_package(LayerShellQt REQUIRED)
find_package(KPipeWire)
find_package(OpenCV 4.7 REQUIRED core imgproc)
+find_package(PkgConfig REQUIRED)
set_package_properties(KPipeWire PROPERTIES DESCRIPTION
"Used to record pipewire streams into a file"
@@ -107,6 +108,8 @@ set_package_properties(KQuickImageEditor PROPERTIES
PURPOSE "Add image editing capability to the screenshots"
)
+pkg_check_modules(TESSERACT REQUIRED IMPORTED_TARGET tesseract)
+
# optional components
find_package(KF6DocTools ${KF6_MIN_VERSION})
set_package_properties(KF6DocTools PROPERTIES DESCRIPTION
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2e9584aff..84adc11dc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -26,7 +26,6 @@ target_sources(spectacle PRIVATE
ExportManager.cpp
Geometry.cpp
OcrManager.cpp
- TesseractRuntimeLoader.cpp
Gui/CaptureWindow.cpp
Gui/ExportMenu.cpp
Gui/HelpMenu.cpp
@@ -130,6 +129,7 @@ target_link_libraries(spectacle PRIVATE
LayerShellQt::Interface
KQuickImageEditor
${OpenCV_LIBRARIES}
+ PkgConfig::TESSERACT
)
# qt_add_qml_module doesn't know how to deal with headers in subdirectories so
diff --git a/src/OcrManager.cpp b/src/OcrManager.cpp
index 6b3b9baa4..84eb7899d 100644
--- a/src/OcrManager.cpp
+++ b/src/OcrManager.cpp
@@ -31,7 +31,6 @@ OcrManager *OcrManager::s_instance = nullptr;
OcrManager::OcrManager(QObject *parent)
: QObject(parent)
, m_tesseract(nullptr)
- , m_runtimeApi(nullptr)
, m_worker(nullptr)
, m_workerThread(std::make_unique<QThread>())
, m_timeoutTimer(new QTimer(this))
@@ -83,9 +82,9 @@ OcrManager::~OcrManager()
delete m_worker;
m_worker = nullptr;
}
- if (m_runtimeApi && m_tesseract) {
- m_runtimeApi->end(m_tesseract);
- m_runtimeApi->dispose(m_tesseract);
+ if (m_tesseract) {
+ m_tesseract->End();
+ delete m_tesseract;
m_tesseract = nullptr;
}
}
@@ -100,7 +99,7 @@ OcrManager *OcrManager::instance()
bool OcrManager::isAvailable() const
{
- return m_initialized && m_tesseract != nullptr && m_runtimeApi != nullptr;
+ return m_initialized && m_tesseract != nullptr;
}
OcrManager::OcrStatus OcrManager::status() const
@@ -317,8 +316,8 @@ void OcrManager::beginRecognition(const QImage &image)
QMetaObject::invokeMethod(
m_worker,
- [worker = m_worker, image, tesseract = m_tesseract, runtimeApi = m_runtimeApi]() {
- worker->processImage(image, tesseract, runtimeApi);
+ [worker = m_worker, image, tesseract = m_tesseract]() {
+ worker->processImage(image, tesseract);
},
Qt::QueuedConnection);
}
@@ -326,43 +325,24 @@ void OcrManager::beginRecognition(const QImage &image)
void OcrManager::initializeTesseract()
{
auto cleanupTesseract = [this]() {
- if (m_runtimeApi && m_tesseract) {
- m_runtimeApi->end(m_tesseract);
- m_runtimeApi->dispose(m_tesseract);
+ if (m_tesseract) {
+ m_tesseract->End();
+ delete m_tesseract;
m_tesseract = nullptr;
}
};
- auto &loader = TesseractRuntimeLoader::instance();
- if (!loader.ensureLoaded()) {
- qCWarning(SPECTACLE_LOG) << "Tesseract runtime library not available";
- setStatus(OcrStatus::Error);
- return;
- }
-
- m_runtimeApi = loader.api();
- if (!m_runtimeApi) {
- qCWarning(SPECTACLE_LOG) << "Missing Tesseract runtime API";
- setStatus(OcrStatus::Error);
- return;
- }
-
try {
- m_tesseract = m_runtimeApi->create();
- if (!m_tesseract) {
- qCWarning(SPECTACLE_LOG) << "Failed to allocate Tesseract API";
- setStatus(OcrStatus::Error);
- return;
- }
+ m_tesseract = new TessBaseAPI;
- if (m_runtimeApi->init3(m_tesseract, nullptr, nullptr) != 0) {
+ if (m_tesseract->Init(nullptr, nullptr) != 0) {
qCWarning(SPECTACLE_LOG) << "Failed to initialize Tesseract OCR engine";
setStatus(OcrStatus::Error);
cleanupTesseract();
return;
}
- const char *datapath = m_runtimeApi->datapath(m_tesseract);
+ const char *datapath = m_tesseract->GetDatapath();
QString tessdataPath = datapath ? QString::fromUtf8(datapath) : QString();
if (tessdataPath.isEmpty()) {
qCWarning(SPECTACLE_LOG) << "Tesseract datapath is empty";
@@ -381,7 +361,7 @@ void OcrManager::initializeTesseract()
return;
}
- m_runtimeApi->end(m_tesseract);
+ m_tesseract->End();
QStringList configLanguages = Settings::ocrLanguages();
QStringList initLanguages;
@@ -411,7 +391,7 @@ void OcrManager::initializeTesseract()
const QString combinedInitLanguages = initLanguages.join(u"+"_s);
qCDebug(SPECTACLE_LOG) << "Initializing Tesseract with languages:" << combinedInitLanguages;
- if (m_runtimeApi->init3(m_tesseract, nullptr, combinedInitLanguages.toUtf8().constData()) != 0) {
+ if (m_tesseract->Init(nullptr, combinedInitLanguages.toUtf8().constData()) != 0) {
qCWarning(SPECTACLE_LOG) << "Failed to initialize Tesseract with languages:" << combinedInitLanguages;
setStatus(OcrStatus::Error);
cleanupTesseract();
@@ -419,7 +399,7 @@ void OcrManager::initializeTesseract()
}
m_currentLanguageCode = combinedInitLanguages;
- m_runtimeApi->setPageSegMode(m_tesseract, PSM_AUTO);
+ m_tesseract->SetPageSegMode(tesseract::PSM_AUTO);
m_initialized = true;
setStatus(OcrStatus::Ready);
@@ -497,11 +477,11 @@ bool OcrManager::isLanguageAvailable(const QString &languageCode) const
bool OcrManager::setupTesseractLanguages(const QStringList &langCodes)
{
- if (!m_tesseract || !m_runtimeApi || langCodes.isEmpty()) {
+ if (!m_tesseract || langCodes.isEmpty()) {
return false;
}
- const char *datapath = m_runtimeApi->datapath(m_tesseract);
+ const char *datapath = m_tesseract->GetDatapath();
QString tessdataPath = datapath ? QString::fromUtf8(datapath) : QString();
if (tessdataPath.isEmpty()) {
@@ -518,11 +498,11 @@ bool OcrManager::setupTesseractLanguages(const QStringList &langCodes)
}
try {
- m_runtimeApi->end(m_tesseract);
+ m_tesseract->End();
const QString combinedLangs = langCodes.join(u"+"_s);
- if (m_runtimeApi->init3(m_tesseract, nullptr, combinedLangs.toUtf8().constData()) != 0) {
+ if (m_tesseract->Init(nullptr, combinedLangs.toUtf8().constData()) != 0) {
// Fallback to first available language
QString fallbackLang;
if (!m_availableLanguages.isEmpty()) {
@@ -534,7 +514,7 @@ bool OcrManager::setupTesseractLanguages(const QStringList &langCodes)
}
}
- if (fallbackLang.isEmpty() || m_runtimeApi->init3(m_tesseract, nullptr, fallbackLang.toUtf8().constData()) != 0) {
+ if (fallbackLang.isEmpty() || m_tesseract->Init(nullptr, fallbackLang.toUtf8().constData()) != 0) {
qCWarning(SPECTACLE_LOG) << "Failed to initialize Tesseract with languages:" << combinedLangs << "and fallback:" << fallbackLang;
return false;
}
@@ -543,7 +523,7 @@ bool OcrManager::setupTesseractLanguages(const QStringList &langCodes)
m_currentLanguageCode = fallbackLang;
}
- m_runtimeApi->setPageSegMode(m_tesseract, PSM_AUTO);
+ m_tesseract->SetPageSegMode(tesseract::PSM_AUTO);
return true;
} catch (const std::exception &e) {
qCWarning(SPECTACLE_LOG) << "Exception while setting up Tesseract languages:" << e.what();
@@ -563,25 +543,16 @@ void OcrManager::setupAvailableLanguages(const QString &tessdataPath)
QStringList detectedLanguages;
- if (!m_runtimeApi) {
- qCWarning(SPECTACLE_LOG) << "Cannot enumerate OCR languages: Runtime API not available";
- return;
- }
-
- char **languages = m_runtimeApi->getAvailableLanguagesAsVector(m_tesseract);
- if (!languages) {
+ std::vector<std::string> languages;
+ m_tesseract->GetAvailableLanguagesAsVector(&languages);
+ if (languages.empty()) {
qCWarning(SPECTACLE_LOG) << "Tesseract API returned no languages";
return;
}
- int count = 0;
- for (char **entry = languages; *entry != nullptr; ++entry) {
- count++;
- }
-
- detectedLanguages.reserve(count);
- for (char **entry = languages; *entry != nullptr; ++entry) {
- const QString langCode = QString::fromUtf8(*entry);
+ detectedLanguages.reserve(languages.size());
+ for (const auto &entry : languages) {
+ const QString langCode = QString::fromUtf8(entry);
if (langCode.isEmpty()) {
continue;
}
@@ -599,8 +570,6 @@ void OcrManager::setupAvailableLanguages(const QString &tessdataPath)
}
}
- m_runtimeApi->deleteTextArray(languages);
-
std::sort(detectedLanguages.begin(), detectedLanguages.end());
m_availableLanguages = detectedLanguages;
@@ -678,11 +647,11 @@ OcrWorker::OcrWorker(QObject *parent)
{
}
-void OcrWorker::processImage(const QImage &image, TessBaseAPI *tesseract, const TesseractRuntimeApi *runtimeApi)
+void OcrWorker::processImage(const QImage &image, TessBaseAPI *tesseract)
{
QMutexLocker locker(&m_mutex);
- if (!tesseract || !runtimeApi || image.isNull()) {
+ if (!tesseract || image.isNull()) {
Q_EMIT imageProcessed(QString(), false);
return;
}
@@ -690,28 +659,28 @@ void OcrWorker::processImage(const QImage &image, TessBaseAPI *tesseract, const
try {
QImage rgbImage = image.convertToFormat(QImage::Format_RGB888);
- runtimeApi->setImage(tesseract, rgbImage.bits(), rgbImage.width(), rgbImage.height(), 3, rgbImage.bytesPerLine());
+ tesseract->SetImage(rgbImage.bits(), rgbImage.width(), rgbImage.height(), 3, rgbImage.bytesPerLine());
- if (runtimeApi->recognize(tesseract, nullptr) != 0) {
+ if (tesseract->Recognize(nullptr) != 0) {
Q_EMIT imageProcessed(QString(), false);
return;
}
QStringList lines;
- TessResultIterator *iterator = runtimeApi->iterator(tesseract);
+ TessResultIterator *iterator = tesseract->GetIterator();
if (iterator) {
do {
- char *lineText = runtimeApi->iteratorText(iterator, RIL_TEXTLINE);
+ char *lineText = iterator->GetUTF8Text(tesseract::RIL_TEXTLINE);
if (lineText != nullptr) {
QString line = QString::fromUtf8(lineText).trimmed();
if (!line.isEmpty()) {
lines.append(line);
}
- runtimeApi->deleteText(lineText);
+ delete lineText;
}
- } while (runtimeApi->iteratorNext(iterator, RIL_TEXTLINE) != 0);
- runtimeApi->iteratorDelete(iterator);
+ } while (iterator->Next(tesseract::RIL_TEXTLINE) != 0);
+ delete iterator;
}
const QString result = lines.join(QLatin1Char('\n')).trimmed();
diff --git a/src/OcrManager.h b/src/OcrManager.h
index 0813763a8..19eeae3c6 100644
--- a/src/OcrManager.h
+++ b/src/OcrManager.h
@@ -8,8 +8,6 @@
#include "Config.h"
-#include "TesseractRuntimeLoader.h"
-
#include <QImage>
#include <QMap>
#include <QMutex>
@@ -20,6 +18,8 @@
#include <memory>
+#include <tesseract/capi.h>
+
/**
* @brief Worker class for OCR processing in background thread
*/
@@ -31,7 +31,7 @@ public:
explicit OcrWorker(QObject *parent = nullptr);
public Q_SLOTS:
- void processImage(const QImage &image, TessBaseAPI *tesseract, const TesseractRuntimeApi *runtimeApi);
+ void processImage(const QImage &image, TessBaseAPI *tesseract);
Q_SIGNALS:
void imageProcessed(const QString &text, bool success);
@@ -153,7 +153,6 @@ private:
static OcrManager *s_instance;
TessBaseAPI *m_tesseract;
- const TesseractRuntimeApi *m_runtimeApi;
OcrWorker *m_worker;
std::unique_ptr<QThread> m_workerThread;
QTimer *m_timeoutTimer;
@@ -169,4 +168,4 @@ private:
bool m_initialized;
private:
-};
\ No newline at end of file
+};
diff --git a/src/TesseractRuntimeLoader.cpp b/src/TesseractRuntimeLoader.cpp
deleted file mode 100644
index 57276fbcc..000000000
--- a/src/TesseractRuntimeLoader.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2025 Jhair Paris <dev@jhairparis.com>
- *
- * SPDX-License-Identifier: LGPL-2.0-or-later
- */
-
-#include "TesseractRuntimeLoader.h"
-
-#include "spectacle_debug.h"
-
-#include <QMutexLocker>
-#include <type_traits>
-
-TesseractRuntimeLoader &TesseractRuntimeLoader::instance()
-{
- static TesseractRuntimeLoader s_instance;
- return s_instance;
-}
-
-TesseractRuntimeLoader::TesseractRuntimeLoader() = default;
-TesseractRuntimeLoader::~TesseractRuntimeLoader()
-{
- if (m_library.isLoaded()) {
- m_library.unload();
- }
-}
-
-bool TesseractRuntimeLoader::ensureLoaded()
-{
- QMutexLocker locker(&m_mutex);
- if (m_loaded) {
- return true;
- }
- return loadLocked();
-}
-
-bool TesseractRuntimeLoader::isLoaded() const
-{
- QMutexLocker locker(&m_mutex);
- return m_loaded;
-}
-
-const TesseractRuntimeApi *TesseractRuntimeLoader::api() const
-{
- QMutexLocker locker(&m_mutex);
- return m_loaded ? &m_api : nullptr;
-}
-
-bool TesseractRuntimeLoader::loadLocked()
-{
- const auto candidates = candidateLibraryNames();
- for (const QString &candidate : candidates) {
- // From https://doc.qt.io/qt-6/qlibrary.html :
- // QLibrary tries the name with different platform-specific file prefixes,
- // like "lib" on Unix and Mac, and suffixes, like ".so" on Unix,
- // ".dylib" on the Mac, or ".dll" on Windows.
- m_library.setFileName(candidate);
- m_library.setLoadHints(QLibrary::ExportExternalSymbolsHint | QLibrary::PreventUnloadHint);
-
- if (!m_library.load()) {
- qCWarning(SPECTACLE_LOG) << "Unable to load Tesseract candidate" << candidate << ':' << m_library.errorString();
- continue;
- }
-
- qCInfo(SPECTACLE_LOG) << "Attempting to use Tesseract library" << candidate;
-
- if (!resolveSymbols()) {
- m_library.unload();
- continue;
- }
-
- if (!validateLoadedVersion()) {
- m_library.unload();
- continue;
- }
-
- m_loaded = true;
- qCInfo(SPECTACLE_LOG) << "Loaded Tesseract runtime library from" << m_library.fileName();
- return true;
- }
-
- qCWarning(SPECTACLE_LOG) << "Unable to locate a suitable Tesseract shared library";
- return false;
-}
-
-bool TesseractRuntimeLoader::resolveSymbols()
-{
- auto resolve = [this](auto &target, const char *symbol) {
- target = reinterpret_cast<std::remove_reference_t<decltype(target)>>(m_library.resolve(symbol));
- if (!target) {
- qCWarning(SPECTACLE_LOG) << "Failed to resolve" << symbol << "from" << m_library.fileName();
- return false;
- }
- return true;
- };
-
- if (!resolve(m_api.create, "TessBaseAPICreate")) {
- return false;
- }
- if (!resolve(m_api.dispose, "TessBaseAPIDelete")) {
- return false;
- }
- if (!resolve(m_api.init3, "TessBaseAPIInit3")) {
- return false;
- }
- if (!resolve(m_api.end, "TessBaseAPIEnd")) {
- return false;
- }
- if (!resolve(m_api.setPageSegMode, "TessBaseAPISetPageSegMode")) {
- return false;
- }
- if (!resolve(m_api.datapath, "TessBaseAPIGetDatapath")) {
- return false;
- }
- if (!resolve(m_api.setImage, "TessBaseAPISetImage")) {
- return false;
- }
- if (!resolve(m_api.recognize, "TessBaseAPIRecognize")) {
- return false;
- }
- if (!resolve(m_api.iterator, "TessBaseAPIGetIterator")) {
- return false;
- }
- if (!resolve(m_api.iteratorText, "TessResultIteratorGetUTF8Text")) {
- return false;
- }
- if (!resolve(m_api.iteratorNext, "TessResultIteratorNext")) {
- return false;
- }
- if (!resolve(m_api.iteratorDelete, "TessResultIteratorDelete")) {
- return false;
- }
- if (!resolve(m_api.deleteText, "TessDeleteText")) {
- return false;
- }
- if (!resolve(m_api.version, "TessVersion")) {
- return false;
- }
- if (!resolve(m_api.getAvailableLanguagesAsVector, "TessBaseAPIGetAvailableLanguagesAsVector")) {
- return false;
- }
- if (!resolve(m_api.deleteTextArray, "TessDeleteTextArray")) {
- return false;
- }
-
- return true;
-}
-
-bool TesseractRuntimeLoader::validateLoadedVersion()
-{
- constexpr int kMinSupportedMajor = 4;
- constexpr int kMaxSupportedMajor = 5;
-
- if (!m_api.version) {
- qCWarning(SPECTACLE_LOG) << "Tesseract runtime missing TessVersion symbol";
- return false;
- }
-
- const char *versionPtr = m_api.version();
- const QString versionString = versionPtr ? QString::fromLatin1(versionPtr) : QString();
-
- if (versionString.isEmpty()) {
- qCWarning(SPECTACLE_LOG) << "Unable to determine Tesseract runtime version";
- return false;
- }
-
- const QString majorComponent = versionString.section(QLatin1Char('.'), 0, 0);
- bool ok = false;
- const int majorVersion = majorComponent.toInt(&ok);
-
- if (!ok) {
- qCWarning(SPECTACLE_LOG) << "Failed to parse Tesseract version" << versionString;
- return false;
- }
-
- if (majorVersion < kMinSupportedMajor || majorVersion > kMaxSupportedMajor) {
- qCWarning(SPECTACLE_LOG) << "Unsupported Tesseract version" << versionString << "(supported major versions" << kMinSupportedMajor << "-"
- << kMaxSupportedMajor << ')';
- return false;
- }
-
- qCInfo(SPECTACLE_LOG) << "Detected Tesseract version" << versionString;
- return true;
-}
-
-QStringList TesseractRuntimeLoader::candidateLibraryNames() const
-{
- return {QStringLiteral("tesseract")};
-}
diff --git a/src/TesseractRuntimeLoader.h b/src/TesseractRuntimeLoader.h
deleted file mode 100644
index 5a86bf0ec..000000000
--- a/src/TesseractRuntimeLoader.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2025 Jhair Paris <dev@jhairparis.com>
- *
- * SPDX-License-Identifier: LGPL-2.0-or-later
- */
-
-#pragma once
-
-#include "Config.h"
-#include "TesseractCompatibility.h"
-
-#include <QLibrary>
-#include <QMutex>
-#include <QStringList>
-
-struct TesseractRuntimeApi {
- using CreateFunc = TessBaseAPI *(*)();
- using DeleteFunc = void (*)(TessBaseAPI *);
- using Init3Func = int (*)(TessBaseAPI *, const char *, const char *);
- using EndFunc = void (*)(TessBaseAPI *);
- using SetPageSegModeFunc = void (*)(TessBaseAPI *, TessPageSegMode);
- using GetDatapathFunc = const char *(*)(TessBaseAPI *);
- using SetImageFunc = void (*)(TessBaseAPI *, const unsigned char *, int, int, int, int);
- using RecognizeFunc = int (*)(TessBaseAPI *, ETEXT_DESC *);
- using GetIteratorFunc = TessResultIterator *(*)(TessBaseAPI *);
- using ResultGetUTF8TextFunc = char *(*)(const TessResultIterator *, TessPageIteratorLevel);
- using ResultNextFunc = int (*)(TessResultIterator *, TessPageIteratorLevel);
- using ResultDeleteFunc = void (*)(TessResultIterator *);
- using DeleteTextFunc = void (*)(char *);
- using DeleteTextArrayFunc = void (*)(char **);
- using VersionFunc = const char *(*)();
- using GetAvailableLanguagesAsVectorFunc = char **(*)(const TessBaseAPI *);
-
- CreateFunc create = nullptr;
- DeleteFunc dispose = nullptr;
- Init3Func init3 = nullptr;
- EndFunc end = nullptr;
- SetPageSegModeFunc setPageSegMode = nullptr;
- GetDatapathFunc datapath = nullptr;
- SetImageFunc setImage = nullptr;
- RecognizeFunc recognize = nullptr;
- GetIteratorFunc iterator = nullptr;
- ResultGetUTF8TextFunc iteratorText = nullptr;
- ResultNextFunc iteratorNext = nullptr;
- ResultDeleteFunc iteratorDelete = nullptr;
- DeleteTextFunc deleteText = nullptr;
- DeleteTextArrayFunc deleteTextArray = nullptr;
- VersionFunc version = nullptr;
- GetAvailableLanguagesAsVectorFunc getAvailableLanguagesAsVector = nullptr;
-};
-
-class TesseractRuntimeLoader
-{
-public:
- static TesseractRuntimeLoader &instance();
-
- bool ensureLoaded();
- bool isLoaded() const;
- const TesseractRuntimeApi *api() const;
-
-private:
- TesseractRuntimeLoader();
- ~TesseractRuntimeLoader();
-
- bool loadLocked();
- bool resolveSymbols();
- bool validateLoadedVersion();
- QStringList candidateLibraryNames() const;
-
- Q_DISABLE_COPY_MOVE(TesseractRuntimeLoader)
-
- mutable QMutex m_mutex;
- bool m_loaded = false;
- QLibrary m_library;
- TesseractRuntimeApi m_api;
-};
--
GitLab

View File

@ -3,13 +3,17 @@
maintainer="team/kde <bribbers@disroot.org>"
pkgname=spectacle
pkgver=6.6.4
pkgrel=1
pkgrel=2
pkgdesc="Application for capturing desktop screenshots"
# armhf blocked by qt6-qtdeclarative
# s390x blocked by opencv
arch="all !armhf !s390x"
# x86 blocked by tesseract-ocr
arch="all !armhf !s390x !x86"
url="https://kde.org/applications/utilities/org.kde.spectacle"
license="GPL-2.0-only"
# Users might want other languages but tesseract needs at least one to function at all
# English seems like a sane default
depends="tesseract-ocr-data-eng"
makedepends="
extra-cmake-modules
kconfig-dev
@ -36,6 +40,7 @@ makedepends="
qt6-qtbase-dev
qt6-qtdeclarative-private-dev
samurai
tesseract-ocr-dev
xcb-util-cursor-dev
xcb-util-image-dev
xcb-util-renderutil-dev
@ -60,6 +65,7 @@ case "$pkgver" in
esac
source="https://download.kde.org/$_rel/plasma/$_pkgver/spectacle-$pkgver.tar.xz
0001-spectacle-Properly-link-against-tesseract.patch
spectacle.desktop
"
@ -82,5 +88,6 @@ package() {
}
sha512sums="
98477f46745f9e42954a422575a78d4e1f5e7ed645c33b939e0d8285b1ab5569cb906c29aa012b676949d61731faec805e8608f0b378e435dae487c8e6159f16 spectacle-6.6.4.tar.xz
9865c6fe52b6472493f6b7d17bc34bfff95170fed1add7bf74f20b05f770c5cb2cf2a80e8f13c39d43041c959b297a08150de4a481162bd5dd6e962a54423f57 0001-spectacle-Properly-link-against-tesseract.patch
7c563d811f30d26f83e01a465e803b95167c5b2b842315257216ab282e07c69e7582a14d7f429cd19678199179ad8f3f2854265092f5a4c9ce9b65c87ed3849d spectacle.desktop
"