File indexing completed on 2024-05-26 05:54:53

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