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 - Exif metadata
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 namespace ExifInternal
0027 {
0028 
0029 FocusPoint create_af_point(float imageWidth,
0030                            float imageHeight,
0031                            float af_x_position,
0032                            float af_y_position,
0033                            float afPointWidth,
0034                            float afPointHeight,
0035                            MetaEngine::ImageOrientation orientation)
0036 {
0037     QRect region;
0038     region.moveCenter(QPoint(af_x_position, af_y_position));
0039     region.setSize(QSize(afPointWidth, afPointHeight));
0040     QSize size = QSize(imageWidth, imageHeight);
0041 
0042     qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: Exif Subject Area before rotation:" << region;
0043 
0044     if      ((orientation == MetaEngine::ORIENTATION_ROT_90)       ||
0045              (orientation == MetaEngine::ORIENTATION_ROT_90_HFLIP) ||
0046              (orientation == MetaEngine::ORIENTATION_ROT_90_VFLIP))
0047     {
0048         region.moveTo(size.height() - region.y() - region.height(), region.x());
0049         region.setSize(region.size().transposed());
0050     }
0051     else if (orientation == MetaEngine::ORIENTATION_ROT_180)
0052     {
0053         region.moveTo(size.width()  - region.x() - region.width(),
0054                       size.height() - region.y() - region.height());
0055 
0056     }
0057     else if (orientation == MetaEngine::ORIENTATION_ROT_270)
0058     {
0059         region.moveTo(region.y(), size.width() - region.x() - region.width());
0060         region.setSize(region.size().transposed());
0061     }
0062 
0063     if      ((orientation == MetaEngine::ORIENTATION_HFLIP) ||
0064              (orientation == MetaEngine::ORIENTATION_ROT_90_HFLIP))
0065     {
0066         region.moveTo(size.width() - region.x() - region.width(), region.y());
0067     }
0068     else if ((orientation == MetaEngine::ORIENTATION_VFLIP) ||
0069              (orientation == MetaEngine::ORIENTATION_ROT_90_VFLIP))
0070     {
0071         region.moveTo(region.x(), size.height() - region.y() - region.height());
0072     }
0073 
0074     qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: Exif Subject Area after rotation:" << region;
0075 
0076     FocusPoint fp(region.center().x() / imageWidth,
0077                   region.center().y() / imageHeight,
0078                   region.width()      / imageWidth,
0079                   region.height()     / imageHeight,
0080                   FocusPoint::TypePoint::SelectedInFocus);
0081 
0082     return fp;
0083 }
0084 
0085 } // namespace ExifInternal
0086 
0087 // Main function to extract af point
0088 FocusPointsExtractor::ListAFPoints FocusPointsExtractor::getAFPoints_exif() const
0089 {
0090     // NOTE: See documentation of this tag contents: https://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/subjectarea.html
0091 
0092     QStringList af_info = findValue(QLatin1String("EXIF.ExifIFD.Camera.SubjectArea")).toString()
0093                                                                                      .split(QLatin1String(" "));
0094 
0095     float af_x_position = 0;
0096     float af_y_position = 0;
0097     float afPointWidth  = 0;
0098     float afPointHeight = 0;
0099 
0100     switch (af_info.size())
0101     {
0102         case 4:
0103         {
0104             // Get center coordinates of AF point.
0105 
0106             af_x_position = af_info[0].toFloat();
0107             af_y_position = af_info[1].toFloat();
0108 
0109             // Get size of af area.
0110 
0111             afPointWidth  = af_info[2].toFloat();
0112             afPointHeight = af_info[3].toFloat();
0113 
0114             break;
0115         }
0116 
0117         case 3:
0118         {
0119             // Get center coordinates of AF point.
0120 
0121             af_x_position = af_info[0].toFloat();
0122             af_y_position = af_info[1].toFloat();
0123 
0124             // Get size of af area (typically a circle transformed as rectangle).
0125 
0126             afPointWidth  = af_info[3].toFloat();
0127             afPointHeight = af_info[3].toFloat();
0128 
0129             break;
0130         }
0131 
0132         case 2:
0133         {
0134             // Get center coordinates of AF point.
0135 
0136             af_x_position = af_info[0].toFloat();
0137             af_y_position = af_info[1].toFloat();
0138 
0139             // Get size of af area (typically a point transformed an arbritary square of size 120 pixels).
0140 
0141             afPointWidth  = 120.0F;
0142             afPointHeight = 120.0F;
0143 
0144             break;
0145         }
0146 
0147         default:    // Other sizes are not valid
0148         {
0149             qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: Invalid Exif Subject Area.";
0150 
0151             // Fail-back to XMP metadata if exists.
0152 
0153             return getAFPoints_xmp();
0154         }
0155     }
0156 
0157     QSizeF fs = QSizeF(originalSize());
0158 
0159     qCDebug(DIGIKAM_METAENGINE_LOG) << "FocusPointsExtractor: Exif Subject Area:" << af_info;
0160 
0161     ListAFPoints points;
0162     FocusPoint afpoint = ExifInternal::create_af_point(
0163                                                        fs.width(),
0164                                                        fs.height(),
0165                                                        af_x_position,
0166                                                        af_y_position,
0167                                                        afPointWidth,
0168                                                        afPointHeight,
0169                                                        orientation()
0170                                                       );
0171 
0172     if (afpoint.getRect().isValid())
0173     {
0174         points << afpoint;
0175     }
0176 
0177     return points;
0178 }
0179 
0180 } // namespace Digikam