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 - Canon devices
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 "digikam_debug.h"
0021 
0022 namespace Digikam
0023 {
0024 
0025 // Internal function to create af point from meta data
0026 
0027 namespace CanonInternal
0028 {
0029 
0030 void set_point_position(FocusPoint& point,
0031                         float imageWidth,
0032                         float imageHeight,
0033                         float af_x_position,
0034                         float af_y_position,
0035                         int yDirection)
0036 {
0037     point.setCenterPosition(0.5 + af_x_position              / imageWidth,
0038                             0.5 + af_y_position * yDirection / imageHeight);
0039 }
0040 
0041 void set_point_size(FocusPoint& point,
0042                     float imageWidth,
0043                     float imageHeight,
0044                     float afPointWidth,
0045                     float afPointHeight)
0046 {
0047     point.setSize(afPointWidth / imageWidth, afPointHeight / imageHeight);
0048 }
0049 
0050 void set_point_type(FocusPoint& point,
0051                     const QStringList& af_selected,
0052                     const QStringList& af_infocus,
0053                     int index)
0054 {
0055     point.setType(FocusPoint::TypePoint::Inactive);
0056 
0057     if (af_infocus.isEmpty() && af_selected.contains(QString::number(index)))
0058     {
0059         point.setType(FocusPoint::TypePoint::Selected);
0060     }
0061 
0062     if (af_infocus.contains(QString::number(index)))
0063     {
0064         point.setType(FocusPoint::TypePoint::SelectedInFocus);
0065     }
0066 }
0067 
0068 FocusPoint create_af_point(float imageWidth,
0069                            float imageHeight,
0070                            float afPointWidth,
0071                            float afPointHeight,
0072                            float af_x_position,
0073                            float af_y_position,
0074                            const QStringList& af_selected,
0075                            const QStringList& af_infocus,
0076                            int   yDirection,
0077                            int   index)
0078 {
0079     FocusPoint point;
0080 
0081     set_point_position(point,
0082                        imageWidth,
0083                        imageHeight,
0084                        af_x_position,
0085                        af_y_position,
0086                        yDirection);
0087 
0088     set_point_size(point,
0089                    imageWidth,
0090                    imageHeight,
0091                    afPointWidth,
0092                    afPointHeight);
0093 
0094     set_point_type(point,
0095                    af_selected,
0096                    af_infocus,
0097                    index);
0098 
0099     return point;
0100 }
0101 
0102 } // namespace CanonInternal
0103 
0104 // Main function to extract af point
0105 FocusPointsExtractor::ListAFPoints FocusPointsExtractor::getAFPoints_canon() const
0106 {
0107     QString TagNameRoot = QLatin1String("MakerNotes.Canon.Camera");
0108 
0109     // Get size image
0110 
0111     QString model       = findValue(QLatin1String("EXIF.IFD0.Camera.Make")).toString();
0112 
0113     QVariant imageWidth, imageHeight;
0114 
0115     if (model.toLower() == QLatin1String("canon eos 5d"))
0116     {
0117         imageWidth  = findValueFirstMatch(QStringList()
0118                                           << QLatin1String("MakerNotes.Canon.Image.CanonImageWidth")
0119                                           << QLatin1String("EXIF.ExifIFD.Image.ExifImageWidth")
0120         );
0121 
0122         imageHeight = findValueFirstMatch(QStringList()
0123                                           << QLatin1String("MakerNotes.Canon.Image.CanonImageHeight")
0124                                           << QLatin1String("EXIF.ExifIFD.Image.ExifImageHeight")
0125         );
0126     }
0127     else
0128     {
0129         imageWidth = findValueFirstMatch(QStringList()
0130                                          << QLatin1String("MakerNotes.Canon.Camera.AFImageWidth")
0131                                          << QLatin1String("EXIF.ExifIFD.Image.ExifImageWidth")
0132         );
0133 
0134         imageHeight = findValueFirstMatch(QStringList()
0135                                           << QLatin1String("MakerNotes.Canon.Camera.AFImageHeight")
0136                                           << QLatin1String("EXIF.ExifIFD.Image.ExifImageHeight")
0137         );
0138     }
0139 
0140     if (imageWidth.isNull() || imageHeight.isNull())
0141     {
0142         qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: invalid Canon Camera image sizes.";
0143 
0144         return getAFPoints_exif();
0145     }
0146 
0147     setOriginalSize(QSize(imageWidth.toInt(), imageHeight.toInt()));
0148 
0149     // Get size of af points
0150 
0151     QVariant afPointWidth      = findValue(TagNameRoot, QLatin1String("AFAreaWidth"));
0152     QVariant afPointHeight     = findValue(TagNameRoot, QLatin1String("AFAreaHeight"));
0153     QStringList afPointWidths  = findValue(TagNameRoot, QLatin1String("AFAreaWidths"),  true).toStringList();
0154     QStringList afPointHeights = findValue(TagNameRoot, QLatin1String("AFAreaHeights"), true).toStringList();
0155 
0156     if (((afPointWidth.isNull())   || (afPointHeight.isNull())) &&
0157         ((afPointWidths.isEmpty()) || (afPointHeights.isEmpty())))
0158     {
0159         qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: invalid sizes from Canon makernotes.";
0160 
0161         return getAFPoints_exif();
0162     }
0163 
0164     // Get coordinate of af points
0165 
0166     QStringList af_x_positions = findValue(TagNameRoot, QLatin1String("AFAreaXPositions"), true).toStringList();
0167     QStringList af_y_positions = findValue(TagNameRoot, QLatin1String("AFAreaYPositions"), true).toStringList();
0168 
0169     if (af_x_positions.isEmpty() || af_y_positions.isEmpty())
0170     {
0171         qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: invalid positions from Canon makernotes.";
0172 
0173         return getAFPoints_exif();
0174     }
0175 
0176     qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: Canon makernotes focus Xs/Ys size:" << af_x_positions.size()
0177                                                                                                   << af_y_positions.size();
0178 
0179     qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: Canon makernotes focus W/H value :" << afPointWidth
0180                                                                                                   << afPointHeight;
0181 
0182     qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: Canon makernotes focus Ws/Hs size:" << afPointWidths.size()
0183                                                                                                   << afPointHeights.size();
0184 
0185     // Get type of af points
0186 
0187     QStringList af_selected = findValueFirstMatch(TagNameRoot, QStringList() << QLatin1String("AFPointsSelected")
0188                                                                              << QLatin1String("AFPointsInFocus"),
0189                                                   true).toStringList();
0190     QStringList af_infocus  = findValue(TagNameRoot, QLatin1String("AFPointsInFocus"), true).toStringList();
0191 
0192     // Check and remove possible (none) keyword
0193 
0194     if (af_infocus.size() == 1)
0195     {
0196         bool ok     = false;
0197         int afPoint = af_infocus.first().toInt(&ok);
0198 
0199         if ((afPoint == 0) && !ok)
0200         {
0201             af_infocus.clear();
0202         }
0203     }
0204 
0205     // If we have focus points in AFPointsInFocus,
0206     // remove them from AFPointsSelected
0207 
0208     Q_FOREACH (const QString& key, af_infocus)
0209     {
0210         af_selected.removeAll(key);
0211     }
0212 
0213     // Get direction
0214 
0215     QString cameraType      = findValue(TagNameRoot, QLatin1String("CameraType")).toString().toUpper();
0216 
0217     int yDirection          = 1;
0218 
0219     if ((cameraType == QLatin1String("COMPACT"))    ||
0220         (cameraType == QLatin1String("EOS HIGH-END")))
0221     {
0222         yDirection = -1;
0223     }
0224 
0225     ListAFPoints points;
0226 
0227     for (int i = 0 ; i < af_x_positions.count() ; ++i)
0228     {
0229         float afPointWidthUsed  = (afPointWidths.isEmpty()) ? afPointWidth.toFloat()
0230                                                             : afPointWidths[i].toFloat();
0231 
0232         float afPointHeightUsed = (afPointWidths.isEmpty()) ? afPointHeight.toFloat()
0233                                                             : afPointWidths[i].toFloat();
0234 
0235         FocusPoint point        = CanonInternal::create_af_point(
0236                                                                  imageWidth.toFloat(),
0237                                                                  imageHeight.toFloat(),
0238                                                                  afPointWidthUsed,
0239                                                                  afPointHeightUsed,
0240                                                                  af_x_positions[i].toFloat(),
0241                                                                  af_y_positions[i].toFloat(),
0242                                                                  af_selected,
0243                                                                  af_infocus,
0244                                                                  yDirection,
0245                                                                  i
0246                                                                 );
0247 
0248         if (!point.getRect().isValid())
0249         {
0250             continue;
0251         }
0252 
0253         points.append(point);
0254     }
0255 
0256     return points;
0257 }
0258 
0259 } // namespace Digikam