1 /**
2  * This file is a part of LuminanceHDR package.
3  * ----------------------------------------------------------------------
4  * Copyright (C) 2006,2007 Giuseppe Rota
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * ----------------------------------------------------------------------
20  *
21  * Original Work
22  * @author Giuseppe Rota <grota@users.sourceforge.net>
23  * Improvements, bugfixing
24  * @author Franco Comida <fcomida@users.sourceforge.net>
25  *
26  */
27 
28 #include <QByteArray>
29 #include <QDebug>
30 #include <QFile>
31 #include <QMessageBox>
32 #include <QScopedPointer>
33 #include <QString>
34 
35 #include "Common/LuminanceOptions.h"
36 #include "Core/TonemappingOptions.h"
37 #include "Fileformat/pfsoutldrimage.h"
38 #include "Viewers/IGraphicsPixmapItem.h"
39 #include "Viewers/LdrViewer.h"
40 
41 #include <Libpfs/frame.h>
42 #include <Libpfs/utils/resourcehandlerlcms.h>
43 
44 using namespace pfs;
45 
46 namespace {
parseOptions(TonemappingOptions * opts,QString & caption)47 void parseOptions(TonemappingOptions *opts, QString &caption) {
48     if (opts == NULL) {
49         caption.clear();
50     } else {
51         TMOptionsOperations tmopts(opts);
52         // postfix = opts->getPostfix();
53         caption = opts->getCaption();
54         // exif_comment = tmopts.getExifComment();
55     }
56 }
57 
doCMSTransform(QImage & qImage,bool doProof,bool doGamutCheck)58 bool doCMSTransform(QImage &qImage, bool doProof, bool doGamutCheck) {
59     LuminanceOptions luminance_opts;
60     QString monitor_fname = luminance_opts.getMonitorProfileFileName();
61     qDebug() << "Monitor profile: " << monitor_fname;
62     QString printer_fname = luminance_opts.getPrinterProfileFileName();
63     qDebug() << "Printer profile: " << printer_fname;
64 
65     // Check Monitor Profile
66     if (monitor_fname.isEmpty()) {
67         return false;
68     }
69 
70     utils::ScopedCmsProfile hsRGB(cmsCreate_sRGBProfile());
71     utils::ScopedCmsProfile hOut(cmsOpenProfileFromFile(
72         QFile::encodeName(monitor_fname).constData(), "r"));
73 
74     utils::ScopedCmsProfile hProof;
75     utils::ScopedCmsTransform xform;
76 
77     // Check whether the output profile is open
78     if (!hOut) {
79         QMessageBox::warning(0, QObject::tr("Warning"),
80                              QObject::tr("I cannot open monitor profile. "
81                                          "Please select a different one."),
82                              QMessageBox::Ok, QMessageBox::NoButton);
83 
84         return false;
85     }
86 
87     //
88     if (doProof && !printer_fname.isEmpty()) {
89         hProof.reset(cmsOpenProfileFromFile(
90             QFile::encodeName(printer_fname).constData(), "r"));
91         if (!hProof) {
92             QMessageBox::warning(0, QObject::tr("Warning"),
93                                  QObject::tr("I cannot open printer profile. "
94                                              "Please select a different one."),
95                                  QMessageBox::Ok, QMessageBox::NoButton);
96             doProof = false;
97         }
98     } else if (doProof) {
99         QMessageBox::warning(0, QObject::tr("Warning"),
100                              QObject::tr("Please select a printer profile ."),
101                              QMessageBox::Ok, QMessageBox::NoButton);
102         doProof = false;
103     }
104 
105     if (doProof) {
106         cmsUInt32Number dwFlags =
107             doGamutCheck ? cmsFLAGS_SOFTPROOFING | cmsFLAGS_GAMUTCHECK
108                          : cmsFLAGS_SOFTPROOFING;
109         cmsUInt16Number alarmCodes[cmsMAXCHANNELS] = {0};
110         alarmCodes[1] = 0xFFFF;
111         cmsSetAlarmCodes(alarmCodes);
112         xform.reset(cmsCreateProofingTransform(
113             hsRGB.data(), TYPE_BGRA_8,  // TYPE_RGBA_8,
114             hOut.data(), TYPE_BGRA_8,   // TYPE_RGBA_8,
115             hProof.data(), INTENT_PERCEPTUAL, INTENT_ABSOLUTE_COLORIMETRIC,
116             dwFlags));
117     } else {
118         xform.reset(cmsCreateTransform(hsRGB.data(),
119                                        TYPE_BGRA_8,  // TYPE_RGBA_8,
120                                        hOut.data(),
121                                        TYPE_BGRA_8,  // TYPE_RGBA_8,
122                                        INTENT_PERCEPTUAL, 0));
123     }
124 
125     if (!xform) {
126         QMessageBox::warning(
127             0, QObject::tr("Warning"),
128             QObject::tr("I cannot perform the color transform. Please select a "
129                         "different monitor profile."),
130             QMessageBox::Ok, QMessageBox::NoButton);
131 
132         return false;
133     }
134 
135     cmsDoTransform(xform.data(), qImage.bits(), qImage.bits(),
136                    qImage.width() * qImage.height());
137 
138     return true;
139 }
140 }
141 
142 // This constructor is a bit of a mess!
LdrViewer(pfs::Frame * frame,TonemappingOptions * opts,QWidget * parent,bool ns,const float devicePixelRatio)143 LdrViewer::LdrViewer(pfs::Frame *frame, TonemappingOptions *opts,
144                      QWidget *parent, bool ns, const float devicePixelRatio)
145     : GenericViewer(frame, parent, ns),
146       informativeLabel(new QLabel(mToolBar)),
147       mTonemappingOptions(opts) {
148     informativeLabel->setSizePolicy(QSizePolicy::Preferred,
149                                     QSizePolicy::Preferred);
150     informativeLabel->setMinimumSize(QSize(200, 36));
151     mToolBar->addWidget(informativeLabel);
152 
153     setDevicePixelRatio(devicePixelRatio);
154 
155     mPixmap->disableSelectionTool();  // disable by default crop functionalities
156 
157     // I shouldn't call a virtual function straight from the constructor,
158     // but specifing correctly which version of this virtual function I want to
159     // call,
160     // I am safe
161     LdrViewer::setTonemappingOptions(opts);
162 
163     QScopedPointer<QImage> temp_qimage(fromLDRPFStoQImage(getFrame()));
164     doCMSTransform(*temp_qimage, false, false);
165     setQImage(*temp_qimage);
166 
167     updateView();
168     retranslateUi();
169 }
170 
~LdrViewer()171 LdrViewer::~LdrViewer() {
172 #ifdef QT_DEBUG
173     qDebug() << "LdrViewer::~LdrViewer()";
174 #endif
175 }
176 
retranslateUi()177 void LdrViewer::retranslateUi() {
178     parseOptions(mTonemappingOptions, caption);
179     informativeLabel->setText(tr("LDR image [%1 x %2]: %3")
180                                   .arg(getWidth())
181                                   .arg(getHeight())
182                                   .arg(caption));
183 
184     GenericViewer::retranslateUi();
185 }
186 
getFileNamePostFix()187 QString LdrViewer::getFileNamePostFix() {
188     return mTonemappingOptions ? mTonemappingOptions->getPostfix() : QString();
189 }
190 
getExifComment()191 QString LdrViewer::getExifComment() {
192     if (mTonemappingOptions) {
193         TMOptionsOperations tm_ops(mTonemappingOptions);
194         return tm_ops.getExifComment();
195     } else {
196         return QString();
197     }
198 }
199 
updatePixmap()200 void LdrViewer::updatePixmap() {
201 #ifdef QT_DEBUG
202     qDebug() << "void LdrViewer::updatePixmap()";
203 #endif
204 
205     QScopedPointer<QImage> temp_qimage(fromLDRPFStoQImage(getFrame()));
206 
207     doCMSTransform(*temp_qimage, false, false);
208     mPixmap->setPixmap(QPixmap::fromImage(*temp_qimage));
209 
210     parseOptions(mTonemappingOptions, caption);
211     informativeLabel->setText(tr("LDR image [%1 x %2]: %3")
212                                   .arg(getWidth())
213                                   .arg(getHeight())
214                                   .arg(caption));
215 }
216 
setTonemappingOptions(TonemappingOptions * tmopts)217 void LdrViewer::setTonemappingOptions(TonemappingOptions *tmopts) {
218     mTonemappingOptions = tmopts;
219 
220     parseOptions(tmopts, caption);
221     setWindowTitle(caption);
222     // setToolTip(caption);
223     informativeLabel->setText(tr("LDR image [%1 x %2]: %3")
224                                   .arg(getWidth())
225                                   .arg(getHeight())
226                                   .arg(caption));
227 }
228 
getTonemappingOptions()229 TonemappingOptions *LdrViewer::getTonemappingOptions() {
230     return mTonemappingOptions;
231 }
232 
233 //! \brief returns max value of the handled frame
getMaxLuminanceValue()234 float LdrViewer::getMaxLuminanceValue() { return 1.0f; }
235 
236 //! \brief returns min value of the handled frame
getMinLuminanceValue()237 float LdrViewer::getMinLuminanceValue() { return 0.0f; }
238 
doSoftProofing(bool doGamutCheck)239 void LdrViewer::doSoftProofing(bool doGamutCheck) {
240     QScopedPointer<QImage> src_image(fromLDRPFStoQImage(getFrame()));
241     if (doCMSTransform(*src_image, true, doGamutCheck)) {
242         mPixmap->setPixmap(QPixmap::fromImage(*src_image));
243     }
244 }
245 
undoSoftProofing()246 void LdrViewer::undoSoftProofing() {
247     QScopedPointer<QImage> src_image(fromLDRPFStoQImage(getFrame()));
248     if (doCMSTransform(*src_image, false, false)) {
249         mPixmap->setPixmap(QPixmap::fromImage(*src_image));
250     }
251 }
252