1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2008-08-04
7  * Description : RAW postProcessedImg widget.
8  *
9  * Copyright (C) 2008-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  *
11  * This program is free software; you can redistribute it
12  * and/or modify it under the terms of the GNU General
13  * Public License as published by the Free Software Foundation;
14  * either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * ============================================================ */
23 
24 #include "rawpreview.h"
25 
26 // Qt includes
27 
28 #include <QString>
29 #include <QPainter>
30 #include <QPixmap>
31 #include <QFileInfo>
32 #include <QResizeEvent>
33 #include <QFontMetrics>
34 #include <QApplication>
35 
36 // KDE includes
37 
38 #include <klocalizedstring.h>
39 
40 // Local includes
41 
42 #include "digikam_debug.h"
43 #include "managedloadsavethread.h"
44 #include "editorcore.h"
45 #include "previewlayout.h"
46 #include "imagepreviewitem.h"
47 
48 namespace DigikamRawImportNativePlugin
49 {
50 
51 class Q_DECL_HIDDEN RawPreview::Private
52 {
53 public:
54 
Private()55     explicit Private()
56       : currentFitWindowZoom(0.0),
57         thread              (nullptr),
58         item                (nullptr)
59     {
60     }
61 
62     double                 currentFitWindowZoom;
63 
64     QUrl                   url;
65 
66     DImg                   demosaicedImg;
67 
68     DRawDecoding           settings;
69     ManagedLoadSaveThread* thread;
70     LoadingDescription     loadingDesc;
71     ImagePreviewItem*      item;
72 };
73 
RawPreview(const QUrl & url,QWidget * const parent)74 RawPreview::RawPreview(const QUrl& url, QWidget* const parent)
75     : GraphicsDImgView(parent),
76       d               (new Private)
77 {
78     d->item   = new ImagePreviewItem();
79     setItem(d->item);
80 
81     d->url    = url;
82     d->thread = new ManagedLoadSaveThread;
83     d->thread->setLoadingPolicy(ManagedLoadSaveThread::LoadingPolicyFirstRemovePrevious);
84 
85     // ------------------------------------------------------------
86 
87     // set default zoom
88 
89     layout()->fitToWindow();
90 
91     installPanIcon();
92 
93     setMinimumWidth(500);
94     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
95 
96     // ------------------------------------------------------------
97 
98     connect(d->thread, SIGNAL(signalImageLoaded(LoadingDescription,DImg)),
99             this, SLOT(slotImageLoaded(LoadingDescription,DImg)));
100 
101     connect(d->thread, SIGNAL(signalLoadingProgress(LoadingDescription,float)),
102             this, SLOT(slotLoadingProgress(LoadingDescription,float)));
103 }
104 
~RawPreview()105 RawPreview::~RawPreview()
106 {
107     delete d->item;
108     delete d;
109 }
110 
setPostProcessedImage(const DImg & image)111 void RawPreview::setPostProcessedImage(const DImg& image)
112 {
113     d->item->setImage(image);
114 }
115 
postProcessedImage() const116 DImg RawPreview::postProcessedImage() const
117 {
118     return d->item->image();
119 }
120 
demosaicedImage() const121 DImg& RawPreview::demosaicedImage() const
122 {
123     return d->demosaicedImg;
124 }
125 
setDecodingSettings(const DRawDecoding & settings)126 void RawPreview::setDecodingSettings(const DRawDecoding& settings)
127 {
128     if ((d->settings == settings) && d->thread->isRunning())
129     {
130         return;
131     }
132 
133     // Save post processing settings.
134 
135     d->settings                     = settings;
136 
137     // All post processing settings will be used after demosaicing.
138 
139     DRawDecoding demosaisedSettings = settings;
140     demosaisedSettings.resetPostProcessingSettings();
141 
142     d->loadingDesc                  = LoadingDescription(d->url.toLocalFile(), demosaisedSettings);
143     d->thread->load(d->loadingDesc, ManagedLoadSaveThread::LoadingPolicyFirstRemovePrevious);
144     emit signalLoadingStarted();
145 }
146 
exposureSettingsChanged()147 void RawPreview::exposureSettingsChanged()
148 {
149     viewport()->update();
150 }
151 
ICCSettingsChanged()152 void RawPreview::ICCSettingsChanged()
153 {
154     viewport()->update();
155 }
156 
cancelLoading()157 void RawPreview::cancelLoading()
158 {
159     d->thread->stopLoading(d->loadingDesc);
160 }
161 
slotLoadingProgress(const LoadingDescription & description,float progress)162 void RawPreview::slotLoadingProgress(const LoadingDescription& description, float progress)
163 {
164     if (description.filePath != d->loadingDesc.filePath)
165     {
166         return;
167     }
168 
169     emit signalLoadingProgress(progress);
170 }
171 
slotImageLoaded(const LoadingDescription & description,const DImg & image)172 void RawPreview::slotImageLoaded(const LoadingDescription& description, const DImg& image)
173 {
174     if (description.filePath != d->loadingDesc.filePath)
175     {
176         return;
177     }
178 
179     if (image.isNull())
180     {
181         QString msg    = i18n("Cannot decode RAW image\n\"%1\"",
182                               QFileInfo(d->loadingDesc.filePath).fileName());
183         QFontMetrics fontMt(font());
184         QRect fontRect = fontMt.boundingRect(0, 0, width(), height(), 0, msg);
185         QPixmap pix(fontRect.size());
186         pix.fill(qApp->palette().color(QPalette::Base));
187         QPainter p(&pix);
188         p.setPen(QPen(qApp->palette().color(QPalette::Text)));
189         p.drawText(0, 0, pix.width(), pix.height(), Qt::AlignCenter | Qt::TextWordWrap, msg);
190         p.end();
191 
192         // three copies - but the image is small
193 
194         setPostProcessedImage(DImg(pix.toImage()));
195         emit signalLoadingFailed();
196     }
197     else
198     {
199         d->demosaicedImg = image;
200         emit signalDemosaicedImage();
201 
202         // NOTE: we will apply all Raw post processing corrections in RawImport class.
203     }
204 }
205 
previewWidth() const206 int RawPreview::previewWidth() const
207 {
208     return d->item->image().width();
209 }
210 
previewHeight() const211 int RawPreview::previewHeight() const
212 {
213     return d->item->image().height();
214 }
215 
previewIsNull() const216 bool RawPreview::previewIsNull() const
217 {
218     return d->item->image().isNull();
219 }
220 
resetPreview()221 void RawPreview::resetPreview()
222 {
223     d->item->setImage(DImg());
224     d->loadingDesc = LoadingDescription();
225     update();
226 }
227 
previewToQImage() const228 QImage RawPreview::previewToQImage() const
229 {
230     return d->item->image().copyQImage();
231 }
232 
233 } // namespace DigikamRawImportNativePlugin
234