bool LoadSaveThread::exifRotate(DImg& image, const QString& filePath) { // Keep in sync with the variant in thumbnailcreator.cpp if (wasExifRotated(image)) { return false; } // Rotate thumbnail based on metadata orientation information bool rotatedOrFlipped = image.rotateAndFlip(exifOrientation(image, filePath)); image.setAttribute("exifRotated", true); return rotatedOrFlipped; }
bool JpegRotator::exifTransform(const MetaEngineRotation& matrix) { FileWriteLocker lock(m_destFile); QFileInfo fi(m_file); if (!fi.exists()) { qCDebug(DIGIKAM_GENERAL_LOG) << "ExifRotate: file does not exist: " << m_file; return false; } if (!isJpegImage(m_file)) { // Not a jpeg image. qCDebug(DIGIKAM_GENERAL_LOG) << "ExifRotate: not a JPEG file: " << m_file; return false; } QList<TransformAction> actions = matrix.transformations(); if (actions.isEmpty()) { if (m_file != m_destFile) { copyFile(m_file, m_destFile); } return true; } QString dest = m_destFile; QString src = m_file; QString dir = fi.absolutePath(); QStringList unlinkLater; for (int i=0; i<actions.size(); i++) { SafeTemporaryFile* const temp = new SafeTemporaryFile(dir + QLatin1String("/JpegRotator-XXXXXX.digikamtempfile.jpg")); temp->setAutoRemove(false); temp->open(); QString tempFile = temp->fileName(); // Crash fix: a QTemporaryFile is not properly closed until its destructor is called. delete temp; if (!performJpegTransform(actions[i], src, tempFile)) { qCDebug(DIGIKAM_GENERAL_LOG) << "JPEG lossless transform failed for" << src; // See bug 320107 : if lossless transform cannot be achieve, do lossy transform. DImg srcImg; qCDebug(DIGIKAM_GENERAL_LOG) << "Trying lossy transform for " << src; if (!srcImg.load(src)) { ::unlink(QFile::encodeName(tempFile).constData()); return false; } if (actions[i] != MetaEngineRotation::NoTransformation) { srcImg.transform(actions[i]); } srcImg.setAttribute(QLatin1String("quality"), getJpegQuality(src)); if (!srcImg.save(tempFile, DImg::JPEG)) { qCDebug(DIGIKAM_GENERAL_LOG) << "Lossy transform failed for" << src; ::unlink(QFile::encodeName(tempFile).constData()); return false; } qCDebug(DIGIKAM_GENERAL_LOG) << "Lossy transform done for " << src; } if (i+1 != actions.size()) { // another round src = tempFile; unlinkLater << tempFile; continue; } // finalize updateMetadata(tempFile, matrix); // atomic rename if (DMetadata::hasSidecar(tempFile)) { QString sidecarTemp = DMetadata::sidecarPath(tempFile); QString sidecarDest = DMetadata::sidecarPath(dest); #ifdef Q_OS_WIN if (::MoveFileEx((LPCWSTR)sidecarTemp.utf16(), (LPCWSTR)sidecarDest.utf16(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == 0) #else if (::rename(QFile::encodeName(sidecarTemp).constData(), QFile::encodeName(sidecarDest).constData()) != 0) #endif { qCDebug(DIGIKAM_GENERAL_LOG) << "Renaming sidecar file" << sidecarTemp << "to" << sidecarDest << "failed"; unlinkLater << sidecarTemp; break; } } #ifdef Q_OS_WIN if (::MoveFileEx((LPCWSTR)tempFile.utf16(), (LPCWSTR)dest.utf16(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == 0) #else if (::rename(QFile::encodeName(tempFile).constData(), QFile::encodeName(dest).constData()) != 0) #endif { qCDebug(DIGIKAM_GENERAL_LOG) << "Renaming" << tempFile << "to" << dest << "failed"; unlinkLater << tempFile; break; } } foreach (const QString& tempFile, unlinkLater) { ::unlink(QFile::encodeName(tempFile).constData()); }