|
|
|
/* ============================================================
|
|
|
|
*
|
|
|
|
* 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, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
|
|
|
|
this, TQT_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
|
|
|
|
|
|
|
|
|