1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2010-11-10
7  * Description : meta-filter to apply FilterAction
8  *
9  * Copyright (C) 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10  * Copyright (C) 2010      by Martin Klapetek <martin dot klapetek at gmail dot com>
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 #include "filteractionfilter.h"
26 
27 // Qt includes
28 
29 #include <QScopedPointer>
30 
31 // KDE includes
32 
33 #include <klocalizedstring.h>
34 
35 // Local includes
36 
37 #include "digikam_debug.h"
38 #include "digikam_export.h"
39 #include "dimgbuiltinfilter.h"
40 #include "dimgfiltermanager.h"
41 #include "filteraction.h"
42 
43 namespace Digikam
44 {
45 
46 class Q_DECL_HIDDEN FilterActionFilter::Private
47 {
48 public:
49 
Private()50     explicit Private()
51       : continueOnError(false)
52     {
53     }
54 
55     bool                continueOnError;
56 
57     QList<FilterAction> actions;
58     QList<FilterAction> appliedActions;
59 
60     QString             errorMessage;
61 };
62 
FilterActionFilter(QObject * const parent)63 FilterActionFilter::FilterActionFilter(QObject* const parent)
64     : DImgThreadedFilter(parent),
65       d(new Private)
66 {
67     initFilter();
68 }
69 
~FilterActionFilter()70 FilterActionFilter::~FilterActionFilter()
71 {
72     delete d;
73 }
74 
setContinueOnError(bool cont)75 void FilterActionFilter::setContinueOnError(bool cont)
76 {
77     d->continueOnError = cont;
78 }
79 
setFilterActions(const QList<FilterAction> & actions)80 void FilterActionFilter::setFilterActions(const QList<FilterAction>& actions)
81 {
82     d->actions = actions;
83 }
84 
addFilterActions(const QList<FilterAction> & actions)85 void FilterActionFilter::addFilterActions(const QList<FilterAction>& actions)
86 {
87     d->actions += actions;
88 }
89 
setFilterAction(const FilterAction & action)90 void FilterActionFilter::setFilterAction(const FilterAction& action)
91 {
92     d->actions.clear();
93     d->actions << action;
94 }
95 
addFilterAction(const FilterAction & action)96 void FilterActionFilter::addFilterAction(const FilterAction& action)
97 {
98     d->actions << action;
99 }
100 
filterActions() const101 QList<FilterAction> FilterActionFilter::filterActions() const
102 {
103     return d->actions;
104 }
105 
isReproducible() const106 bool FilterActionFilter::isReproducible() const
107 {
108     foreach (const FilterAction& action, d->actions)
109     {
110         if (!action.isNull() &&
111             (action.category() != FilterAction::ReproducibleFilter))
112         {
113             return false;
114         }
115     }
116 
117     return true;
118 }
119 
isComplexAction() const120 bool FilterActionFilter::isComplexAction() const
121 {
122     foreach (const FilterAction& action, d->actions)
123     {
124         if (!action.isNull()                                        &&
125             (action.category() != FilterAction::ReproducibleFilter) &&
126             (action.category() != FilterAction::ComplexFilter))
127         {
128             return false;
129         }
130     }
131 
132     return true;
133 }
134 
isSupported() const135 bool FilterActionFilter::isSupported() const
136 {
137     foreach (const FilterAction& action, d->actions)
138     {
139         if (!action.isNull() && !DImgFilterManager::instance()->isSupported(action.identifier(), action.version()))
140         {
141             return false;
142         }
143     }
144 
145     return true;
146 }
147 
completelyApplied() const148 bool FilterActionFilter::completelyApplied() const
149 {
150     return (d->appliedActions.size() == d->actions.size());
151 }
152 
appliedFilterActions() const153 QList<FilterAction> FilterActionFilter::appliedFilterActions() const
154 {
155     return d->appliedActions;
156 }
157 
failedAction() const158 FilterAction FilterActionFilter::failedAction() const
159 {
160     if (d->appliedActions.size() >= d->actions.size())
161     {
162         return FilterAction();
163     }
164 
165     return d->actions.at(d->appliedActions.size());
166 }
167 
failedActionIndex() const168 int FilterActionFilter::failedActionIndex() const
169 {
170     return d->appliedActions.size();
171 }
172 
failedActionMessage() const173 QString FilterActionFilter::failedActionMessage() const
174 {
175     return d->errorMessage;
176 }
177 
filterImage()178 void FilterActionFilter::filterImage()
179 {
180     d->appliedActions.clear();
181     d->errorMessage.clear();
182     const float progressIncrement = 1.0 / qMax(1, d->actions.size());
183     float progress                = 0;
184 
185     postProgress(0);
186 
187     DImg img = m_orgImage;
188 
189     foreach (const FilterAction& action, d->actions)
190     {
191         qCDebug(DIGIKAM_DIMG_LOG) << "Replaying action" << action.identifier();
192 
193         if (action.isNull())
194         {
195             continue;
196         }
197 
198         if (DImgBuiltinFilter::isSupported(action.identifier()))
199         {
200             DImgBuiltinFilter filter(action);
201 
202             if (!filter.isValid())
203             {
204                 d->errorMessage = i18n("Built-in transformation not supported");
205 
206                 if (d->continueOnError)
207                 {
208                     continue;
209                 }
210                 else
211                 {
212                     break;
213                 }
214             }
215 
216             filter.apply(img);
217             d->appliedActions << filter.filterAction();
218         }
219         else
220         {
221             QScopedPointer<DImgThreadedFilter> filter
222             (DImgFilterManager::instance()->createFilter(action.identifier(), action.version()));
223 
224             if (!filter)
225             {
226                 d->errorMessage = i18n("Filter identifier or version is not supported");
227 
228                 if (d->continueOnError)
229                 {
230                     continue;
231                 }
232                 else
233                 {
234                     break;
235                 }
236             }
237 
238             filter->readParameters(action);
239 
240             if (!filter->parametersSuccessfullyRead())
241             {
242                 d->errorMessage = filter->readParametersError(action);
243 
244                 if (d->continueOnError)
245                 {
246                     continue;
247                 }
248                 else
249                 {
250                     break;
251                 }
252             }
253 
254             // compute
255             filter->setupAndStartDirectly(img, this, (int)progress, (int)(progress + progressIncrement));
256             img = filter->getTargetImage();
257             d->appliedActions << filter->filterAction();
258         }
259 
260         progress += progressIncrement;
261         postProgress((int)progress);
262     }
263 
264     m_destImage = img;
265 }
266 
267 } // namespace Digikam
268