diff --git a/lib/thumbnailprovider/thumbnailgenerator.cpp b/lib/thumbnailprovider/thumbnailgenerator.cpp index 93fa57b8..26402cf2 100644 --- a/lib/thumbnailprovider/thumbnailgenerator.cpp +++ b/lib/thumbnailprovider/thumbnailgenerator.cpp @@ -1,307 +1,304 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2012 Aurélien Gâteau 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 of the License, 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "thumbnailgenerator.h" // Local #include "jpegcontent.h" #include "gwenviewconfig.h" #include "exiv2imageloader.h" // KDE #include #ifdef KDCRAW_FOUND #include #endif // Qt #include #include #include namespace Gwenview { #undef ENABLE_LOG #undef LOG //#define ENABLE_LOG #ifdef ENABLE_LOG #define LOG(x) //qDebug() << x #else #define LOG(x) ; #endif -const int MIN_PREV_SIZE = 1000; - //------------------------------------------------------------------------ // // ThumbnailContext // //------------------------------------------------------------------------ bool ThumbnailContext::load(const QString &pixPath, int pixelSize) { mImage = QImage(); mNeedCaching = true; QImage originalImage; QSize originalSize; QByteArray formatHint = pixPath.section(QLatin1Char('.'), -1).toLocal8Bit().toLower(); QImageReader reader(pixPath); JpegContent content; QByteArray format; QByteArray data; QBuffer buffer; int previewRatio = 1; #ifdef KDCRAW_FOUND // raw images deserve special treatment if (KDcrawIface::KDcraw::rawFilesList().contains(QString::fromLatin1(formatHint))) { // use KDCraw to extract the preview bool ret = KDcrawIface::KDcraw::loadEmbeddedPreview(data, pixPath); // We need QImage. Loading JpegContent from QImage - exif lost // Loading QImage from JpegContent - unimplemented, would go with loadFromData - if (!ret || !originalImage.loadFromData(data) || qMin(originalImage.width(), originalImage.height()) < MIN_PREV_SIZE) { - // if the embedded preview loading failed or gets just a small image, load - // half preview instead. That's slower... + if (!ret) { + // if the embedded preview loading failed, load half preview instead. That's slower... if (!KDcrawIface::KDcraw::loadHalfPreview(data, pixPath)) { qWarning() << "unable to get preview for " << pixPath.toUtf8().constData(); return false; } previewRatio = 2; } // And we need JpegContent too because of EXIF (orientation!). if (!content.loadFromData(data)) { qWarning() << "unable to load preview for " << pixPath.toUtf8().constData(); return false; } buffer.setBuffer(&data); buffer.open(QIODevice::ReadOnly); reader.setDevice(&buffer); reader.setFormat(formatHint); } else { #else { #endif if (!reader.canRead()) { reader.setDecideFormatFromContent(true); // Set filename again, otherwise QImageReader won't restart from scratch reader.setFileName(pixPath); } if (reader.format() == "jpeg" && GwenviewConfig::applyExifOrientation()) { content.load(pixPath); } } // If there's jpeg content (from jpg or raw files), try to load an embedded thumbnail, if available. if (!content.rawData().isEmpty()) { QImage thumbnail = content.thumbnail(); if (qMax(thumbnail.width(), thumbnail.height()) >= pixelSize) { mImage = std::move(thumbnail); mOriginalWidth = content.size().width(); mOriginalHeight = content.size().height(); return true; } } // Generate thumbnail from full image originalSize = reader.size(); if (originalSize.isValid() && reader.supportsOption(QImageIOHandler::ScaledSize) && qMax(originalSize.width(), originalSize.height()) >= pixelSize) { QSizeF scaledSize = originalSize; scaledSize.scale(pixelSize, pixelSize, Qt::KeepAspectRatio); if (!scaledSize.isEmpty()) { reader.setScaledSize(scaledSize.toSize()); } } // Rotate if necessary if (GwenviewConfig::applyExifOrientation()) { reader.setAutoTransform(true); } // format() is empty after QImageReader::read() is called format = reader.format(); if (!reader.read(&originalImage)) { return false; } if (!originalSize.isValid()) { originalSize = originalImage.size(); } mOriginalWidth = originalSize.width() * previewRatio; mOriginalHeight = originalSize.height() * previewRatio; if (qMax(mOriginalWidth, mOriginalHeight) <= pixelSize) { mImage = originalImage; mNeedCaching = format != "png"; } else { mImage = originalImage.scaled(pixelSize, pixelSize, Qt::KeepAspectRatio); } if (reader.autoTransform() && (reader.transformation() & QImageIOHandler::TransformationRotate90)) { qSwap(mOriginalWidth, mOriginalHeight); } return true; } //------------------------------------------------------------------------ // // ThumbnailGenerator // //------------------------------------------------------------------------ ThumbnailGenerator::ThumbnailGenerator() : mCancel(false) {} void ThumbnailGenerator::load( const QString& originalUri, time_t originalTime, KIO::filesize_t originalFileSize, const QString& originalMimeType, const QString& pixPath, const QString& thumbnailPath, ThumbnailGroup::Enum group) { QMutexLocker lock(&mMutex); Q_ASSERT(mPixPath.isNull()); mOriginalUri = originalUri; mOriginalTime = originalTime; mOriginalFileSize = originalFileSize; mOriginalMimeType = originalMimeType; mPixPath = pixPath; mThumbnailPath = thumbnailPath; mThumbnailGroup = group; if (!isRunning()) start(); mCond.wakeOne(); } QString ThumbnailGenerator::originalUri() const { return mOriginalUri; } time_t ThumbnailGenerator::originalTime() const { return mOriginalTime; } KIO::filesize_t ThumbnailGenerator::originalFileSize() const { return mOriginalFileSize; } QString ThumbnailGenerator::originalMimeType() const { return mOriginalMimeType; } bool ThumbnailGenerator::testCancel() { QMutexLocker lock(&mMutex); return mCancel; } void ThumbnailGenerator::cancel() { QMutexLocker lock(&mMutex); mCancel = true; mCond.wakeOne(); } void ThumbnailGenerator::run() { LOG(""); while (!testCancel()) { QString pixPath; int pixelSize; { QMutexLocker lock(&mMutex); // empty mPixPath means nothing to do LOG("Waiting for mPixPath"); if (mPixPath.isNull()) { LOG("mPixPath.isNull"); mCond.wait(&mMutex); } } if (testCancel()) { return; } { QMutexLocker lock(&mMutex); pixPath = mPixPath; pixelSize = ThumbnailGroup::pixelSize(mThumbnailGroup); } Q_ASSERT(!pixPath.isNull()); LOG("Loading" << pixPath); ThumbnailContext context; bool ok = context.load(pixPath, pixelSize); { QMutexLocker lock(&mMutex); if (ok) { mImage = context.mImage; mOriginalWidth = context.mOriginalWidth; mOriginalHeight = context.mOriginalHeight; if (context.mNeedCaching && mThumbnailGroup <= ThumbnailGroup::Large) { cacheThumbnail(); } } else { // avoid emitting the thumb from the previous successful run mImage = QImage(); qWarning() << "Could not generate thumbnail for file" << mOriginalUri; } mPixPath.clear(); // done, ready for next } if (testCancel()) { return; } { QSize size(mOriginalWidth, mOriginalHeight); LOG("emitting done signal, size=" << size); QMutexLocker lock(&mMutex); emit done(mImage, size); LOG("Done"); } } LOG("Ending thread"); } void ThumbnailGenerator::cacheThumbnail() { mImage.setText(QStringLiteral("Thumb::URI") , mOriginalUri); mImage.setText(QStringLiteral("Thumb::MTime") , QString::number(mOriginalTime)); mImage.setText(QStringLiteral("Thumb::Size") , QString::number(mOriginalFileSize)); mImage.setText(QStringLiteral("Thumb::Mimetype") , mOriginalMimeType); mImage.setText(QStringLiteral("Thumb::Image::Width") , QString::number(mOriginalWidth)); mImage.setText(QStringLiteral("Thumb::Image::Height"), QString::number(mOriginalHeight)); mImage.setText(QStringLiteral("Software") , QStringLiteral("Gwenview")); emit thumbnailReadyToBeCached(mThumbnailPath, mImage); } } // namespace