File indexing completed on 2025-01-05 03:56:31

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 28/08/2021
0007  * Description : Extraction of focus points by exiftool data
0008  *
0009  * SPDX-FileCopyrightText: 2021-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2021 by Phuoc Khanh Le <phuockhanhnk94 at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "focuspoints_extractor.h"
0017 
0018 // Local includes
0019 
0020 #include "exiftoolparser.h"
0021 #include "digikam_debug.h"
0022 
0023 namespace Digikam
0024 {
0025 
0026 class Q_DECL_HIDDEN FocusPointsExtractor::Private
0027 {
0028 
0029 public:
0030 
0031     explicit Private()
0032         : exifToolAvailable(false),
0033           afPointsReadOnly (true),
0034           orientation      (MetaEngine::ORIENTATION_UNSPECIFIED)
0035     {
0036     }
0037 
0038     ListAFPoints                    af_points;          ///< List of AF points extracted from metadata.
0039     bool                            exifToolAvailable;  ///< True if ExifTool binary is available.
0040     ExifToolParser::ExifToolData    metadata;           ///< List of tags parsed by ExifTool.
0041     bool                            afPointsReadOnly;   ///< True if AF points are read-only in metadata.
0042     QString                         make;               ///< Camera Manufacturer Name
0043     QString                         model;              ///< Camera Model Name.
0044     QSize                           originalSize;       ///< Original size of image taken by camera
0045     MetaEngine::ImageOrientation    orientation;        ///< Image orientation set by camera.
0046 };
0047 
0048 FocusPointsExtractor::FocusPointsExtractor(QObject* const parent,const QString& image_path)
0049     : QObject(parent),
0050       d      (new Private)
0051 {
0052     QScopedPointer<ExifToolParser> const parser(new ExifToolParser(this));
0053 
0054     if (parser->exifToolAvailable())
0055     {
0056         parser->load(image_path);
0057     }
0058 
0059     d->exifToolAvailable = parser->exifToolAvailable();
0060     d->metadata          = parser->currentData();
0061     d->make              = findValue(QLatin1String("EXIF.IFD0.Camera.Make")).toString();
0062     d->make              = d->make.split(QLatin1String(" "))[0].toUpper();
0063     d->model             = findValue(QLatin1String("EXIF.IFD0.Camera.Model")).toString();
0064     d->model             = d->model.split(QLatin1String(" "))[0].toUpper();
0065 
0066     // NOTE: init image size properties with generic values taken from file by default,
0067     //       this will be overwrited by delegate with findADPoints().
0068 
0069     QVariant imageWidth  = findValue(QLatin1String("File.File.Image.ImageWidth"));
0070     QVariant imageHeight = findValue(QLatin1String("File.File.Image.ImageHeight"));
0071     setOriginalSize(QSize(imageWidth.toInt(), imageHeight.toInt()));
0072 
0073     QVariant direction   = findNumValue(QLatin1String("EXIF.IFD0.Image.Orientation"));
0074     d->orientation       = direction.isNull() ? MetaEngine::ORIENTATION_UNSPECIFIED
0075                                               : (MetaEngine::ImageOrientation)direction.toInt();
0076     qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: orientation:" << d->orientation;
0077 
0078     d->af_points         = findAFPoints();
0079 }
0080 
0081 FocusPointsExtractor::~FocusPointsExtractor()
0082 {
0083     delete d;
0084 }
0085 
0086 QVariant FocusPointsExtractor::findValue(const QString& tagName, bool isList) const
0087 {
0088     QVariantList result = d->metadata.value(tagName);
0089 
0090     if (result.empty())
0091     {
0092         return QVariant();
0093     }
0094 
0095     if (isList)
0096     {
0097         QString str = result[0].toString();
0098 
0099         if (str.contains(QLatin1Char(',')))
0100         {
0101             return str.split(QLatin1Char(','));
0102         }
0103         else
0104         {
0105             return str.split(QLatin1Char(' '));
0106         }
0107     }
0108     else
0109     {
0110         return result[0];
0111     }
0112 }
0113 
0114 QVariant FocusPointsExtractor::findNumValue(const QString& tagName) const
0115 {
0116     QVariantList result = d->metadata.value(tagName);
0117 
0118     if (result.empty() || (result.size() < 4))
0119     {
0120         return QVariant();
0121     }
0122 
0123     return result[3];
0124 }
0125 
0126 QVariant FocusPointsExtractor::findValue(const QString& tagNameRoot, const QString& key, bool isList) const
0127 {
0128     return findValue(tagNameRoot + QLatin1String(".") + key, isList);
0129 }
0130 
0131 QVariant FocusPointsExtractor::findValueFirstMatch(const QStringList& listTagNames, bool isList) const
0132 {
0133     for (const QString& tagName : listTagNames)
0134     {
0135         QVariant tmp = findValue(tagName, isList);
0136 
0137         if (!tmp.isNull())
0138         {
0139             return tmp;
0140         }
0141     }
0142 
0143     return QVariant();
0144 }
0145 
0146 QVariant FocusPointsExtractor::findValueFirstMatch(const QString& tagNameRoot, const QStringList& keys, bool isList) const
0147 {
0148     for (const QString& key : keys)
0149     {
0150         QVariant tmp = findValue(tagNameRoot, key, isList);
0151 
0152         if (!tmp.isNull())
0153         {
0154             return tmp;
0155         }
0156     }
0157 
0158     return QVariant();
0159 }
0160 
0161 FocusPointsExtractor::ListAFPoints FocusPointsExtractor::findAFPoints() const
0162 {
0163     if (!d->exifToolAvailable)
0164     {
0165         return ListAFPoints();
0166     }
0167 
0168     if (!d->make.isNull())
0169     {
0170         if (d->make == QLatin1String("APPLE"))
0171         {
0172             qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: use Apple Exif metadata";
0173 
0174             return getAFPoints_exif();
0175         }
0176 
0177         if (d->make == QLatin1String("CANON"))
0178         {
0179             qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: use Canon makernotes";
0180 
0181             return getAFPoints_canon();
0182         }
0183 
0184         if (d->make == QLatin1String("NIKON"))
0185         {
0186             qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: use Nikon makernotes";
0187 
0188             return getAFPoints_nikon();
0189         }
0190 
0191         if (d->make == QLatin1String("PANASONIC"))
0192         {
0193             qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: use Panasonic makernotes";
0194 
0195             return getAFPoints_panasonic();
0196         }
0197 
0198         if (d->make == QLatin1String("SONY"))
0199         {
0200             qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: use Sony makernotes";
0201 
0202             return getAFPoints_sony();
0203         }
0204     }
0205 
0206     qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: use Exif or XMP metadata";
0207 
0208     return getAFPoints_exif();
0209 }
0210 
0211 FocusPointsExtractor::ListAFPoints FocusPointsExtractor::get_af_points(FocusPoint::TypePoint type)
0212 {
0213     ListAFPoints points;
0214 
0215     for (const auto& point : d->af_points)
0216     {
0217         if (type == FocusPoint::TypePoint::Inactive)
0218         {
0219             if (point.getType() == type)
0220             {
0221                 points.push_back(point);
0222             }
0223         }
0224         else
0225         {
0226             if ((point.getType() & type) == type)
0227             {
0228                 points.push_back(point);
0229             }
0230         }
0231     }
0232 
0233     return points;
0234 }
0235 
0236 FocusPointsExtractor::ListAFPoints FocusPointsExtractor::get_af_points()
0237 {
0238     return d->af_points;
0239 }
0240 
0241 bool FocusPointsExtractor::isAFPointsReadOnly() const
0242 {
0243     findAFPoints();
0244 
0245     return d->afPointsReadOnly;
0246 }
0247 
0248 void FocusPointsExtractor::setAFPointsReadOnly(bool readOnly) const
0249 {
0250     d->afPointsReadOnly = readOnly;
0251 }
0252 
0253 void FocusPointsExtractor::setOriginalSize(const QSize& size) const
0254 {
0255     d->originalSize = size;
0256 }
0257 
0258 QSize FocusPointsExtractor::originalSize() const
0259 {
0260     return d->originalSize;
0261 }
0262 
0263 QString FocusPointsExtractor::make() const
0264 {
0265     return d->make;
0266 }
0267 
0268 QString FocusPointsExtractor::model() const
0269 {
0270     return d->model;
0271 }
0272 
0273 MetaEngine::ImageOrientation FocusPointsExtractor::orientation() const
0274 {
0275     return d->orientation;
0276 }
0277 
0278 } // namespace Digikam
0279 
0280 #include "moc_focuspoints_extractor.cpp"