1 /* ============================================================ 2 * 3 * This file is a part of digiKam project 4 * https://www.digikam.org 5 * 6 * Date : 2005-05-25 7 * Description : threaded image filter class. 8 * 9 * Copyright (C) 2005-2021 by Gilles Caulier <caulier dot gilles at gmail dot com> 10 * Copyright (C) 2007-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 11 * 12 * This program is free software; you can redistribute it 13 * and/or modify it under the terms of the GNU General 14 * Public License as published by the Free Software Foundation; 15 * either version 2, or (at your option) 16 * any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * ============================================================ */ 24 25 #ifndef DIGIKAM_DIMG_THREADED_FILTER_H 26 #define DIGIKAM_DIMG_THREADED_FILTER_H 27 28 // Local includes 29 30 #include "digikam_export.h" 31 #include "dimg.h" 32 #include "dynamicthread.h" 33 #include "filteraction.h" 34 35 class QObject; 36 37 namespace Digikam 38 { 39 40 class DIGIKAM_EXPORT DImgThreadedFilter : public DynamicThread 41 { 42 Q_OBJECT 43 44 public: 45 46 /** 47 * Constructs a filter without argument. 48 * You need to call setupFilter() and startFilter() 49 * to start the threaded computation. 50 * To run filter without to use multithreading, call startFilterDirectly(). 51 */ 52 explicit DImgThreadedFilter(QObject* const parent = nullptr, const QString& name = QString()); 53 54 /** 55 * Constructs a filter with all arguments (ready to use). 56 * The given original image will be copied. 57 * You need to call startFilter() to start the threaded computation. 58 * To run filter without to use multithreading, call startFilterDirectly(). 59 */ 60 DImgThreadedFilter(DImg* const orgImage, 61 QObject* const parent, 62 const QString& name = QString()); 63 64 ~DImgThreadedFilter() override; 65 66 /** 67 * You need to call this and then start filter of you used 68 * the constructor not setting an original image. 69 * The original image's data will not be copied. 70 */ 71 void setupFilter(const DImg& orgImage); 72 73 /** 74 * Initializes the filter for use as a slave and directly starts computation (in-thread) 75 */ 76 void setupAndStartDirectly(const DImg& orgImage, 77 DImgThreadedFilter* const master, 78 int progressBegin = 0, 79 int progressEnd = 100); 80 81 void setOriginalImage(const DImg& orgImage); 82 void setFilterName(const QString& name); 83 getTargetImage()84 DImg getTargetImage() 85 { 86 return m_destImage; 87 }; 88 filterName()89 const QString& filterName() 90 { 91 return m_name; 92 }; 93 94 /** 95 * This method return a list of steps to process parallelized operation in filter using QtConcurrents API. 96 * Usually, start and stop are rows or columns from image to process. By default, whole image will be processed 97 * and start value is 0. In this case stop will be last row or column to process. 98 * Between range [start,stop], this method will divide by equal steps depending of number of CPU cores available. 99 * To be sure that all values will be processed, in case of CPU core division give rest, the last step compensate 100 * the difference. 101 * See Blur filter loop implementation for example to see how to use this method with QtConcurrents API. 102 */ 103 QList<int> multithreadedSteps(int stop, int start = 0) const; 104 105 /** 106 * Start the threaded computation. 107 */ 108 virtual void startFilter(); 109 110 /** 111 * Cancel the threaded computation. 112 */ 113 virtual void cancelFilter(); 114 115 /** 116 * Start computation of this filter, directly in this thread. 117 */ 118 virtual void startFilterDirectly(); 119 120 /** 121 * Returns the action description corresponding to currently set options. 122 */ 123 virtual FilterAction filterAction() = 0; 124 125 virtual void readParameters(const FilterAction&) = 0; 126 127 /** 128 * Return the identifier for this filter in the image history. 129 */ 130 virtual QString filterIdentifier() const = 0; 131 132 virtual QList<int> supportedVersions() const; 133 134 /** 135 * Replaying a filter action: 136 * Set the filter version. A filter may implement different versions, to preserve 137 * image history when the algorithm is changed. 138 * Any value set here must be contained in supportedVersions, otherwise 139 * this call will be ignored. Default value is 1. 140 * (Note: If you intend to _record_ a filter action, please look at FilterAction's m_version) 141 */ 142 void setFilterVersion(int version); 143 int filterVersion() const; 144 145 /** 146 * Optional: error handling for readParameters. 147 * When readParameters() has been called, this method will return true 148 * if the call was successful, and false if not. 149 * If returning false, readParametersError() will give an error message. 150 * The default implementation always returns success. You only need to reimplement 151 * when a filter is likely to fail in a different environment, e.g. 152 * depending on availability of installed files. 153 * These methods have an undefined return value if readParameters() was not called 154 * previously. 155 */ 156 virtual bool parametersSuccessfullyRead() const; 157 virtual QString readParametersError(const FilterAction& actionThatFailed) const; 158 159 Q_SIGNALS: 160 161 /** 162 * This signal is emitted when image data is available and the computation has started. 163 */ 164 void started(); 165 166 /** 167 * Emitted when progress info from the calculation is available. 168 */ 169 void progress(int progress); 170 171 /** 172 * Emitted when the computation has completed. 173 * @param success True if computation finished without interruption on valid data 174 * False if the thread was canceled, or no data is available. 175 */ 176 void finished(bool success); 177 178 protected: 179 180 /** 181 * Start filter operation before threaded method. Must be called by your constructor. 182 */ 183 virtual void initFilter(); 184 185 /** 186 * List of threaded operations by filter. 187 */ 188 void run() override; 189 190 /** 191 * Main image filter method. Override in subclass. 192 */ 193 virtual void filterImage() = 0; 194 195 /** 196 * Clean up filter data if necessary, called by stopComputation() method. 197 * Override in subclass. 198 */ cleanupFilter()199 virtual void cleanupFilter() {}; 200 201 /** 202 * Emit progress info. 203 */ 204 void postProgress(int progress); 205 206 protected: 207 208 /** 209 * Support for chaining two filters as master and thread. 210 * 211 * Do not call startFilter() or startFilterDirectly() on this. 212 * The computation will be started from initFilter() which you must 213 * call from the derived class constructor. 214 * 215 * Constructor for slave mode: 216 * Constructs a new slave filter with the specified master. 217 * The filter will be executed in the current thread. 218 * orgImage and destImage will not be copied. 219 * Note that the slave is still free to reallocate his destImage. 220 * progressBegin and progressEnd can indicate the progress span 221 * that the slave filter uses in the parent filter's progress. 222 * Any derived filter class that is publicly available to other filters 223 * should implement an additional constructor using this constructor. 224 */ 225 DImgThreadedFilter(DImgThreadedFilter* const master, 226 const DImg& orgImage, 227 const DImg& destImage, 228 int progressBegin = 0, 229 int progressEnd = 100, 230 const QString& name = QString()); 231 232 /** 233 * Initialize the filter for use as a slave - reroutes progress info to master. 234 * Note: Computation will be started from setupFilter(). 235 */ 236 void initSlave(DImgThreadedFilter* const master, 237 int progressBegin = 0, 238 int progressEnd = 100); 239 240 /** 241 * Inform the master that there is currently a slave. At destruction of the slave, call with slave=0. 242 */ 243 void setSlave(DImgThreadedFilter* const slave); 244 245 /** 246 * This method modulates the progress value from the 0..100 span to the span of this slave. 247 * Called by postProgress if master is not null. 248 */ 249 virtual int modulateProgress(int progress); 250 251 void initMaster(); 252 virtual void prepareDestImage(); 253 254 /** 255 * Convenience class to spare the few repeating lines of code 256 */ 257 template <class Filter> 258 259 class DefaultFilterAction : public FilterAction 260 { 261 public: 262 263 explicit DefaultFilterAction(FilterAction::Category category = FilterAction::ReproducibleFilter) FilterAction(Filter::FilterIdentifier (),Filter::CurrentVersion (),category)264 : FilterAction(Filter::FilterIdentifier(), Filter::CurrentVersion(), category) 265 { 266 setDisplayableName(Filter::DisplayableName()); 267 } 268 DefaultFilterAction(bool isReproducible)269 explicit DefaultFilterAction(bool isReproducible) 270 : FilterAction(Filter::FilterIdentifier(), Filter::CurrentVersion(), 271 isReproducible ? FilterAction::ReproducibleFilter : FilterAction::ComplexFilter) 272 { 273 setDisplayableName(Filter::DisplayableName()); 274 } 275 276 /** 277 * Preserve backwards compatibility: 278 * If a given condition (some new feature is not used) is true, 279 * decrease the version so that older digikam versions can still replay the action 280 */ supportOlderVersionIf(int version,bool condition)281 void supportOlderVersionIf(int version, bool condition) 282 { 283 if (condition && (version <= m_version)) 284 { 285 m_version = version; 286 } 287 } 288 289 }; 290 291 protected: 292 293 int m_version; 294 295 bool m_wasCancelled; 296 297 /** 298 * The progress span that a slave filter uses in the parent filter's progress. 299 */ 300 int m_progressBegin; 301 int m_progressSpan; 302 int m_progressCurrent; ///< To prevent signals bombarding with progress indicator value in postProgress(). 303 304 /** 305 * Filter name. 306 */ 307 QString m_name; 308 309 /** 310 * Copy of original Image data. 311 */ 312 DImg m_orgImage; 313 314 /** 315 * Output image data. 316 */ 317 DImg m_destImage; 318 319 /** 320 * The current slave. Any filter might want to use another filter while processing. 321 */ 322 DImgThreadedFilter* m_slave; 323 324 /** 325 * The master of this slave filter. Progress info will be routed to this one. 326 */ 327 DImgThreadedFilter* m_master; 328 }; 329 330 } // namespace Digikam 331 332 #endif // DIGIKAM_DIMG_THREADED_FILTER_H 333