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"