File indexing completed on 2024-04-28 15:39:40

0001 /************************************************************************
0002  *                                  *
0003  *  This file is part of Kooka, a scanning/OCR application using    *
0004  *  Qt <http://www.qt.io> and KDE Frameworks <http://www.kde.org>.  *
0005  *                                  *
0006  *  Copyright (C) 2000-2018 Klaas Freitag <freitag@suse.de>     *
0007  *                          Jonathan Marten <jjm@keelhaul.me.uk>    *
0008  *                                  *
0009  *  Kooka is free software; you can redistribute it and/or modify it    *
0010  *  under the terms of the GNU Library General Public License as    *
0011  *  published by the Free Software Foundation and appearing in the  *
0012  *  file COPYING included in the packaging of this file;  either    *
0013  *  version 2 of the License, or (at your option) any later version.    *
0014  *                                  *
0015  *  As a special exception, permission is given to link this program    *
0016  *  with any version of the KADMOS OCR/ICR engine (a product of     *
0017  *  reRecognition GmbH, Kreuzlingen), and distribute the resulting  *
0018  *  executable without including the source code for KADMOS in the  *
0019  *  source distribution.                        *
0020  *                                  *
0021  *  This program is distributed in the hope that it will be useful, *
0022  *  but WITHOUT ANY WARRANTY; without even the implied warranty of  *
0023  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *
0024  *  GNU General Public License for more details.            *
0025  *                                  *
0026  *  You should have received a copy of the GNU General Public       *
0027  *  License along with this program;  see the file COPYING.  If     *
0028  *  not, see <http://www.gnu.org/licenses/>.                *
0029  *                                  *
0030  ************************************************************************/
0031 
0032 #ifndef ABSTRACTOCRENGINE_H
0033 #define ABSTRACTOCRENGINE_H
0034 
0035 #include <qobject.h>
0036 #include <qtextformat.h>
0037 #include <qprocess.h>
0038 
0039 #include "scanimage.h"
0040 #include "abstractplugin.h"
0041 
0042 /**
0043   *@author Klaas Freitag
0044   */
0045 
0046 class QProcess;
0047 class KConfigSkeletonItem;
0048 class ImageFormat;
0049 class ImageCanvas;
0050 class AbstractOcrDialogue;
0051 
0052 #ifndef PLUGIN_EXPORT
0053 #define PLUGIN_EXPORT
0054 #endif
0055 
0056 // Using a QTextDocument for the OCR results, with the source image rectangle
0057 // and other OCR information held as text properties.
0058 
0059 class OcrWordData : public QTextCharFormat
0060 {
0061 public:
0062     enum DataType {
0063         Rectangle = QTextFormat::UserProperty,      // QRect
0064         Alternatives,                   // QStringList
0065         KNode                       // int - not sure what this ever did
0066     };
0067 
0068     OcrWordData() : QTextCharFormat()           {}
0069 };
0070 
0071 
0072 class PLUGIN_EXPORT AbstractOcrEngine : public AbstractPlugin
0073 {
0074     Q_OBJECT
0075 
0076 public:
0077     virtual ~AbstractOcrEngine();
0078 
0079     bool openOcrDialogue(QWidget *pnt = nullptr);
0080 
0081     /**
0082      * Sets an image canvas that displays the result image of the OCR.
0083      * If this is set to @c nullptr (or never set) no result image is displayed.
0084      * The OCR fabric passes a new image to the canvas which is a copy of
0085      * the image to OCR.
0086      */
0087     void setImageCanvas(ImageCanvas *canvas);
0088     void setTextDocument(QTextDocument *doc);
0089 
0090     /**
0091      * Specify the image to be OCRed.
0092      *
0093      * @param img The image
0094      **/
0095     void setImage(ScanImage::Ptr img);
0096 
0097     /**
0098      * Check whether the image to be OCRed is black/white (just a bitmap).
0099      *
0100      * @return @c true if the image is pure black/white
0101      **/
0102     bool isBW();
0103 
0104     QString findExecutable(QString (*settingFunc)(), KConfigSkeletonItem *settingItem);
0105 
0106     void setErrorText(const QString &msg)           { m_errorText.append(msg); }
0107 
0108     /**
0109      * Check whether the engine has advanced settings:  for example, the
0110      * pathname of an executable which performs the OCR.  The actual dialogue
0111      * will be requested by @c openAdvancedSettings().
0112      *
0113      * @return @c true if the engine has advanced settings
0114      **/
0115     virtual bool hasAdvancedSettings() const            { return (false); }
0116 
0117     /**
0118      * Open a dialogue for advanced engine settings.  This will only be
0119      * called if the engine has indicated that it has advanced settings,
0120      * by returning @c true from @c hasAdvancedSettings().
0121      **/
0122     virtual void openAdvancedSettings()             {}
0123 
0124 protected:
0125     explicit AbstractOcrEngine(QObject *pnt, const char *name);
0126 
0127     virtual AbstractOcrDialogue *createOcrDialogue(AbstractOcrEngine *plugin, QWidget *pnt) = 0;
0128 
0129     virtual QStringList tempFiles(bool retain) = 0;
0130 
0131     /**
0132      * Save an image to a temporary file.
0133      *
0134      * @param img The image to save
0135      * @param format The image format to save in
0136      * @param colors The colour depth (bits per pixel) required.  If specified,
0137      * this must be either 1, 8, 24 or 32.  The default is for no colour
0138      * conversion.
0139      *
0140      * @return The file name as saved, or @c QString() if there was
0141      *         an error.
0142      **/
0143     QString tempSaveImage(ScanImage::Ptr img, const ImageFormat &format, int colors = -1);
0144 
0145     /**
0146      * Get a name to use for a temporary file.
0147      *
0148      * @param suffix File name suffix, no leading '.' is required
0149      * @return The temporary file name, or @c QString() if the file could not be created
0150      *
0151      * @note The temporary file is created and is left in place under the returned name,
0152      * but is not opened.  Its name should be saved and eventually returned in the
0153      * @c tempFiles() list so that it will be removed.
0154      **/
0155     QString tempFileName(const QString &suffix, const QString &baseName = "ocrtemp");
0156 
0157     QTextDocument *startResultDocument();
0158     void finishResultDocument();
0159 
0160     void startLine();
0161     void addWord(const QString &word, const OcrWordData &data);
0162     void finishLine();
0163 
0164     bool verboseDebug() const;
0165 
0166     virtual bool createOcrProcess(AbstractOcrDialogue *dia, ScanImage::Ptr img) = 0;
0167 
0168     QProcess *initOcrProcess();
0169     QProcess *ocrProcess() const                { return (m_ocrProcess); }
0170     bool runOcrProcess();
0171     virtual bool finishedOcrProcess(QProcess *proc)     { Q_UNUSED(proc); return (true); }
0172 
0173     void setResultImage(const QString &file)            { m_ocrResultFile = file; }
0174 
0175 signals:
0176     void newOCRResultText();
0177     void openOcrPrefs();
0178 
0179     void setSpellCheckConfig(const QString &configFile);
0180     void startSpellCheck(bool interactive, bool background);
0181 
0182     /**
0183      * Indicates that the text editor holding the text that came through
0184      * newOCRResultText should be set to readonly or not. Can be connected
0185      * to QTextEdit::setReadOnly directly.
0186      */
0187     void readOnlyEditor(bool isReadOnly);
0188 
0189     /**
0190      * Progress of the OCR process. The first integer is the main progress,
0191      * the second the sub progress. If there is only one progress, it is the
0192      * first parameter while the second should be -1.
0193      * Both have a range from 0..100.
0194      *
0195      * Note that this signal may not be emitted if the engine does not support
0196      * progress.
0197      */
0198     void ocrProgress(int progress, int subprogress);
0199 
0200     /**
0201      * Select a word in the editor corresponding to the position within
0202      * the result image.
0203      */
0204     void selectWord(const QPoint &p);
0205 
0206 public slots:
0207     void slotHighlightWord(const QRect &r);
0208     void slotScrollToWord(const QRect &r);
0209 
0210 private slots:
0211     void slotStartOCR();
0212     void slotStopOCR();
0213     void slotClose();
0214 
0215     void slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus);
0216 
0217     /**
0218      * Handle mouse double clicks on the image viewer showing the
0219      * OCR result image.
0220      */
0221     void slotImagePosition(const QPoint &p);
0222 
0223 private:
0224     void stopOcrProcess(bool tellUser);
0225     void removeTempFiles();
0226     void finishedOcr(bool success);
0227 
0228     QString collectErrorMessages(const QString &starter, const QString &ender);
0229 
0230 private:
0231     QWidget *m_parent;
0232 
0233     QProcess *m_ocrProcess;
0234     bool m_ocrRunning;
0235     AbstractOcrDialogue *m_ocrDialog;
0236     QStringList m_errorText;
0237     QString m_ocrStderrLog;
0238 
0239     QString m_ocrResultFile;
0240     ImageCanvas *m_imgCanvas;
0241 
0242     ScanImage::Ptr m_introducedImage;
0243     bool m_resolvedBW;
0244     bool m_isBW;
0245 
0246     QTextDocument *m_document;
0247     QTextCursor *m_cursor;
0248     int m_currHighlight;
0249     bool m_trackingActive;
0250 
0251     int m_wordCount;
0252 };
0253 
0254 #endif                          // ABSTRACTOCRENGINE_H