File indexing completed on 2022-10-04 17:30:13

0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 // SPDX-FileCopyrightText: 2008 Dominik Seichter <domseichter@web.de>
0003 
0004 #include "exiv2plugin.h"
0005 
0006 #include "../config-krename.h"
0007 
0008 #include <KLocalizedString>
0009 
0010 #include <exiv2/error.hpp>
0011 #include <exiv2/exif.hpp>
0012 #include <exiv2/image.hpp>
0013 #include <exiv2/iptc.hpp>
0014 #ifdef HAVE_LIBEXIV2_0_27
0015     #include <exiv2/xmp_exiv2.hpp>
0016 #else
0017     #include <exiv2/xmp.hpp>
0018 #endif
0019 #include <exiv2/tags.hpp>
0020 
0021 #include "batchrenamer.h"
0022 #include "tokenhelpdialog.h"
0023 
0024 using namespace Exiv2;
0025 
0026 static const char *exifTags[] = {
0027     "Exif.Image.ImageWidth",
0028     "Exif.Image.ImageLength",
0029     "Exif.Image.BitsPerSample",
0030     "Exif.Image.Compression",
0031     "Exif.Image.PhotometricInterpretation",
0032     "Exif.Image.Orientation",
0033     "Exif.Image.SamplesPerPixel",
0034     "Exif.Image.PlanarConfiguration",
0035     "Exif.Image.YCbCrSubSampling",
0036     "Exif.Image.YCbCrPositioning",
0037     "Exif.Image.XResolution",
0038     "Exif.Image.YResolution",
0039     "Exif.Image.ResolutionUnit",
0040     "Exif.Image.TransferFunction",
0041     "Exif.Image.WhitePoint",
0042     "Exif.Image.PrimaryChromaticities",
0043     "Exif.Image.YCbCrCoefficients",
0044     "Exif.Image.ReferenceBlackWhite",
0045     "Exif.Image.DateTime",
0046     "Exif.Image.ImageDescription",
0047     "Exif.Image.Make",
0048     "Exif.Image.Model",
0049     "Exif.Image.Software",
0050     "Exif.Image.Artist",
0051     "Exif.Image.Copyright",
0052     "Exif.Photo.ExifVersion",
0053     "Exif.Photo.FlashpixVersion",
0054     "Exif.Photo.ColorSpace",
0055     "Exif.Photo.ComponentsConfiguration",
0056     "Exif.Photo.CompressedBitsPerPixel",
0057     "Exif.Photo.PixelXDimension",
0058     "Exif.Photo.PixelYDimension",
0059     "Exif.Photo.UserComment",
0060     "Exif.Photo.RelatedSoundFile",
0061     "Exif.Photo.DateTimeOriginal",
0062     "Exif.Photo.DateTimeDigitized",
0063     "Exif.Photo.ExposureTime",
0064     "Exif.Photo.FNumber",
0065     "Exif.Photo.ExposureProgram",
0066     "Exif.Photo.SpectralSensitivity",
0067     "Exif.Photo.ISOSpeedRatings",
0068     "Exif.Photo.OECF",
0069     "Exif.Photo.ShutterSpeedValue",
0070     "Exif.Photo.ApertureValue",
0071     "Exif.Photo.BrightnessValue",
0072     "Exif.Photo.ExposureBiasValue",
0073     "Exif.Photo.MaxApertureValue",
0074     "Exif.Photo.SubjectDistance",
0075     "Exif.Photo.MeteringMode",
0076     "Exif.Photo.LightSource",
0077     "Exif.Photo.Flash",
0078     "Exif.Photo.FocalLength",
0079     "Exif.Photo.SubjectArea",
0080     "Exif.Photo.FlashEnergy",
0081     "Exif.Photo.SpatialFrequencyResponse",
0082     "Exif.Photo.FocalPlaneXResolution",
0083     "Exif.Photo.FocalPlaneYResolution",
0084     "Exif.Photo.FocalPlaneResolutionUnit",
0085     "Exif.Photo.SubjectLocation",
0086     "Exif.Photo.ExposureIndex",
0087     "Exif.Photo.SensingMethod",
0088     "Exif.Photo.FileSource",
0089     "Exif.Photo.SceneType",
0090     "Exif.Photo.CFAPattern",
0091     "Exif.Photo.CustomRendered",
0092     "Exif.Photo.ExposureMode",
0093     "Exif.Photo.WhiteBalance",
0094     "Exif.Photo.DigitalZoomRatio",
0095     "Exif.Photo.FocalLengthIn35mmFilm",
0096     "Exif.Photo.SceneCaptureType",
0097     "Exif.Photo.GainControl",
0098     "Exif.Photo.Contrast",
0099     "Exif.Photo.Saturation",
0100     "Exif.Photo.Sharpness",
0101     "Exif.Photo.DeviceSettingDescription",
0102     "Exif.Photo.SubjectDistanceRange",
0103     "Exif.Photo.ImageUniqueID",
0104     "Exif.GPSInfo.GPSVersionID",
0105     "Exif.GPSInfo.GPSLatitude",
0106     "Exif.GPSInfo.GPSLongitude",
0107     "Exif.GPSInfo.GPSAltitudeRef",
0108     "Exif.GPSInfo.GPSAltitude",
0109     "Exif.GPSInfo.GPSTimeStamp",
0110     "Exif.GPSInfo.GPSSatellites",
0111     "Exif.GPSInfo.GPSStatus",
0112     "Exif.GPSInfo.GPSMeasureMode",
0113     "Exif.GPSInfo.GPSDOP",
0114     "Exif.GPSInfo.GPSSpeedRef",
0115     "Exif.GPSInfo.GPSSpeed",
0116     "Exif.GPSInfo.GPSTrackRef",
0117     "Exif.GPSInfo.GPSTrack",
0118     "Exif.GPSInfo.GPSImgDirectionRef",
0119     "Exif.GPSInfo.GPSImgDirection",
0120     "Exif.GPSInfo.GPSMapDatum",
0121     "Exif.GPSInfo.GPSDestLatitude",
0122     "Exif.GPSInfo.GPSDestLongitude",
0123     "Exif.GPSInfo.GPSDestBearingRef",
0124     "Exif.GPSInfo.GPSDestBearing",
0125     "Exif.GPSInfo.GPSDestDistanceRef",
0126     "Exif.GPSInfo.GPSDestDistance",
0127     "Exif.GPSInfo.GPSProcessingMethod",
0128     "Exif.GPSInfo.GPSAreaInformation",
0129     "Exif.GPSInfo.GPSDifferential",
0130     nullptr
0131 };
0132 
0133 static const char *xmpTags[] = {
0134     "Xmp.tiff.ImageWidth",
0135     "Xmp.tiff.ImageLength",
0136     "Xmp.tiff.BitsPerSample",
0137     "Xmp.tiff.Compression",
0138     "Xmp.tiff.PhotometricInterpretation",
0139     "Xmp.tiff.Orientation",
0140     "Xmp.tiff.SamplesPerPixe",
0141     "Xmp.tiff.PlanarConfiguration",
0142     "Xmp.tiff.YCbCrSubSampling",
0143     "Xmp.tiff.YCbCrPositioning",
0144     "Xmp.tiff.XResolution",
0145     "Xmp.tiff.YResolution",
0146     "Xmp.tiff.ResolutionUnit",
0147     "Xmp.tiff.TransferFunction",
0148     "Xmp.tiff.WhitePoint",
0149     "Xmp.tiff.PrimaryChromaticities",
0150     "Xmp.tiff.YCbCrCoefficients",
0151     "Xmp.tiff.ReferenceBlackWhite",
0152     "Xmp.tiff.DateTime",
0153     "Xmp.dc.description",
0154     "Xmp.tiff.Make",
0155     "Xmp.tiff.Model",
0156     "Xmp.tiff.Software",
0157     "Xmp.dc.creator",
0158     "Xmp.dc.rights",
0159     "Xmp.exif.ExifVersion",
0160     "Xmp.exif.FlashpixVersion",
0161     "Xmp.exif.ColorSpace",
0162     "Xmp.exif.ComponentsConfiguration",
0163     "Xmp.exif.CompressedBitsPerPixel",
0164     "Xmp.exif.PixelXDimension",
0165     "Xmp.exif.PixelYDimension",
0166     "Xmp.exif.UserComment",
0167     "Xmp.exif.RelatedSoundFile",
0168     "Xmp.exif.DateTimeOriginal",
0169     "Xmp.exif.DateTimeDigitized",
0170     "Xmp.exif.ExposureTime",
0171     "Xmp.exif.FNumber",
0172     "Xmp.exif.ExposureProgram",
0173     "Xmp.exif.SpectralSensitivity",
0174     "Xmp.exif.ISOSpeedRatings",
0175     "Xmp.exif.OECF",
0176     "Xmp.exif.ShutterSpeedValue",
0177     "Xmp.exif.ApertureValue",
0178     "Xmp.exif.BrightnessValue",
0179     "Xmp.exif.ExposureBiasValue",
0180     "Xmp.exif.MaxApertureValue",
0181     "Xmp.exif.SubjectDistance",
0182     "Xmp.exif.MeteringMode",
0183     "Xmp.exif.LightSource",
0184     "Xmp.exif.Flash",
0185     "Xmp.exif.FocalLength",
0186     "Xmp.exif.SubjectArea",
0187     "Xmp.exif.FlashEnergy",
0188     "Xmp.exif.SpatialFrequencyResponse",
0189     "Xmp.exif.FocalPlaneXResolution",
0190     "Xmp.exif.FocalPlaneYResolution",
0191     "Xmp.exif.FocalPlaneResolutionUnit",
0192     "Xmp.exif.SubjectLocation",
0193     "Xmp.exif.ExposureIndex",
0194     "Xmp.exif.SensingMethod",
0195     "Xmp.exif.FileSource",
0196     "Xmp.exif.SceneType",
0197     "Xmp.exif.CFAPattern",
0198     "Xmp.exif.CustomRendered",
0199     "Xmp.exif.ExposureMode",
0200     "Xmp.exif.WhiteBalance",
0201     "Xmp.exif.DigitalZoomRatio",
0202     "Xmp.exif.FocalLengthIn35mmFilm",
0203     "Xmp.exif.SceneCaptureType",
0204     "Xmp.exif.GainControl",
0205     "Xmp.exif.Contrast",
0206     "Xmp.exif.Saturation",
0207     "Xmp.exif.Sharpness",
0208     "Xmp.exif.DeviceSettingDescription",
0209     "Xmp.exif.SubjectDistanceRange",
0210     "Xmp.exif.ImageUniqueID",
0211     "Xmp.exif.GPSVersionID",
0212     "Xmp.exif.GPSLatitude",
0213     "Xmp.exif.GPSLongitude",
0214     "Xmp.exif.GPSAltitudeRef",
0215     "Xmp.exif.GPSAltitude",
0216     "Xmp.exif.GPSTimeStamp",
0217     "Xmp.exif.GPSSatellites",
0218     "Xmp.exif.GPSStatus",
0219     "Xmp.exif.GPSMeasureMode",
0220     "Xmp.exif.GPSDOP",
0221     "Xmp.exif.GPSSpeedRef",
0222     "Xmp.exif.GPSSpeed",
0223     "Xmp.exif.GPSTrackRef",
0224     "Xmp.exif.GPSTrack",
0225     "Xmp.exif.GPSImgDirectionRef",
0226     "Xmp.exif.GPSImgDirection",
0227     "Xmp.exif.GPSMapDatum",
0228     "Xmp.exif.GPSDestLatitude",
0229     "Xmp.exif.GPSDestLongitude",
0230     "Xmp.exif.GPSDestBearingRef",
0231     "Xmp.exif.GPSDestBearing",
0232     "Xmp.exif.GPSDestDistanceRef",
0233     "Xmp.exif.GPSDestDistance",
0234     "Xmp.exif.GPSProcessingMethod",
0235     "Xmp.exif.GPSAreaInformation",
0236     "Xmp.exif.GPSDifferential",
0237     "Xmp.dc.title",
0238     "Xmp.photoshop.Urgency",
0239     "Xmp.photoshop.Category",
0240     "Xmp.photoshop.SupplementalCategory",
0241     "Xmp.dc.subject",
0242     "Xmp.iptc.Location",
0243     "Xmp.photoshop.Instruction",
0244     "Xmp.photoshop.DateCreated",
0245     "Xmp.dc.creator",
0246     "Xmp.photoshop.AuthorsPosition",
0247     "Xmp.photoshop.City",
0248     "Xmp.photoshop.State",
0249     "Xmp.iptc.CountryCode",
0250     "Xmp.photoshop.Country",
0251     "Xmp.photoshop.TransmissionReference",
0252     "Xmp.photoshop.Headline",
0253     "Xmp.photoshop.Credit",
0254     "Xmp.photoshop.Source",
0255     "Xmp.dc.rights",
0256     "Xmp.dc.description",
0257     "Xmp.photoshop.CaptionWriter",
0258     nullptr
0259 };
0260 
0261 static const char *iptcTags[] = {
0262     "Iptc.Application2.ObjectName",
0263     "Iptc.Application2.Urgency",
0264     "Iptc.Application2.Category",
0265     "Iptc.Application2.SuppCategory",
0266     "Iptc.Application2.Keywords",
0267     "Iptc.Application2.LocationName",
0268     "Iptc.Application2.SpecialInstructions",
0269     "Iptc.Application2.DateCreated",
0270     "Iptc.Application2.Byline",
0271     "Iptc.Application2.BylineTitle",
0272     "Iptc.Application2.City",
0273     "Iptc.Application2.ProvinceState",
0274     "Iptc.Application2.CountryCode",
0275     "Iptc.Application2.CountryName",
0276     "Iptc.Application2.TransmissionReference",
0277     "Iptc.Application2.Headline",
0278     "Iptc.Application2.Credit",
0279     "Iptc.Application2.Source",
0280     "Iptc.Application2.Copyright",
0281     "Iptc.Application2.Caption",
0282     "Iptc.Application2.Writer",
0283     nullptr
0284 };
0285 
0286 Exiv2Plugin::Exiv2Plugin(PluginLoader *loader)
0287     : FilePlugin(loader)
0288 {
0289     const QString prefix("exif");
0290     const char **token;
0291 
0292     this->addSupportedToken("exifComment");
0293     //this->addSupportedToken("exifWidth");
0294     //this->addSupportedToken("exifHeight");
0295     m_help.append("[exifComment]" + TokenHelpDialog::getTokenSeparator() + i18n("Insert the comment of an image"));
0296     //m_help.append( "[exifWidth]" + TokenHelpDialog::getTokenSeparator() + i18n("Insert the width in pixel of an image") );
0297     //m_help.append( "[exifHeight]" + TokenHelpDialog::getTokenSeparator() + i18n("Insert the height in pixel of an image") );
0298 
0299     // Add exif taks
0300     token = exifTags;
0301     while (*token) {
0302         ExifKey key(*token);
0303         QString help;
0304         try {
0305             help = QString::fromUtf8(key.tagLabel().c_str());
0306         } catch (const std::exception &e) {
0307             help = "";
0308             // exiv2 throws sometimes exceptions
0309             // because it tries to create std::string from NULL pointers
0310         }
0311 
0312         QString cur(*token);
0313         this->addSupportedToken(prefix + cur);
0314         m_help.append(QString("[") + prefix + cur + QString("]")  + TokenHelpDialog::getTokenSeparator() + help);
0315 
0316         m_mapRealKeys[QString(prefix + cur).toLower()] = cur;
0317         ++token;
0318     }
0319 
0320     // Add exif taks
0321     token = xmpTags;
0322     while (*token) {
0323         XmpKey key(*token);
0324         QString help;
0325         try {
0326             help = QString::fromUtf8(key.tagLabel().c_str());
0327         } catch (const std::exception &e) {
0328             help = "";
0329             // exiv2 throws sometimes exceptions
0330             // because it tries to create std::string from NULL pointers
0331         }
0332 
0333         QString cur(*token);
0334         this->addSupportedToken(prefix + cur);
0335         m_help.append(QString("[") + prefix + cur + QString("]") + TokenHelpDialog::getTokenSeparator() + help);
0336 
0337         m_mapRealKeys[QString(prefix + cur).toLower()] = cur;
0338         ++token;
0339     }
0340 
0341     // Add exif taks
0342     token = iptcTags;
0343     while (*token) {
0344         IptcKey key(*token);
0345         QString help;
0346         try {
0347             help = QString::fromUtf8(key.tagLabel().c_str());
0348         } catch (const std::exception &e) {
0349             help = "";
0350             // exiv2 throws sometimes exceptions
0351             // because it tries to create std::string from NULL pointers
0352         }
0353 
0354         QString cur(*token);
0355         this->addSupportedToken(prefix + cur);
0356         m_help.append(QString("[") + prefix + cur + QString("]") + TokenHelpDialog::getTokenSeparator() + help);
0357 
0358         m_mapRealKeys[QString(prefix + cur).toLower()] = cur;
0359         ++token;
0360     }
0361 
0362     m_name = i18n("Exiv2 (JPEG/TIFF Exif) Plugin");
0363     m_comment = i18n("<qt>This plugin supports reading tags from "
0364                      "JPEG and TIFF files.</qt>");
0365 
0366     m_icon = "image-x-generic";
0367 }
0368 
0369 QString Exiv2Plugin::processFile(BatchRenamer *b, int index, const QString &filenameOrToken, EPluginType)
0370 {
0371     QString token(filenameOrToken.toLower());
0372     QString filename = (*b->files())[index].srcUrl().path();
0373 
0374     if (!this->supports(token)) {
0375         return QString("");
0376     }
0377 
0378     //const QByteArray asc = filename.toAscii();
0379     // Use toUtf8 so that unicode filenames will work
0380     const QByteArray asc = filename.toUtf8();
0381     std::string strFilename(asc.constData(), asc.length());
0382 
0383     try {
0384         Image::AutoPtr image = Exiv2::ImageFactory::open(strFilename);
0385         if (image.get() != nullptr && image->good()) {
0386             image->readMetadata();
0387 
0388             if (token == "exifcomment") {
0389                 return QString::fromUtf8(image->comment().c_str());
0390             }
0391             /*
0392               else if( token =="exifwidth" )
0393               return QString::number( image->pixelWidth() );
0394               else if( token =="exifheight" )
0395               return QString::number( image->pixelHeight() );
0396             */
0397             if (token.startsWith(QLatin1String("exifexif."))) {
0398                 ExifKey key(m_mapRealKeys[token].toLatin1().data());
0399                 ExifData::const_iterator it = image->exifData().findKey(key);
0400                 if (it != image->exifData().end()) {
0401                     std::string val = (*it).toString();
0402                     return QString::fromUtf8(val.c_str());
0403                 }
0404             } else if (token.startsWith(QLatin1String("exifxmp."))) {
0405                 XmpKey key(m_mapRealKeys[token].toLatin1().data());
0406                 XmpData::const_iterator it = image->xmpData().findKey(key);
0407                 if (it != image->xmpData().end()) {
0408                     std::string val = (*it).toString();
0409                     return QString::fromUtf8(val.c_str());
0410                 }
0411             } else if (token.startsWith(QLatin1String("exifiptc."))) {
0412                 IptcKey key(m_mapRealKeys[token].toLatin1().data());
0413                 IptcData::const_iterator it = image->iptcData().findKey(key);
0414                 if (it != image->iptcData().end()) {
0415                     std::string val = (*it).toString();
0416                     return QString::fromUtf8(val.c_str());
0417                 }
0418             }
0419         }
0420     } catch (const std::exception &err) {
0421         return QString::fromUtf8(err.what());
0422     }
0423 
0424     return QString("");
0425 }