1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2006-02-23
7  * Description : item metadata interface - photo info helpers.
8  *
9  * Copyright (C) 2006-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C) 2006-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
11  * Copyright (C) 2011      by Leif Huhn <leif at dkstat dot com>
12  *
13  * This program is free software; you can redistribute it
14  * and/or modify it under the terms of the GNU General
15  * Public License as published by the Free Software Foundation;
16  * either version 2, or (at your option)
17  * any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * ============================================================ */
25 
26 #include "dmetadata.h"
27 
28 // C++ includes
29 
30 #include <cmath>
31 
32 // Qt includes
33 
34 #include <QLocale>
35 
36 // Local includes
37 
38 #include "metaenginesettings.h"
39 #include "digikam_version.h"
40 #include "digikam_globals.h"
41 #include "digikam_debug.h"
42 
43 namespace Digikam
44 {
45 
getPhotographInformation() const46 PhotoInfoContainer DMetadata::getPhotographInformation() const
47 {
48     PhotoInfoContainer photoInfo;
49 
50     if (hasExif() || hasXmp())
51     {
52         photoInfo.dateTime = getItemDateTime();
53 
54         // -----------------------------------------------------------------------------------
55 
56         photoInfo.make     = getExifTagString("Exif.Image.Make");
57 
58         if (photoInfo.make.isEmpty())
59         {
60             photoInfo.make = getXmpTagString("Xmp.tiff.Make");
61         }
62 
63         if (photoInfo.make.isEmpty())
64         {
65             photoInfo.make = getExifTagString("Exif.PanasonicRaw.Make");
66         }
67 
68         // -----------------------------------------------------------------------------------
69 
70         photoInfo.model    = getExifTagString("Exif.Image.Model");
71 
72         if (photoInfo.model.isEmpty())
73         {
74             photoInfo.model = getXmpTagString("Xmp.tiff.Model");
75         }
76 
77         if (photoInfo.model.isEmpty())
78         {
79             photoInfo.model = getExifTagString("Exif.PanasonicRaw.Model");
80         }
81 
82         // -----------------------------------------------------------------------------------
83 
84         photoInfo.lens     = getLensDescription();
85 
86         // -----------------------------------------------------------------------------------
87 
88         photoInfo.aperture = getExifTagString("Exif.Photo.FNumber");
89 
90         if (photoInfo.aperture.isEmpty())
91         {
92             photoInfo.aperture = getExifTagString("Exif.Image.FNumber");
93         }
94 
95         if (photoInfo.aperture.isEmpty())
96         {
97             photoInfo.aperture = getExifTagString("Exif.Photo.ApertureValue");
98         }
99 
100         if (photoInfo.aperture.isEmpty())
101         {
102             photoInfo.aperture = getXmpTagString("Xmp.exif.FNumber");
103         }
104 
105         if (photoInfo.aperture.isEmpty())
106         {
107             photoInfo.aperture = getXmpTagString("Xmp.exif.ApertureValue");
108         }
109 
110         // -----------------------------------------------------------------------------------
111 
112         photoInfo.exposureTime = getExifTagString("Exif.Photo.ExposureTime");
113 
114         if (photoInfo.exposureTime.isEmpty())
115         {
116             photoInfo.exposureTime = getExifTagString("Exif.Image.ExposureTime");
117         }
118 
119         if (photoInfo.exposureTime.isEmpty())
120         {
121             photoInfo.exposureTime = getExifTagString("Exif.Photo.ShutterSpeedValue");
122         }
123 
124         if (photoInfo.exposureTime.isEmpty())
125         {
126             photoInfo.exposureTime = getXmpTagString("Xmp.exif.ExposureTime");
127         }
128 
129         if (photoInfo.exposureTime.isEmpty())
130         {
131             photoInfo.exposureTime = getXmpTagString("Xmp.exif.ShutterSpeedValue");
132         }
133 
134         // -----------------------------------------------------------------------------------
135 
136         photoInfo.exposureMode    = getExifTagString("Exif.Photo.ExposureMode");
137 
138         if (photoInfo.exposureMode.isEmpty())
139         {
140             photoInfo.exposureMode = getXmpTagString("Xmp.exif.ExposureMode");
141         }
142 
143         if (photoInfo.exposureMode.isEmpty())
144         {
145             photoInfo.exposureMode = getExifTagString("Exif.CanonCs.MeteringMode");
146         }
147 
148         // -----------------------------------------------------------------------------------
149 
150         photoInfo.exposureProgram = getExifTagString("Exif.Photo.ExposureProgram");
151 
152         if (photoInfo.exposureProgram.isEmpty())
153         {
154             photoInfo.exposureProgram = getXmpTagString("Xmp.exif.ExposureProgram");
155         }
156 
157         if (photoInfo.exposureProgram.isEmpty())
158         {
159             photoInfo.exposureProgram = getExifTagString("Exif.CanonCs.ExposureProgram");
160         }
161 
162         // -----------------------------------------------------------------------------------
163 
164         photoInfo.focalLength     = getExifTagString("Exif.Photo.FocalLength");
165 
166         if (photoInfo.focalLength.isEmpty())
167         {
168             photoInfo.focalLength = getXmpTagString("Exif.Image.FocalLength");
169         }
170 
171         if (photoInfo.focalLength.isEmpty())
172         {
173             photoInfo.focalLength = getXmpTagString("Xmp.exif.FocalLength");
174         }
175 
176         if (photoInfo.focalLength.isEmpty())
177         {
178             photoInfo.focalLength = getExifTagString("Exif.Canon.FocalLength");
179         }
180 
181         // -----------------------------------------------------------------------------------
182 
183         photoInfo.focalLength35mm = getExifTagString("Exif.Photo.FocalLengthIn35mmFilm");
184 
185         if (photoInfo.focalLength35mm.isEmpty())
186         {
187             photoInfo.focalLength35mm = getXmpTagString("Xmp.exif.FocalLengthIn35mmFilm");
188         }
189 
190         // -----------------------------------------------------------------------------------
191 
192         QStringList ISOSpeedTags;
193 
194         ISOSpeedTags << QLatin1String("Exif.Photo.ISOSpeedRatings");
195         ISOSpeedTags << QLatin1String("Exif.Photo.ExposureIndex");
196         ISOSpeedTags << QLatin1String("Exif.Image.ISOSpeedRatings");
197         ISOSpeedTags << QLatin1String("Xmp.exif.ISOSpeedRatings");
198         ISOSpeedTags << QLatin1String("Xmp.exif.ExposureIndex");
199         ISOSpeedTags << QLatin1String("Exif.CanonSi.ISOSpeed");
200         ISOSpeedTags << QLatin1String("Exif.CanonCs.ISOSpeed");
201         ISOSpeedTags << QLatin1String("Exif.Nikon1.ISOSpeed");
202         ISOSpeedTags << QLatin1String("Exif.Nikon2.ISOSpeed");
203         ISOSpeedTags << QLatin1String("Exif.Nikon3.ISOSpeed");
204         ISOSpeedTags << QLatin1String("Exif.NikonIi.ISO");
205         ISOSpeedTags << QLatin1String("Exif.NikonIi.ISO2");
206         ISOSpeedTags << QLatin1String("Exif.MinoltaCsNew.ISOSetting");
207         ISOSpeedTags << QLatin1String("Exif.MinoltaCsOld.ISOSetting");
208         ISOSpeedTags << QLatin1String("Exif.MinoltaCs5D.ISOSpeed");
209         ISOSpeedTags << QLatin1String("Exif.MinoltaCs7D.ISOSpeed");
210         ISOSpeedTags << QLatin1String("Exif.Sony1Cs.ISOSetting");
211         ISOSpeedTags << QLatin1String("Exif.Sony2Cs.ISOSetting");
212         ISOSpeedTags << QLatin1String("Exif.Sony1Cs2.ISOSetting");
213         ISOSpeedTags << QLatin1String("Exif.Sony2Cs2.ISOSetting");
214         ISOSpeedTags << QLatin1String("Exif.Sony1MltCsA100.ISOSetting");
215         ISOSpeedTags << QLatin1String("Exif.PanasonicRaw.ISOSpeed");
216         ISOSpeedTags << QLatin1String("Exif.Pentax.ISO");
217         ISOSpeedTags << QLatin1String("Exif.Olympus.ISOSpeed");
218         ISOSpeedTags << QLatin1String("Exif.Samsung2.ISO");
219 
220         photoInfo.sensitivity = getExifTagStringFromTagsList(ISOSpeedTags);
221 
222         // -----------------------------------------------------------------------------------
223 
224         photoInfo.flash = getExifTagString("Exif.Photo.Flash");
225 
226         if (photoInfo.flash.isEmpty())
227         {
228             photoInfo.flash = getXmpTagString("Xmp.exif.Flash");
229         }
230 
231         if (photoInfo.flash.isEmpty())
232         {
233             photoInfo.flash = getExifTagString("Exif.CanonCs.FlashActivity");
234         }
235 
236         // -----------------------------------------------------------------------------------
237 
238         photoInfo.whiteBalance = getExifTagString("Exif.Photo.WhiteBalance");
239 
240         if (photoInfo.whiteBalance.isEmpty())
241         {
242             photoInfo.whiteBalance = getXmpTagString("Xmp.exif.WhiteBalance");
243         }
244 
245         // -----------------------------------------------------------------------------------
246 
247         double l, L, a;
248         photoInfo.hasCoordinates = getGPSInfo(a, l, L);
249     }
250 
251     return photoInfo;
252 }
253 
getLensDescription() const254 QString DMetadata::getLensDescription() const
255 {
256     QString     lens;
257     QStringList lensExifTags;
258 
259     // In first, try to get Lens information from makernotes.
260 
261     lensExifTags.append(QLatin1String("Exif.CanonCs.LensType"));      ///< Canon Cameras Makernote.
262     lensExifTags.append(QLatin1String("Exif.CanonCs.Lens"));          ///< Canon Cameras Makernote.
263     lensExifTags.append(QLatin1String("Exif.Canon.0x0095"));          ///< Alternative Canon Cameras Makernote.
264     lensExifTags.append(QLatin1String("Exif.NikonLd1.LensIDNumber")); ///< Nikon Cameras Makernote.
265     lensExifTags.append(QLatin1String("Exif.NikonLd2.LensIDNumber")); ///< Nikon Cameras Makernote.
266     lensExifTags.append(QLatin1String("Exif.NikonLd3.LensIDNumber")); ///< Nikon Cameras Makernote.
267     lensExifTags.append(QLatin1String("Exif.Minolta.LensID"));        ///< Minolta Cameras Makernote.
268     lensExifTags.append(QLatin1String("Exif.Sony1.LensID"));          ///< Sony Cameras Makernote.
269     lensExifTags.append(QLatin1String("Exif.Sony2.LensID"));          ///< Sony Cameras Makernote.
270     lensExifTags.append(QLatin1String("Exif.SonyMinolta.LensID"));    ///< Sony Cameras Makernote.
271     lensExifTags.append(QLatin1String("Exif.Pentax.LensType"));       ///< Pentax Cameras Makernote.
272     lensExifTags.append(QLatin1String("Exif.PentaxDng.LensType"));    ///< Pentax Cameras Makernote.
273     lensExifTags.append(QLatin1String("Exif.Panasonic.0x0051"));      ///< Panasonic Cameras Makernote.
274     lensExifTags.append(QLatin1String("Exif.Panasonic.0x0310"));      ///< Panasonic Cameras Makernote.
275     lensExifTags.append(QLatin1String("Exif.Sigma.LensRange"));       ///< Sigma Cameras Makernote.
276     lensExifTags.append(QLatin1String("Exif.Samsung2.LensType"));     ///< Samsung Cameras Makernote.
277     lensExifTags.append(QLatin1String("Exif.Photo.0xFDEA"));          ///< Non-standard Exif tag set by Camera Raw.
278     lensExifTags.append(QLatin1String("Exif.OlympusEq.LensType"));    ///< Olympus Cameras Makernote.
279     lensExifTags.append(QLatin1String("Exif.OlympusEq.LensModel"));   ///< Olympus Cameras Makernote.
280 
281     // Check Makernotes first.
282 
283     // Sony Cameras Makernote and others.
284 
285     QString make      = getExifTagString("Exif.Image.Make");
286     QString lensModel = QLatin1String("Exif.Photo.LensModel");
287 
288     if (make.contains(QLatin1String("SONY"), Qt::CaseInsensitive))
289     {
290         lensExifTags.prepend(lensModel);
291     }
292     else
293     {
294         lensExifTags.append(lensModel);
295     }
296 
297     // TODO : add Fuji camera Makernotes.
298 
299     // -------------------------------------------------------------------
300     // Try to get Lens Data information from Exif.
301 
302     for (QStringList::const_iterator it = lensExifTags.constBegin() ; it != lensExifTags.constEnd() ; ++it)
303     {
304         lens = getExifTagString((*it).toLatin1().constData());
305 
306         // To prevent undecoded tag values from Exiv2 as "(65535)"
307         // or the value "----" from Exif.Photo.LensModel
308 
309         if (!lens.isEmpty()                        &&
310             (lens != QLatin1String("----"))        &&
311             (lens != QLatin1String("65535"))       &&
312             !(lens.startsWith(QLatin1Char('('))    &&
313               lens.endsWith(QLatin1Char(')'))
314              )
315            )
316         {
317             return lens;
318         }
319     }
320 
321     // -------------------------------------------------------------------
322     // Try to get Lens Data information from XMP.
323     // XMP aux tags.
324 
325     lens = getXmpTagString("Xmp.aux.Lens");
326 
327     if (lens.isEmpty())
328     {
329         // XMP M$ tags (Lens Maker + Lens Model).
330 
331         lens = getXmpTagString("Xmp.MicrosoftPhoto.LensManufacturer");
332 
333         if (!lens.isEmpty())
334         {
335             lens.append(QLatin1Char(' '));
336         }
337 
338         lens.append(getXmpTagString("Xmp.MicrosoftPhoto.LensModel"));
339     }
340 
341     return lens;
342 }
343 
getCameraSerialNumber() const344 QString DMetadata::getCameraSerialNumber() const
345 {
346     QString sn = getExifTagString("Exif.Image.CameraSerialNumber");
347 
348     if (sn.isEmpty())
349     {
350         sn = getExifTagString("Exif.Canon.SerialNumber");
351     }
352 
353     if (sn.isEmpty())
354     {
355         sn = getExifTagString("Exif.Fujifilm.SerialNumber");
356     }
357 
358     if (sn.isEmpty())
359     {
360         sn = getExifTagString("Exif.Nikon3.SerialNumber");
361     }
362 
363     if (sn.isEmpty())
364     {
365         sn = getExifTagString("Exif.Nikon3.SerialNO");
366     }
367 
368     if (sn.isEmpty())
369     {
370         sn = getExifTagString("Exif.OlympusEq.SerialNumber");
371     }
372 
373     if (sn.isEmpty())
374     {
375         sn = getExifTagString("Exif.Olympus.SerialNumber2");
376     }
377 
378     if (sn.isEmpty())
379     {
380         sn = getExifTagString("Exif.OlympusEq.InternalSerialNumber");
381     }
382 
383     if (sn.isEmpty())
384     {
385         sn = getExifTagString("Exif.Panasonic.InternalSerialNumber");
386     }
387 
388     if (sn.isEmpty())
389     {
390         sn = getExifTagString("Exif.Sigma.SerialNumber");
391     }
392 
393     if (sn.isEmpty())
394     {
395         sn = getExifTagString("Exif.Sigma.SerialNumber");
396     }
397 
398     if (sn.isEmpty())
399     {
400         sn = getExifTagString("Exif.Sigma.SerialNumber");
401     }
402 
403     if (sn.isEmpty())
404     {
405         sn = getExifTagString("Exif.Pentax.SerialNumber");
406     }
407 
408     if (sn.isEmpty())
409     {
410         sn = getXmpTagString("Xmp.exifEX.BodySerialNumber");
411     }
412 
413     if (sn.isEmpty())
414     {
415         sn = getXmpTagString("Xmp.aux.SerialNumber");
416     }
417 
418     if (sn.isEmpty())
419     {
420         sn = getXmpTagString("Xmp.MicrosoftPhoto.CameraSerialNumber");
421     }
422 
423     return sn;
424 }
425 
apexApertureToFNumber(double aperture)426 double DMetadata::apexApertureToFNumber(double aperture)
427 {
428     // convert from APEX. See Exif spec, Annex C.
429 
430     if      (aperture == 0.0)
431     {
432         return 1;
433     }
434     else if (aperture == 1.0)
435     {
436         return 1.4;
437     }
438     else if (aperture == 2.0)
439     {
440         return 2;
441     }
442     else if (aperture == 3.0)
443     {
444         return 2.8;
445     }
446     else if (aperture == 4.0)
447     {
448         return 4;
449     }
450     else if (aperture == 5.0)
451     {
452         return 5.6;
453     }
454     else if (aperture == 6.0)
455     {
456         return 8;
457     }
458     else if (aperture == 7.0)
459     {
460         return 11;
461     }
462     else if (aperture == 8.0)
463     {
464         return 16;
465     }
466     else if (aperture == 9.0)
467     {
468         return 22;
469     }
470     else if (aperture == 10.0)
471     {
472         return 32;
473     }
474 
475     return exp(log(2) * aperture / 2.0);
476 }
477 
apexShutterSpeedToExposureTime(double shutterSpeed)478 double DMetadata::apexShutterSpeedToExposureTime(double shutterSpeed)
479 {
480     // convert from APEX. See Exif spec, Annex C.
481 
482     if      (shutterSpeed == -5.0)
483     {
484         return 30;
485     }
486     else if (shutterSpeed == -4.0)
487     {
488         return 15;
489     }
490     else if (shutterSpeed == -3.0)
491     {
492         return 8;
493     }
494     else if (shutterSpeed == -2.0)
495     {
496         return 4;
497     }
498     else if (shutterSpeed == -1.0)
499     {
500         return 2;
501     }
502     else if (shutterSpeed == 0.0)
503     {
504         return 1;
505     }
506     else if (shutterSpeed == 1.0)
507     {
508         return 0.5;
509     }
510     else if (shutterSpeed == 2.0)
511     {
512         return 0.25;
513     }
514     else if (shutterSpeed == 3.0)
515     {
516         return 0.125;
517     }
518     else if (shutterSpeed == 4.0)
519     {
520         return 1.0 / 15.0;
521     }
522     else if (shutterSpeed == 5.0)
523     {
524         return 1.0 / 30.0;
525     }
526     else if (shutterSpeed == 6.0)
527     {
528         return 1.0 / 60.0;
529     }
530     else if (shutterSpeed == 7.0)
531     {
532         return 0.008;    // 1/125
533     }
534     else if (shutterSpeed == 8.0)
535     {
536         return 0.004;    // 1/250
537     }
538     else if (shutterSpeed == 9.0)
539     {
540         return 0.002;    // 1/500
541     }
542     else if (shutterSpeed == 10.0)
543     {
544         return 0.001;    // 1/1000
545     }
546     else if (shutterSpeed == 11.0)
547     {
548         return 0.0005;    // 1/2000
549     }
550     // supplemental rules
551     else if (shutterSpeed == 12.0)
552     {
553         return 0.00025;    // 1/4000
554     }
555     else if (shutterSpeed == 13.0)
556     {
557         return 0.000125;    // 1/8000
558     }
559 
560     return exp( - log(2) * shutterSpeed);
561 }
562 
563 } // namespace Digikam
564