diff --git a/CMakeLists.txt b/CMakeLists.txt index f11c3a12..74d45ef6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ SET(ENV{LC_ALL} "C") # Project properties PROJECT(gimagereader C CXX) SET(PACKAGE_NAME gImageReader) +SET(PACKAGE_DESCRIPTION "A GTK/Qt frontend to tesseract OCR") SET(PACKAGE_VERSION 3.4.3) SET(PACKAGE_LOCALE_DIR "${CMAKE_INSTALL_PREFIX}/share/locale") @@ -44,6 +45,7 @@ ENDFOREACH() # Definitions ADD_DEFINITIONS(-DPACKAGE_NAME=\"${PACKAGE_NAME}\") +ADD_DEFINITIONS(-DPACKAGE_DESCRIPTION=\"${PACKAGE_DESCRIPTION}\") ADD_DEFINITIONS(-DPACKAGE_VERSION=\"${PACKAGE_VERSION}\") ADD_DEFINITIONS(-DPACKAGE_REVISION=\"${PACKAGE_REVISION}\") ADD_DEFINITIONS(-DGETTEXT_PACKAGE=\"${CMAKE_PROJECT_NAME}\") @@ -61,12 +63,12 @@ PKG_CHECK_MODULES(ddjvuapi REQUIRED ddjvuapi) PKG_CHECK_MODULES(PODOFO libpodofo) IF(NOT TESSERACT_FOUND) MESSAGE(WARNING "Using hardcoded cflags and ldflags for tesseract") - SET(TESSERACT_INCLUDE_DIRS /usr/include/tesseract) + SET(TESSERACT_INCLUDE_DIRS /var/empty/include/tesseract) SET(TESSERACT_LDFLAGS -ltesseract) ENDIF(NOT TESSERACT_FOUND) IF(NOT PODOFO_FOUND) MESSAGE(WARNING "Using hardcoded cflags and ldflags for podofo") - SET(PODOFO_INCLUDE_DIRS /usr/include/) + SET(PODOFO_INCLUDE_DIRS /var/empty/include/) SET(PODOFO_LDFLAGS -lpodofo) ENDIF(NOT PODOFO_FOUND) IF(UNIX) diff --git a/gtk/src/MainWindow.cc b/gtk/src/MainWindow.cc index f0ea86ee..c04ab0e6 100644 --- a/gtk/src/MainWindow.cc +++ b/gtk/src/MainWindow.cc @@ -223,7 +223,10 @@ void MainWindow::openFiles(const std::vector> & files) std::vector> otherFiles; for (const Glib::RefPtr& file : files) { std::string filename = file->get_path(); - if (Glib::ustring(filename.substr(filename.length() - 5)).lowercase() == ".html") { + if ( + Glib::ustring(filename.substr(filename.length() - 5)).lowercase() == ".html" || + Glib::ustring(filename.substr(filename.length() - 5)).lowercase() == ".hocr" + ) { hocrFiles.push_back(file); } else { otherFiles.push_back(file); @@ -243,7 +246,10 @@ void MainWindow::openOutput(const std::string& filename) { if (setOutputMode(OutputModeText)) { m_outputEditor->open(filename); } - } else if (Utils::string_endswith(Glib::ustring(filename).lowercase(), ".html")) { + } else if ( + Utils::string_endswith(Glib::ustring(filename).lowercase(), ".html") || + Utils::string_endswith(Glib::ustring(filename).lowercase(), ".hocr") + ) { if (setOutputMode(OutputModeHOCR)) { m_outputEditor->open(filename); } diff --git a/gtk/src/SourceManager.cc b/gtk/src/SourceManager.cc index 4c0b7224..696f97a3 100644 --- a/gtk/src/SourceManager.cc +++ b/gtk/src/SourceManager.cc @@ -151,7 +151,11 @@ int SourceManager::addSources(const std::vector> & file m_watchedDirectories[dir].first += 1; } std::string base = Utils::split_filename(filename).first; - if (Glib::file_test(base + ".txt", Glib::FILE_TEST_EXISTS) || Glib::file_test(base + ".html", Glib::FILE_TEST_EXISTS)) { + if ( + Glib::file_test(base + ".txt", Glib::FILE_TEST_EXISTS) || + Glib::file_test(base + ".html", Glib::FILE_TEST_EXISTS) || + Glib::file_test(base + ".hocr", Glib::FILE_TEST_EXISTS) + ) { m_fileTreeModel->setFileEditable(index, true); } selectIters.push_back(index); @@ -437,6 +441,8 @@ void SourceManager::indexClicked(const Gtk::TreePath& path, Gtk::TreeViewColumn* std::string base = Utils::split_filename(source->file->get_path()).first; bool hasTxt = Glib::file_test(base + ".txt", Glib::FILE_TEST_EXISTS); bool hasHtml = Glib::file_test(base + ".html", Glib::FILE_TEST_EXISTS); + bool hasHocr = Glib::file_test(base + ".hocr", Glib::FILE_TEST_EXISTS); + // FIXME handle all cases... if (hasTxt && hasHtml) { Utils::Button::Type response = Utils::messageBox(Gtk::MESSAGE_QUESTION, _("Open output"), _("Both a text and a hOCR output were found. Which one do you want to open?"), "", Utils::Button::Text | Utils::Button::HOCR | Utils::Button::Cancel); if (response == Utils::Button::Text) { @@ -448,6 +454,8 @@ void SourceManager::indexClicked(const Gtk::TreePath& path, Gtk::TreeViewColumn* MAIN->openOutput(base + ".txt"); } else if (hasHtml) { MAIN->openOutput(base + ".html"); + } else if (hasHocr) { + MAIN->openOutput(base + ".hocr"); } } } @@ -517,7 +525,11 @@ void SourceManager::fileChanged(const Glib::RefPtr& file, const Glib: m_watchedDirectories[dir].first += 1; } std::string base = Utils::split_filename(otherFile->get_path()).first; - m_fileTreeModel->setFileEditable(it, Glib::file_test(base + ".txt", Glib::FILE_TEST_EXISTS) || Glib::file_test(base + ".html", Glib::FILE_TEST_EXISTS)); + m_fileTreeModel->setFileEditable(it, ( + Glib::file_test(base + ".txt", Glib::FILE_TEST_EXISTS) || + Glib::file_test(base + ".html", Glib::FILE_TEST_EXISTS || + Glib::file_test(base + ".hocr", Glib::FILE_TEST_EXISTS + ))); } else if (event == Gio::FILE_MONITOR_EVENT_DELETED) { Utils::messageBox(Gtk::MESSAGE_ERROR, _("Missing File"), Glib::ustring::compose(_("The following file has been deleted or moved:\n%1"), file->get_path())); m_fileTreeModel->removeIndex(it); @@ -544,7 +556,11 @@ void SourceManager::dirChanged(const Glib::RefPtr& file, const Glib:: Source* source = m_fileTreeModel->fileData (child); if (source) { std::string base = Utils::split_filename(source->file->get_path()).first; - m_fileTreeModel->setFileEditable(child, Glib::file_test(base + ".txt", Glib::FILE_TEST_EXISTS) || Glib::file_test(base + ".html", Glib::FILE_TEST_EXISTS)); + m_fileTreeModel->setFileEditable(child, ( + Glib::file_test(base + ".txt", Glib::FILE_TEST_EXISTS) || + Glib::file_test(base + ".html", Glib::FILE_TEST_EXISTS) || + Glib::file_test(base + ".hocr", Glib::FILE_TEST_EXISTS) + )); } } } diff --git a/gtk/src/hocr/HOCRBatchExportDialog.cc b/gtk/src/hocr/HOCRBatchExportDialog.cc index fc84a868..42cf9b51 100644 --- a/gtk/src/hocr/HOCRBatchExportDialog.cc +++ b/gtk/src/hocr/HOCRBatchExportDialog.cc @@ -125,7 +125,10 @@ void HOCRBatchExportDialog::scanSourceDir(const std::string& dir, std::vector file = it->next_file()) { if (file->get_file_type() == Gio::FILE_TYPE_DIRECTORY) { scanSourceDir(Glib::build_filename(dir, file->get_name()), files); - } else if (Utils::string_endswith(file->get_name(), ".html")) { + } else if ( + Utils::string_endswith(file->get_name(), ".html") || + Utils::string_endswith(file->get_name(), ".hocr") + ) { files.push_back(Glib::build_filename(dir, file->get_name())); } } diff --git a/gtk/src/hocr/OutputEditorHOCR.cc b/gtk/src/hocr/OutputEditorHOCR.cc index 73636de5..3df88675 100644 --- a/gtk/src/hocr/OutputEditorHOCR.cc +++ b/gtk/src/hocr/OutputEditorHOCR.cc @@ -1017,7 +1017,7 @@ bool OutputEditorHOCR::open(InsertMode mode, std::vectoropen(filename); } - } else if (filename.endsWith(".html", Qt::CaseInsensitive)) { + } else if ( + filename.endsWith(".html", Qt::CaseInsensitive) || + filename.endsWith(".hocr", Qt::CaseInsensitive) + ) { if (setOutputMode(OutputModeHOCR)) { m_outputEditor->open(filename); } diff --git a/qt/src/SourceManager.cc b/qt/src/SourceManager.cc index aa576bb5..f5d6b13f 100644 --- a/qt/src/SourceManager.cc +++ b/qt/src/SourceManager.cc @@ -134,7 +134,11 @@ int SourceManager::addSources(const QStringList& files, bool suppressWarnings) { if (m_watchedDirectories[finfo.absolutePath()] == 1) { m_fsWatcher.addPath(finfo.absolutePath()); } - if (QFile(base + ".txt").exists() || QFile(base + ".html").exists()) { + if ( + QFile(base + ".txt").exists() || + QFile(base + ".html").exists() || + QFile(base + ".hocr").exists() + ) { m_fileTreeModel->setFileEditable(index, true); } sel.select(index, index); @@ -473,17 +477,22 @@ void SourceManager::indexClicked(const QModelIndex& index) { QString base = finfo.absoluteDir().absoluteFilePath(finfo.baseName()); bool hasTxt = QFile(base + ".txt").exists(); bool hasHtml = QFile(base + ".html").exists(); + bool hasHocr = QFile(base + ".hocr").exists(); + // FIXME handle all cases... if (hasTxt && hasHtml) { QMessageBox box(QMessageBox::Question, _("Open output"), _("Both a text and a hOCR output were found. Which one do you want to open?"), QMessageBox::Cancel); QAbstractButton* textButton = box.addButton(_("Text"), QMessageBox::AcceptRole); QAbstractButton* hocrButton = box.addButton(_("hOCR"), QMessageBox::AcceptRole); connect(textButton, &QAbstractButton::clicked, this, [base] { MAIN->openOutput(base + ".txt"); }); + // TODO use .hocr by default? connect(hocrButton, &QAbstractButton::clicked, this, [base] { MAIN->openOutput(base + ".html"); }); box.exec(); } else if (hasTxt) { MAIN->openOutput(base + ".txt"); } else if (hasHtml) { MAIN->openOutput(base + ".html"); + } else if (hasHocr) { + MAIN->openOutput(base + ".hocr"); } } } @@ -519,7 +528,11 @@ void SourceManager::directoryChanged(const QString& dir) { if (source) { QFileInfo finfo(source->path); QString base = finfo.absoluteDir().absoluteFilePath(finfo.baseName()); - m_fileTreeModel->setFileEditable(child, QFile(base + ".txt").exists() || QFile(base + ".html").exists()); + m_fileTreeModel->setFileEditable(child, ( + QFile(base + ".txt").exists() || + QFile(base + ".html").exists() || + QFile(base + ".hocr").exists() + )); } } } diff --git a/qt/src/hocr/OutputEditorHOCR.cc b/qt/src/hocr/OutputEditorHOCR.cc index 65965a79..91dc880b 100644 --- a/qt/src/hocr/OutputEditorHOCR.cc +++ b/qt/src/hocr/OutputEditorHOCR.cc @@ -920,7 +920,7 @@ bool OutputEditorHOCR::open(InsertMode mode, QStringList files) { return false; } if (files.isEmpty()) { - files = FileDialogs::openDialog(_("Open hOCR File"), "", "outputdir", QString("%1 (*.html)").arg(_("hOCR HTML Files")), true); + files = FileDialogs::openDialog(_("Open hOCR File"), "", "outputdir", QString("%1 (*.html *.hocr)").arg(_("hOCR HTML Files")), true); } if (files.isEmpty()) { return false; @@ -996,6 +996,7 @@ bool OutputEditorHOCR::save(const QString& filename) { suggestion = _("output"); } } + // TODO use .hocr by default? outname = FileDialogs::saveDialog(_("Save hOCR Output..."), suggestion + ".html", "outputdir", QString("%1 (*.html)").arg(_("hOCR HTML Files"))); if (outname.isEmpty()) { return false; @@ -1031,6 +1032,7 @@ bool OutputEditorHOCR::save(const QString& filename) { } QString OutputEditorHOCR::crashSave(const QString& filename) const { + // TODO use .hocr by default? QFile file(filename + ".html"); if (file.open(QIODevice::WriteOnly)) { QString header = QString( @@ -1046,6 +1048,7 @@ QString OutputEditorHOCR::crashSave(const QString& filename) const { file.write(m_document->toHTML().toUtf8()); m_document->convertSourcePaths(QFileInfo(filename).absolutePath(), true); file.write("\n"); + // TODO use .hocr by default? return filename + ".html"; } return ""; diff --git a/qt/src/hocr/OutputEditorHOCR.hh b/qt/src/hocr/OutputEditorHOCR.hh index 61956381..f68d810e 100644 --- a/qt/src/hocr/OutputEditorHOCR.hh +++ b/qt/src/hocr/OutputEditorHOCR.hh @@ -37,6 +37,7 @@ class OutputEditorHOCR : public OutputEditor { public: class HOCRBatchProcessor : public BatchProcessor { public: + // TODO use .hocr by default? QString fileSuffix() const override { return QString(".html"); } void writeHeader(QIODevice* dev, tesseract::TessBaseAPI* tess, const PageInfo& pageInfo) const override; void writeFooter(QIODevice* dev) const override; diff --git a/qt/src/main.cc b/qt/src/main.cc index 9908fd9f..0bb345f5 100644 --- a/qt/src/main.cc +++ b/qt/src/main.cc @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,8 @@ int main(int argc, char* argv[]) { QApplication::setOrganizationName(PACKAGE_NAME); QApplication::setApplicationName(PACKAGE_NAME); + QApplication::setApplicationVersion(QString("%1 (%2)").arg(PACKAGE_VERSION, QString(PACKAGE_REVISION).left(6))); + QIcon::setFallbackSearchPaths(QIcon::fallbackSearchPaths() << ":/extra-theme-icons"); #ifdef Q_OS_WIN @@ -89,12 +92,37 @@ int main(int argc, char* argv[]) { qputenv("TWAINDSM_LOG", packageDir.absoluteFilePath("twain.log").toLocal8Bit()); std::freopen(packageDir.absoluteFilePath("gimagereader.log").toLocal8Bit().data(), "w", stderr); #endif + + QCommandLineParser parser; + parser.setApplicationDescription(PACKAGE_DESCRIPTION); + parser.addHelpOption(); + parser.addVersionOption(); + + parser.addPositionalArgument( + "files", + QCoreApplication::translate( + "main", + "Files to open, optionally." + " These can be image files or hocr files." + " Every image file is seen as one page." + // TODO verify: these image paths are relative to the hocr dirname + " Hocr files can reference image files for pages or graphics." + ), + "[files...]" + ); + parser.process(app); + QStringList files; - for (int i = 1; i < argc; ++i) { - if (QFile(argv[i]).exists()) { - files.append(argv[i]); + for (const QString arg : parser.positionalArguments()) { + if (QFile(arg).exists()) { + qDebug("adding file: %s", arg.toUtf8().data()); + files.append(arg); + } + else { + qInfo("ignoring non-file argument: %s", arg.toUtf8().data()); } } + window = new MainWindow(files); } window->show();