diff options
Diffstat (limited to 'src/libs/thumbbar/thumbnailjob.cpp')
-rw-r--r-- | src/libs/thumbbar/thumbnailjob.cpp | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/src/libs/thumbbar/thumbnailjob.cpp b/src/libs/thumbbar/thumbnailjob.cpp new file mode 100644 index 00000000..dcabb393 --- /dev/null +++ b/src/libs/thumbbar/thumbnailjob.cpp @@ -0,0 +1,318 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-10-14 + * Description : digiKam TDEIO thumbnails generator interface + * + * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// C Ansi includes. + +extern "C" +{ +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <fcntl.h> +#include <unistd.h> +} + +// TQt includes. + +#include <tqstring.h> +#include <tqdir.h> +#include <tqfileinfo.h> +#include <tqimage.h> +#include <tqpixmap.h> +#include <tqpainter.h> +#include <tqcolor.h> +#include <tqdatastream.h> + +// KDE includes. + +#include <tdeglobal.h> + +// Local includes. + +#include "ddebug.h" +#include "thumbnailjob.h" +#include "thumbnailjob.moc" + +namespace Digikam +{ + +class ThumbnailJobPriv +{ +public: + + bool highlight; + bool exifRotate; + bool running; + + int size; + + // Shared memory segment Id. The segment is allocated to a size + // of extent x extent x 4 (32 bit image) on first need. + int shmid; + + // And the data area + uchar *shmaddr; + + KURL curr_url; + KURL next_url; + KURL::List urlList; +}; + +ThumbnailJob::ThumbnailJob(const KURL& url, int size, + bool highlight, bool exifRotate) + : TDEIO::Job(false) +{ + d = new ThumbnailJobPriv; + + d->urlList.append(url); + + d->size = size; + d->highlight = highlight; + d->exifRotate = exifRotate; + d->curr_url = d->urlList.first(); + d->next_url = d->curr_url; + d->running = false; + d->shmid = -1; + d->shmaddr = 0; + + processNext(); +} + +ThumbnailJob::ThumbnailJob(const KURL::List& urlList, int size, + bool highlight, bool exifRotate) + : TDEIO::Job(false) +{ + d = new ThumbnailJobPriv; + + d->urlList = urlList; + d->size = size; + d->highlight = highlight; + d->running = false; + d->exifRotate = exifRotate; + d->curr_url = d->urlList.first(); + d->next_url = d->curr_url; + d->shmid = -1; + d->shmaddr = 0; + + processNext(); +} + +ThumbnailJob::~ThumbnailJob() +{ + if (d->shmaddr) + { + shmdt((char*)d->shmaddr); + shmctl(d->shmid, IPC_RMID, 0); + } + + delete d; +} + +void ThumbnailJob::addItem(const KURL& url) +{ + d->urlList.append(url); + + if (!d->running && subjobs.isEmpty()) + processNext(); +} + +void ThumbnailJob::addItems(const KURL::List& urlList) +{ + for (KURL::List::const_iterator it = urlList.begin(); + it != urlList.end(); ++it) + { + d->urlList.append(*it); + } + + if (!d->running && subjobs.isEmpty()) + processNext(); +} + +bool ThumbnailJob::setNextItemToLoad(const KURL& url) +{ + KURL::List::const_iterator it = d->urlList.find(url); + if (it != d->urlList.end()) + { + d->next_url = *it; + return true; + } + + return false; +} + +void ThumbnailJob::removeItem(const KURL& url) +{ + d->urlList.remove(url); +} + +void ThumbnailJob::processNext() +{ + if (d->urlList.isEmpty()) + { + d->running = false; + emit signalCompleted(); + return; + } + + KURL::List::iterator it = d->urlList.find(d->next_url); + if (it == d->urlList.end()) + { + it = d->urlList.begin(); + } + + d->curr_url = *it; + it = d->urlList.remove(it); + if (it != d->urlList.end()) + { + d->next_url = *it; + } + else + { + d->next_url = KURL(); + } + + KURL url(d->curr_url); + url.setProtocol("digikamthumbnail"); + + TDEIO::TransferJob *job = TDEIO::get(url, false, false); + job->addMetaData("size", TQString::number(d->size)); + createShmSeg(); + + if (d->shmid != -1) + job->addMetaData("shmid", TQString::number(d->shmid)); + + // Rotate thumbnail accordindly with Exif rotation tag if necessary. + if (d->exifRotate) + job->addMetaData("exif", "yes"); + + connect(job, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)), + this, TQ_SLOT(slotThumbData(TDEIO::Job *, const TQByteArray &))); + + addSubjob(job); + d->running = true; +} + +void ThumbnailJob::slotResult(TDEIO::Job *job) +{ + subjobs.remove(job); + Q_ASSERT( subjobs.isEmpty() ); + + if (job->error()) + { + emit signalFailed(d->curr_url); + } + + d->running = false; + processNext(); +} + +void ThumbnailJob::createShmSeg() +{ + if (d->shmid == -1) + { + if (d->shmaddr) + { + shmdt((char*)d->shmaddr); + shmctl(d->shmid, IPC_RMID, 0); + } + + d->shmid = shmget(IPC_PRIVATE, 256 * 256 * 4, IPC_CREAT|0600); + if (d->shmid != -1) + { + d->shmaddr = static_cast<uchar *>(shmat(d->shmid, 0, SHM_RDONLY)); + if (d->shmaddr == (uchar *)-1) + { + shmctl(d->shmid, IPC_RMID, 0); + d->shmaddr = 0; + d->shmid = -1; + } + } + else + d->shmaddr = 0; + } +} + +void ThumbnailJob::slotThumbData(TDEIO::Job*, const TQByteArray &data) +{ + if (data.isEmpty()) + return; + + TQImage thumb; + TQDataStream stream(data, IO_ReadOnly); + if (d->shmaddr) + { + int width, height, depth; + stream >> width >> height >> depth; + thumb = TQImage(d->shmaddr, width, height, depth, + 0, 0, TQImage::IgnoreEndian); + + // The buffer supplied to the TQImage constructor above must remain valid + // throughout the lifetime of the object. + // This is not true, the shared memory will be freed or reused. + // If we pass the object around, we must do a deep copy. + thumb = thumb.copy(); + } + else + { + stream >> thumb; + } + + if (thumb.isNull()) + { + DWarning() << k_funcinfo << "thumbnail is null" << endl; + emit signalFailed(d->curr_url); + return; + } + + emitThumbnail(thumb); +} + +void ThumbnailJob::emitThumbnail(TQImage& thumb) +{ + if (thumb.isNull()) + { + return; + } + + TQPixmap pix(thumb); + + int w = pix.width(); + int h = pix.height(); + + // highlight only when requested and when thumbnail + // width and height are greater than 10 + if (d->highlight && (w >= 10 && h >= 10)) + { + TQPainter p(&pix); + p.setPen(TQPen(TQColor(0,0,0),1)); + p.drawRect(0,0,w,h); + p.end(); + } + + emit signalThumbnail(d->curr_url, pix); +} + +} // namespace Digikam + + |