diff options
Diffstat (limited to 'src/libs/threadimageio/loadsavethread.cpp')
-rw-r--r-- | src/libs/threadimageio/loadsavethread.cpp | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/src/libs/threadimageio/loadsavethread.cpp b/src/libs/threadimageio/loadsavethread.cpp new file mode 100644 index 00000000..188592e9 --- /dev/null +++ b/src/libs/threadimageio/loadsavethread.cpp @@ -0,0 +1,331 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-12-17 + * Description : image file IO threaded interface. + * + * Copyright (C) 2005-2007 by Marcel Wiesweg <marcel.wiesweg@gmx.de> + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * 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. + * + * ============================================================ */ + +// Local includes. + +#include "ddebug.h" +#include "dmetadata.h" +#include "loadsavethread.h" +#include "managedloadsavethread.h" +#include "sharedloadsavethread.h" +#include "loadsavetask.h" + +namespace Digikam +{ + +class LoadSaveThreadPriv +{ +public: + + LoadSaveThreadPriv() + { + running = true; + blockNotification = false; + lastTask = 0; + } + + bool running; + bool blockNotification; + LoadSaveTask *lastTask; + + TQTime notificationTime; +}; + +//--------------------------------------------------------------------------------------------------- + +LoadSaveThread::LoadSaveThread() +{ + d = new LoadSaveThreadPriv; + m_currentTask = 0; + m_notificationPolicy = NotificationPolicyTimeLimited; + + start(); +} + +LoadSaveThread::~LoadSaveThread() +{ + d->running = false; + { + TQMutexLocker lock(&m_mutex); + m_condVar.wakeAll(); + } + + wait(); + + if (d->lastTask) + delete d->lastTask; + delete d; +} + +void LoadSaveThread::load(LoadingDescription description) +{ + TQMutexLocker lock(&m_mutex); + m_todo.append(new LoadingTask(this, description)); + m_condVar.wakeAll(); +} + +void LoadSaveThread::save(DImg &image, const TQString& filePath, const TQString &format) +{ + TQMutexLocker lock(&m_mutex); + m_todo.append(new SavingTask(this, image, filePath, format)); + m_condVar.wakeAll(); +} + +void LoadSaveThread::run() +{ + while (d->running) + { + { + TQMutexLocker lock(&m_mutex); + if (d->lastTask) + { + delete d->lastTask; + d->lastTask = 0; + } + m_currentTask = m_todo.getFirst(); + if (m_currentTask) + { + m_todo.removeFirst(); + if (m_notificationPolicy == NotificationPolicyTimeLimited) + { + // set timing values so that first event is sent only + // after an initial time span. + d->notificationTime = TQTime::currentTime(); + d->blockNotification = true; + } + } + else + m_condVar.wait(&m_mutex, 1000); + } + if (m_currentTask) + m_currentTask->execute(); + } +} + +void LoadSaveThread::taskHasFinished() +{ + // This function is called by the tasks before they send their final message. + // This is to guarantee the user of the API that at least the final message + // is sent after load() has been called. This might not been the case + // if m_currentTask is currently loading the same image and a race condition + // between the return from execute and the next run of the loop above occurs. + TQMutexLocker lock(&m_mutex); + d->lastTask = m_currentTask; + m_currentTask = 0; +} + +void LoadSaveThread::customEvent(TQCustomEvent *event) +{ + if (event->type() == NotifyEvent::notifyEventId()) + { + switch (m_notificationPolicy) + { + case NotificationPolicyDirect: + d->blockNotification = false; + break; + case NotificationPolicyTimeLimited: + break; + } + ((NotifyEvent *)event)->notify(this); + } +} + +void LoadSaveThread::setNotificationPolicy(NotificationPolicy notificationPolicy) +{ + m_notificationPolicy = notificationPolicy; + d->blockNotification = false; +} + +bool LoadSaveThread::querySendNotifyEvent() +{ + // This function is called from the thread to ask for permission to send a notify event. + switch (m_notificationPolicy) + { + case NotificationPolicyDirect: + // Note that m_blockNotification is not protected by a mutex. However, if there is a + // race condition, the worst case is that one event is not sent, which is no problem. + if (d->blockNotification) + return false; + else + { + d->blockNotification = true; + return true; + } + break; + case NotificationPolicyTimeLimited: + // Current default time value: 100 millisecs. + if (d->blockNotification) + d->blockNotification = d->notificationTime.msecsTo(TQTime::currentTime()) < 100; + + if (d->blockNotification) + return false; + else + { + d->notificationTime = TQTime::currentTime(); + d->blockNotification = true; + return true; + } + break; + } + return false; +} + + +// This is a hack needed to prevent hanging when a TDEProcess-based loader (raw loader) +// is waiting for the process to finish, but the main thread is waiting +// for the thread to finish and no TDEProcess events are delivered. +// Remove when porting to TQt4. +bool LoadSaveThread::isShuttingDown() +{ + // the condition is met after d->running is set to false in the destructor + return running() && !d->running; +} + +bool LoadSaveThread::exifRotate(DImg &image, const TQString& filePath) +{ + TQVariant attribute(image.attribute("exifRotated")); + if (attribute.isValid() && attribute.toBool()) + return false; + + // Raw files are already rotated properlly by dcraw. Only perform auto-rotation with JPEG/PNG/TIFF file. + // We don't have a feedback from dcraw about auto-rotated RAW file during decoding. Return true anyway. + + attribute = image.attribute("fromRawEmbeddedPreview"); + if (DImg::fileFormat(filePath) == DImg::RAW && !(attribute.isValid() && attribute.toBool()) ) + { + return true; + } + + // Rotate thumbnail based on metadata orientation information + + DMetadata metadata(filePath); + DMetadata::ImageOrientation orientation = metadata.getImageOrientation(); + + bool rotatedOrFlipped = false; + + if(orientation != DMetadata::ORIENTATION_NORMAL) + { + switch (orientation) + { + case DMetadata::ORIENTATION_NORMAL: + case DMetadata::ORIENTATION_UNSPECIFIED: + break; + + case DMetadata::ORIENTATION_HFLIP: + image.flip(DImg::HORIZONTAL); + rotatedOrFlipped = true; + break; + + case DMetadata::ORIENTATION_ROT_180: + image.rotate(DImg::ROT180); + rotatedOrFlipped = true; + break; + + case DMetadata::ORIENTATION_VFLIP: + image.flip(DImg::VERTICAL); + rotatedOrFlipped = true; + break; + + case DMetadata::ORIENTATION_ROT_90_HFLIP: + image.rotate(DImg::ROT90); + image.flip(DImg::HORIZONTAL); + rotatedOrFlipped = true; + break; + + case DMetadata::ORIENTATION_ROT_90: + image.rotate(DImg::ROT90); + rotatedOrFlipped = true; + break; + + case DMetadata::ORIENTATION_ROT_90_VFLIP: + image.rotate(DImg::ROT90); + image.flip(DImg::VERTICAL); + rotatedOrFlipped = true; + break; + + case DMetadata::ORIENTATION_ROT_270: + image.rotate(DImg::ROT270); + rotatedOrFlipped = true; + break; + } + } + + image.setAttribute("exifRotated", true); + return rotatedOrFlipped; + + /* + if (orientation == DMetadata::ORIENTATION_NORMAL || + orientation == DMetadata::ORIENTATION_UNSPECIFIED) + return; + + TQWMatrix matrix; + + switch (orientation) + { + case DMetadata::ORIENTATION_NORMAL: + case DMetadata::ORIENTATION_UNSPECIFIED: + break; + + case DMetadata::ORIENTATION_HFLIP: + matrix.scale(-1, 1); + break; + + case DMetadata::ORIENTATION_ROT_180: + matrix.rotate(180); + break; + + case DMetadata::ORIENTATION_VFLIP: + matrix.scale(1, -1); + break; + + case DMetadata::ORIENTATION_ROT_90_HFLIP: + matrix.scale(-1, 1); + matrix.rotate(90); + break; + + case DMetadata::ORIENTATION_ROT_90: + matrix.rotate(90); + break; + + case DMetadata::ORIENTATION_ROT_90_VFLIP: + matrix.scale(1, -1); + matrix.rotate(90); + break; + + case DMetadata::ORIENTATION_ROT_270: + matrix.rotate(270); + break; + } + + // transform accordingly + thumb = thumb.xForm( matrix ); + */ +} + + + + +} // namespace Digikam + +#include "loadsavethread.moc" |