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 lens 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 "exiflens.h"
0016 
0017 // C++ includes
0018 
0019 #include <cmath>
0020 
0021 // Qt includes
0022 
0023 #include <QGridLayout>
0024 #include <QApplication>
0025 #include <QStyle>
0026 #include <QComboBox>
0027 #include <QSpinBox>
0028 
0029 // KDE includes
0030 
0031 #include <klocalizedstring.h>
0032 
0033 // Local includes
0034 
0035 #include "metadatacheckbox.h"
0036 
0037 namespace DigikamGenericMetadataEditPlugin
0038 {
0039 
0040 class Q_DECL_HIDDEN EXIFLens::Private
0041 {
0042 public:
0043 
0044     explicit Private()
0045     {
0046         apertureCheck         = nullptr;
0047         maxApertureCheck      = nullptr;
0048         focalLength35mmCheck  = nullptr;
0049         focalLengthCheck      = nullptr;
0050         digitalZoomRatioCheck = nullptr;
0051         apertureCB            = nullptr;
0052         maxApertureCB         = nullptr;
0053         focalLength35mmEdit   = nullptr;
0054         focalLengthEdit       = nullptr;
0055         digitalZoomRatioEdit  = nullptr;
0056 
0057         apertureValues.append(QLatin1String("f/1.0"));
0058         apertureValues.append(QLatin1String("f/1.1"));
0059         apertureValues.append(QLatin1String("f/1.2"));
0060         apertureValues.append(QLatin1String("f/1.3"));
0061         apertureValues.append(QLatin1String("f/1.4"));
0062         apertureValues.append(QLatin1String("f/1.6"));
0063         apertureValues.append(QLatin1String("f/1.8"));
0064         apertureValues.append(QLatin1String("f/2.0"));
0065         apertureValues.append(QLatin1String("f/2.2"));
0066         apertureValues.append(QLatin1String("f/2.5"));
0067         apertureValues.append(QLatin1String("f/2.8"));
0068         apertureValues.append(QLatin1String("f/3.2"));
0069         apertureValues.append(QLatin1String("f/3.5"));
0070         apertureValues.append(QLatin1String("f/3.6"));
0071         apertureValues.append(QLatin1String("f/4.0"));
0072         apertureValues.append(QLatin1String("f/4.5"));
0073         apertureValues.append(QLatin1String("f/4.9"));
0074         apertureValues.append(QLatin1String("f/5.0"));
0075         apertureValues.append(QLatin1String("f/5.6"));
0076         apertureValues.append(QLatin1String("f/5.7"));
0077         apertureValues.append(QLatin1String("f/6.3"));
0078         apertureValues.append(QLatin1String("f/7.0"));
0079         apertureValues.append(QLatin1String("f/7.1"));
0080         apertureValues.append(QLatin1String("f/8.0"));
0081         apertureValues.append(QLatin1String("f/9.0"));
0082         apertureValues.append(QLatin1String("f/10.0"));
0083         apertureValues.append(QLatin1String("f/10.1"));
0084         apertureValues.append(QLatin1String("f/11.0"));
0085         apertureValues.append(QLatin1String("f/11.3"));
0086         apertureValues.append(QLatin1String("f/12.0"));
0087         apertureValues.append(QLatin1String("f/12.7"));
0088         apertureValues.append(QLatin1String("f/13.0"));
0089         apertureValues.append(QLatin1String("f/14.0"));
0090         apertureValues.append(QLatin1String("f/14.3"));
0091         apertureValues.append(QLatin1String("f/16.0"));
0092         apertureValues.append(QLatin1String("f/18.0"));
0093         apertureValues.append(QLatin1String("f/20.0"));
0094         apertureValues.append(QLatin1String("f/20.2"));
0095         apertureValues.append(QLatin1String("f/22.0"));
0096         apertureValues.append(QLatin1String("f/22.6"));
0097         apertureValues.append(QLatin1String("f/25.0"));
0098         apertureValues.append(QLatin1String("f/25.4"));
0099         apertureValues.append(QLatin1String("f/28.5"));
0100         apertureValues.append(QLatin1String("f/29.0"));
0101         apertureValues.append(QLatin1String("f/32.0"));
0102         apertureValues.append(QLatin1String("f/35.9"));
0103         apertureValues.append(QLatin1String("f/36.0"));
0104         apertureValues.append(QLatin1String("f/40.0"));
0105         apertureValues.append(QLatin1String("f/40.3"));
0106         apertureValues.append(QLatin1String("f/45.0"));
0107         apertureValues.append(QLatin1String("f/45.3"));
0108         apertureValues.append(QLatin1String("f/50.8"));
0109         apertureValues.append(QLatin1String("f/51.0"));
0110         apertureValues.append(QLatin1String("f/57.0"));
0111         apertureValues.append(QLatin1String("f/64.0"));
0112         apertureValues.append(QLatin1String("f/72.0"));
0113         apertureValues.append(QLatin1String("f/81.0"));
0114         apertureValues.append(QLatin1String("f/91.0"));
0115     }
0116 
0117     QStringList       apertureValues;
0118 
0119     QCheckBox*        focalLength35mmCheck;
0120     QCheckBox*        focalLengthCheck;
0121     QCheckBox*        digitalZoomRatioCheck;
0122 
0123     QComboBox*        apertureCB;
0124     QComboBox*        maxApertureCB;
0125 
0126     QSpinBox*         focalLength35mmEdit;
0127 
0128     QDoubleSpinBox*   focalLengthEdit;
0129     QDoubleSpinBox*   digitalZoomRatioEdit;
0130 
0131     MetadataCheckBox* apertureCheck;
0132     MetadataCheckBox* maxApertureCheck;
0133 };
0134 
0135 EXIFLens::EXIFLens(QWidget* const parent)
0136     : MetadataEditPage(parent),
0137       d               (new Private)
0138 {
0139     QGridLayout* const grid = new QGridLayout(widget());
0140 
0141     // --------------------------------------------------------
0142 
0143     d->focalLengthCheck = new QCheckBox(i18n("Focal length (mm):"), this);
0144     d->focalLengthEdit  = new QDoubleSpinBox(this);
0145     d->focalLengthEdit->setRange(1.0, 10000.0);
0146     d->focalLengthEdit->setSingleStep(1.0);
0147     d->focalLengthEdit->setValue(50.0);
0148     d->focalLengthEdit->setDecimals(1);
0149     d->focalLengthEdit->setWhatsThis(i18n("Set here the lens focal length in millimeters "
0150                                           "used by camera to take the picture."));
0151 
0152     // --------------------------------------------------------
0153 
0154     d->focalLength35mmCheck = new QCheckBox(i18n("Focal length in 35mm film (mm):"), this);
0155     d->focalLength35mmEdit  = new QSpinBox(this);
0156     d->focalLength35mmEdit->setMinimum(1);
0157     d->focalLength35mmEdit->setMaximum(10000);
0158     d->focalLength35mmEdit->setSingleStep(1);
0159     d->focalLength35mmEdit->setValue(1);
0160     d->focalLength35mmEdit->setWhatsThis(i18n("Set here equivalent focal length assuming "
0161                                               "a 35mm film camera, in mm. A value of 0 means the focal "
0162                                               "length is unknown."));
0163 
0164     // --------------------------------------------------------
0165 
0166     d->digitalZoomRatioCheck = new QCheckBox(i18n("Digital zoom ratio:"), this);
0167     d->digitalZoomRatioEdit  = new QDoubleSpinBox(this);
0168     d->digitalZoomRatioEdit->setRange(0.0, 100.0);
0169     d->digitalZoomRatioEdit->setSingleStep(0.1);
0170     d->digitalZoomRatioEdit->setValue(1.0);
0171     d->digitalZoomRatioEdit->setDecimals(1);
0172     d->digitalZoomRatioEdit->setWhatsThis(i18n("Set here the digital zoom ratio "
0173                                                "used by camera to take the picture."));
0174 
0175     // --------------------------------------------------------
0176 
0177     d->apertureCheck = new MetadataCheckBox(i18n("Lens aperture (f-number):"), this);
0178     d->apertureCB    = new QComboBox(this);
0179     d->apertureCB->insertItems(0, d->apertureValues);
0180     d->apertureCB->setWhatsThis(i18n("Select here the lens aperture used by camera "
0181                                      "to take the picture."));
0182 
0183     // --------------------------------------------------------
0184 
0185     d->maxApertureCheck = new MetadataCheckBox(i18n("Max. lens aperture (f-number):"), this);
0186     d->maxApertureCB    = new QComboBox(this);
0187     d->maxApertureCB->insertItems(0, d->apertureValues);
0188     d->maxApertureCB->setWhatsThis(i18n("Select here the smallest aperture of the lens used by camera "
0189                                         "to take the picture."));
0190 
0191     grid->addWidget(d->focalLengthCheck,        0, 0, 1, 1);
0192     grid->addWidget(d->focalLengthEdit,         0, 2, 1, 1);
0193     grid->addWidget(d->focalLength35mmCheck,    1, 0, 1, 1);
0194     grid->addWidget(d->focalLength35mmEdit,     1, 2, 1, 1);
0195     grid->addWidget(d->digitalZoomRatioCheck,   2, 0, 1, 1);
0196     grid->addWidget(d->digitalZoomRatioEdit,    2, 2, 1, 1);
0197     grid->addWidget(d->apertureCheck,           3, 0, 1, 1);
0198     grid->addWidget(d->apertureCB,              3, 2, 1, 1);
0199     grid->addWidget(d->maxApertureCheck,        4, 0, 1, 1);
0200     grid->addWidget(d->maxApertureCB,           4, 2, 1, 1);
0201     grid->setColumnStretch(1, 10);
0202     grid->setRowStretch(5, 10);
0203 
0204     int spacing = qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0205                        QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing));
0206 
0207     grid->setContentsMargins(spacing, spacing, spacing, spacing);
0208     grid->setSpacing(spacing);
0209 
0210     // --------------------------------------------------------
0211 
0212     connect(d->focalLengthCheck, SIGNAL(toggled(bool)),
0213             d->focalLengthEdit, SLOT(setEnabled(bool)));
0214 
0215     connect(d->focalLength35mmCheck, SIGNAL(toggled(bool)),
0216             d->focalLength35mmEdit, SLOT(setEnabled(bool)));
0217 
0218     connect(d->digitalZoomRatioCheck, SIGNAL(toggled(bool)),
0219             d->digitalZoomRatioEdit, SLOT(setEnabled(bool)));
0220 
0221     connect(d->apertureCheck, SIGNAL(toggled(bool)),
0222             d->apertureCB, SLOT(setEnabled(bool)));
0223 
0224     connect(d->maxApertureCheck, SIGNAL(toggled(bool)),
0225             d->maxApertureCB, SLOT(setEnabled(bool)));
0226 
0227     // --------------------------------------------------------
0228 
0229     connect(d->focalLength35mmCheck, SIGNAL(toggled(bool)),
0230             this, SIGNAL(signalModified()));
0231 
0232     connect(d->focalLengthCheck, SIGNAL(toggled(bool)),
0233             this, SIGNAL(signalModified()));
0234 
0235     connect(d->digitalZoomRatioCheck, SIGNAL(toggled(bool)),
0236             this, SIGNAL(signalModified()));
0237 
0238     connect(d->apertureCheck, SIGNAL(toggled(bool)),
0239             this, SIGNAL(signalModified()));
0240 
0241     connect(d->maxApertureCheck, SIGNAL(toggled(bool)),
0242             this, SIGNAL(signalModified()));
0243 
0244     // --------------------------------------------------------
0245 
0246     connect(d->apertureCB, SIGNAL(activated(int)),
0247             this, SIGNAL(signalModified()));
0248 
0249     connect(d->maxApertureCB, SIGNAL(activated(int)),
0250             this, SIGNAL(signalModified()));
0251 
0252     connect(d->focalLength35mmEdit, SIGNAL(valueChanged(int)),
0253             this, SIGNAL(signalModified()));
0254 
0255     connect(d->focalLengthEdit, SIGNAL(valueChanged(double)),
0256             this, SIGNAL(signalModified()));
0257 
0258     connect(d->digitalZoomRatioEdit, SIGNAL(valueChanged(double)),
0259             this, SIGNAL(signalModified()));
0260 }
0261 
0262 EXIFLens::~EXIFLens()
0263 {
0264     delete d;
0265 }
0266 
0267 void EXIFLens::readMetadata(const DMetadata& meta)
0268 {
0269     blockSignals(true);
0270 
0271     long int num=1, den=1;
0272     long     val=0;
0273 
0274     d->focalLengthEdit->setValue(50.0);
0275     d->focalLengthCheck->setChecked(false);
0276 
0277     if (meta.getExifTagRational("Exif.Photo.FocalLength", num, den))
0278     {
0279         d->focalLengthEdit->setValue((double)(num) / (double)(den));
0280         d->focalLengthCheck->setChecked(true);
0281     }
0282 
0283     d->focalLengthEdit->setEnabled(d->focalLengthCheck->isChecked());
0284 
0285     d->focalLength35mmEdit->setValue(10);
0286     d->focalLength35mmCheck->setChecked(false);
0287 
0288     if (meta.getExifTagLong("Exif.Photo.FocalLengthIn35mmFilm", val))
0289     {
0290         d->focalLength35mmEdit->setValue(val);
0291         d->focalLength35mmCheck->setChecked(true);
0292     }
0293 
0294     d->focalLength35mmEdit->setEnabled(d->focalLength35mmCheck->isChecked());
0295 
0296     d->digitalZoomRatioEdit->setValue(1.0);
0297     d->digitalZoomRatioCheck->setChecked(false);
0298 
0299     if (meta.getExifTagRational("Exif.Photo.DigitalZoomRatio", num, den))
0300     {
0301         d->digitalZoomRatioEdit->setValue((num == 0) ? 0.0 : (double)(num) / (double)(den));
0302         d->digitalZoomRatioCheck->setChecked(true);
0303     }
0304 
0305     d->digitalZoomRatioEdit->setEnabled(d->digitalZoomRatioCheck->isChecked());
0306 
0307     d->apertureCB->setCurrentIndex(0);
0308     d->apertureCheck->setChecked(false);
0309 
0310     if (meta.getExifTagRational("Exif.Photo.FNumber", num, den))
0311     {
0312         QString fnumber = QString::number((double)(num)/(double)(den), 'f', 1);
0313         int item        = -1;
0314 
0315         for (int i = 0 ; i < d->apertureCB->count() ; ++i)
0316         {
0317             if (d->apertureCB->itemText(i).remove(0, 2) == fnumber)
0318                 item = i;
0319         }
0320 
0321         if (item != -1)
0322         {
0323             d->apertureCB->setCurrentIndex(item);
0324             d->apertureCheck->setChecked(true);
0325         }
0326     }
0327     else if (meta.getExifTagRational("Exif.Photo.ApertureValue", num, den))
0328     {
0329         double aperture = std::pow(2.0, ((double)(num)/(double)(den))/2.0);
0330         QString fnumber = QString::number(aperture, 'f', 1);
0331         int item        = -1;
0332 
0333         for (int i = 0 ; i < d->apertureCB->count() ; ++i)
0334         {
0335             if (d->apertureCB->itemText(i).remove(0, 2) == fnumber)
0336                 item = i;
0337         }
0338 
0339         if (item != -1)
0340         {
0341             d->apertureCB->setCurrentIndex(item);
0342             d->apertureCheck->setChecked(true);
0343         }
0344         else
0345             d->apertureCheck->setValid(false);
0346     }
0347     d->apertureCB->setEnabled(d->apertureCheck->isChecked());
0348 
0349     d->maxApertureCB->setCurrentIndex(0);
0350     d->maxApertureCheck->setChecked(false);
0351 
0352     if (meta.getExifTagRational("Exif.Photo.MaxApertureValue", num, den))
0353     {
0354         double maxAperture = std::pow(2.0, ((double)(num)/(double)(den))/2.0);
0355         QString fnumber    = QString::number(maxAperture, 'f', 1);
0356         int item           = -1;
0357 
0358         for (int i = 0 ; i < d->apertureCB->count() ; ++i)
0359         {
0360             if (d->maxApertureCB->itemText(i).remove(0, 2) == fnumber)
0361                 item = i;
0362         }
0363 
0364         if (item != -1)
0365         {
0366             d->maxApertureCB->setCurrentIndex(item);
0367             d->maxApertureCheck->setChecked(true);
0368         }
0369         else
0370         {
0371             d->maxApertureCheck->setValid(false);
0372         }
0373     }
0374 
0375     d->maxApertureCB->setEnabled(d->maxApertureCheck->isChecked());
0376 
0377     blockSignals(false);
0378 }
0379 
0380 void EXIFLens::applyMetadata(const DMetadata& meta)
0381 {
0382     long int num=1, den=1;
0383 
0384     if (d->focalLengthCheck->isChecked())
0385     {
0386         meta.convertToRational(d->focalLengthEdit->value(), &num, &den, 1);
0387         meta.setExifTagRational("Exif.Photo.FocalLength", num, den);
0388     }
0389     else
0390         meta.removeExifTag("Exif.Photo.FocalLength");
0391 
0392     if (d->focalLength35mmCheck->isChecked())
0393         meta.setExifTagLong("Exif.Photo.FocalLengthIn35mmFilm", d->focalLength35mmEdit->value());
0394     else
0395         meta.removeExifTag("Exif.Photo.FocalLengthIn35mmFilm");
0396 
0397     if (d->digitalZoomRatioCheck->isChecked())
0398     {
0399         meta.convertToRational(d->digitalZoomRatioEdit->value(), &num, &den, 1);
0400         meta.setExifTagRational("Exif.Photo.DigitalZoomRatio", num, den);
0401     }
0402     else
0403         meta.removeExifTag("Exif.Photo.DigitalZoomRatio");
0404 
0405     if (d->apertureCheck->isChecked())
0406     {
0407         meta.convertToRational(d->apertureCB->currentText().remove(0, 2).toDouble(), &num, &den, 1);
0408         meta.setExifTagRational("Exif.Photo.FNumber", num, den);
0409 
0410         double fnumber  = d->apertureCB->currentText().remove(0, 2).toDouble();
0411         double aperture = 2.0*(std::log(fnumber)/std::log(2.0));
0412         meta.convertToRational(aperture, &num, &den, 8);
0413         meta.setExifTagRational("Exif.Photo.ApertureValue", num, den);
0414     }
0415     else if (d->apertureCheck->isValid())
0416     {
0417         meta.removeExifTag("Exif.Photo.FNumber");
0418         meta.removeExifTag("Exif.Photo.ApertureValue");
0419     }
0420 
0421     if (d->maxApertureCheck->isChecked())
0422     {
0423         double fnumber  = d->maxApertureCB->currentText().remove(0, 2).toDouble();
0424         double aperture = 2.0*(std::log(fnumber)/std::log(2.0));
0425         meta.convertToRational(aperture, &num, &den, 8);
0426         meta.setExifTagRational("Exif.Photo.MaxApertureValue", num, den);
0427     }
0428     else if (d->maxApertureCheck->isValid())
0429         meta.removeExifTag("Exif.Photo.MaxApertureValue");
0430 }
0431 
0432 } // namespace DigikamGenericMetadataEditPlugin
0433 
0434 #include "moc_exiflens.cpp"