8 #include "exiv2extractor.h"
11 using namespace KFileMetaData;
14 Exiv2Extractor::Exiv2Extractor(
QObject* parent)
17 #ifdef EXV_ENABLE_BMFF
18 Exiv2::enableBMFF(
true);
25 QStringLiteral(
"image/bmp"),
26 QStringLiteral(
"image/gif"),
27 QStringLiteral(
"image/jp2"),
28 QStringLiteral(
"image/jpeg"),
29 QStringLiteral(
"image/pgf"),
30 QStringLiteral(
"image/png"),
31 QStringLiteral(
"image/tiff"),
32 #ifdef HAVE_WEBP_SUPPORT
33 QStringLiteral(
"image/webp"),
35 #ifdef EXV_ENABLE_BMFF
36 QStringLiteral(
"image/avif"),
37 QStringLiteral(
"image/heif"),
38 QStringLiteral(
"image/jxl"),
39 QStringLiteral(
"image/x-canon-cr3"),
41 QStringLiteral(
"image/x-exv"),
42 QStringLiteral(
"image/x-canon-cr2"),
43 QStringLiteral(
"image/x-canon-crw"),
44 QStringLiteral(
"image/x-fuji-raf"),
45 QStringLiteral(
"image/x-minolta-mrw"),
46 QStringLiteral(
"image/x-nikon-nef"),
47 QStringLiteral(
"image/x-olympus-orf"),
48 QStringLiteral(
"image/x-panasonic-rw2"),
49 QStringLiteral(
"image/x-pentax-pef"),
50 QStringLiteral(
"image/x-photoshop"),
51 QStringLiteral(
"image/x-samsung-srw"),
52 QStringLiteral(
"image/x-tga"),
57 const std::string str = value.toString();
61 QVariant toVariantDateTime(
const Exiv2::Value& value)
63 if (value.typeId() == Exiv2::asciiString) {
75 QVariant toVariantLong(
const Exiv2::Value& value)
77 if (value.typeId() == Exiv2::unsignedLong || value.typeId() == Exiv2::signedLong) {
78 qlonglong val = value.toLong();
84 int val = str.toInt(&ok);
92 QVariant toVariantDouble(
const Exiv2::Value& value)
94 if (value.typeId() == Exiv2::tiffFloat || value.typeId() == Exiv2::tiffDouble
95 || value.typeId() == Exiv2::unsignedRational || value.typeId() == Exiv2::signedRational) {
96 return QVariant(
static_cast<double>(value.toFloat()));
101 double val = str.toDouble(&ok);
109 QVariant toVariantString(
const Exiv2::Value& value)
120 if (value.count() == 0) {
125 return toVariantLong(value);
128 return toVariantDateTime(value);
131 return toVariantDouble(value);
135 return toVariantString(value);
142 return supportedMimeTypes;
148 std::string fileString(arr.
data(), arr.
length());
150 #if EXIV2_TEST_VERSION(0, 28, 0)
151 Exiv2::Image::UniquePtr image;
153 Exiv2::Image::AutoPtr image;
156 image = Exiv2::ImageFactory::open(fileString);
157 }
catch (
const std::exception&) {
165 image->readMetadata();
166 }
catch (
const std::exception&) {
171 if (!(result->
inputFlags() & ExtractionResult::ExtractMetaData)) {
175 if (image->pixelHeight()) {
176 result->
add(Property::Height, image->pixelHeight());
179 if (image->pixelWidth()) {
180 result->
add(Property::Width, image->pixelWidth());
183 std::string comment = image->comment();
184 if (!comment.empty()) {
188 const Exiv2::ExifData& data = image->exifData();
197 add(result, data, Property::ImageOrientation,
"Exif.Image.Orientation",
QVariant::Int);
199 add(result, data, Property::PhotoPixelXDimension,
"Exif.Photo.PixelXDimension",
QVariant::Int);
200 add(result, data, Property::PhotoPixelYDimension,
"Exif.Photo.PixelYDimension",
QVariant::Int);
201 add(result, data, Property::PhotoDateTimeOriginal,
"Exif.Photo.DateTimeOriginal",
QVariant::DateTime);
203 add(result, data, Property::PhotoFocalLengthIn35mmFilm,
"Exif.Photo.FocalLengthIn35mmFilm",
QVariant::Double);
204 add(result, data, Property::PhotoExposureTime,
"Exif.Photo.ExposureTime",
QVariant::Double);
205 add(result, data, Property::PhotoExposureBiasValue,
"Exif.Photo.ExposureBiasValue",
QVariant::Double);
207 add(result, data, Property::PhotoApertureValue,
"Exif.Photo.ApertureValue",
QVariant::Double);
208 add(result, data, Property::PhotoWhiteBalance,
"Exif.Photo.WhiteBalance",
QVariant::Int);
209 add(result, data, Property::PhotoMeteringMode,
"Exif.Photo.MeteringMode",
QVariant::Int);
210 add(result, data, Property::PhotoISOSpeedRatings,
"Exif.Photo.ISOSpeedRatings",
QVariant::Int);
211 add(result, data, Property::PhotoSaturation,
"Exif.Photo.Saturation",
QVariant::Int);
212 add(result, data, Property::PhotoSharpness,
"Exif.Photo.Sharpness",
QVariant::Int);
214 double latitude = fetchGpsDouble(data,
"Exif.GPSInfo.GPSLatitude");
215 double longitude = fetchGpsDouble(data,
"Exif.GPSInfo.GPSLongitude");
216 double altitude = fetchGpsAltitude(data);
218 QByteArray latRef = fetchByteArray(data,
"Exif.GPSInfo.GPSLatitudeRef");
219 if (!latRef.
isEmpty() && latRef[0] ==
'S') {
223 QByteArray longRef = fetchByteArray(data,
"Exif.GPSInfo.GPSLongitudeRef");
224 if (!longRef.
isEmpty() && longRef[0] ==
'W') {
228 if (!std::isnan(latitude)) {
229 result->
add(Property::PhotoGpsLatitude, latitude);
232 if (!std::isnan(longitude)) {
233 result->
add(Property::PhotoGpsLongitude, longitude);
236 if (!std::isnan(altitude)) {
237 result->
add(Property::PhotoGpsAltitude, altitude);
241 void Exiv2Extractor::add(
ExtractionResult* result,
const Exiv2::ExifData& data,
245 Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name));
246 if (it != data.end()) {
247 QVariant value = toVariant(it->value(), type);
249 result->
add(prop, value);
254 double Exiv2Extractor::fetchGpsDouble(
const Exiv2::ExifData& data,
const char* name)
256 Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name));
257 if (it != data.end() && it->count() == 3) {
261 n = (*it).toRational(0).first;
262 d = (*it).toRational(0).second;
265 return std::numeric_limits<double>::quiet_NaN();
270 n = (*it).toRational(1).first;
271 d = (*it).toRational(1).second;
282 n = (*it).toRational(2).first;
283 d = (*it).toRational(2).second;
297 return std::numeric_limits<double>::quiet_NaN();
300 double Exiv2Extractor::fetchGpsAltitude(
const Exiv2::ExifData& data)
302 double alt = std::numeric_limits<double>::quiet_NaN();
303 Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitude"));
304 if (it != data.end() && it->count() > 0 &&
305 (it->value().typeId() == Exiv2::unsignedRational || it->value().typeId() == Exiv2::signedRational)) {
306 auto ratio = it->value().toRational();
307 if (ratio.second == 0) {
310 it = data.findKey(Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitudeRef"));
311 if (it != data.end() && it->count() > 0 &&
312 (it->value().typeId() == Exiv2::unsignedByte || it->value().typeId() == Exiv2::signedByte)) {
313 auto altRef = it->value().toLong();
315 alt = -1.0 * ratio.first / ratio.second;
317 alt = 1.0 * ratio.first / ratio.second;
324 QByteArray Exiv2Extractor::fetchByteArray(
const Exiv2::ExifData& data,
const char* name)
326 Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name));
327 if (it != data.end() && it->count() > 0) {
328 std::string str = it->value().toString();