You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
378 lines
10 KiB
378 lines
10 KiB
/*************************************************************************** |
|
* Copyright (C) 2006 by Pino Toscano <toscano.pino@tiscali.it> * |
|
* * |
|
* 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. * |
|
***************************************************************************/ |
|
|
|
#include <qdatetime.h> |
|
#include <qfile.h> |
|
#include <qimage.h> |
|
#include <qlist.h> |
|
#include <qpainter.h> |
|
#include <qthread.h> |
|
#include <kglobal.h> |
|
#include <klocale.h> |
|
#include <kprinter.h> |
|
|
|
#include <okular/core/document.h> |
|
#include <okular/core/page.h> |
|
|
|
#include "generator_tiff.h" |
|
|
|
#include <tiff.h> |
|
#include <tiffio.h> |
|
|
|
class TIFFGenerator::Private |
|
{ |
|
public: |
|
Private() |
|
: tiff( 0 ) {} |
|
|
|
TIFF* tiff; |
|
}; |
|
|
|
|
|
class TIFFGeneratorThread : public QThread |
|
{ |
|
public: |
|
TIFFGeneratorThread(); |
|
|
|
void startGeneration( Okular::PixmapRequest* request, TIFF* tiff ); |
|
void endGeneration(); |
|
|
|
Okular::PixmapRequest *request() const; |
|
QImage takeImage(); |
|
|
|
private: |
|
void run(); |
|
|
|
Okular::PixmapRequest* m_request; |
|
QImage m_img; |
|
TIFF* m_tiff; |
|
}; |
|
|
|
TIFFGeneratorThread::TIFFGeneratorThread() |
|
: QThread(), m_request( 0 ), m_tiff( 0 ) |
|
{ |
|
} |
|
|
|
void TIFFGeneratorThread::startGeneration( Okular::PixmapRequest* request, TIFF* tiff ) |
|
{ |
|
m_request = request; |
|
m_tiff = tiff; |
|
start( QThread::InheritPriority ); |
|
} |
|
|
|
void TIFFGeneratorThread::endGeneration() |
|
{ |
|
m_request = 0; |
|
m_tiff = 0; |
|
} |
|
|
|
Okular::PixmapRequest* TIFFGeneratorThread::request() const |
|
{ |
|
return m_request; |
|
} |
|
|
|
QImage TIFFGeneratorThread::takeImage() |
|
{ |
|
QImage p = m_img; |
|
m_img = QImage(); |
|
return p; |
|
} |
|
|
|
void TIFFGeneratorThread::run() |
|
{ |
|
bool generated = false; |
|
|
|
if ( TIFFSetDirectory( m_tiff, m_request->page()->number() ) ) |
|
{ |
|
int rotation = m_request->page()->rotation(); |
|
uint32 width = (uint32)m_request->page()->width(); |
|
uint32 height = (uint32)m_request->page()->height(); |
|
if ( rotation % 2 == 1 ) |
|
qSwap( width, height ); |
|
|
|
QImage image( width, height, QImage::Format_RGB32 ); |
|
uint32 * data = (uint32 *)image.bits(); |
|
|
|
// read data |
|
if ( TIFFReadRGBAImageOriented( m_tiff, width, height, data, ORIENTATION_TOPLEFT ) != 0 ) |
|
{ |
|
// an image read by ReadRGBAImage is ABGR, we need ARGB, so swap red and blue |
|
uint32 size = width * height; |
|
for ( uint32 i = 0; i < size; ++i ) |
|
{ |
|
uint32 red = ( data[i] & 0x00FF0000 ) >> 16; |
|
uint32 blue = ( data[i] & 0x000000FF ) << 16; |
|
data[i] = ( data[i] & 0xFF00FF00 ) + red + blue; |
|
} |
|
|
|
int reqwidth = m_request->width(); |
|
int reqheight = m_request->height(); |
|
if ( rotation % 2 == 1 ) |
|
qSwap( reqwidth, reqheight ); |
|
m_img = image.scaled( reqwidth, reqheight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); |
|
|
|
generated = true; |
|
} |
|
} |
|
|
|
if ( !generated ) |
|
{ |
|
m_img = QImage( m_request->width(), m_request->height(), QImage::Format_RGB32 ); |
|
m_img.fill( qRgb( 255, 255, 255 ) ); |
|
} |
|
} |
|
|
|
static QDateTime convertTIFFDateTime( const char* tiffdate ) |
|
{ |
|
if ( !tiffdate ) |
|
return QDateTime(); |
|
|
|
return QDateTime::fromString( QString::fromLatin1( tiffdate ), "yyyy:MM:dd HH:mm:ss" ); |
|
} |
|
|
|
OKULAR_EXPORT_PLUGIN(TIFFGenerator) |
|
|
|
TIFFGenerator::TIFFGenerator() : Okular::Generator(), |
|
d( new Private ), ready( false ), m_docInfo( 0 ) |
|
{ |
|
thread = new TIFFGeneratorThread(); |
|
connect( thread, SIGNAL( finished() ), this, SLOT( slotThreadFinished() ), Qt::QueuedConnection ); |
|
} |
|
|
|
TIFFGenerator::~TIFFGenerator() |
|
{ |
|
if ( d->tiff ) |
|
{ |
|
TIFFClose( d->tiff ); |
|
d->tiff = 0; |
|
} |
|
if ( thread ) |
|
{ |
|
thread->wait(); |
|
} |
|
delete thread; |
|
delete m_docInfo; |
|
|
|
delete d; |
|
} |
|
|
|
bool TIFFGenerator::loadDocument( const QString & fileName, QVector<Okular::Page*> & pagesVector ) |
|
{ |
|
d->tiff = TIFFOpen( QFile::encodeName( fileName ), "r" ); |
|
if ( !d->tiff ) |
|
return false; |
|
|
|
loadPages( pagesVector ); |
|
|
|
ready = true; |
|
|
|
return true; |
|
} |
|
|
|
bool TIFFGenerator::closeDocument() |
|
{ |
|
// closing the old document |
|
if ( d->tiff ) |
|
{ |
|
TIFFClose( d->tiff ); |
|
d->tiff = 0; |
|
delete m_docInfo; |
|
m_docInfo = 0; |
|
} |
|
|
|
ready = false; |
|
|
|
return true; |
|
} |
|
|
|
bool TIFFGenerator::canGeneratePixmap( bool /*async*/ ) const |
|
{ |
|
return ready; |
|
} |
|
|
|
void TIFFGenerator::generatePixmap( Okular::PixmapRequest * request ) |
|
{ |
|
ready = false; |
|
|
|
if ( request->asynchronous() ) |
|
{ |
|
thread->startGeneration( request, d->tiff ); |
|
return; |
|
} |
|
|
|
bool generated = false; |
|
QImage img; |
|
|
|
if ( TIFFSetDirectory( d->tiff, request->page()->number() ) ) |
|
{ |
|
int rotation = request->page()->rotation(); |
|
uint32 width = (uint32)request->page()->width(); |
|
uint32 height = (uint32)request->page()->height(); |
|
if ( rotation % 2 == 1 ) |
|
qSwap( width, height ); |
|
|
|
QImage image( width, height, QImage::Format_RGB32 ); |
|
uint32 * data = (uint32 *)image.bits(); |
|
|
|
// read data |
|
if ( TIFFReadRGBAImageOriented( d->tiff, width, height, data, ORIENTATION_TOPLEFT ) != 0 ) |
|
{ |
|
// an image read by ReadRGBAImage is ABGR, we need ARGB, so swap red and blue |
|
uint32 size = width * height; |
|
for ( uint32 i = 0; i < size; ++i ) |
|
{ |
|
uint32 red = ( data[i] & 0x00FF0000 ) >> 16; |
|
uint32 blue = ( data[i] & 0x000000FF ) << 16; |
|
data[i] = ( data[i] & 0xFF00FF00 ) + red + blue; |
|
} |
|
|
|
int reqwidth = request->width(); |
|
int reqheight = request->height(); |
|
if ( rotation % 2 == 1 ) |
|
qSwap( reqwidth, reqheight ); |
|
img = image.scaled( reqwidth, reqheight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); |
|
|
|
generated = true; |
|
} |
|
} |
|
|
|
if ( !generated ) |
|
{ |
|
img = QImage( request->width(), request->height(), QImage::Format_RGB32 ); |
|
img.fill( qRgb( 255, 255, 255 ) ); |
|
} |
|
|
|
request->page()->setPixmap( request->id(), new QPixmap( QPixmap::fromImage( img ) ) ); |
|
|
|
ready = true; |
|
|
|
// signal that the request has been accomplished |
|
signalRequestDone( request ); |
|
} |
|
|
|
const Okular::DocumentInfo * TIFFGenerator::generateDocumentInfo() |
|
{ |
|
if ( !d->tiff ) |
|
return 0; |
|
|
|
if ( m_docInfo ) |
|
return m_docInfo; |
|
|
|
m_docInfo = new Okular::DocumentInfo(); |
|
|
|
m_docInfo->set( "mimeType", "image/tiff" ); |
|
|
|
char* buffer = 0; |
|
TIFFGetField( d->tiff, TIFFTAG_IMAGEDESCRIPTION, &buffer ); |
|
m_docInfo->set( "description", buffer ? QString::fromLatin1( buffer ) : i18n( "Unknown" ), i18n( "Description" ) ); |
|
|
|
buffer = 0; |
|
TIFFGetField( d->tiff, TIFFTAG_SOFTWARE, &buffer ); |
|
m_docInfo->set( "software", buffer ? QString::fromLatin1( buffer ) : i18n( "Unknown" ), i18n( "Software" ) ); |
|
|
|
buffer = 0; |
|
TIFFGetField( d->tiff, TIFFTAG_COPYRIGHT, &buffer ); |
|
m_docInfo->set( "copyright", buffer ? QString::fromLatin1( buffer ) : i18n( "Unknown" ), i18n( "Copyright" ) ); |
|
|
|
buffer = 0; |
|
TIFFGetField( d->tiff, TIFFTAG_ARTIST, &buffer ); |
|
m_docInfo->set( "artist", buffer ? QString::fromLatin1( buffer ) : i18n( "Unknown" ), i18n( "Artist" ) ); |
|
|
|
buffer = 0; |
|
TIFFGetField( d->tiff, TIFFTAG_DATETIME, &buffer ); |
|
QDateTime date = convertTIFFDateTime( buffer ); |
|
m_docInfo->set( "dateTime", date.isValid() ? KGlobal::locale()->formatDateTime( date, false, true ) : i18n( "Unknown" ), i18n( "Creation date" ) ); |
|
|
|
return m_docInfo; |
|
} |
|
|
|
void TIFFGenerator::slotThreadFinished() |
|
{ |
|
Okular::PixmapRequest * request = thread->request(); |
|
thread->endGeneration(); |
|
|
|
request->page()->setPixmap( request->id(), new QPixmap( QPixmap::fromImage( thread->takeImage() ) ) ); |
|
|
|
ready = true; |
|
|
|
signalRequestDone( request ); |
|
} |
|
|
|
void TIFFGenerator::loadPages( QVector<Okular::Page*> & pagesVector ) |
|
{ |
|
if ( !d->tiff ) |
|
return; |
|
|
|
tdir_t dirs = TIFFNumberOfDirectories( d->tiff ); |
|
pagesVector.resize( dirs ); |
|
|
|
uint32 width = 0; |
|
uint32 height = 0; |
|
|
|
for ( tdir_t i = 0; i < dirs; ++i ) |
|
{ |
|
if ( !TIFFSetDirectory( d->tiff, i ) ) |
|
continue; |
|
|
|
if ( TIFFGetField( d->tiff, TIFFTAG_IMAGEWIDTH, &width ) != 1 || |
|
TIFFGetField( d->tiff, TIFFTAG_IMAGELENGTH, &height ) != 1 ) |
|
continue; |
|
|
|
delete pagesVector[i]; |
|
Okular::Page * page = new Okular::Page( i, width, height, Okular::Rotation0 ); |
|
pagesVector[i] = page; |
|
|
|
} |
|
} |
|
|
|
bool TIFFGenerator::print( KPrinter& printer ) |
|
{ |
|
uint32 width = 0; |
|
uint32 height = 0; |
|
|
|
tdir_t dirs = TIFFNumberOfDirectories( d->tiff ); |
|
|
|
QPainter p( &printer ); |
|
|
|
for ( tdir_t i = 0; i < dirs; ++i ) |
|
{ |
|
if ( !TIFFSetDirectory( d->tiff, i ) ) |
|
continue; |
|
|
|
if ( TIFFGetField( d->tiff, TIFFTAG_IMAGEWIDTH, &width ) != 1 || |
|
TIFFGetField( d->tiff, TIFFTAG_IMAGELENGTH, &height ) != 1 ) |
|
continue; |
|
|
|
QImage image( width, height, QImage::Format_RGB32 ); |
|
uint32 * data = (uint32 *)image.bits(); |
|
|
|
// read data |
|
if ( TIFFReadRGBAImageOriented( d->tiff, width, height, data, ORIENTATION_TOPLEFT ) != 0 ) |
|
{ |
|
// an image read by ReadRGBAImage is ABGR, we need ARGB, so swap red and blue |
|
uint32 size = width * height; |
|
for ( uint32 i = 0; i < size; ++i ) |
|
{ |
|
uint32 red = ( data[i] & 0x00FF0000 ) >> 16; |
|
uint32 blue = ( data[i] & 0x000000FF ) << 16; |
|
data[i] = ( data[i] & 0xFF00FF00 ) + red + blue; |
|
} |
|
} |
|
|
|
if ( i != 0 ) |
|
printer.newPage(); |
|
|
|
p.drawImage( 0, 0, image ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
#include "generator_tiff.moc" |
|
|
|
|