File indexing completed on 2025-01-19 03:55:58

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2006-02-23
0007  * Description : item metadata interface - photo info helpers.
0008  *
0009  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2006-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0011  * SPDX-FileCopyrightText: 2011      by Leif Huhn <leif at dkstat dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "dmetadata.h"
0018 
0019 // C++ includes
0020 
0021 #include <cmath>
0022 
0023 // Qt includes
0024 
0025 #include <QLocale>
0026 
0027 // Local includes
0028 
0029 #include "metaenginesettings.h"
0030 #include "digikam_version.h"
0031 #include "digikam_globals.h"
0032 #include "digikam_debug.h"
0033 
0034 namespace Digikam
0035 {
0036 
0037 PhotoInfoContainer DMetadata::getPhotographInformation() const
0038 {
0039     PhotoInfoContainer photoInfo;
0040 
0041     if (hasExif() || hasXmp())
0042     {
0043         photoInfo.dateTime = getItemDateTime();
0044 
0045         // -----------------------------------------------------------------------------------
0046 
0047         photoInfo.make     = getExifTagString("Exif.Image.Make");
0048 
0049         if (photoInfo.make.isEmpty())
0050         {
0051             photoInfo.make = getXmpTagString("Xmp.tiff.Make");
0052         }
0053 
0054         if (photoInfo.make.isEmpty())
0055         {
0056             photoInfo.make = getExifTagString("Exif.PanasonicRaw.Make");
0057         }
0058 
0059         // -----------------------------------------------------------------------------------
0060 
0061         photoInfo.model    = getExifTagString("Exif.Image.Model");
0062 
0063         if (photoInfo.model.isEmpty())
0064         {
0065             photoInfo.model = getXmpTagString("Xmp.tiff.Model");
0066         }
0067 
0068         if (photoInfo.model.isEmpty())
0069         {
0070             photoInfo.model = getExifTagString("Exif.PanasonicRaw.Model");
0071         }
0072 
0073         // -----------------------------------------------------------------------------------
0074 
0075         photoInfo.lens     = getLensDescription();
0076 
0077         // -----------------------------------------------------------------------------------
0078 
0079         photoInfo.aperture = getExifTagString("Exif.Photo.FNumber");
0080 
0081         if (photoInfo.aperture.isEmpty())
0082         {
0083             photoInfo.aperture = getExifTagString("Exif.Image.FNumber");
0084         }
0085 
0086         if (photoInfo.aperture.isEmpty())
0087         {
0088             photoInfo.aperture = getExifTagString("Exif.Photo.ApertureValue");
0089         }
0090 
0091         if (photoInfo.aperture.isEmpty())
0092         {
0093             photoInfo.aperture = getXmpTagString("Xmp.exif.FNumber");
0094         }
0095 
0096         if (photoInfo.aperture.isEmpty())
0097         {
0098             photoInfo.aperture = getXmpTagString("Xmp.exif.ApertureValue");
0099         }
0100 
0101         // -----------------------------------------------------------------------------------
0102 
0103         photoInfo.exposureTime = getExifTagString("Exif.Photo.ExposureTime");
0104 
0105         if (photoInfo.exposureTime.isEmpty())
0106         {
0107             photoInfo.exposureTime = getExifTagString("Exif.Image.ExposureTime");
0108         }
0109 
0110         if (photoInfo.exposureTime.isEmpty())
0111         {
0112             photoInfo.exposureTime = getExifTagString("Exif.Photo.ShutterSpeedValue");
0113         }
0114 
0115         if (photoInfo.exposureTime.isEmpty())
0116         {
0117             photoInfo.exposureTime = getXmpTagString("Xmp.exif.ExposureTime");
0118         }
0119 
0120         if (photoInfo.exposureTime.isEmpty())
0121         {
0122             photoInfo.exposureTime = getXmpTagString("Xmp.exif.ShutterSpeedValue");
0123         }
0124 
0125         // -----------------------------------------------------------------------------------
0126 
0127         photoInfo.exposureMode    = getExifTagString("Exif.Photo.ExposureMode");
0128 
0129         if (photoInfo.exposureMode.isEmpty())
0130         {
0131             photoInfo.exposureMode = getXmpTagString("Xmp.exif.ExposureMode");
0132         }
0133 
0134         if (photoInfo.exposureMode.isEmpty())
0135         {
0136             photoInfo.exposureMode = getExifTagString("Exif.CanonCs.MeteringMode");
0137         }
0138 
0139         // -----------------------------------------------------------------------------------
0140 
0141         photoInfo.exposureProgram = getExifTagString("Exif.Photo.ExposureProgram");
0142 
0143         if (photoInfo.exposureProgram.isEmpty())
0144         {
0145             photoInfo.exposureProgram = getXmpTagString("Xmp.exif.ExposureProgram");
0146         }
0147 
0148         if (photoInfo.exposureProgram.isEmpty())
0149         {
0150             photoInfo.exposureProgram = getExifTagString("Exif.CanonCs.ExposureProgram");
0151         }
0152 
0153         // -----------------------------------------------------------------------------------
0154 
0155         photoInfo.focalLength     = getExifTagString("Exif.Photo.FocalLength");
0156 
0157         if (photoInfo.focalLength.isEmpty())
0158         {
0159             photoInfo.focalLength = getXmpTagString("Exif.Image.FocalLength");
0160         }
0161 
0162         if (photoInfo.focalLength.isEmpty())
0163         {
0164             photoInfo.focalLength = getXmpTagString("Xmp.exif.FocalLength");
0165         }
0166 
0167         if (photoInfo.focalLength.isEmpty())
0168         {
0169             photoInfo.focalLength = getExifTagString("Exif.Canon.FocalLength");
0170         }
0171 
0172         // -----------------------------------------------------------------------------------
0173 
0174         photoInfo.focalLength35mm = getExifTagString("Exif.Photo.FocalLengthIn35mmFilm");
0175 
0176         if (photoInfo.focalLength35mm.isEmpty())
0177         {
0178             photoInfo.focalLength35mm = getXmpTagString("Xmp.exif.FocalLengthIn35mmFilm");
0179         }
0180 
0181         // -----------------------------------------------------------------------------------
0182 
0183         QStringList ISOSpeedTags;
0184 
0185         ISOSpeedTags << QLatin1String("Exif.Photo.ISOSpeedRatings");
0186         ISOSpeedTags << QLatin1String("Exif.Photo.ExposureIndex");
0187         ISOSpeedTags << QLatin1String("Exif.Image.ISOSpeedRatings");
0188         ISOSpeedTags << QLatin1String("Xmp.exif.ISOSpeedRatings");
0189         ISOSpeedTags << QLatin1String("Xmp.exif.ExposureIndex");
0190         ISOSpeedTags << QLatin1String("Exif.CanonSi.ISOSpeed");
0191         ISOSpeedTags << QLatin1String("Exif.CanonCs.ISOSpeed");
0192         ISOSpeedTags << QLatin1String("Exif.Nikon1.ISOSpeed");
0193         ISOSpeedTags << QLatin1String("Exif.Nikon2.ISOSpeed");
0194         ISOSpeedTags << QLatin1String("Exif.Nikon3.ISOSpeed");
0195         ISOSpeedTags << QLatin1String("Exif.NikonIi.ISO");
0196         ISOSpeedTags << QLatin1String("Exif.NikonIi.ISO2");
0197         ISOSpeedTags << QLatin1String("Exif.MinoltaCsNew.ISOSetting");
0198         ISOSpeedTags << QLatin1String("Exif.MinoltaCsOld.ISOSetting");
0199         ISOSpeedTags << QLatin1String("Exif.MinoltaCs5D.ISOSpeed");
0200         ISOSpeedTags << QLatin1String("Exif.MinoltaCs7D.ISOSpeed");
0201         ISOSpeedTags << QLatin1String("Exif.Sony1Cs.ISOSetting");
0202         ISOSpeedTags << QLatin1String("Exif.Sony2Cs.ISOSetting");
0203         ISOSpeedTags << QLatin1String("Exif.Sony1Cs2.ISOSetting");
0204         ISOSpeedTags << QLatin1String("Exif.Sony2Cs2.ISOSetting");
0205         ISOSpeedTags << QLatin1String("Exif.Sony1MltCsA100.ISOSetting");
0206         ISOSpeedTags << QLatin1String("Exif.PanasonicRaw.ISOSpeed");
0207         ISOSpeedTags << QLatin1String("Exif.Pentax.ISO");
0208         ISOSpeedTags << QLatin1String("Exif.Olympus.ISOSpeed");
0209         ISOSpeedTags << QLatin1String("Exif.Samsung2.ISO");
0210 
0211         photoInfo.sensitivity = getExifTagStringFromTagsList(ISOSpeedTags);
0212 
0213         // -----------------------------------------------------------------------------------
0214 
0215         photoInfo.flash = getExifTagString("Exif.Photo.Flash");
0216 
0217         if (photoInfo.flash.isEmpty())
0218         {
0219             photoInfo.flash = getXmpTagString("Xmp.exif.Flash/exif:Mode");
0220         }
0221 
0222         if (photoInfo.flash.isEmpty())
0223         {
0224             photoInfo.flash = getExifTagString("Exif.CanonCs.FlashActivity");
0225         }
0226 
0227         // -----------------------------------------------------------------------------------
0228 
0229         photoInfo.whiteBalance = getExifTagString("Exif.Photo.WhiteBalance");
0230 
0231         if (photoInfo.whiteBalance.isEmpty())
0232         {
0233             photoInfo.whiteBalance = getXmpTagString("Xmp.exif.WhiteBalance");
0234         }
0235 
0236         // -----------------------------------------------------------------------------------
0237 
0238         double l, L, a;
0239         photoInfo.hasCoordinates = getGPSInfo(a, l, L);
0240     }
0241 
0242     return photoInfo;
0243 }
0244 
0245 QString DMetadata::getLensDescription() const
0246 {
0247     QString     lens;
0248     QStringList lensExifTags;
0249 
0250     // In first, try to get Lens information from Makernotes.
0251 
0252     lensExifTags.append(QLatin1String("Exif.CanonCs.LensType"));      ///< Canon Cameras Makernote.
0253     lensExifTags.append(QLatin1String("Exif.CanonCs.Lens"));          ///< Canon Cameras Makernote.
0254     lensExifTags.append(QLatin1String("Exif.Canon.0x0095"));          ///< Alternative Canon Cameras Makernote.
0255     lensExifTags.append(QLatin1String("Exif.NikonLd1.LensIDNumber")); ///< Nikon Cameras Makernote.
0256     lensExifTags.append(QLatin1String("Exif.NikonLd2.LensIDNumber")); ///< Nikon Cameras Makernote.
0257     lensExifTags.append(QLatin1String("Exif.NikonLd3.LensIDNumber")); ///< Nikon Cameras Makernote.
0258     lensExifTags.append(QLatin1String("Exif.Minolta.LensID"));        ///< Minolta Cameras Makernote.
0259     lensExifTags.append(QLatin1String("Exif.Sony1.LensID"));          ///< Sony Cameras Makernote.
0260     lensExifTags.append(QLatin1String("Exif.Sony2.LensID"));          ///< Sony Cameras Makernote.
0261     lensExifTags.append(QLatin1String("Exif.SonyMinolta.LensID"));    ///< Sony Cameras Makernote.
0262     lensExifTags.append(QLatin1String("Exif.Pentax.LensType"));       ///< Pentax Cameras Makernote.
0263     lensExifTags.append(QLatin1String("Exif.PentaxDng.LensType"));    ///< Pentax Cameras Makernote.
0264     lensExifTags.append(QLatin1String("Exif.Panasonic.0x0051"));      ///< Panasonic Cameras Makernote.
0265     lensExifTags.append(QLatin1String("Exif.Panasonic.0x0310"));      ///< Panasonic Cameras Makernote.
0266     lensExifTags.append(QLatin1String("Exif.Sigma.LensRange"));       ///< Sigma Cameras Makernote.
0267     lensExifTags.append(QLatin1String("Exif.Samsung2.LensType"));     ///< Samsung Cameras Makernote.
0268     lensExifTags.append(QLatin1String("Exif.Photo.0xFDEA"));          ///< Non-standard Exif tag set by Camera Raw.
0269     lensExifTags.append(QLatin1String("Exif.OlympusEq.LensModel"));   ///< Olympus Cameras Makernote.
0270     lensExifTags.append(QLatin1String("Exif.OlympusEq.LensType"));    ///< Olympus Cameras Makernote.
0271 
0272     // Try Exif.Photo.LensModel for Sony and Canon first.
0273 
0274     QString make      = getExifTagString("Exif.Image.Make");
0275     QString lensModel = QLatin1String("Exif.Photo.LensModel");
0276 
0277     if      (make.contains(QLatin1String("SONY"), Qt::CaseInsensitive))
0278     {
0279         lensExifTags.prepend(lensModel);
0280     }
0281     else if (make.contains(QLatin1String("CANON"), Qt::CaseInsensitive))
0282     {
0283         QString canonLt = QLatin1String("Exif.CanonCs.LensType");
0284         QString canonCs = getExifTagString(canonLt.toLatin1().constData());
0285         QString exifMod = getExifTagString(lensModel.toLatin1().constData());
0286 
0287         if ((exifMod == QLatin1String("RF70-200mm F2.8 L IS USM"))   &&
0288             (canonCs == QLatin1String("Canon RF 70-200mm F4L IS USM")))
0289         {
0290             return QLatin1String("Canon RF 70-200mm F2.8L IS USM");
0291         }
0292         else
0293         {
0294             lensExifTags.prepend(lensModel);
0295         }
0296     }
0297     else
0298     {
0299         lensExifTags.append(lensModel);
0300     }
0301 
0302     // TODO : add Fuji camera Makernotes.
0303 
0304     // -------------------------------------------------------------------
0305     // Try to get Lens Data information from Exif.
0306 
0307     for (QStringList::const_iterator it = lensExifTags.constBegin() ; it != lensExifTags.constEnd() ; ++it)
0308     {
0309         lens = getExifTagString((*it).toLatin1().constData());
0310 
0311         // To prevent undecoded tag values from Exiv2 as "(65535)"
0312         // or the value "----" from Exif.Photo.LensModel
0313 
0314         if (!lens.isEmpty()                        &&
0315             (lens != QLatin1String("----"))        &&
0316             (lens != QLatin1String("65535"))       &&
0317             !(lens.startsWith(QLatin1Char('('))    &&
0318               lens.endsWith(QLatin1Char(')'))
0319              )
0320            )
0321         {
0322             return lens;
0323         }
0324     }
0325 
0326     // -------------------------------------------------------------------
0327     // Try to get Lens Data information from XMP.
0328     // XMP aux tags.
0329 
0330     lens = getXmpTagString("Xmp.aux.Lens");
0331 
0332     if (lens.isEmpty())
0333     {
0334         // XMP M$ tags (Lens Maker + Lens Model).
0335 
0336         lens = getXmpTagString("Xmp.MicrosoftPhoto.LensManufacturer");
0337 
0338         if (!lens.isEmpty())
0339         {
0340             lens.append(QLatin1Char(' '));
0341         }
0342 
0343         lens.append(getXmpTagString("Xmp.MicrosoftPhoto.LensModel"));
0344     }
0345 
0346     return lens;
0347 }
0348 
0349 QString DMetadata::getCameraSerialNumber() const
0350 {
0351     QString sn = getExifTagString("Exif.Image.CameraSerialNumber");
0352 
0353     if (sn.isEmpty())
0354     {
0355         sn = getExifTagString("Exif.Canon.SerialNumber");
0356     }
0357 
0358     if (sn.isEmpty())
0359     {
0360         sn = getExifTagString("Exif.Fujifilm.SerialNumber");
0361     }
0362 
0363     if (sn.isEmpty())
0364     {
0365         sn = getExifTagString("Exif.Nikon3.SerialNumber");
0366     }
0367 
0368     if (sn.isEmpty())
0369     {
0370         sn = getExifTagString("Exif.Nikon3.SerialNO");
0371     }
0372 
0373     if (sn.isEmpty())
0374     {
0375         sn = getExifTagString("Exif.OlympusEq.SerialNumber");
0376     }
0377 
0378     if (sn.isEmpty())
0379     {
0380         sn = getExifTagString("Exif.Olympus.SerialNumber2");
0381     }
0382 
0383     if (sn.isEmpty())
0384     {
0385         sn = getExifTagString("Exif.OlympusEq.InternalSerialNumber");
0386     }
0387 
0388     if (sn.isEmpty())
0389     {
0390         sn = getExifTagString("Exif.Panasonic.InternalSerialNumber");
0391     }
0392 
0393     if (sn.isEmpty())
0394     {
0395         sn = getExifTagString("Exif.Sigma.SerialNumber");
0396     }
0397 
0398     if (sn.isEmpty())
0399     {
0400         sn = getExifTagString("Exif.Sigma.SerialNumber");
0401     }
0402 
0403     if (sn.isEmpty())
0404     {
0405         sn = getExifTagString("Exif.Sigma.SerialNumber");
0406     }
0407 
0408     if (sn.isEmpty())
0409     {
0410         sn = getExifTagString("Exif.Pentax.SerialNumber");
0411     }
0412 
0413     if (sn.isEmpty())
0414     {
0415         sn = getXmpTagString("Xmp.exifEX.BodySerialNumber");
0416     }
0417 
0418     if (sn.isEmpty())
0419     {
0420         sn = getXmpTagString("Xmp.aux.SerialNumber");
0421     }
0422 
0423     if (sn.isEmpty())
0424     {
0425         sn = getXmpTagString("Xmp.MicrosoftPhoto.CameraSerialNumber");
0426     }
0427 
0428     return sn;
0429 }
0430 
0431 double DMetadata::apexApertureToFNumber(double aperture)
0432 {
0433     // convert from APEX. See Exif spec, Annex C.
0434 
0435     if      (aperture == 0.0)
0436     {
0437         return 1;
0438     }
0439     else if (aperture == 1.0)
0440     {
0441         return 1.4;
0442     }
0443     else if (aperture == 2.0)
0444     {
0445         return 2;
0446     }
0447     else if (aperture == 3.0)
0448     {
0449         return 2.8;
0450     }
0451     else if (aperture == 4.0)
0452     {
0453         return 4;
0454     }
0455     else if (aperture == 5.0)
0456     {
0457         return 5.6;
0458     }
0459     else if (aperture == 6.0)
0460     {
0461         return 8;
0462     }
0463     else if (aperture == 7.0)
0464     {
0465         return 11;
0466     }
0467     else if (aperture == 8.0)
0468     {
0469         return 16;
0470     }
0471     else if (aperture == 9.0)
0472     {
0473         return 22;
0474     }
0475     else if (aperture == 10.0)
0476     {
0477         return 32;
0478     }
0479 
0480     return exp(log(2) * aperture / 2.0);
0481 }
0482 
0483 double DMetadata::apexShutterSpeedToExposureTime(double shutterSpeed)
0484 {
0485     // convert from APEX. See Exif spec, Annex C.
0486 
0487     if      (shutterSpeed == -5.0)
0488     {
0489         return 30;
0490     }
0491     else if (shutterSpeed == -4.0)
0492     {
0493         return 15;
0494     }
0495     else if (shutterSpeed == -3.0)
0496     {
0497         return 8;
0498     }
0499     else if (shutterSpeed == -2.0)
0500     {
0501         return 4;
0502     }
0503     else if (shutterSpeed == -1.0)
0504     {
0505         return 2;
0506     }
0507     else if (shutterSpeed == 0.0)
0508     {
0509         return 1;
0510     }
0511     else if (shutterSpeed == 1.0)
0512     {
0513         return 0.5;
0514     }
0515     else if (shutterSpeed == 2.0)
0516     {
0517         return 0.25;
0518     }
0519     else if (shutterSpeed == 3.0)
0520     {
0521         return 0.125;
0522     }
0523     else if (shutterSpeed == 4.0)
0524     {
0525         return 1.0 / 15.0;
0526     }
0527     else if (shutterSpeed == 5.0)
0528     {
0529         return 1.0 / 30.0;
0530     }
0531     else if (shutterSpeed == 6.0)
0532     {
0533         return 1.0 / 60.0;
0534     }
0535     else if (shutterSpeed == 7.0)
0536     {
0537         return 0.008;    // 1/125
0538     }
0539     else if (shutterSpeed == 8.0)
0540     {
0541         return 0.004;    // 1/250
0542     }
0543     else if (shutterSpeed == 9.0)
0544     {
0545         return 0.002;    // 1/500
0546     }
0547     else if (shutterSpeed == 10.0)
0548     {
0549         return 0.001;    // 1/1000
0550     }
0551     else if (shutterSpeed == 11.0)
0552     {
0553         return 0.0005;    // 1/2000
0554     }
0555     // supplemental rules
0556     else if (shutterSpeed == 12.0)
0557     {
0558         return 0.00025;    // 1/4000
0559     }
0560     else if (shutterSpeed == 13.0)
0561     {
0562         return 0.000125;    // 1/8000
0563     }
0564 
0565     return exp( - log(2) * shutterSpeed);
0566 }
0567 
0568 } // namespace Digikam