diff --git a/core/libs/dimg/filters/lens/lensfuncameraselector.cpp b/core/libs/dimg/filters/lens/lensfuncameraselector.cpp index 4d28d58127..584f00e095 100644 --- a/core/libs/dimg/filters/lens/lensfuncameraselector.cpp +++ b/core/libs/dimg/filters/lens/lensfuncameraselector.cpp @@ -1,804 +1,804 @@ /* ============================================================ * * Date : 2008-02-10 * Description : a tool to fix automatically camera lens aberrations * * Copyright (C) 2008 by Adrian Schroeter * Copyright (C) 2008-2019 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "lensfuncameraselector.h" // Qt includes #include #include #include #include #include #include #include // KDE includes #include #include // Local includes #include "dlayoutbox.h" #include "digikam_debug.h" #include "squeezedcombobox.h" #include "dnuminput.h" #include "dexpanderbox.h" namespace Digikam { class Q_DECL_HIDDEN LensFunCameraSelector::Private { public: explicit Private() : configUseMetadata(QLatin1String("UseMetadata")), configCameraModel(QLatin1String("CameraModel")), configCameraMake(QLatin1String("CameraMake")), configLensModel(QLatin1String("LensModel")), configSubjectDistance(QLatin1String("SubjectDistance")), configFocalLength(QLatin1String("FocalLength")), configCropFactor(QLatin1String("CropFactor")), configAperture(QLatin1String("Aperture")), redStyle(QLatin1String("QLabel {color: red;}")), orangeStyle(QLatin1String("QLabel {color: orange;}")), greenStyle(QLatin1String("QLabel {color: green;}")) { metadataUsage = 0; make = 0; model = 0; lens = 0; focal = 0; aperture = 0; distance = 0; iface = 0; metadataResult = 0; makeLabel = 0; modelLabel = 0; lensLabel = 0; focalLabel = 0; aperLabel = 0; distLabel = 0; lensDescription = 0; makeDescription = 0; modelDescription = 0; passiveMetadataUsage = false; } bool passiveMetadataUsage; QCheckBox* metadataUsage; QLabel* metadataResult; QLabel* makeLabel; QLabel* modelLabel; QLabel* lensLabel; QLabel* focalLabel; QLabel* aperLabel; QLabel* distLabel; const QString configUseMetadata; const QString configCameraModel; const QString configCameraMake; const QString configLensModel; const QString configSubjectDistance; const QString configFocalLength; const QString configCropFactor; const QString configAperture; const QString redStyle; const QString orangeStyle; const QString greenStyle; DAdjustableLabel* lensDescription; DAdjustableLabel* makeDescription; DAdjustableLabel* modelDescription; SqueezedComboBox* make; SqueezedComboBox* model; SqueezedComboBox* lens; DDoubleNumInput* focal; DDoubleNumInput* aperture; DDoubleNumInput* distance; DMetadata metadata; LensFunIface* iface; }; LensFunCameraSelector::LensFunCameraSelector(QWidget* const parent) : QWidget(parent), d(new Private) { d->iface = new LensFunIface(); QGridLayout* const grid = new QGridLayout(this); DHBox* const hbox = new DHBox(this); d->metadataUsage = new QCheckBox(i18n("Use Metadata"), hbox); QLabel* const space = new QLabel(hbox); d->metadataResult = new QLabel(hbox); hbox->setStretchFactor(space, 10); DHBox* const hbox1 = new DHBox(this); d->makeLabel = new QLabel(i18nc("camera make", "Make:"), hbox1); QLabel* const space1 = new QLabel(hbox1); d->makeDescription = new DAdjustableLabel(hbox1); hbox1->setStretchFactor(space1, 10); d->makeDescription->setAlignment(Qt::AlignVCenter | Qt::AlignRight); d->makeDescription->setWhatsThis(i18n("This is the camera maker description string found in image meta-data. " "This one is used to query and find relevant camera device information from Lensfun database.")); d->make = new SqueezedComboBox(this); d->make->setCurrentIndex(0); DHBox* const hbox2 = new DHBox(this); d->modelLabel = new QLabel(i18nc("camera model", "Model:"), hbox2); QLabel* const space2 = new QLabel(hbox2); d->modelDescription = new DAdjustableLabel(hbox2); hbox2->setStretchFactor(space2, 10); d->modelDescription->setAlignment(Qt::AlignVCenter | Qt::AlignRight); d->modelDescription->setWhatsThis(i18n("This is the camera model description string found in image meta-data. " "This one is used to query and found relevant camera device information from Lensfun database.")); d->model = new SqueezedComboBox(this); d->model->setCurrentIndex(0); DHBox* const hbox3 = new DHBox(this); d->lensLabel = new QLabel(i18nc("camera lens", "Lens:"), hbox3); QLabel* const space3 = new QLabel(hbox3); d->lensDescription = new DAdjustableLabel(hbox3); d->lensDescription->setAlignment(Qt::AlignVCenter | Qt::AlignRight); d->lensDescription->setWhatsThis(i18n("This is the lens description string found in image meta-data. " "This one is used to query and found relevant lens information from Lensfun database.")); hbox3->setStretchFactor(space3, 10); d->lens = new SqueezedComboBox(this); d->lens->setCurrentIndex(0); d->metadataUsage->setEnabled(false); d->metadataUsage->setCheckState(Qt::Unchecked); d->metadataUsage->setWhatsThis(i18n("Set this option to try to guess the right camera/lens settings " "from the image metadata (as Exif or XMP).")); d->focalLabel = new QLabel(i18n("Focal Length (mm):"), this); d->aperLabel = new QLabel(i18n("Aperture:"), this); d->distLabel = new QLabel(i18n("Subject Distance (m):"), this); d->focal = new DDoubleNumInput(this); d->focal->setDecimals(1); d->focal->setRange(1.0, 10000.0, 0.01); d->focal->setDefaultValue(1.0); d->aperture = new DDoubleNumInput(this); d->aperture->setDecimals(1); d->aperture->setRange(1.1, 256.0, 0.1); d->aperture->setDefaultValue(1.1); d->distance = new DDoubleNumInput(this); d->distance->setDecimals(1); d->distance->setRange(0.0, 10000.0, 0.1); d->distance->setDefaultValue(0.0); grid->addWidget(hbox, 0, 0, 1, 3); grid->addWidget(hbox1, 1, 0, 1, 3); grid->addWidget(d->make, 2, 0, 1, 3); grid->addWidget(hbox2, 3, 0, 1, 3); grid->addWidget(d->model, 4, 0, 1, 3); grid->addWidget(hbox3, 5, 0, 1, 3); grid->addWidget(d->lens, 6, 0, 1, 3); grid->addWidget(d->focalLabel, 7, 0, 1, 1); grid->addWidget(d->focal, 7, 1, 1, 2); grid->addWidget(d->aperLabel, 8, 0, 1, 1); grid->addWidget(d->aperture, 8, 1, 1, 2); grid->addWidget(d->distLabel, 9, 0, 1, 1); grid->addWidget(d->distance, 9, 1, 1, 2); grid->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); grid->setContentsMargins(QMargins()); connect(d->metadataUsage, SIGNAL(toggled(bool)), this, SLOT(slotUseMetadata(bool))); connect(d->make, SIGNAL(currentIndexChanged(int)), this, SLOT(slotMakeSelected())); connect(d->model, SIGNAL(currentIndexChanged(int)), this, SLOT(slotModelChanged())); connect(d->lens, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLensSelected())); connect(d->focal, SIGNAL(valueChanged(double)), this, SLOT(slotFocalChanged())); connect(d->aperture, SIGNAL(valueChanged(double)), this, SLOT(slotApertureChanged())); connect(d->distance, SIGNAL(valueChanged(double)), this, SLOT(slotDistanceChanged())); } LensFunCameraSelector::~LensFunCameraSelector() { delete d->iface; delete d; } LensFunIface* LensFunCameraSelector::iface() const { return d->iface; } LensFunContainer LensFunCameraSelector::settings() { // Update settings in LensFun interface blockSignals(true); slotModelSelected(); slotLensSelected(); slotFocalChanged(); slotApertureChanged(); slotDistanceChanged(); blockSignals(false); return d->iface->settings(); } void LensFunCameraSelector::setSettings(const LensFunContainer& settings) { blockSignals(true); d->iface->setSettings(settings); refreshSettingsView(); blockSignals(false); } void LensFunCameraSelector::resetToDefault() { setUseMetadata(true); } void LensFunCameraSelector::readSettings(KConfigGroup& group) { setUseMetadata(group.readEntry(d->configUseMetadata, true)); if (!useMetadata()) { LensFunContainer settings = d->iface->settings(); settings.cameraModel = group.readEntry(d->configCameraModel, QString()); settings.cameraMake = group.readEntry(d->configCameraMake, QString()); settings.lensModel = group.readEntry(d->configLensModel, QString()); if (settings.subjectDistance <= 0.0) { settings.subjectDistance = group.readEntry(d->configSubjectDistance, -1.0); } if (settings.focalLength <= 0.0) { settings.focalLength = group.readEntry(d->configFocalLength, -1.0); } settings.cropFactor = group.readEntry(d->configCropFactor, -1.0); if (settings.aperture <= 0.0) { settings.aperture = group.readEntry(d->configAperture, -1.0); } setSettings(settings); } slotUseMetadata(useMetadata()); } void LensFunCameraSelector::writeSettings(KConfigGroup& group) { group.writeEntry(d->configUseMetadata, useMetadata()); group.writeEntry(d->configCameraModel, d->iface->settings().cameraModel); group.writeEntry(d->configCameraMake, d->iface->settings().cameraMake); group.writeEntry(d->configLensModel, d->iface->settings().lensModel); group.writeEntry(d->configSubjectDistance, d->iface->settings().subjectDistance); group.writeEntry(d->configFocalLength, d->iface->settings().focalLength); group.writeEntry(d->configCropFactor, d->iface->settings().cropFactor); group.writeEntry(d->configAperture, d->iface->settings().aperture); } void LensFunCameraSelector::setMetadata(const DMetadata& meta) { d->metadata = meta; } void LensFunCameraSelector::setEnabledUseMetadata(bool b) { d->metadataUsage->setEnabled(b); } void LensFunCameraSelector::setUseMetadata(bool b) { d->metadataUsage->setChecked(b); } bool LensFunCameraSelector::useMetadata() const { return (d->metadataUsage->isChecked()); } void LensFunCameraSelector::setPassiveMetadataUsage(bool b) { d->passiveMetadataUsage = b; } void LensFunCameraSelector::slotUseMetadata(bool b) { d->makeDescription->setAdjustedText(); d->modelDescription->setAdjustedText(); d->lensDescription->setAdjustedText(); d->metadataResult->clear(); d->makeLabel->setStyleSheet(qApp->styleSheet()); d->modelLabel->setStyleSheet(qApp->styleSheet()); d->lensLabel->setStyleSheet(qApp->styleSheet()); d->focalLabel->setStyleSheet(qApp->styleSheet()); d->aperLabel->setStyleSheet(qApp->styleSheet()); d->distLabel->setStyleSheet(qApp->styleSheet()); d->make->setEnabled(true); d->model->setEnabled(true); d->lens->setEnabled(true); d->focal->setEnabled(true); d->aperture->setEnabled(true); d->distance->setEnabled(true); if (b) { if (d->passiveMetadataUsage) { d->make->setEnabled(false); d->model->setEnabled(false); d->lens->setEnabled(false); d->focal->setEnabled(false); d->aperture->setEnabled(false); d->distance->setEnabled(false); emit signalLensSettingsChanged(); } else { LensFunIface::MetadataMatch ret = findFromMetadata(); switch (ret) { case LensFunIface::MetadataUnavailable: d->metadataResult->setText(i18n("(no metadata available)")); d->metadataResult->setStyleSheet(d->redStyle); break; case LensFunIface::MetadataNoMatch: d->metadataResult->setText(i18n("(no match found)")); d->metadataResult->setStyleSheet(d->redStyle); break; case LensFunIface::MetadataPartialMatch: d->metadataResult->setText(i18n("(partial match found)")); d->metadataResult->setStyleSheet(d->orangeStyle); break; default: d->metadataResult->setText(i18n("(exact match found)")); d->metadataResult->setStyleSheet(d->greenStyle); break; } } } } LensFunIface::MetadataMatch LensFunCameraSelector::findFromMetadata() { LensFunIface::MetadataMatch ret = d->iface->findFromMetadata(d->metadata); refreshSettingsView(); slotModelSelected(); slotLensSelected(); return ret; } void LensFunCameraSelector::refreshSettingsView() { d->make->blockSignals(true); d->model->blockSignals(true); d->lens->blockSignals(true); d->makeLabel->setStyleSheet(qApp->styleSheet()); d->modelLabel->setStyleSheet(qApp->styleSheet()); d->lensLabel->setStyleSheet(qApp->styleSheet()); d->focalLabel->setStyleSheet(qApp->styleSheet()); d->aperLabel->setStyleSheet(qApp->styleSheet()); d->distLabel->setStyleSheet(qApp->styleSheet()); if (!d->passiveMetadataUsage) { d->makeDescription->setAdjustedText(QString::fromLatin1("%1").arg(d->iface->makeDescription())); } int makerIdx = -1; if (d->iface->usedCamera()) { makerIdx = d->make->findText(d->iface->settings().cameraMake); qCDebug(DIGIKAM_DIMG_LOG) << "makerIdx: " << makerIdx << " (" << d->iface->settings().cameraMake << ")"; } else { int i = d->make->findText(d->iface->makeDescription()); if (i == -1) { i = d->make->findText(QLatin1String("Generic")); } if (i >= 0) { d->make->setCurrentIndex(i); populateDeviceCombos(); } if (!d->passiveMetadataUsage) { d->makeLabel->setStyleSheet(d->orangeStyle); } } if (makerIdx >= 0) { d->make->setCurrentIndex(makerIdx); d->make->setEnabled(d->passiveMetadataUsage); if (!d->passiveMetadataUsage) { d->makeLabel->setStyleSheet(d->greenStyle); } populateDeviceCombos(); } // ------------------------------------------------------------------------------------------------ if (!d->passiveMetadataUsage) { d->modelDescription->setAdjustedText(QString::fromLatin1("%1").arg(d->iface->modelDescription())); } int modelIdx = -1; if (d->iface->usedCamera()) { modelIdx = d->model->findText(d->iface->settings().cameraModel); qCDebug(DIGIKAM_DIMG_LOG) << "modelIdx: " << modelIdx << " (" << d->iface->settings().cameraModel << ")"; } if (modelIdx >= 0) { d->model->setCurrentIndex(modelIdx); d->model->setEnabled(d->passiveMetadataUsage); if (!d->passiveMetadataUsage) { d->modelLabel->setStyleSheet(d->greenStyle); } populateLensCombo(); } else { if (!d->passiveMetadataUsage) { d->modelLabel->setStyleSheet(d->orangeStyle); } } // ------------------------------------------------------------------------------------------------ if (!d->passiveMetadataUsage) { d->lensDescription->setAdjustedText(QString::fromLatin1("%1").arg(d->iface->lensDescription())); } int lensIdx = -1; if (d->iface->usedLens()) { lensIdx = d->lens->findText(d->iface->settings().lensModel); qCDebug(DIGIKAM_DIMG_LOG) << "lensIdx: " << lensIdx << " (" << d->iface->settings().lensModel << ")"; } if (lensIdx >= 0) { // found lens model directly, best case :) d->lens->setCurrentIndex(lensIdx); d->lens->setEnabled(d->passiveMetadataUsage); if (!d->passiveMetadataUsage) { d->lensLabel->setStyleSheet(d->greenStyle); } } else { if (!d->passiveMetadataUsage) { d->lensLabel->setStyleSheet(d->orangeStyle); } } // ------------------------------------------------------------------------------------------------ if (d->iface->settings().focalLength != -1.0) { d->focal->setValue(d->iface->settings().focalLength); d->focal->setEnabled(d->passiveMetadataUsage); if (!d->passiveMetadataUsage) { d->focalLabel->setStyleSheet(d->greenStyle); } } else { if (!d->passiveMetadataUsage) { d->focalLabel->setStyleSheet(d->orangeStyle); } } if (d->iface->settings().aperture != -1.0) { d->aperture->setValue(d->iface->settings().aperture); d->aperture->setEnabled(d->passiveMetadataUsage); if (!d->passiveMetadataUsage) { d->aperLabel->setStyleSheet(d->greenStyle); } } else { if (!d->passiveMetadataUsage) { d->aperLabel->setStyleSheet(d->orangeStyle); } } if (d->iface->settings().subjectDistance != -1.0) { d->distance->setValue(d->iface->settings().subjectDistance); d->distance->setEnabled(d->passiveMetadataUsage); if (!d->passiveMetadataUsage) { d->distLabel->setStyleSheet(d->greenStyle); } } else { if (!d->passiveMetadataUsage) { d->distLabel->setStyleSheet(d->orangeStyle); } } d->make->blockSignals(false); d->model->blockSignals(false); d->lens->blockSignals(false); } void LensFunCameraSelector::populateDeviceCombos() { d->make->blockSignals(true); d->model->blockSignals(true); const lfCamera* const* it = d->iface->lensFunCameras(); // reset box d->model->clear(); bool firstRun = false; if (d->make->count() == 0) { firstRun = true; } while (*it) { if (firstRun) { // Maker DB does not change, so we fill it only once. if ((*it)->Maker) { QString t = QLatin1String((*it)->Maker); if (d->make->findText(t, Qt::MatchExactly) < 0) { d->make->addSqueezedItem(t); } } } // Fill models for current selected maker if ((*it)->Model && QLatin1String((*it)->Maker) == d->make->itemHighlighted()) { LensFunIface::DevicePtr dev = *it; QVariant b = qVariantFromValue(dev); d->model->addSqueezedItem(QLatin1String(dev->Model), b); } ++it; } //d->make->model()->sort(0, Qt::AscendingOrder); //d->model->model()->sort(0, Qt::AscendingOrder); d->make->blockSignals(false); d->model->blockSignals(false); } void LensFunCameraSelector::populateLensCombo() { d->lens->blockSignals(true); d->lens->clear(); d->lens->blockSignals(false); QVariant v = d->model->itemData(d->model->currentIndex()); if (!v.isValid() || v.isNull()) { qCDebug(DIGIKAM_DIMG_LOG) << "Invalid variant value for device!"; return; } qCDebug(DIGIKAM_DIMG_LOG) << "variant: " << v; LensFunIface::DevicePtr dev = v.value(); if (!dev) { qCDebug(DIGIKAM_DIMG_LOG) << "Device is null!"; return; } qCDebug(DIGIKAM_DIMG_LOG) << "dev: " << dev->Maker << " :: " << dev->Model << " :: " << dev->CropFactor; d->lens->blockSignals(true); const lfLens** lenses = d->iface->lensFunDataBase()->FindLenses(dev, 0, 0); LensFunContainer settings = d->iface->settings(); settings.cropFactor = dev ? dev->CropFactor : -1.0; d->iface->setSettings(settings); QMultiMap lensMap; while (lenses && *lenses) { LensFunIface::LensPtr lens = *lenses; QVariant b = qVariantFromValue(lens); lensMap.insert(QLatin1String(lens->Model), b); ++lenses; } - QMap::ConstIterator it = lensMap.constBegin(); + QMultiMap::ConstIterator it = lensMap.constBegin(); for ( ; it != lensMap.constEnd() ; ++it) { d->lens->addSqueezedItem(it.key(), it.value()); } //d->lens->model()->sort(0, Qt::AscendingOrder); d->lens->blockSignals(false); } void LensFunCameraSelector::slotMakeSelected() { populateDeviceCombos(); slotModelSelected(); // Fill Lens list for current Maker & Model and fire signalLensSettingsChanged() populateLensCombo(); slotLensSelected(); } void LensFunCameraSelector::slotModelChanged() { populateLensCombo(); slotModelSelected(); } void LensFunCameraSelector::slotModelSelected() { QVariant v = d->model->itemData(d->model->currentIndex()); d->iface->setUsedCamera(d->metadataUsage->isChecked() && d->passiveMetadataUsage ? 0 : v.value()); emit signalLensSettingsChanged(); } void LensFunCameraSelector::slotLensSelected() { QVariant v = d->lens->itemData(d->lens->currentIndex()); d->iface->setUsedLens(d->metadataUsage->isChecked() && d->passiveMetadataUsage ? 0 : v.value()); LensFunContainer settings = d->iface->settings(); if (d->iface->usedLens() && settings.cropFactor <= 0.0) // this should not happen { qCDebug(DIGIKAM_DIMG_LOG) << "No crop factor is set for camera, using lens calibration data: " << d->iface->usedLens()->CropFactor; settings.cropFactor = d->iface->usedLens()->CropFactor; } d->iface->setSettings(settings); emit signalLensSettingsChanged(); } void LensFunCameraSelector::slotFocalChanged() { LensFunContainer settings = d->iface->settings(); settings.focalLength = d->metadataUsage->isChecked() && d->passiveMetadataUsage ? -1.0 : d->focal->value(); d->iface->setSettings(settings); emit signalLensSettingsChanged(); } void LensFunCameraSelector::slotApertureChanged() { LensFunContainer settings = d->iface->settings(); settings.aperture = d->metadataUsage->isChecked() && d->passiveMetadataUsage ? -1.0 : d->aperture->value(); d->iface->setSettings(settings); emit signalLensSettingsChanged(); } void LensFunCameraSelector::slotDistanceChanged() { LensFunContainer settings = d->iface->settings(); settings.subjectDistance = d->metadataUsage->isChecked() && d->passiveMetadataUsage ? -1.0 : d->distance->value(); d->iface->setSettings(settings); emit signalLensSettingsChanged(); } void LensFunCameraSelector::showEvent(QShowEvent* event) { QWidget::showEvent(event); populateDeviceCombos(); populateLensCombo(); if (d->metadata.isEmpty()) { d->metadataUsage->setCheckState(Qt::Unchecked); setEnabledUseMetadata(false); } else { setEnabledUseMetadata(true); findFromMetadata(); } } } // namespace Digikam diff --git a/core/libs/fileactionmanager/fileworkeriface.cpp b/core/libs/fileactionmanager/fileworkeriface.cpp index 618ddd544c..da13e517cd 100644 --- a/core/libs/fileactionmanager/fileworkeriface.cpp +++ b/core/libs/fileactionmanager/fileworkeriface.cpp @@ -1,383 +1,383 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-01-18 * Description : database worker interface * * Copyright (C) 2012 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "fileworkeriface.h" // KDE includes #include // Local includes #include "digikam_debug.h" #include "metaenginesettings.h" #include "fileactionmngr_p.h" #include "itemattributeswatch.h" #include "iteminfotasksplitter.h" #include "scancontroller.h" #include "digikam_globals.h" #include "jpegutils.h" #include "dimg.h" #include "facetagseditor.h" namespace Digikam { void FileActionMngrFileWorker::writeOrientationToFiles(FileActionItemInfoList infos, int orientation) { QStringList failedItems; foreach (const ItemInfo& info, infos) { if (state() == WorkerObject::Deactivating) { break; } QString path = info.filePath(); DMetadata metadata(path); DMetadata::ImageOrientation o = (DMetadata::ImageOrientation)orientation; metadata.setItemOrientation(o); if (!metadata.applyChanges()) { failedItems.append(info.name()); } else { emit imageDataChanged(path, true, true); QUrl url = QUrl::fromLocalFile(path); ItemAttributesWatch::instance()->fileMetadataChanged(url); } infos.writtenToOne(); } if (!failedItems.isEmpty()) { emit imageChangeFailed(i18n("Failed to revise Exif orientation these files:"), failedItems); } infos.finishedWriting(); } void FileActionMngrFileWorker::writeMetadataToFiles(FileActionItemInfoList infos) { d->startingToWrite(infos); ScanController::instance()->suspendCollectionScan(); foreach (const ItemInfo& info, infos) { MetadataHub hub; if (state() == WorkerObject::Deactivating) { break; } hub.load(info); QString filePath = info.filePath(); if (MetaEngineSettings::instance()->settings().useLazySync) { hub.write(filePath, MetadataHub::WRITE_ALL); } else { ScanController::FileMetadataWrite writeScope(info); writeScope.changed(hub.write(filePath, MetadataHub::WRITE_ALL)); } // hub emits fileMetadataChanged infos.writtenToOne(); } ScanController::instance()->resumeCollectionScan(); infos.finishedWriting(); } void FileActionMngrFileWorker::writeMetadata(FileActionItemInfoList infos, int flags) { d->startingToWrite(infos); ScanController::instance()->suspendCollectionScan(); foreach (const ItemInfo& info, infos) { MetadataHub hub; if (state() == WorkerObject::Deactivating) { break; } hub.load(info); // apply to file metadata if (MetaEngineSettings::instance()->settings().useLazySync) { hub.writeToMetadata(info, (MetadataHub::WriteComponents)flags); } else { ScanController::FileMetadataWrite writeScope(info); writeScope.changed(hub.writeToMetadata(info, (MetadataHub::WriteComponents)flags)); } // hub emits fileMetadataChanged infos.writtenToOne(); } ScanController::instance()->resumeCollectionScan(); infos.finishedWriting(); } void FileActionMngrFileWorker::transform(FileActionItemInfoList infos, int action) { d->startingToWrite(infos); QStringList failedItems; ScanController::instance()->suspendCollectionScan(); foreach (const ItemInfo& info, infos) { if (state() == WorkerObject::Deactivating) { break; } QString path = info.filePath(); QString format = info.format(); MetaEngine::ImageOrientation currentOrientation = (MetaEngine::ImageOrientation)info.orientation(); bool isRaw = info.format().startsWith(QLatin1String("RAW")); bool rotateAsJpeg = false; bool rotateLossy = false; MetaEngineSettingsContainer::RotationBehaviorFlags behavior; behavior = MetaEngineSettings::instance()->settings().rotationBehavior; bool rotateByMetadata = (behavior & MetaEngineSettingsContainer::RotateByMetadataFlag); // Check if rotation by content, as desired, is feasible // We'll later check again if it was successful if (behavior & MetaEngineSettingsContainer::RotatingPixels) { if (format == QLatin1String("JPG") && JPEGUtils::isJpegImage(path)) { rotateAsJpeg = true; } if (behavior & MetaEngineSettingsContainer::RotateByLossyRotation) { DImg::FORMAT format = DImg::fileFormat(path); switch (format) { case DImg::JPEG: case DImg::PNG: case DImg::TIFF: case DImg::JP2K: case DImg::PGF: rotateLossy = true; default: break; } } } MetaEngineRotation matrix; matrix *= currentOrientation; matrix *= (MetaEngineRotation::TransformationAction)action; MetaEngine::ImageOrientation finalOrientation = matrix.exifOrientation(); bool rotatedPixels = false; if (rotateAsJpeg) { JPEGUtils::JpegRotator rotator(path); rotator.setCurrentOrientation(currentOrientation); if (action == MetaEngineRotation::NoTransformation) { rotatedPixels = rotator.autoExifTransform(); } else { rotatedPixels = rotator.exifTransform((MetaEngineRotation::TransformationAction)action); } if (!rotatedPixels) { failedItems.append(info.name()); } } else if (rotateLossy) { // Non-JPEG image: DImg DImg image; if (!image.load(path)) { failedItems.append(info.name()); } else { if (action == MetaEngineRotation::NoTransformation) { image.rotateAndFlip(currentOrientation); } else { image.transform(action); } // TODO: Atomic operation!! // prepare metadata, including to reset Exif tag image.prepareMetadataToSave(path, image.format(), true); if (image.save(path, image.detectedFormat())) { rotatedPixels = true; } else { failedItems.append(info.name()); } } } if (rotatedPixels) { adjustFaceRectangles(info, finalOrientation); // reset for DB. Metadata is already edited. finalOrientation = MetaEngine::ORIENTATION_NORMAL; } if (rotateByMetadata) { // Setting the rotation flag on Raws with embedded JPEG is a mess // Can apply to the RAW data, or to the embedded JPEG, or to both. if (!isRaw) { DMetadata metadata(path); metadata.setItemOrientation(finalOrientation); metadata.applyChanges(); } } // DB rotation ItemInfo(info).setOrientation(finalOrientation); if (!failedItems.contains(info.name())) { emit imageDataChanged(path, true, true); ItemAttributesWatch::instance()->fileMetadataChanged(info.fileUrl()); } infos.writtenToOne(); } if (!failedItems.isEmpty()) { emit imageChangeFailed(i18n("Failed to transform these files:"), failedItems); } infos.finishedWriting(); ScanController::instance()->resumeCollectionScan(); } void FileActionMngrFileWorker::adjustFaceRectangles(const ItemInfo& info, int orientation) { /** * Get all faces from database and rotate them */ QList facesList = FaceTagsEditor().databaseFaces(info.id()); if (facesList.isEmpty()) { return; } QSize fullSize = info.dimensions(); QMultiMap adjustedFaces; foreach (const FaceTagsIface& dface, facesList) { QRect faceRect = dface.region().toRect(); QString name = FaceTags::faceNameForTag(dface.tagId()); fullSize = TagRegion::adjustToOrientation(faceRect, orientation, info.dimensions()); if (dface.tagId() == FaceTags::unknownPersonTagId()) { name.clear(); } adjustedFaces.insertMulti(name, faceRect); } /** * Delete all old faces and add rotated ones */ FaceTagsEditor().removeAllFaces(info.id()); - QMap::ConstIterator it = adjustedFaces.constBegin(); + QMultiMap::ConstIterator it = adjustedFaces.constBegin(); for ( ; it != adjustedFaces.constEnd() ; ++it) { TagRegion region(it.value()); if (it.key().isEmpty()) { int tagId = FaceTags::unknownPersonTagId(); FaceTagsIface face(FaceTagsIface::UnknownName, info.id(), tagId, region); FaceTagsEditor().addManually(face); } else { int tagId = FaceTags::getOrCreateTagForPerson(it.key()); if (!tagId) { qCDebug(DIGIKAM_GENERAL_LOG) << "Failed to create a person tag for name" << it.key(); } FaceTagsEditor().add(info.id(), tagId, region, false); } } /** * Write medatada */ MetadataHub hub; hub.load(info); // Adjusted fullSize hub.loadFaceTags(info, fullSize); hub.write(info.filePath(), MetadataHub::WRITE_ALL); } } // namespace Digikam