From b43f2c4d28e48e55d075f022d519e9fef3991ee5 Mon Sep 17 00:00:00 2001 From: Pino Toscano Date: Fri, 7 Jul 2006 14:58:12 +0000 Subject: [PATCH] A new backend: TIFF. It uses directly the libTIFF, and actually can load TIFF documents even better than the fax generator (that uses libkfaximage). The generator can also rotate the images, but it is not tested as the menus with the current kdelibs snapshot don't work. svn path=/trunk/playground/graphics/okular/; revision=559514 --- generators/CMakeLists.txt | 3 + generators/tiff/CMakeLists.txt | 27 ++ generators/tiff/generator_tiff.cpp | 292 ++++++++++++++++++ generators/tiff/generator_tiff.h | 46 +++ .../tiff/libokularGenerator_tiff.desktop | 11 + 5 files changed, 379 insertions(+) create mode 100644 generators/tiff/CMakeLists.txt create mode 100644 generators/tiff/generator_tiff.cpp create mode 100644 generators/tiff/generator_tiff.h create mode 100644 generators/tiff/libokularGenerator_tiff.desktop diff --git a/generators/CMakeLists.txt b/generators/CMakeLists.txt index 8db672f47..9b131e538 100644 --- a/generators/CMakeLists.txt +++ b/generators/CMakeLists.txt @@ -15,6 +15,9 @@ if(DJVULIBRE_FOUND) add_subdirectory(djvu) endif(DJVULIBRE_FOUND) add_subdirectory(dvi) +if(TIFF_FOUND) + add_subdirectory(tiff) +endif(TIFF_FOUND) #original Makefile.am contents follow: diff --git a/generators/tiff/CMakeLists.txt b/generators/tiff/CMakeLists.txt new file mode 100644 index 000000000..b0be53ea8 --- /dev/null +++ b/generators/tiff/CMakeLists.txt @@ -0,0 +1,27 @@ +include_directories( + ${CMAKE_SOURCE_DIR}/okular + ${TIFF_INCLUDE_DIR} +) + + +########### next target ############### + +set(okularGenerator_tiff_SRCS + generator_tiff.cpp +) + +kde4_automoc(${okularGenerator_tiff_SRCS}) + +kde4_add_plugin(okularGenerator_tiff WITH_PREFIX ${okularGenerator_tiff_SRCS}) + +kde4_install_libtool_file( ${PLUGIN_INSTALL_DIR} okularGenerator_tiff ) + +target_link_libraries(okularGenerator_tiff ${KDE4_KDECORE_LIBS} okularcore ${TIFF_LIBRARIES} ${KDE4_KDEUI_LIBS} ) + +install(TARGETS okularGenerator_tiff DESTINATION ${PLUGIN_INSTALL_DIR}) + + +########### install files ############### + +install( FILES libokularGenerator_tiff.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + diff --git a/generators/tiff/generator_tiff.cpp b/generators/tiff/generator_tiff.cpp new file mode 100644 index 000000000..154d848d7 --- /dev/null +++ b/generators/tiff/generator_tiff.cpp @@ -0,0 +1,292 @@ +/*************************************************************************** + * Copyright (C) 2006 by Pino Toscano * + * * + * 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 +#include +#include +#include +#include +#include + +#include "core/page.h" +#include "generator_tiff.h" + +#include +#include + +class TIFFGenerator::Private +{ + public: + Private() + : tiff( 0 ) {} + + TIFF* tiff; +}; + + +class TIFFGeneratorThread : public QThread +{ + public: + TIFFGeneratorThread(); + + void startGeneration( PixmapRequest* request, TIFF* tiff ); + void endGeneration(); + + PixmapRequest *request() const; + QPixmap * takePixmap(); + + private: + void run(); + + PixmapRequest* m_request; + QPixmap* m_pix; + TIFF* m_tiff; +}; + +TIFFGeneratorThread::TIFFGeneratorThread() + : QThread(), m_request( 0 ), m_pix( 0 ), m_tiff( 0 ) +{ +} + +void TIFFGeneratorThread::startGeneration( PixmapRequest* request, TIFF* tiff ) +{ + m_request = request; + m_tiff = tiff; + start( QThread::InheritPriority ); +} + +void TIFFGeneratorThread::endGeneration() +{ + m_request = 0; + m_tiff = 0; +} + +PixmapRequest* TIFFGeneratorThread::request() const +{ + return m_request; +} + +QPixmap* TIFFGeneratorThread::takePixmap() +{ + QPixmap* p = m_pix; + m_pix = 0; + return p; +} + +void TIFFGeneratorThread::run() +{ + bool generated = false; + m_pix = new QPixmap( m_request->width, m_request->height ); + + if ( TIFFSetDirectory( m_tiff, m_request->page->number() ) ) + { + int rotation = m_request->documentRotation; + 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 ); + QImage smoothImage = image.scaled( reqwidth, reqheight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); + QImage finalImage = rotation > 0 + ? KImageEffect::rotate( smoothImage, (KImageEffect::RotateDirection)( rotation - 1 ) ) + : smoothImage; + *m_pix = QPixmap::fromImage( finalImage ); + + generated = true; + } + } + + if ( !generated ) + { + m_pix->fill(); + } +} + + +OKULAR_EXPORT_PLUGIN(TIFFGenerator) + +TIFFGenerator::TIFFGenerator( KPDFDocument * document ) : Generator( document ), + d( new Private ), ready( false ) +{ + 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 d; +} + +bool TIFFGenerator::loadDocument( const QString & fileName, QVector & pagesVector ) +{ + // closing the old document + if ( d->tiff ) + { + TIFFClose( d->tiff ); + d->tiff = 0; + } + + d->tiff = TIFFOpen( QFile::encodeName( fileName ), "r" ); + if ( !d->tiff ) + return false; + + loadPages( pagesVector, 0 ); + + ready = true; + + return true; +} + +bool TIFFGenerator::canGeneratePixmap( bool /*async*/ ) +{ + return ready; +} + +void TIFFGenerator::generatePixmap( PixmapRequest * request ) +{ + ready = false; + + if ( request->async ) + { + thread->startGeneration( request, d->tiff ); + return; + } + + bool generated = false; + QPixmap * p = new QPixmap( request->width, request->height ); + + if ( TIFFSetDirectory( d->tiff, request->page->number() ) ) + { + int rotation = request->documentRotation; + 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 ); + QImage smoothImage = image.scaled( reqwidth, reqheight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); + QImage finalImage = rotation > 0 + ? KImageEffect::rotate( smoothImage, (KImageEffect::RotateDirection)( rotation - 1 ) ) + : smoothImage; + *p = QPixmap::fromImage( finalImage ); + + generated = true; + } + } + + if ( !generated ) + { + p->fill(); + } + + request->page->setPixmap( request->id, p ); + + ready = true; + + // signal that the request has been accomplished + signalRequestDone( request ); +} + +void TIFFGenerator::setOrientation( QVector & pagesVector, int orientation ) +{ + loadPages( pagesVector, orientation ); +} + +void TIFFGenerator::slotThreadFinished() +{ + PixmapRequest * request = thread->request(); + thread->endGeneration(); + + request->page->setPixmap( request->id, thread->takePixmap() ); + + ready = true; + + signalRequestDone( request ); +} + +void TIFFGenerator::loadPages( QVector & pagesVector, int rotation ) +{ + 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; + + if ( rotation % 2 == 1 ) + qSwap( width, height ); + + delete pagesVector[i]; + KPDFPage * page = new KPDFPage( i, width, height, rotation ); + pagesVector[i] = page; + + } +} + +#include "generator_tiff.moc" + diff --git a/generators/tiff/generator_tiff.h b/generators/tiff/generator_tiff.h new file mode 100644 index 000000000..d24209d13 --- /dev/null +++ b/generators/tiff/generator_tiff.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2006 by Pino Toscano * + * * + * 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. * + ***************************************************************************/ + +#ifndef _OKULAR_GENERATOR_TIFF_H_ +#define _OKULAR_GENERATOR_TIFF_H_ + +#include "core/generator.h" + +class TIFFGeneratorThread; + +class TIFFGenerator : public Generator +{ + Q_OBJECT + public: + TIFFGenerator( KPDFDocument * document ); + virtual ~TIFFGenerator(); + + bool loadDocument( const QString & fileName, QVector & pagesVector ); + + bool canGeneratePixmap( bool async ); + void generatePixmap( PixmapRequest * request ); + + bool supportsRotation() { return true; }; + void setOrientation( QVector & pagesVector, int orientation ); + + private slots: + void slotThreadFinished(); + + private: + class Private; + Private * const d; + + TIFFGeneratorThread* thread; + + void loadPages( QVector & pagesVector, int rotation ); + + bool ready; +}; + +#endif diff --git a/generators/tiff/libokularGenerator_tiff.desktop b/generators/tiff/libokularGenerator_tiff.desktop new file mode 100644 index 000000000..dc6a70197 --- /dev/null +++ b/generators/tiff/libokularGenerator_tiff.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Service +Name=okular TIFF Library +Comment=TIFF backend for okular +ServiceTypes=okular/Generator +MimeType=image/tiff; +X-KDE-Library=libokularGenerator_tiff +X-KDE-Priority=4 +X-KDE-okularAPIVersion=1 +X-KDE-okularHasInternalSettings=false