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