File indexing completed on 2025-01-19 03:51:22

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2006-10-18
0007  * Description : EXIF light settings page.
0008  *
0009  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "exiflight.h"
0016 
0017 // C++ includes
0018 
0019 #include <cmath>
0020 
0021 // Qt includes
0022 
0023 #include <QMap>
0024 #include <QGridLayout>
0025 #include <QComboBox>
0026 #include <QApplication>
0027 #include <QStyle>
0028 #include <QDoubleSpinBox>
0029 
0030 // KDE includes
0031 
0032 #include <klocalizedstring.h>
0033 
0034 // Local includes
0035 
0036 #include "metadatacheckbox.h"
0037 
0038 namespace DigikamGenericMetadataEditPlugin
0039 {
0040 
0041 class Q_DECL_HIDDEN FlashMode
0042 {
0043 public:
0044 
0045     FlashMode()
0046       : m_id(0)
0047     {
0048     }
0049     FlashMode(int id, const QString& desc)
0050       : m_id  (id),
0051         m_desc(desc)
0052     {
0053     }
0054 
0055     int     id()   const
0056     {
0057         return m_id;
0058     }
0059 
0060     QString desc() const
0061     {
0062         return m_desc;
0063     }
0064 
0065 private:
0066 
0067     int     m_id;
0068     QString m_desc;
0069 };
0070 
0071 // --------------------------------------------------------------------------
0072 
0073 class Q_DECL_HIDDEN EXIFLight::Private
0074 {
0075 public:
0076 
0077     explicit Private()
0078     {
0079         lightSourceCheck     = nullptr;
0080         flashModeCheck       = nullptr;
0081         flashEnergyCheck     = nullptr;
0082         whiteBalanceCheck    = nullptr;
0083         lightSourceCB        = nullptr;
0084         flashEnergyEdit      = nullptr;
0085         flashModeCB          = nullptr;
0086         whiteBalanceCB       = nullptr;
0087 
0088         flashModeMap.insert(0,  FlashMode( 0x00, i18n("No flash") ));
0089         flashModeMap.insert(1,  FlashMode( 0x01, i18n("Fired") ));
0090         flashModeMap.insert(2,  FlashMode( 0x05, i18n("Fired, no strobe return light") ));
0091         flashModeMap.insert(3,  FlashMode( 0x07, i18n("Fired, strobe return light") ));
0092         flashModeMap.insert(4,  FlashMode( 0x09, i18n("Yes, compulsory") ));
0093         flashModeMap.insert(5,  FlashMode( 0x0d, i18n("Yes, compulsory, no return light") ));
0094         flashModeMap.insert(6,  FlashMode( 0x0f, i18n("Yes, compulsory, return light") ));
0095         flashModeMap.insert(7,  FlashMode( 0x10, i18n("No, compulsory") ));
0096         flashModeMap.insert(8,  FlashMode( 0x18, i18n("No, auto") ));
0097         flashModeMap.insert(9,  FlashMode( 0x19, i18n("Yes, auto") ));
0098         flashModeMap.insert(10, FlashMode( 0x1d, i18n("Yes, auto, no return light") ));
0099         flashModeMap.insert(11, FlashMode( 0x1f, i18n("Yes, auto, return light") ));
0100         flashModeMap.insert(12, FlashMode( 0x20, i18n("No flash function") ));
0101         flashModeMap.insert(13, FlashMode( 0x41, i18n("Yes, red-eye") ));
0102         flashModeMap.insert(14, FlashMode( 0x45, i18n("Yes, red-eye, no return light") ));
0103         flashModeMap.insert(15, FlashMode( 0x47, i18n("Yes, red-eye, return light") ));
0104         flashModeMap.insert(16, FlashMode( 0x49, i18n("Yes, compulsory, red-eye") ));
0105         flashModeMap.insert(17, FlashMode( 0x4d, i18n("Yes, compulsory, red-eye, no return light") ));
0106         flashModeMap.insert(18, FlashMode( 0x4f, i18n("Yes, compulsory, red-eye, return light") ));
0107         flashModeMap.insert(19, FlashMode( 0x59, i18n("Yes, auto, red-eye") ));
0108         flashModeMap.insert(20, FlashMode( 0x5d, i18n("Yes, auto, red-eye, no return light") ));
0109         flashModeMap.insert(21, FlashMode( 0x5f, i18n("Yes, auto, red-eye, return light") ));
0110     }
0111 
0112     typedef QMap<int, FlashMode> FlashModeMap;
0113 
0114     FlashModeMap      flashModeMap;
0115 
0116     QCheckBox*        flashEnergyCheck;
0117 
0118     QComboBox*        lightSourceCB;
0119     QComboBox*        flashModeCB;
0120     QComboBox*        whiteBalanceCB;
0121 
0122     QDoubleSpinBox*   flashEnergyEdit;
0123 
0124     MetadataCheckBox* lightSourceCheck;
0125     MetadataCheckBox* flashModeCheck;
0126     MetadataCheckBox* whiteBalanceCheck;
0127 };
0128 
0129 // --------------------------------------------------------------------------
0130 
0131 EXIFLight::EXIFLight(QWidget* const parent)
0132     : MetadataEditPage(parent),
0133       d               (new Private)
0134 {
0135     QGridLayout* const grid = new QGridLayout(widget());
0136 
0137     // --------------------------------------------------------
0138 
0139     d->lightSourceCheck = new MetadataCheckBox(i18n("Light source:"), this);
0140     d->lightSourceCB    = new QComboBox(this);
0141     d->lightSourceCB->insertItem(0,  i18nc("light source", "Unknown"));
0142     d->lightSourceCB->insertItem(1,  i18nc("light source", "Daylight"));
0143     d->lightSourceCB->insertItem(2,  i18nc("light source", "Fluorescent"));
0144     d->lightSourceCB->insertItem(3,  i18nc("light source", "Tungsten (incandescent light)"));
0145     d->lightSourceCB->insertItem(4,  i18nc("light source", "Flash"));
0146     d->lightSourceCB->insertItem(5,  i18nc("light source", "Fine weather"));
0147     d->lightSourceCB->insertItem(6,  i18nc("light source", "Cloudy weather"));
0148     d->lightSourceCB->insertItem(7,  i18nc("light source", "Shade"));
0149     d->lightSourceCB->insertItem(8,  i18nc("light source", "Daylight fluorescent (D 5700 - 7100K)"));
0150     d->lightSourceCB->insertItem(9,  i18nc("light source", "Day white fluorescent (N 4600 - 5400K)"));
0151     d->lightSourceCB->insertItem(10, i18nc("light source", "Cool white fluorescent (W 3900 - 4500K)"));
0152     d->lightSourceCB->insertItem(11, i18nc("light source", "White fluorescent (WW 3200 - 3700K)"));
0153     d->lightSourceCB->insertItem(12, i18nc("light source", "Standard light A"));
0154     d->lightSourceCB->insertItem(13, i18nc("light source", "Standard light B"));
0155     d->lightSourceCB->insertItem(14, i18nc("light source", "Standard light C"));
0156     d->lightSourceCB->insertItem(15, i18nc("light source", "D55"));
0157     d->lightSourceCB->insertItem(16, i18nc("light source", "D65"));
0158     d->lightSourceCB->insertItem(17, i18nc("light source", "D75"));
0159     d->lightSourceCB->insertItem(18, i18nc("light source", "D50"));
0160     d->lightSourceCB->insertItem(19, i18nc("light source", "ISO studio tungsten"));
0161     d->lightSourceCB->insertItem(20, i18nc("light source", "Other light source"));
0162     d->lightSourceCB->setWhatsThis(i18n("Select here the kind of light source used "
0163                                         "to take the picture."));
0164 
0165     // --------------------------------------------------------
0166 
0167     d->flashModeCheck = new MetadataCheckBox(i18n("Flash mode:"), this);
0168     d->flashModeCB    = new QComboBox(this);
0169 
0170     for (Private::FlashModeMap::Iterator it = d->flashModeMap.begin(); it != d->flashModeMap.end(); ++it )
0171        d->flashModeCB->addItem(it.value().desc());
0172 
0173     d->flashModeCB->setWhatsThis(i18n("Select here the flash program mode used by the camera "
0174                                       "to take the picture."));
0175 
0176     // --------------------------------------------------------
0177 
0178     d->flashEnergyCheck = new QCheckBox(i18n("Flash energy (BCPS):"), this);
0179     d->flashEnergyEdit  = new QDoubleSpinBox(this);
0180     d->flashEnergyEdit->setRange(1.0, 10000.0);
0181     d->flashEnergyEdit->setSingleStep(1.0);
0182     d->flashEnergyEdit->setValue(1.0);
0183     d->flashEnergyEdit->setDecimals(1);
0184     d->flashEnergyEdit->setWhatsThis(i18n("Set here the flash energy used to take the picture "
0185                                           "in BCPS units. Beam Candle Power Seconds is the measure "
0186                                           "of effective intensity of a light source when it is "
0187                                           "focused into a beam by a reflector or lens. This value "
0188                                           "is the effective intensity for a period of one second."));
0189 
0190     // --------------------------------------------------------
0191 
0192     d->whiteBalanceCheck = new MetadataCheckBox(i18n("White balance:"), this);
0193     d->whiteBalanceCB    = new QComboBox(this);
0194     d->whiteBalanceCB->insertItem(0, i18nc("@item: white balance", "Auto"));
0195     d->whiteBalanceCB->insertItem(1, i18nc("@item: white balance", "Manual"));
0196     d->whiteBalanceCB->setWhatsThis(i18nc("@info", "Select here the white balance mode set by the camera when "
0197                                          "the picture was taken."));
0198 
0199     // --------------------------------------------------------
0200 
0201     grid->addWidget(d->lightSourceCheck,    0, 0, 1, 1);
0202     grid->addWidget(d->lightSourceCB,       0, 2, 1, 2);
0203     grid->addWidget(d->flashModeCheck,      1, 0, 1, 1);
0204     grid->addWidget(d->flashModeCB,         1, 2, 1, 2);
0205     grid->addWidget(d->flashEnergyCheck,    2, 0, 1, 1);
0206     grid->addWidget(d->flashEnergyEdit,     2, 2, 1, 1);
0207     grid->addWidget(d->whiteBalanceCheck,   3, 0, 1, 1);
0208     grid->addWidget(d->whiteBalanceCB,      3, 2, 1, 1);
0209     grid->setColumnStretch(1, 10);
0210     grid->setRowStretch(4, 10);
0211 
0212     int spacing = qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0213                        QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing));
0214 
0215     grid->setContentsMargins(spacing, spacing, spacing, spacing);
0216     grid->setSpacing(spacing);
0217 
0218     // --------------------------------------------------------
0219 
0220     connect(d->lightSourceCheck, SIGNAL(toggled(bool)),
0221             d->lightSourceCB, SLOT(setEnabled(bool)));
0222 
0223     connect(d->flashModeCheck, SIGNAL(toggled(bool)),
0224             d->flashModeCB, SLOT(setEnabled(bool)));
0225 
0226     connect(d->flashEnergyCheck, SIGNAL(toggled(bool)),
0227             d->flashEnergyEdit, SLOT(setEnabled(bool)));
0228 
0229     connect(d->whiteBalanceCheck, SIGNAL(toggled(bool)),
0230             d->whiteBalanceCB, SLOT(setEnabled(bool)));
0231 
0232     // --------------------------------------------------------
0233 
0234     connect(d->flashEnergyCheck, SIGNAL(toggled(bool)),
0235             this, SIGNAL(signalModified()));
0236 
0237     connect(d->lightSourceCheck, SIGNAL(toggled(bool)),
0238             this, SIGNAL(signalModified()));
0239 
0240     connect(d->flashModeCheck, SIGNAL(toggled(bool)),
0241             this, SIGNAL(signalModified()));
0242 
0243     connect(d->whiteBalanceCheck, SIGNAL(toggled(bool)),
0244             this, SIGNAL(signalModified()));
0245 
0246     // --------------------------------------------------------
0247 
0248     connect(d->lightSourceCB, SIGNAL(activated(int)),
0249             this, SIGNAL(signalModified()));
0250 
0251     connect(d->flashModeCB, SIGNAL(activated(int)),
0252             this, SIGNAL(signalModified()));
0253 
0254     connect(d->whiteBalanceCB, SIGNAL(activated(int)),
0255             this, SIGNAL(signalModified()));
0256 
0257     connect(d->flashEnergyEdit, SIGNAL(valueChanged(double)),
0258             this, SIGNAL(signalModified()));
0259 }
0260 
0261 EXIFLight::~EXIFLight()
0262 {
0263     delete d;
0264 }
0265 
0266 void EXIFLight::readMetadata(const DMetadata& meta)
0267 {
0268     blockSignals(true);
0269 
0270     long int num=1, den=1;
0271     long     val=0;
0272 
0273     d->lightSourceCB->setCurrentIndex(0);
0274     d->lightSourceCheck->setChecked(false);
0275 
0276     if (meta.getExifTagLong("Exif.Photo.LightSource", val))
0277     {
0278         if ((val>=0 && val <=4) || (val> 8 && val <16) || (val> 16 && val <25) || val == 255)
0279         {
0280             if (val > 8 && val < 16)
0281                 val = val - 4;
0282             else if (val > 16 && val < 25)
0283                 val = val - 5;
0284             else if (val == 255)
0285                 val = 20;
0286 
0287             d->lightSourceCB->setCurrentIndex(val);
0288             d->lightSourceCheck->setChecked(true);
0289         }
0290         else
0291         {
0292             d->lightSourceCheck->setValid(false);
0293         }
0294     }
0295 
0296     d->lightSourceCB->setEnabled(d->lightSourceCheck->isChecked());
0297 
0298     d->flashModeCB->setCurrentIndex(0);
0299     d->flashModeCheck->setChecked(false);
0300 
0301     if (meta.getExifTagLong("Exif.Photo.Flash", val))
0302     {
0303         int item = -1;
0304 
0305         for (Private::FlashModeMap::Iterator it = d->flashModeMap.begin();
0306             it != d->flashModeMap.end(); ++it )
0307         {
0308             if (it.value().id() == val)
0309                 item = it.key();
0310         }
0311 
0312         if (item != -1)
0313         {
0314             d->flashModeCB->setCurrentIndex(item);
0315             d->flashModeCheck->setChecked(true);
0316         }
0317         else
0318         {
0319             d->flashModeCheck->setValid(false);
0320         }
0321     }
0322 
0323     d->flashModeCB->setEnabled(d->flashModeCheck->isChecked());
0324 
0325     d->flashEnergyEdit->setValue(1.0);
0326     d->flashEnergyCheck->setChecked(false);
0327 
0328     if (meta.getExifTagRational("Exif.Photo.FlashEnergy", num, den))
0329     {
0330         d->flashEnergyEdit->setValue((double)(num) / (double)(den));
0331         d->flashEnergyCheck->setChecked(true);
0332     }
0333 
0334     d->flashEnergyEdit->setEnabled(d->flashEnergyCheck->isChecked());
0335 
0336     d->whiteBalanceCB->setCurrentIndex(0);
0337     d->whiteBalanceCheck->setChecked(false);
0338 
0339     if (meta.getExifTagLong("Exif.Photo.WhiteBalance", val))
0340     {
0341         if (val>=0 && val<=1)
0342         {
0343             d->whiteBalanceCB->setCurrentIndex(val);
0344             d->whiteBalanceCheck->setChecked(true);
0345         }
0346         else
0347         {
0348             d->whiteBalanceCheck->setValid(false);
0349         }
0350     }
0351 
0352     d->whiteBalanceCB->setEnabled(d->whiteBalanceCheck->isChecked());
0353 
0354     blockSignals(false);
0355 }
0356 
0357 void EXIFLight::applyMetadata(const DMetadata& meta)
0358 {
0359     long int num=1, den=1;
0360 
0361     if (d->lightSourceCheck->isChecked())
0362     {
0363         long val = d->lightSourceCB->currentIndex();
0364 
0365         if (val > 4 && val < 12)
0366             val = val + 4;
0367         else if (val > 11 && val < 20)
0368             val = val + 5;
0369         else if (val == 20)
0370             val = 255;
0371 
0372         meta.setExifTagLong("Exif.Photo.LightSource", val);
0373     }
0374     else if (d->lightSourceCheck->isValid())
0375     {
0376         meta.removeExifTag("Exif.Photo.LightSource");
0377     }
0378 
0379     if (d->flashModeCheck->isChecked())
0380     {
0381         long val = d->flashModeCB->currentIndex();
0382         meta.setExifTagLong("Exif.Photo.Flash", d->flashModeMap[val].id());
0383     }
0384     else if (d->flashModeCheck->isValid())
0385     {
0386         meta.removeExifTag("Exif.Photo.Flash");
0387     }
0388 
0389     if (d->flashEnergyCheck->isChecked())
0390     {
0391         meta.convertToRational(d->flashEnergyEdit->value(), &num, &den, 1);
0392         meta.setExifTagRational("Exif.Photo.FlashEnergy", num, den);
0393     }
0394     else
0395     {
0396         meta.removeExifTag("Exif.Photo.FlashEnergy");
0397     }
0398 
0399     if (d->whiteBalanceCheck->isChecked())
0400         meta.setExifTagLong("Exif.Photo.WhiteBalance", d->whiteBalanceCB->currentIndex());
0401     else if (d->whiteBalanceCheck->isValid())
0402         meta.removeExifTag("Exif.Photo.WhiteBalance");
0403 }
0404 
0405 } // namespace DigikamGenericMetadataEditPlugin
0406 
0407 #include "moc_exiflight.cpp"