From 47d455dd55be855e4cc691c32f687f723d9247ee Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kpdf/ui/pagepainter.cpp | 252 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 kpdf/ui/pagepainter.cpp (limited to 'kpdf/ui/pagepainter.cpp') diff --git a/kpdf/ui/pagepainter.cpp b/kpdf/ui/pagepainter.cpp new file mode 100644 index 00000000..f68df254 --- /dev/null +++ b/kpdf/ui/pagepainter.cpp @@ -0,0 +1,252 @@ +/*************************************************************************** + * Copyright (C) 2005 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +// qt / kde includes +#include +#include +#include +#include +#include +#include + +// local includes +#include "pagepainter.h" +#include "core/page.h" +#include "conf/settings.h" + +void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags, + QPainter * destPainter, const QRect & limits, int width, int height ) +{ + QPixmap * pixmap = 0; + + // if a pixmap is present for given id, use it + if ( page->m_pixmaps.contains( id ) ) + pixmap = page->m_pixmaps[ id ]; + + // else find the closest match using pixmaps of other IDs (great optim!) + else if ( !page->m_pixmaps.isEmpty() && width != -1 ) + { + int minDistance = -1; + QMap< int,QPixmap * >::const_iterator it = page->m_pixmaps.begin(), end = page->m_pixmaps.end(); + for ( ; it != end; ++it ) + { + int pixWidth = (*it)->width(), + distance = pixWidth > width ? pixWidth - width : width - pixWidth; + if ( minDistance == -1 || distance < minDistance ) + { + pixmap = *it; + minDistance = distance; + } + } + } + + // if have no pixmap, draw blank page with gray cross and exit + if ( !pixmap ) + { + QColor color = Qt::white; + if ( KpdfSettings::changeColors() ) + { + switch ( KpdfSettings::renderMode() ) + { + case KpdfSettings::EnumRenderMode::Inverted: + color = Qt::black; + break; + case KpdfSettings::EnumRenderMode::Paper: + color = KpdfSettings::paperColor(); + break; + case KpdfSettings::EnumRenderMode::Recolor: + color = KpdfSettings::recolorBackground(); + break; + default: ; + } + } + destPainter->fillRect( limits, color ); + + // draw a cross (to that the pixmap as not yet been loaded) + // helps a lot on pages that take much to render + destPainter->setPen( Qt::gray ); + destPainter->drawLine( 0, 0, width-1, height-1 ); + destPainter->drawLine( 0, height-1, width-1, 0 ); + // idea here: draw a hourglass (or kpdf icon :-) on top-left corner + return; + } + + // find out what to paint over the pixmap (manipulations / overlays) + bool paintAccessibility = (flags & Accessibility) && KpdfSettings::changeColors() && (KpdfSettings::renderMode() != KpdfSettings::EnumRenderMode::Paper); + bool paintHighlights = (flags & Highlights) && !page->m_highlights.isEmpty(); + bool enhanceLinks = (flags & EnhanceLinks) && KpdfSettings::highlightLinks(); + bool enhanceImages = (flags & EnhanceImages) && KpdfSettings::highlightImages(); + // check if there are really some highlightRects to paint + if ( paintHighlights ) + { + // precalc normalized 'limits rect' for intersection + double nXMin = (double)limits.left() / (double)width, + nXMax = (double)limits.right() / (double)width, + nYMin = (double)limits.top() / (double)height, + nYMax = (double)limits.bottom() / (double)height; + // if no rect intersects limits, disable paintHighlights + paintHighlights = false; + QValueList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end(); + for ( ; hIt != hEnd; ++hIt ) + { + if ( (*hIt)->intersects( nXMin, nYMin, nXMax, nYMax ) ) + { + paintHighlights = true; + break; + } + } + } + + // use backBuffer if 'pixmap direct manipulation' is needed + bool backBuffer = paintAccessibility || paintHighlights; + QPixmap * backPixmap = 0; + QPainter * p = destPainter; + if ( backBuffer ) + { + // let's paint using a buffered painter + backPixmap = new QPixmap( limits.width(), limits.height() ); + p = new QPainter( backPixmap ); + p->translate( -limits.left(), -limits.top() ); + } + + // 1. fast blit the pixmap if it has the right size.. + if ( pixmap->width() == width && pixmap->height() == height ) + p->drawPixmap( limits.topLeft(), *pixmap, limits ); + // ..else set a scale matrix to the painter and paint a quick 'zoomed' pixmap + else + { + p->save(); + // TODO paint only the needed part (note: hope that Qt4 transforms are faster) + p->scale( width / (double)pixmap->width(), height / (double)pixmap->height() ); + p->drawPixmap( 0,0, *pixmap, 0,0, pixmap->width(), pixmap->height() ); + p->restore(); + } + + // 2. mangle pixmap: convert it to 32-bit qimage and perform pixel-level manipulations + if ( backBuffer ) + { + QImage backImage = backPixmap->convertToImage(); + // 2.1. modify pixmap following accessibility settings + if ( paintAccessibility ) + { + switch ( KpdfSettings::renderMode() ) + { + case KpdfSettings::EnumRenderMode::Inverted: + // Invert image pixels using QImage internal function + backImage.invertPixels(false); + break; + case KpdfSettings::EnumRenderMode::Recolor: + // Recolor image using KImageEffect::flatten with dither:0 + KImageEffect::flatten( backImage, KpdfSettings::recolorForeground(), KpdfSettings::recolorBackground() ); + break; + case KpdfSettings::EnumRenderMode::BlackWhite: + // Manual Gray and Contrast + unsigned int * data = (unsigned int *)backImage.bits(); + int val, pixels = backImage.width() * backImage.height(), + con = KpdfSettings::bWContrast(), thr = 255 - KpdfSettings::bWThreshold(); + for( int i = 0; i < pixels; ++i ) + { + val = qGray( data[i] ); + if ( val > thr ) + val = 128 + (127 * (val - thr)) / (255 - thr); + else if ( val < thr ) + val = (128 * val) / thr; + if ( con > 2 ) + { + val = con * ( val - thr ) / 2 + thr; + if ( val > 255 ) + val = 255; + else if ( val < 0 ) + val = 0; + } + data[i] = qRgba( val, val, val, 255 ); + } + break; + } + } + // 2.2. highlight rects in page + if ( paintHighlights ) + { + // draw highlights that are inside the 'limits' paint region + QValueList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end(); + for ( ; hIt != hEnd; ++hIt ) + { + HighlightRect * r = *hIt; + QRect highlightRect = r->geometry( width, height ); + if ( highlightRect.isValid() && highlightRect.intersects( limits ) ) + { + // find out the rect to highlight on pixmap + highlightRect = highlightRect.intersect( limits ); + highlightRect.moveBy( -limits.left(), -limits.top() ); + + // highlight composition (product: highlight color * destcolor) + unsigned int * data = (unsigned int *)backImage.bits(); + int val, newR, newG, newB, + rh = r->color.red(), + gh = r->color.green(), + bh = r->color.blue(), + offset = highlightRect.top() * backImage.width(); + for( int y = highlightRect.top(); y <= highlightRect.bottom(); ++y ) + { + for( int x = highlightRect.left(); x <= highlightRect.right(); ++x ) + { + val = data[ x + offset ]; + newR = (qRed(val) * rh) / 255; + newG = (qGreen(val) * gh) / 255; + newB = (qBlue(val) * bh) / 255; + data[ x + offset ] = qRgba( newR, newG, newB, 255 ); + } + offset += backImage.width(); + } + } + } + } + backPixmap->convertFromImage( backImage ); + } + + // 3. visually enchance links and images if requested + if ( enhanceLinks || enhanceImages ) + { + QColor normalColor = QApplication::palette().active().highlight(); + QColor lightColor = normalColor.light( 140 ); + // enlarging limits for intersection is like growing the 'rectGeometry' below + QRect limitsEnlarged = limits; + limitsEnlarged.addCoords( -2, -2, 2, 2 ); + // draw rects that are inside the 'limits' paint region as opaque rects + QValueList< ObjectRect * >::const_iterator lIt = page->m_rects.begin(), lEnd = page->m_rects.end(); + for ( ; lIt != lEnd; ++lIt ) + { + ObjectRect * rect = *lIt; + if ( (enhanceLinks && rect->objectType() == ObjectRect::Link) || + (enhanceImages && rect->objectType() == ObjectRect::Image) ) + { + QRect rectGeometry = rect->geometry( width, height ); + if ( rectGeometry.intersects( limitsEnlarged ) ) + { + // expand rect and draw inner border + rectGeometry.addCoords( -1,-1,1,1 ); + p->setPen( lightColor ); + p->drawRect( rectGeometry ); + // expand rect to draw outer border + rectGeometry.addCoords( -1,-1,1,1 ); + p->setPen( normalColor ); + p->drawRect( rectGeometry ); + } + } + } + } + + // 4. if was backbuffering, copy the backPixmap to destination + if ( backBuffer ) + { + delete p; + destPainter->drawPixmap( limits.left(), limits.top(), *backPixmap ); + delete backPixmap; + } +} -- cgit v1.2.1