File indexing completed on 2025-01-05 03:53:10
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2012-03-15 0007 * Description : a tool to create panorama by fusion of several images. 0008 * 0009 * SPDX-FileCopyrightText: 2012-2016 by Benjamin Girault <benjamin dot girault at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "copyfilestask.h" 0016 0017 // Qt includes 0018 0019 #include <QFileInfo> 0020 #include <QDateTime> 0021 #include <QScopedPointer> 0022 0023 // KDE includes 0024 0025 #include <klocalizedstring.h> 0026 0027 // Local includes 0028 0029 #include "digikam_debug.h" 0030 #include "drawdecoder.h" 0031 #include "panomanager.h" 0032 0033 namespace DigikamGenericPanoramaPlugin 0034 { 0035 0036 CopyFilesTask::CopyFilesTask(const QString& workDirPath, 0037 const QUrl& panoUrl, 0038 const QUrl& finalPanoUrl, 0039 const QUrl& ptoUrl, 0040 const PanoramaItemUrlsMap& urls, 0041 bool sPTO, 0042 bool GPlusMetadata) 0043 : PanoTask(PANO_COPY, workDirPath), 0044 panoUrl(panoUrl), 0045 finalPanoUrl(finalPanoUrl), 0046 ptoUrl(ptoUrl), 0047 urlList(&urls), 0048 savePTO(sPTO), 0049 addGPlusMetadata(GPlusMetadata) 0050 { 0051 } 0052 0053 CopyFilesTask::~CopyFilesTask() 0054 { 0055 } 0056 0057 void CopyFilesTask::run(ThreadWeaver::JobPointer, ThreadWeaver::Thread*) 0058 { 0059 QFile panoFile(panoUrl.toLocalFile()); 0060 QFile finalPanoFile(finalPanoUrl.toLocalFile()); 0061 0062 QFileInfo fi(finalPanoUrl.toLocalFile()); 0063 QUrl finalPTOUrl = finalPanoUrl.adjusted(QUrl::RemoveFilename); 0064 finalPTOUrl.setPath(finalPTOUrl.path() + fi.completeBaseName() + QLatin1String(".pto")); 0065 0066 QFile ptoFile(ptoUrl.toLocalFile()); 0067 QFile finalPTOFile(finalPTOUrl.toLocalFile()); 0068 0069 if (!panoFile.exists()) 0070 { 0071 errString = i18n("Temporary panorama file does not exists."); 0072 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Temporary panorama file does not exists: " << panoUrl; 0073 successFlag = false; 0074 return; 0075 } 0076 0077 if (finalPanoFile.exists()) 0078 { 0079 errString = i18n("A panorama file named <filename>%1</filename> already exists.", finalPanoUrl.fileName()); 0080 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Final panorama file already exists: " << finalPanoUrl; 0081 successFlag = false; 0082 return; 0083 } 0084 0085 if (savePTO && !ptoFile.exists()) 0086 { 0087 errString = i18n("Temporary project file does not exist."); 0088 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Temporary project file does not exists: " << ptoUrl; 0089 successFlag = false; 0090 return; 0091 } 0092 0093 if (savePTO && finalPTOFile.exists()) 0094 { 0095 errString = i18n("A project file named <filename>%1</filename> already exists.", finalPTOUrl.fileName()); 0096 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Final project file already exists: " << finalPTOUrl; 0097 successFlag = false; 0098 return; 0099 } 0100 0101 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Copying GPS info..."; 0102 0103 // Find first src image which contain geolocation and save it to target pano file. 0104 0105 double lat, lng, alt; 0106 QScopedPointer<DMetadata> meta(new DMetadata); 0107 0108 for (PanoramaItemUrlsMap::const_iterator i = urlList->constBegin() ; i != urlList->constEnd() ; ++i) 0109 { 0110 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << i.key(); 0111 0112 meta->load(i.key().toLocalFile()); 0113 0114 if (meta->getGPSInfo(alt, lat, lng)) 0115 { 0116 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "GPS info found and saved in " << panoUrl; 0117 meta->load(panoUrl.toLocalFile()); 0118 meta->setGPSInfo(alt, lat, lng); 0119 meta->applyChanges(true); 0120 break; 0121 } 0122 } 0123 0124 // Restore usual and common metadata from first shot. 0125 0126 meta->load(urlList->constBegin().key().toLocalFile()); 0127 QByteArray iptc = meta->getIptc(); 0128 QByteArray xmp = meta->getXmp(); 0129 QString make = meta->getExifTagString("Exif.Image.Make"); 0130 QString model = meta->getExifTagString("Exif.Image.Model"); 0131 QDateTime dt = meta->getItemDateTime(); 0132 0133 meta->load(panoUrl.toLocalFile()); 0134 meta->setIptc(iptc); 0135 meta->setXmp(xmp); 0136 meta->setXmpTagString("Xmp.tiff.Make", make); 0137 meta->setXmpTagString("Xmp.tiff.Model", model); 0138 meta->setImageDateTime(dt); 0139 0140 QString filesList; 0141 0142 for (PanoramaItemUrlsMap::const_iterator i = urlList->constBegin() ; i != urlList->constEnd() ; ++i) 0143 { 0144 filesList.append(i.key().fileName() + QLatin1String(" ; ")); 0145 } 0146 0147 filesList.truncate(filesList.length()-3); 0148 0149 meta->setXmpTagString("Xmp.digiKam.PanoramaInputFiles", filesList); 0150 0151 // NOTE : See https://developers.google.com/photo-sphere/metadata/ for details 0152 0153 if (addGPlusMetadata) 0154 { 0155 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Adding PhotoSphere metadata..."; 0156 meta->registerXmpNameSpace(QLatin1String("http://ns.google.com/photos/1.0/panorama/"), // krazy:exclude=insecurenet 0157 QLatin1String("GPano")); 0158 meta->setXmpTagString("Xmp.GPano.UsePanoramaViewer", QLatin1String("True")); 0159 meta->setXmpTagString("Xmp.GPano.StitchingSoftware", QLatin1String("Panorama digiKam tool with Hugin")); 0160 meta->setXmpTagString("Xmp.GPano.ProjectionType", QLatin1String("equirectangular")); 0161 } 0162 0163 meta->applyChanges(true); 0164 0165 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Copying panorama file..."; 0166 0167 if (!panoFile.copy(finalPanoUrl.toLocalFile()) || !panoFile.remove()) 0168 { 0169 errString = i18n("Cannot move panorama from <filename>%1</filename> to <filename>%2</filename>.", 0170 panoUrl.toLocalFile(), 0171 finalPanoUrl.toLocalFile()); 0172 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Cannot move panorama: QFile error = " << panoFile.error(); 0173 successFlag = false; 0174 0175 return; 0176 } 0177 0178 if (savePTO) 0179 { 0180 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Copying project file..."; 0181 0182 if (!ptoFile.copy(finalPTOUrl.toLocalFile())) 0183 { 0184 errString = i18n("Cannot move project file from <filename>%1</filename> to <filename>%2</filename>.", 0185 panoUrl.toLocalFile(), 0186 finalPanoUrl.toLocalFile()); 0187 successFlag = false; 0188 0189 return; 0190 } 0191 0192 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Copying converted RAW files..."; 0193 0194 for (PanoramaItemUrlsMap::const_iterator i = urlList->constBegin() ; i != urlList->constEnd() ; ++i) 0195 { 0196 if (DRawDecoder::isRawFile(i.key())) 0197 { 0198 QUrl finalImgUrl = finalPanoUrl.adjusted(QUrl::RemoveFilename); 0199 finalImgUrl.setPath(finalImgUrl.path() + i->preprocessedUrl.fileName()); 0200 QFile finalImgFile(finalImgUrl.toLocalFile()); 0201 QFile imgFile(i->preprocessedUrl.toLocalFile()); 0202 0203 if (finalImgFile.exists()) 0204 { 0205 continue; 0206 } 0207 0208 if (!imgFile.copy(finalImgUrl.toLocalFile())) 0209 { 0210 errString = i18n("Cannot copy converted image file from <filename>%1</filename> to <filename>%2</filename>.", 0211 i->preprocessedUrl.toLocalFile(), 0212 finalImgUrl.toLocalFile()); 0213 successFlag = false; 0214 0215 return; 0216 } 0217 } 0218 } 0219 } 0220 0221 Q_EMIT PanoManager::instance()->updateHostApp(finalPanoUrl); 0222 0223 successFlag = true; 0224 } 0225 0226 } // namespace DigikamGenericPanoramaPlugin